Subject: Re: [TI994A] VDP throughput (was: Re: TMS9918 demo)

From: "Tursi" <[email-masked]>
Date: Tue, 10 Nov 2009 17:45:14 -0500

> I think Paul Urbanus later told that it was about 2 times faster to 
> use ScratchPad opposed to going thru the multiplexer while testing the 
> scroll of surface in Parsec. Guess it was a combination of workspace, 
> variables, code and static data.
>

This is well known and not contested, however, in this particular test, 
everything was in scratchpad (code and registers both), so the 
multiplexer doesn't come into it.

Even better, assuming that the rest of the test matches my original 
code, R13 points to memory that IS on the 8-bit bus, meaning that the 
MOV *R13,*R12 should be triggering the multiplexer for the *R13 part, 
but the MOV R13,*R12 should not. Yet it's the former that is much 
faster!

So.. yeah, I think we definately need a peek under the hood. Will add 
this to my queue and try to run a test under the analyzer, unless 
someone else has one? :)

---

From: Insane Multitasker <[email-masked]>
Date: Tue, 10 Nov 2009 16:56:16 -0600

Isn't Paul a member of the SWPB group?   :)
 
> To: [email-masked]
> From: [email-masked]
> Date: Tue, 10 Nov 2009 17:45:14 -0500
> Subject: Re: [TI994A] VDP throughput (was: Re: TMS9918 demo)
> 
> ------------------------------------
> 
> Yahoo! Groups Links
> 
> 
> 
 		 	   		  
_________________________________________________________________
Find the right PC with Windows 7 and Windows Live. 
http://www.microsoft.com/Windows/pc-scout/laptop-set-criteria.aspx?cbid=wl&filt=200,2400,10,19,1,3,1,7,50,650,2,12,0,1000&cat=1,2,3,4,5,6&brands=5,6,7,8,9,10,11,12,13,14,15,16&addf=4,5,9&ocid=PID24727::T:WLMTAGL:ON:WL:en-US:WWL_WIN_evergreen2:112009

---

From: Marc Hull <[email-masked]>
Date: Tue, 10 Nov 2009 15:32:28 -0800 (PST)

Where does the second BYTE in the address pointed to by R13 go?

--- On Tue, 11/10/09, kabldb <[email-masked]> wrote:

From: kabldb <[email-masked]>
Subject: [TI994A] VDP throughput (was: Re: TMS9918 demo)
To: [email-masked]
Date: Tuesday, November 10, 2009, 4:28 PM

  

      Wow !

I guess @VDPWD (the value >8c00) is located outside ScratchPad RAM, while *R12 gets the value (>8c00) from ScratchPad RAM.

The funny thing about MOV *R13,*R12 is that the first part (*R13) is indirect (get value in R13 and use that to get value), while the last part (*R12) just gets the value in R12.

http://tech. groups.yahoo. com/group/ ti99-4a/message/ 45333

I think Paul Urbanus later told that it was about 2 times faster to use ScratchPad opposed to going thru the multiplexer while testing the scroll of surface in Parsec. Guess it was a combination of workspace, variables, code and static data.

:-)

--- In TI994A@yahoogroups. com, "Matthew" <matthew@... > wrote:

> Okay, here my initial numbers.  I ran 3 versions of the program (VDP1, VDP2, VDP3) 5 times each and took an average.  The second two versions have R12 loaded with the VDPWD address.

> VDPWD >8C00

> LI R12,VDPWD

> MOV *R13,@VDPWD

> VDP1: 1576 1576 1584 1608 1608 = 1590

> MOV *R13,*R12

> VDP2: 3728 3728 3768 3840 3856 = 3784 2.37x (237.98%) faster than VDP1

> MOV R13,*R12

> VDP3: 3896 3904 3920 3928 3968 = 3923 0.03x (  3.60%) faster than VDP2

> What I want to know is, why is the indirect addressing so much faster than the symbolic (direct) access?  The datasheet indicates that the only difference should be about 4 clock cycles per instruction:

>  14   +4   +8

> MOV *R13,>8C00

>  14   +4   +4

> MOV *R13,*R12

> How do we get such a huge discrepancy?  Writing to the VDP aside, this is a big deal as it greatly affects the ability to write an accurate emulator.  According to the 9900 datasheet, the time difference between VDP1 and VDP2 should be similar to the difference between VDP2 and VDP3.

> Matthew

---

From: ti99_forever <[email-masked]>
Date: Tue, 10 Nov 2009 15:37:03 -0800 (PST)

Well, >8C00 is the port, so one byte is written to the port, the next is written to >8C01, effectively nowhere...
Hit me if I'm wrong...

--- On Tue, 11/10/09, Marc Hull <[email-masked]> wrote:

From: Marc Hull <[email-masked]>
Subject: Re: [TI994A] VDP throughput (was: Re: TMS9918 demo)
To: [email-masked]
Date: Tuesday, November 10, 2009, 6:32 PM

  

--- On Tue, 11/10/09, kabldb <kabldb@yahoo. dk> wrote:

From: kabldb <kabldb@yahoo. dk>
Subject: [TI994A] VDP throughput (was: Re: TMS9918 demo)
To: TI994A@yahoogroups. com
Date: Tuesday, November 10, 2009, 4:28 PM

    

      Wow !

:-)

--- In TI994A@yahoogroups. com, "Matthew" <matthew@... > wrote:

---

From: "Tursi" <[email-masked]>
Date: Tue, 10 Nov 2009 18:37:37 -0500

>Where does the second BYTE in the address pointed to by R13 go?

No where. The VDP is attached to the 16-bit bus, but only to half of it, 
as it's an 8-bit device.

---

From: Marc Hull <[email-masked]>
Date: Tue, 10 Nov 2009 15:39:34 -0800 (PST)

I thought that the >8300 space was not completely decoded.  Are your sure your not writing the MSB and then the LSB to >8300?  I am assuming that MOV is a faster instruction than MOVB?

--- On Tue, 11/10/09, ti99_forever <[email-masked]> wrote:

From: ti99_forever <[email-masked]>
Subject: Re: [TI994A] VDP throughput (was: Re: TMS9918 demo)
To: [email-masked]
Date: Tuesday, November 10, 2009, 5:37 PM

  

--- On Tue, 11/10/09, Marc Hull <marc.hull@sbcglobal .net> wrote:

From: Marc Hull <marc.hull@sbcglobal .net>
Subject: Re: [TI994A] VDP throughput (was: Re: TMS9918 demo)
To: TI994A@yahoogroups. com
Date: Tuesday, November 10, 2009, 6:32 PM

    

 

      Wow !

:-)

--- In TI994A@yahoogroups. com, "Matthew" <matthew@... > wrote:

---

From: "Matthew" <[email-masked]>
Date: Tue, 10 Nov 2009 23:46:51 -0000

> this to my queue and try to run a test under the analyzer, unless 

The code I am using is what you (Tursi) posted on the 99er forum.  All reads and writes are to/from 16-bit memory.  I have only modified the MOV instruction in the loop and added the LI R12,>8C00.  However, I don't understand what you mean by the MOV *R13,*R12 triggering the multiplexer.  From what I can see it should not.  R13 is loaded such:

LI R13,>8300

So, in the original form:

MOV *R13,@>8C00

That moves the word at >8300 (*R13) to >8C00.  As we know, both >8300 and the VDP at >8C00 are on the 16-bit bus.  Also, the workspace is set to >8300, so that instruction essentially moves the MSB of R0 to the VDP.

MOV *R13,*R12

Does exactly the same as the first instruction with the *only* difference being that in the first form, the immediate value of >8C00 follows the instruction in memory and causes 4 extra cycles.

MOV R13,*R12

This was my attempt to speed up the write even more by simply removing one of the indirect references.  Basically the MSB of the the 16-bit value in R13 is being written to the VDP.  In this particular case, >83 is being written since R13 was loaded with >8300.  This could be used in a practical way to write the same data to many addresses in the VDP RAM, like when initializing the VDP RAM or clearing the screen.

Tursi, if you have an analyzer to clock the real hardware then, well, that is awesome! ;-)  I still really want to know why symbolic addressing is so much slower than the register indirect.  It does not make sense, and the 9900 datasheet specifies it should only be 4 clocks per instruction different, which simply does not add up to much, and certainly not the 2x speed up we are seeing.

Matthew

---

From: Marc Hull <[email-masked]>
Date: Tue, 10 Nov 2009 15:50:00 -0800 (PST)

So the VDP is connected to A0-A7 only ?  Still why the MOV and not MOVB?  Also in the tests.... were the Registers in scratchpad while the code was in 8 bit memory?  I have a sneaking suspicion that this has more to do with 16 bit memory than the instructions.  Of course that's only conjecture on my part.... Bad Marc....  ;-)

--- On Tue, 11/10/09, Tursi <[email-masked]> wrote:

From: Tursi <[email-masked]>
Subject: Re: [TI994A] VDP throughput (was: Re: TMS9918 demo)
To: [email-masked]
Date: Tuesday, November 10, 2009, 5:37 PM

  

as it's an 8-bit device.

---

From: "Matthew" <[email-masked]>
Date: Tue, 10 Nov 2009 23:59:03 -0000

--- In [email-masked], Marc Hull <marc.hull@...> wrote:
>
> I thought that the >8300 space was not completely decoded.Â  Are your sure your not writing the MSB and then the LSB to >8300?Â  I am assuming that MOV is a faster instruction than MOVB?
> 
>

The addresses from >8000 to >83FF are not fully decoded.  That's why the 256 byte scratch pad RAM can be addressed at:

>8000 to >80FF
>8100 to >81FF
>8200 to >82FF
>8300 to >83FF

Basically >8000 to >9000 are for memory mapped devices and huge chunks of the addresses are not decoded or used.  The VDP is mapped in at a few addresses:

VDPRD  EQU  >8800             VDP RAM READ DATA
VDPSTA EQU  >8802             VDP RAM STATUS
VDPWD  EQU  >8C00             VDP RAM WRITE DATA
VDPWA  EQU  >8C02             VDP RAM READ/WRITE ADDRESS

Notice the 1K of address space between the read and write mappings!  That is painful when memory on these machines is already so limited.

Anyway, the base MOV and MOVB instructions take the same number of clock cycles (14) and the same number of memory accesses (4).  There are modifiers depending on the addressing type (register indirect, symbolic, indexed, and auto increment).  But the modifiers are almost identical for both instructions as well.

So, the individual instructions are pretty much equal.  Where you can see big differences is when doing things like block moves.  MOV can move 2 bytes in the same time MOVB can only move 1 byte.  So even though both execute in the same time, MOV can do twice as much as MOVB if the situation is right.

Matthew

---

From: "Matthew" <[email-masked]>
Date: Wed, 11 Nov 2009 00:02:40 -0000

> So the VDP is connected to A0-A7 only ?  Still why the MOV and not MOVB?  Also in the tests.... were the Registers in scratchpad while the code was in 8 bit memory?  I have a sneaking suspicion tha…

Nope, the workspace and the critical loop are in 16-bit scratch pad RAM.  You can see the code here:

http://www.99er.net/cgi-bin/ikonboard/ikonboard.cgi?act=ST;f=3;t=23

I'll save you having to click the link, here is the critical section:

       AORG >8310
WAITS1 MOVB @VDPSTA,R1
       COC @STAT,R1
       JNE WAITS1
* WE GOT A SYNC, START COPYING
TIGHTL MOV *R13,@VDPWD
       MOV *R13,@VDPWD
       MOV *R13,@VDPWD
       MOV *R13,@VDPWD
       MOV *R13,@VDPWD
       MOV *R13,@VDPWD
       MOV *R13,@VDPWD
       MOV *R13,@VDPWD

      DEC R14
      JNE TIGHTL
* CHECK IF THE SYNC ALREADY HAPPENED
      MOVB @VDPSTA,R1
      B @RESUME

      RORG
RESUME COC @STAT,R1

As for MOV vs. MOVB, no reason really since in this case it *should* not make any difference.  Hmm.  Maybe I'll test that. :-)

Matthew

---

From: "Tursi" <[email-masked]>
Date: Tue, 10 Nov 2009 19:06:22 -0500

>I thought that the >8300 space was not completely decoded. Are your 
>sure your not writing the MSB and then the LSB to >>8300? I am assuming 
>that MOV is a faster instruction than MOVB?

The scratchpad is not completely decoded - it reponds from >8000 to 
 >83FF. But I think you are confused about what this means, or you meant 
to write >8C00.

The VDP (at >8C00) is slightly better decoded, at least at the 
individual index level, but there is no A15 to the video chip and thus 
there /is/ no byte address involved. >8C00 in a single write is all that 
happens. Remember that the byte address is a feature of the multiplexer, 
the 9900 CAN NOT access byte addresses as it only as 15 addresss bits. 
It only deals in words. The decoding still is pretty loose, but A14 is 
connected to the VDP port select so that >8C02 has a different meaning.

So if you access >8C00 or >8C01 with a MOV instruction, the actual 
result on the bus is the same, because you can only move to even 
addresses. Both will do a move to >8C00. If you use a MOVB to >8C01, the 
results to the video chip are relatively unpredictable, since the CPU 
will read 16 bits from >8C00 (and not get anything useful), modify the 
wrong byte, then write the result back (I suspect it'll write 0).

Since the video chip is not after the multiplexor, it is handled by the 
16-bit bus. However, Theirry's page asserts that the wait state 
generator is still engaged, so it still induces a delay to access it.

MOV is not faster than MOVB. In fact the only difference is inside the 
chip. Both instructions go out and read 16 bits, modify that word, then 
write back 16 bits. The datasheet shows both need 14 clock cycles and 4 
memory accesses. The only difference is that MOV replaces both bytes 
internally, while MOVB only replaces one.

---

From: "Tursi" <[email-masked]>
Date: Tue, 10 Nov 2009 19:11:46 -0500

> The code I am using is what you (Tursi) posted on the 99er forum.  All 
> reads and writes are to/from 16-bit memory.  I have only modified the 
> MOV instruction in the loop and added the LI R12,>8C00.  However, I 
> don't understand what you mean by the MOV *R13,*R12 triggering the 
> multiplexer.  From what I can see it should not.  R13 is loaded such:
> LI R13,>8300

Ah.... just bad memory on my part, then. The original goal of that test 
was not merely "as fast as possible", but "as fast as possible from the 
cartridge port", so it was originally using 8-bit RAM as a source.

Being not the case here, that's fine. :)

> This was my attempt to speed up the write even more by simply removing 
> one of the indirect references.  Basically the MSB of the the 16-bit 
> value in R13 is being written to the VDP.  In this particular case, 
>  >83 is being written since R13 was loaded with >8300.  This could be 
> used in a practical way to write the same data to many addresses in 
> the VDP RAM, like when initializing the VDP RAM or clearing the 
> screen.
>

ugh..  see.. I misread the message. When I read "3.60% faster" I thought 
you were comparing /both/ tests to the first one -- so I was stunned 
that this was slower than form 2!! Now I see it's not, and it makes a 
heck of a lot more sense. :) I have looked back and I see I needed to 
read the numbers more carefully. :) Almost 4k per frame! Pretty nice!

> Tursi, if you have an analyzer to clock the real hardware then, well, 
> that is awesome! ;-)  I still really want to know why symbolic 
> addressing is so much slower than the register indirect.  It does not 
> make sense, and the 9900 datasheet specifies it should only be 4 
> clocks per instruction different, which simply does not add up to 
> much, and certainly not the 2x speed up we are seeing.
>

Yeah.. back to the theory I proposed, then, it MUST have to do with 
instruction fetch... the datasheet probably is not taking instruction 
fetch time into account (although the memory cycles count seems to imply 
it does!)

I have the analyzer, I just need some time. :)

---

From: Marc Hull <[email-masked]>
Date: Tue, 10 Nov 2009 16:14:09 -0800 (PST)

Did you REF VDPWD in the source or did you equate an address in scratchpad to >8300?

--- On Tue, 11/10/09, Matthew <[email-masked]> wrote:

From: Matthew <[email-masked]>
Subject: [TI994A] Re: VDP throughput (was: Re: TMS9918 demo)
To: [email-masked]
Date: Tuesday, November 10, 2009, 6:02 PM

  

      --- In TI994A@yahoogroups. com, Marc Hull <marc.hull@. ..> wrote:

> So the VDP is connected to A0-A7 only ?Â  Still why the MOV and not MOVB?Â  Also in the tests.... were the Registers in scratchpad while the code was in 8 bit memory?Â  I have a sneaking suspicion that this has more to do with 16 bit memory than the instructions.Â  Of course that's only conjecture on my part.... Bad Marc....Â  ;-)

http://www.99er. net/cgi-bin/ ikonboard/ ikonboard. cgi?act=ST; f=3;t=23

AORG >8310

WAITS1 MOVB @VDPSTA,R1

       COC @STAT,R1

       JNE WAITS1

TIGHTL MOV *R13,@VDPWD

       MOV *R13,@VDPWD

       MOV *R13,@VDPWD

       MOV *R13,@VDPWD

       MOV *R13,@VDPWD

       MOV *R13,@VDPWD

       MOV *R13,@VDPWD

       MOV *R13,@VDPWD

DEC R14

      JNE TIGHTL

      MOVB @VDPSTA,R1

      B @RESUME

RORG

RESUME COC @STAT,R1

Matthew

---

From: "Matthew" <[email-masked]>
Date: Wed, 11 Nov 2009 00:33:20 -0000

> I have the analyzer, I just need some time. :)

Get crackin'!! ;-)

I don't know how instruction fetch could be a cause?  Even if the multiplexer is engaged as Thierry's page indicates, it should affect the register indirect the same as the symbolic reference!?  I'm pretty sure the datasheet is taking all the fetch times into consideration too.  I've been doing the calculations on those instructions all day long and cannot come up with anything.

But yeah, almost 4K per second is pretty nice!  I only wish I knew exactly how we were doing it. ;-)  Also keep in mind that this does not test the accuracy of the writes yet.  We could be missing a ton of that data.

Matthew

---

From: "Tursi" <[email-masked]>
Date: Tue, 10 Nov 2009 21:46:11 -0500

> I don't know how instruction fetch could be a cause?  Even if the 
> multiplexer is engaged as Thierry's page indicates, it should affect 
> the register indirect the same as the symbolic reference!?  I'm pretty 
> sure the datasheet is taking all the fetch times into consideration 
> too.  I've been doing the calculations on those instructions all day 
> long and cannot come up with anything.
>

Nothing to do with the multiplexor or wait state generator, just the 
length of the instruction. MOV *R13,@>8C00 is twice as long in memory as 
MOV *R13,*R12. ;)

The datasheet is obviously not taking something into account, because it 
comes up short. If you want to discount theory A (without evidence), you 
have to come up with theory B (at least, that's the rule we use for 
choosing where to go for lunch at work ;) ).

---

From: mark wills <[email-masked]>
Date: Tue, 10 Nov 2009 20:29:11 -0800 (PST)

Matthew

Could it be the longer instruction?

MOV *Rx,*Rx - 2 bytes
MOV *Rx,Rx - 2 bytes
MOV Rx,*Rx - 2 bytes
MOV Rx,Rx - 2 bytes
MOV Rx,@ADDR - 4 bytes <-------

This would surely take at least twice as long to fetch from memory? Two memory fetch cylces, instead of one?

Mark.

>Sent: Wed, 11 November, 2009 1:33:20

---

From: mark wills <[email-masked]>
Date: Tue, 10 Nov 2009 20:30:59 -0800 (PST)

Ah, Tursi beat me to it ;-)

>
>From: mark wills <[email-masked]>
>Sent: Wed, 11 November, 2009 5:29:11
>Subject: Re: [TI994A] Re: VDP throughput (was: Re: TMS9918 demo)
>
> >
>
>
>
>
>  >
>>      
> 
>Matthew
>
>>From: Matthew <matthew@mundomateo. com>

---

From: "Tursi" <[email-masked]>
Date: Wed, 11 Nov 2009 00:11:32 -0500

>>Ah, Tursi beat me to it ;-)

Only three times so far this week (and several times in the original 
thread). I sometimes get the feeling nobody's listening... ;)

---

From: "Matthew" <[email-masked]>
Date: Wed, 11 Nov 2009 06:10:39 -0000

> choosing where to go for lunch at work ;) ).

Haha, I like that lunch theory!  Can I use that with my wife too? ;-)

As for the instruction, yes it is twice as long *in memory*, since the instruction is stored as 1 word (16-bit) and the symbolic address is stored in memory following the instruction.  However the symbolic addressing only adds a single memory read over the source and target register indirect.

PC = program counter
WP = workspace pointer

The fastest MOV instruction is 14 clocks and 4 memory accesses:

MOV R13,R12

Fetch instruction at PC (read 1)
PC+2
decode
Fetch src value from WP+26 (R13) (read 2)
Fetch dst value from WP+24 (R12) (read 3)
Store src value to WP+24 (R12) (write 1)

The 3rd read is not necessary in this case, but demonstrates the read-before-write that the 9900 does to facilitate the byte operations.

The other addressing modes add "modifiers" to the clock cycles and memory accesses.  Indirect addressing adds 1 memory access and 4 clocks for each operand that uses indirect addressing:

MOV *R13,*R12

Fetch instruction at PC (read 1)
PC+2
decode
Fetch src value from WP+26 (R13) (read 2)
Fetch src value from memory by using current src value as an address (read 3)
Fetch dst value from WP+24 (R12) (read 4)
Fetch dst value from memory by using current dst value as an address (read 5)
Store src value to memory by using current dst value as an address (write 1)

So this is the normal 4 memory accesses plus the two additional accesses needed because of the indirect addressing.

The symbolic addressing does not add any memory accesses over the previous indirect move:

MOV *R13,@>8C00

Fetch instruction at PC (read 1)
PC+2
decode
Fetch src value from WP+26 (R13) (read 2)
Fetch src value from memory by using current src value as an address (read 3)
Fetch dst value from address at the PC (read 4)
PC+2
Fetch dst value from memory by using current dst value as an address (read 5)
Store src value to memory by using current dst value as an address (write 1)

The only difference is in the symbolic version the PC has to be incremented after reading the symbolic address which immediately follows the instruction in memory.  I can't believe the internal incrementing of the PC would double the execution time...  Also, the datasheet seems to take this into account because using symbolic addressing adds 1 memory access per operand and 8 clocks vs. the 1 memory access and 4 clocks for immediate addressing:

C = extra clocks
M = extra memory accesses

           C   M
indirect | 4 | 1
symbolic | 8 | 1

The MOV *R13,*R12 should only be 4 clock cycles longer than MOV *R13,@>8C00 yet as we have seen it is more that twice as fast.  AND, since the 9900 is all memory based registers, technically MOV R13,R12 is the same as symbolic except the WP holds the base address so you don't need the extra read.  Symbolic addressing is also called "memory direct" in the datasheet... hmm... Seems direct memory access would be the fastest.

There is something we are not being told about symbolic addressing.  Also, all this assumes memory on the 16-bit address/data bus, which is where the test was run.

Matthew

---

From: ti99_forever <[email-masked]>
Date: Wed, 11 Nov 2009 03:40:37 -0800 (PST)

You know guys? I think it may have to do with the instruction length and fetch times, because the one instruction with the indirect memory address is longer than the other.
Whaddya think? 
(ducks and runs for cover)

--- On Wed, 11/11/09, Tursi <[email-masked]> wrote:

From: Tursi <[email-masked]>
Subject: Re: [TI994A] Re: VDP throughput (was: Re: TMS9918 demo)
To: [email-masked]
Date: Wednesday, November 11, 2009, 12:11 AM

  

      >>>This would surely take at least twice as long to fetch from memory? 

>>>Two memory fetch cylces, instead of one?

---

From: "Tursi" <[email-masked]>
Date: Wed, 11 Nov 2009 15:51:23 -0500

> As for the instruction, yes it is twice as long *in memory*, since the 
> instruction is stored as 1 word (16-bit) and the symbolic address is 
> stored in memory following the instruction.  However the symbolic 
> addressing only adds a single memory read over the source and target 
> register indirect.
>

This is interesting...

I loaded it up in Classic99, just to make sure we were not missing 
anything obvious. It doesn't run.

Even better, so far as I can see, it shouldn't run.

In looking through it, I see the code in scratchpad is corrupted. While 
I don't know all the reasons (I suspect Editor/Assembler is partially 
responsible), one thing that's clear is that the workspace overlaps the 
code. The WP is at >8300 and the code starts at >8310, which is R8. 
Anything R8 or higher will corrupt the code.

Did you make any changes to the code?

Any chance you can try and make it run in the emulator? That, or add a 
copy loop to the test code on the real TI that copies it into scratchpad 
before running it, to make sure it's valid. (And change the WP).

I did try changing just the WP (to >83E0), but that didn't fix the 
corruption in the scratchpad code.

This is starting to make a little more sense, but I can't play with it 
more right this moment. We may be seeing simple corruption of the code 
in such a way that it APPEARS that much faster... ;) If you can't get to 
it I will take a few minutes after work to try it out again. :)

---

From: Insane Multitasker <[email-masked]>
Date: Wed, 11 Nov 2009 16:26:46 -0600

I looked at the 99er forum today but could not find the test code.  Curiosity got the 

best of me ;)   So... could someone point me in the right direction?  I'd like to try the code on my Geneve...

_________________________________________________________________
Hotmail: Trusted email with powerful SPAM protection.
http://clk.atdmt.com/GBL/go/177141665/direct/01/

---

From: "Tursi" <[email-masked]>
Date: Wed, 11 Nov 2009 18:49:43 -0500

>I'd like to try the code on my Geneve...

It's under "Projects->VDP Access Speed": 
http://www.99er.net/cgi-bin/ikonboard/ikonboard.cgi?act=ST;f=3;t=23;st=0

---

From: "Matthew" <[email-masked]>
Date: Thu, 12 Nov 2009 03:53:03 -0000

> it I will take a few minutes after work to try it out again. :)

Wow, you are correct.  The WP is set to >8300 and the AORG is >8310 which is only 16 bytes, not 32.  I thought about that actually, and I should have noticed that the AORG was wrong.  Ah well.

I figured I could just change the AORG to >8320 for the critical code, but when I did that some *very* weird things happen when I try to load via EA3.  The screen totally wigs out in a way I have never seen before, like there is no video signal or as if the video cable came loose or something.  Power off/on fixes everything, try to load via EA3 again and I get the same problem.

Based on what I see happening on the real hardware, it is no wonder it crashes in the emulator.  At first I thought maybe the loader was using part of the scratch pad RAM, but the EA manual says the loader loads into the low 32K expansion area.

I'm not sure what is going on yet, but I'll post something when I have some sort of results.

Matthew

---

From: "Tursi" <[email-masked]>
Date: Thu, 12 Nov 2009 00:19:16 -0500

> Based on what I see happening on the real hardware, it is no wonder it 
> crashes in the emulator.  At first I thought maybe the loader was 
> using part of the scratch pad RAM, but the EA manual says the loader 
> loads into the low 32K expansion area.
>

The loader itself doesn't, but the GPL interpreter that is running it, 
does.

I've been working for a little while -- you got me to get my PEB out of 
storage. It's hooked up (on my bed, no place of honor yet), and I got it 
all working. I /just/ built a version of the code that runs on the 
emulator, and am about to run it on the real hardware...

First run (MOV *R13,@VDPWD) - 0558 = 1368 bytes (hmm... lower than your 
score... but got this twice in a row.)

Second run (MOV *R13,*R12) - 0600 = 1536 bytes. (two runs again)

So now we see the shorter instruction length is still faster, but 
(probably due to the extra memory access), only 168 bytes per frame 
faster. Also, on my system at least, the results seem a lot more 
consistent, which makes sense since they /shouldn't/ vary unless you 
have LOAD interrupts coming in (others are masked out).

I'd say that result makes a hell of a lot more sense, even if it's 
disappointing (Marc, I guess you can come out from under your desks, my 
new code isn't fast enough to track you after all ;) ). I've been 
wanting to understand those results since I first got them.

According to the disassembly in Classic99, the scratchpad is completely 
hosed by the time the test starts -- and one of the most damaging things 
is that it doesn't actually wait for the vsync, because the jump 
instruction for the test is one of the corrupted instructions.

These results are disappointing. But NOW you guys have me on your side, 
I do believe on a non-accelerated console that it is very likely you can 
pump VDP data... I'll leave that proof to you, Matt. I'm really glad you 
dug this out.

The nice side of this means of testing (from scratchpad), is that if the 
code works, it's /also/ safe for machines with all RAM on the 16-bit 
bus. Only machines that actually overclock the system should have any 
problem.

Pasted below is the new version of the code (slow version) -- this 
version copies the test into scratchpad right before executing it to 
avoid any issues from GPL or the loader:

      DEF START
      REF VWTR,VDPWA,VDPWD,VDPSTA
      REF VSBW
      REF GPLLNK

   AORG >a000
TABLE  TEXT '0123456789ABCDEF'
      EVEN
STAT   BYTE >80
      EVEN
* SET UP BITMAP MODE
* JUST SETTING THE MODE, NOT THE TABLES

START  LWPI >8300
      LIMI >0000
      LI R0,>0002
      BLWP @VWTR
* OPTIONAL CODE - BLANK THE SCREEN TO
* REMOVE VDP WAITS (NO EFFECT ON THIS TEST
* SPEED, BUT MAY HELP IF WRITES FAIL)
*      LI R0,>01A0
*      BLWP @VWTR

* DISABLE SPRITES TO REDUCE THEIR IMPACT
* BY SETTING THE FIRST ONE TO DISABLED
      LI R0,>0503
      BLWP @VWTR        * >1800
      LI R0,>1800
      LI R1,>D0D0
      BLWP @VSBW

* COPY FROM WAITS1 TO RESUME TO SCRATCHPAD
      LI R0,WAITS1
      LI R1,>8320
CPCLP MOV *R0+,*R1+
      CI R0,RESUME
      JL CPCLP

* NOW WE RUN THE TEST, A COUNT LIVES
* IN R15. WE HAVE TO USE DIRECT ACCESS
* TO THE VDP AS BLWP IS TOO SLOW
      LI R15,>0200
TESTLP MOV R15,R14
      LI R13,>8300      * ADDRESS TO READ
* SET START ADDRESS TO >1802 FOR MAX ROOM
* TWO MS BITS ARE 01 FOR WRITE MODE (NO PREFETCH)
* THEN SWAP BYTES FOR LSB FIRST
      LI R0,>0258
      MOVB R0,@VDPWA
      SWPB R0
      MOVB R0,@VDPWA
* WAIT FOR VDP SYNC
      CLR R1
      MOVB @VDPSTA,R1   * EACH READ CLEARS IT
      B @>8320

*     AORG >8320
WAITS1 MOVB @VDPSTA,R1
      COC @STAT,R1
      JNE WAITS1
TIGHTL MOVB *R13,@VDPWD
      MOVB *R13,@VDPWD
      MOVB *R13,@VDPWD
      MOVB *R13,@VDPWD
      MOVB *R13,@VDPWD
      MOVB *R13,@VDPWD
      MOVB *R13,@VDPWD
      MOVB *R13,@VDPWD
*      MOVB *R13,@VDPWD
*      MOVB *R13,@VDPWD
*      MOVB *R13,@VDPWD
*      MOVB *R13,@VDPWD
*      MOVB *R13,@VDPWD
*      MOVB *R13,@VDPWD
*      MOVB *R13,@VDPWD
*      MOVB *R13,@VDPWD

      DEC R14
      JNE TIGHTL

*     RORG
RESUME COC @STAT,R1
      JNE OK
* ALREADY FIRED, SO DEC THE COUNT
      DEC R15
      JEQ OK
      JMP TESTLP
* GET BACK TO A REASONABLE
* DISPLAY MODE AND SHOW THE VALUE
* R15 WILL BE 0000 ON FAILURE
OK     CLR R0
      BLWP @VWTR        * BITMAP OFF
      LI R0,>01E0
      BLWP @VWTR        * RESTORE SCREEN
      CLR R2
      MOVB R2,@>837C    * GPL STATUS
      BLWP @GPLLNK
      DATA >0016        * LOAD CHR SET
      LI R0,80
      LI R1,>4300
      BLWP @VSBW
      INC R0
      LI R1,>4E00
      BLWP @VSBW
      INC R0
      LI R1,>5400
      BLWP @VSBW
* BEFORE DISPLAYING R15, MULTIPLY BY UNROLL
      SLA R15,3

      INCT R0
      MOV R15,R10
      ANDI R10,>F000
      SRL R10,12
      AI R10,TABLE
      MOVB *R10,R1
      BLWP @VSBW

      INC R0
      MOV R15,R10
      ANDI R10,>0F00
      SRL R10,8
      AI R10,TABLE
      MOVB *R10,R1
      BLWP @VSBW

      INC R0
      MOV R15,R10
      ANDI R10,>00F0
      SRL R10,4
      AI R10,TABLE
      MOVB *R10,R1
      BLWP @VSBW

      INC R0
      MOV R15,R10
      ANDI R10,>000F
      AI R10,TABLE
      MOVB *R10,R1
      BLWP @VSBW

FOREVR LIMI 2
      LIMI 0
      JMP FOREVR

      END

---

From: ti99_forever <[email-masked]>
Date: Wed, 11 Nov 2009 21:30:49 -0800 (PST)

Ok, time for my "Stupid Question of the Day!"

Why is it some games when run from 16-bit RAM wind up with messed up character definitions, usually on the sprites?

Is it because they aren't timing to VSYNC? Didn't think that was EVER necessary, but maybe that is why TI advises NOPs.

--- On Thu, 11/12/09, Tursi <[email-masked]> wrote:

From: Tursi <[email-masked]>
Subject: Re: [TI994A] VDP throughput (was: Re: TMS9918 demo)
To: [email-masked]
Date: Thursday, November 12, 2009, 12:19 AM

  

does.

dug this out.

problem.

DEF START

      REF VWTR,VDPWA,VDPWD, VDPSTA

      REF VSBW

      REF GPLLNK

AORG >a000

      EVEN

STAT   BYTE >80

      EVEN

* SET UP BITMAP MODE

START  LWPI >8300

      LIMI >0000

      LI R0,>0002

      BLWP @VWTR

*      LI R0,>01A0

*      BLWP @VWTR

      LI R0,>0503

      BLWP @VWTR        * >1800

      LI R0,>1800

      LI R1,>D0D0

      BLWP @VSBW

      LI R0,WAITS1

      LI R1,>8320

CPCLP MOV *R0+,*R1+

      CI R0,RESUME

      JL CPCLP

      LI R15,>0200

TESTLP MOV R15,R14

      LI R0,>0258

      MOVB R0,@VDPWA

      SWPB R0

      MOVB R0,@VDPWA

* WAIT FOR VDP SYNC

      CLR R1

      B @>8320

*     AORG >8320

WAITS1 MOVB @VDPSTA,R1

      COC @STAT,R1

      JNE WAITS1

TIGHTL MOVB *R13,@VDPWD

      MOVB *R13,@VDPWD

      MOVB *R13,@VDPWD

      MOVB *R13,@VDPWD

      MOVB *R13,@VDPWD

      MOVB *R13,@VDPWD

      MOVB *R13,@VDPWD

      MOVB *R13,@VDPWD

*      MOVB *R13,@VDPWD

*      MOVB *R13,@VDPWD

*      MOVB *R13,@VDPWD

*      MOVB *R13,@VDPWD

*      MOVB *R13,@VDPWD

*      MOVB *R13,@VDPWD

*      MOVB *R13,@VDPWD

*      MOVB *R13,@VDPWD

DEC R14

      JNE TIGHTL

      MOVB @VDPSTA,R1

      B @RESUME

*     RORG

RESUME COC @STAT,R1

      JNE OK

      DEC R15

      JEQ OK

      JMP TESTLP

OK     CLR R0

      BLWP @VWTR        * BITMAP OFF

      LI R0,>01E0

      CLR R2

      BLWP @GPLLNK

      LI R0,80

      LI R1,>4300

      BLWP @VSBW

      INC R0

      LI R1,>4E00

      BLWP @VSBW

      INC R0

      LI R1,>5400

      BLWP @VSBW

      SLA R15,3

INCT R0

      MOV R15,R10

      ANDI R10,>F000

      SRL R10,12

      AI R10,TABLE

      MOVB *R10,R1

      BLWP @VSBW

INC R0

      MOV R15,R10

      ANDI R10,>0F00

      SRL R10,8

      AI R10,TABLE

      MOVB *R10,R1

      BLWP @VSBW

INC R0

      MOV R15,R10

      ANDI R10,>00F0

      SRL R10,4

      AI R10,TABLE

      MOVB *R10,R1

      BLWP @VSBW

INC R0

      MOV R15,R10

      ANDI R10,>000F

      AI R10,TABLE

      MOVB *R10,R1

      BLWP @VSBW

FOREVR LIMI 2

      LIMI 0

      JMP FOREVR

END

---

From: "Tursi" <[email-masked]>
Date: Thu, 12 Nov 2009 00:45:01 -0500

>Why is it some games when run from 16-bit RAM wind up with messed up 
>character definitions, usually on the sprites?
>Is it because they aren't timing to VSYNC? Didn't think that was EVER 
>necessary, but maybe that is why TI advises >NOPs.

Well.. no, we haven't proven that it IS always safe yet.. I'm just 
willing to believe that it might be. :) I believe we've found the reason 
for the apparent gigantic jump in performance using indirect mode -- it 
was a bug, and I'm just waiting for secondary confirmation on that one. 
It still appears faster, but only about 12%, not 250%. ;)

The next step is to actually run some tests and see what kind of timing 
is actually safe.. at a minimum there are two extremes -- while the 
screen is not being displayed (blanking and vertical blank - all cycles 
are CPU access cycles), and during maximum screen activity (bitmap mode 
with all sprites active).

My new prediction is that during the blanking periods, the 9900 can not 
overflow the VDP even with tight scratchpad code. I'm putting even money 
on the "maximum screen activity" side of things, though (even though 
there /is/ evidence out there of software that gets corruption to the 
video memory from 16-bit RAM.) I remember hearing back in the day, too, 
that it varied by machine a bit, a program like that might work on one, 
but not another.

Off hand, Ben, can you think of a game that does have trouble? Since my 
machine is set up with 16-bit RAM now, I can take a look at them.

---

From: mark wills <[email-masked]>
Date: Wed, 11 Nov 2009 21:52:55 -0800 (PST)

Your machine has 32K on the 16-bit bus? :-0

OH I'M SO JELOUS.

<wail> <knash> etc

;-)

---

From: "Tursi" <[email-masked]>
Date: Thu, 12 Nov 2009 01:16:35 -0500

>Your machine has 32K on the 16-bit bus? :-0

Of course not, don't be ridiculous.

My machine has 128k on the 16-bit bus. (CRU selectable ;) )

When I get time to go back in there, I'll add the switches to make it 
192k (DSR and Cart space mapped ;) )

I made some tweaks to Mainbyte's documentation to cover the larger 
memory, but I've never heard back on my offer to update his page or to 
publish myself. Does anyone know what's up with Ron? I'll probably go 
ahead and publish the mod myself, though (all I did was use 128k RAM 
chips instead of 32k RAM chips, and hook the two extra address lines to 
the 9901). Because it's such a simple tweak, it's less useful - the 
entire 32k space banks when you change it. (I only did it because 128k 
chips were all I had).

It was a one-evening job (though a long evening, the mod has a lot of 
wires), but the Mainbyte description of HOW to do it is fantastic. I 
took it a little further, and added explanation about how it worked, and 
then my own little changes to it for 128k.

It's rather academic, though. It's a simple enough tweak to the standard 
32k-16bit mod, but I don't think it's the right approach moving forward. 
I think Bill's right, we should do an AMS compatible memory upgrade so 
that there is at least SOME software that supports it. It's something 
I'll look into when I finally reach that point.

---

From: ti99_forever <[email-masked]>
Date: Wed, 11 Nov 2009 22:22:29 -0800 (PST)

No, but the disk was either "Super Cart Games One" or Super Cart Games Two", these two disks were sent out by Bud Mills with the kit...

From: Tursi <[email-masked]>
Subject: Re: [TI994A] VDP throughput (was: Re: TMS9918 demo)
To: [email-masked]
Date: Thursday, November 12, 2009, 12:45 AM

  

but not another.

---

From: Marc Hull <[email-masked]>
Date: Thu, 12 Nov 2009 05:54:13 -0800 (PST)

Peeking up from under his desk ;-)...............

<I'd say that result makes a hell of a lot more sense, even if it's disappointing>...

I wouldn't say it's disappointing Mike. 12.25 percent increase and fewer bytes seems like a good thing to me.  It's not the 200 percent but I don't think that was ever realistic.  The overall speed increase  will drop again when this method is applied to an app where the VDP write is  only a small percentage of the code but as it is faster and potentially uses less memory, I plan on using it.  I appreciate the lesson from both you guys...

I am assuming that it is agreed then that the increase in speed is completely due to the shorter instruction ?  since this should apply across the board it makes me look at things a bit differently....  Anybody got a 9900 data book they want to sell or trade?

From: Tursi <[email-masked]>
Subject: Re: [TI994A] VDP throughput (was: Re: TMS9918 demo)
To: [email-masked]
Date: Wednesday, November 11, 2009, 11:19 PM

  

does.

dug this out.

problem.

DEF START

      REF VSBW

      REF GPLLNK

AORG >a000

      EVEN

STAT   BYTE >80

      EVEN

* SET UP BITMAP MODE

START  LWPI >8300

      LIMI >0000

      LI R0,>0002

      BLWP @VWTR

*      LI R0,>01A0

*      BLWP @VWTR

      LI R0,>0503

      BLWP @VWTR        * >1800

      LI R0,>1800

      LI R1,>D0D0

      BLWP @VSBW

      LI R0,WAITS1

      LI R1,>8320

CPCLP MOV *R0+,*R1+

      CI R0,RESUME

      JL CPCLP

      LI R15,>0200

TESTLP MOV R15,R14

      LI R0,>0258

      MOVB R0,@VDPWA

      SWPB R0

      MOVB R0,@VDPWA

* WAIT FOR VDP SYNC

      CLR R1

      B @>8320

*     AORG >8320

WAITS1 MOVB @VDPSTA,R1

      COC @STAT,R1

      JNE WAITS1

TIGHTL MOVB *R13,@VDPWD

      MOVB *R13,@VDPWD

      MOVB *R13,@VDPWD

      MOVB *R13,@VDPWD

      MOVB *R13,@VDPWD

      MOVB *R13,@VDPWD

      MOVB *R13,@VDPWD

      MOVB *R13,@VDPWD

*      MOVB *R13,@VDPWD

*      MOVB *R13,@VDPWD

*      MOVB *R13,@VDPWD

*      MOVB *R13,@VDPWD

*      MOVB *R13,@VDPWD

*      MOVB *R13,@VDPWD

*      MOVB *R13,@VDPWD

*      MOVB *R13,@VDPWD

DEC R14

      JNE TIGHTL

      MOVB @VDPSTA,R1

      B @RESUME

*     RORG

RESUME COC @STAT,R1

      JNE OK

      DEC R15

      JEQ OK

      JMP TESTLP

OK     CLR R0

      BLWP @VWTR        * BITMAP OFF

      LI R0,>01E0

      CLR R2

      BLWP @GPLLNK

      LI R0,80

      LI R1,>4300

      BLWP @VSBW

      INC R0

      LI R1,>4E00

      BLWP @VSBW

      INC R0

      LI R1,>5400

      BLWP @VSBW

      SLA R15,3

INCT R0

      MOV R15,R10

      ANDI R10,>F000

      SRL R10,12

      AI R10,TABLE

      MOVB *R10,R1

      BLWP @VSBW

INC R0

      MOV R15,R10

      ANDI R10,>0F00

      SRL R10,8

      AI R10,TABLE

      MOVB *R10,R1

      BLWP @VSBW

INC R0

      MOV R15,R10

      ANDI R10,>00F0

      SRL R10,4

      AI R10,TABLE

      MOVB *R10,R1

      BLWP @VSBW

INC R0

      MOV R15,R10

      ANDI R10,>000F

      AI R10,TABLE

      MOVB *R10,R1

      BLWP @VSBW

FOREVR LIMI 2

      LIMI 0

      JMP FOREVR

END

---

From: Owen Brand <[email-masked]>
Date: Thu, 12 Nov 2009 11:12:30 -0500

:) I got 2 for ya... Pristine condition

Owen Brand
**Oprysoft**
Opry99er.com

On Nov 12, 2009, at 8:54 AM, Marc Hull <[email-masked]> wrote:

> I wouldn't say it's disappointing Mike. 12.25 percent increase and  
> fewer bytes seems like a good thing to me.  It's not the 200 percent  
> but I don't think that was ever realistic.  The overall speed  
> increase  will drop again when this method is applied to an app  
> where the VDP write is  only a small percentage of the code but as  
> it is faster and potentially uses less memory, I plan on using it.   
> I appreciate the lesson from both you guys...
>
> I am assuming that it is agreed then that the increase in speed is  
> completely due to the shorter instruction ?  since this should apply  
> across the board it makes me look at things a bit differently....   
> Anybody got a 9900 data book they want to sell or trade?
>
>
>
>
>
>
>
>
>
>
>

---

From: R Halter <[email-masked]>
Date: Thu, 12 Nov 2009 10:32:17 -0600

> Anybody got a 9900 data book they want to sell or trade?

I think I *had* one, but gave it away in an eBay auction, with a bunch 
of other random TI-related books.  Sorry...  -_-'

-- 
"Which key is the 'Any' key?"

---

From: "Matthew" <[email-masked]>
Date: Thu, 12 Nov 2009 16:44:00 -0000

I have the databook in PDF form, but I'd love a real manual if you (or anyone else) is willing to trade/sell/give or whatever.  Just email me the price and where to send the money (snail mail or PayPal works for me).

Matthew

--- In [email-masked], Owen Brand <owenbrand@...> wrote:
> On Nov 12, 2009, at 8:54 AM, Marc Hull <marc.hull@...> wrote:
> 
> > --- On Wed, 11/11/09, Tursi <yahoogroup@...> wrote:
> >
> > From: Tursi <yahoogroup@...>

---

From: "Matthew" <[email-masked]>
Date: Thu, 12 Nov 2009 17:00:11 -0000

> The loader itself doesn't, but the GPL interpreter that is running it, 

Yup, that would explain it then.  So the EA and associated utilities are written in GPL?

> emulator, and am about to run it on the real hardware...

WHAT?  Your PEB was packed away??  That's like a 99/4A sin. ;-)  Glad to know you dug it out though. :-)

> instruction for the test is one of the corrupted instructions.

Yeah, the original program was not compiling right either.  I tried using the Asm994a but did not trust the generated opcodes, but the real TI assembler created the same thing.  In the original code, in the critical section that followed the AORG >8320, all the addresses based on labels were messed up.  Now I don't know that I trust AORG / RORG, and at the very least I'm wondering if I truly understand how to use them.  I see you also used some absolute addresses in the new code instead of labels.

> pump VDP data... I'll leave that proof to you, Matt. I'm really glad you 

Hey, glad to do the digging.  I like coding against the real hardware, I *really* like optimizing for performance and making things faster, and I like graphics.  Any time I see some code I think "bet I could make that faster", it is kind of like a little challenge for me and fills some small need I have.  It pays off more on the older computers where speeding things up is more important.  On modern systems, every one blows off optimization to the compiler or they simply think computers are so fast that we don't need to bother any more.  I disagree.

Now, let's talk about that you were not on our side to begin with... ;-)

I'll try your new code now and see what I come up with.

Matthew

---

From: "Tursi" <[email-masked]>
Date: Thu, 12 Nov 2009 12:46:08 -0500

> Yup, that would explain it then.  So the EA and associated utilities 

Yep! When I wrote that code, I had to position it carefully to avoid 
breaking the GPL interpreter -- that's probably why I missed I had 
pushed it down into the workspace. It's also why the unroll is only 8 
moves but there are 16 in the code, half commented out. :)

> to know you dug it out though. :-)

I've been using that as an excuse to Marc for a year now, hehe. ;)

> Yeah, the original program was not compiling right either.  I tried 
> using the Asm994a but did not trust the generated opcodes, but the 
> real TI assembler created the same thing.  In the original code, in 
> the critical section that followed the AORG >8320, all the addresses 
> based on labels were messed up.  Now I don't know that I trust AORG / 
> RORG, and at the very least I'm wondering if I truly understand how to 
> use them.  I see you also used some absolute addresses in the new code 
> instead of labels.
>

AORG and RORG do the right thing, but because the scratchpad code is now 
assembled and loaded into high memory expansion first, the labels have 
the wrong addresses, so when I move them to scratchpad, I have to jump 
absolutely instead of to the label.

The jumps inside that loop are all relative so it's okay for them to use 
the labels.

> Hey, glad to do the digging.  I like coding against the real hardware, 
> I *really* like optimizing for performance and making things faster, 
> and I like graphics.  Any time I see some code I think "bet I could 
> make that faster", it is kind of like a little challenge for me and 
> fills some small need I have.  It pays off more on the older computers 
> where speeding things up is more important.  On modern systems, every 
> one blows off optimization to the compiler or they simply think 
> computers are so fast that we don't need to bother any more.  I 
> disagree.
>

Agree on the optimizing bit, of course, but always good to have a second 
pair of eyes on the code.

> I'll try your new code now and see what I come up with.

hehehe... hey, I'm the cold fusion guys, I /saw/ it work! ;)

---

From: "Matthew" <[email-masked]>
Date: Thu, 12 Nov 2009 18:39:24 -0000

> The jumps inside that loop are all relative so it's okay for them to use 

I did have to think about the JNE use in the critical loop, and remembered they are relative, like you said.  That is confusing though, if you didn't know that nuance.  My problem, however, is not with the jump addresses, it is with the MOVB instruction.  Here is part of the assembler listing.  It was the same when using AORG and in the new code:

A072 D81D TIGHTL MOVB *R13,@VDPWD
A074 0000
A076 D81D       MOVB *R13,@VDPWD
A078 A074
A07A D81D       MOVB *R13,@VDPWD
A07C A078
A07E D81D       MOVB *R13,@VDPWD
A080 A07C
A082 D81D       MOVB *R13,@VDPWD
A084 A080
A086 D81D       MOVB *R13,@VDPWD
A088 A084
A08A D81D       MOVB *R13,@VDPWD
A08C A088
A08E D81D       MOVB *R13,@VDPWD
A090 A08C

The opcode is correct (D81D), but the symbolic address is wrong.  The @VDPWD should be coded as >8C00 following every opcode.  Unless the loader fixes these up?  But I don't see why is should, VDPWD is known at compile time, is it not?

Matthew

---

From: tursi <[email-masked]>
Date: Thu, 12 Nov 2009 11:20:35 -0800 (PST)

> The opcode is correct (D81D), but the symbolic address is wrong.  The 
> @VDPWD should be coded as >8C00 following every opcode.  Unless the 
> loader fixes these up?  But I don't see why is should, VDPWD is known at 
> compile time, is it not?

Nope, it's not! Remember, you could be loading this into Editor/Assembler, 
MiniMemory, Extended BASIC, or some other environment TI never considered. 
The utilities are located at different addresses in all of them.

Now, the /hardware/ is at the same addresses of course, but the system 
doesn't look at that. If VDPWD was an EQU, then it would be known at 
compile time, but because it's a REF, that means the code expects some 
other module to fill in the correct value. Basically, the EA cart exports 
DEFs for all those labels when it initializes, so that when you load 
files, the labels can be fixed up. The values stored in there form a link 
chain so that starting at the first one, all the REFs in the file for that 
label can be found.

---

From: "Matthew" <[email-masked]>
Date: Thu, 12 Nov 2009 20:35:45 -0000

> chain so that starting at the first one, all the REFs in the file for that 

Cool.  I see it now.  Thanks for clearing that up!

Okay, here are my numbers.  You're not going to believe it...

VDP1: 1368 (0558)
VDP2: 1536 (0600) 168 bytes diff = 10.9% faster than VDP1
VDP3: 1752 (06D8) 216 bytes diff = 12.3% faster than VDP2

I could not believe the results were *exactly* what you got!  Well, good test for sure!  Now the only thing bugging me is that the speed of the loop is not exactly what it should be based on how many times the loop could be run in the 16.6mS frame time.

I'm curious, if you have your console open could you check the CPU clock?  Based on the timing of the loop, it seems like the CPU is running at 2.66MHz instead of the assumed 3MHz.

Basically, counting the clock cycles for the critical loop, we should see about 219 iterations in the 16.6mS frame time.  The actual iterations of the loop is about 171.

MOVB *R13,@>8C00
(14 + 4 + 8) * 0.333 = 8.658uS

There are 8 MOVB instructions in the loop:

8.658uS * 8 = 69.264uS

DEC R14
10 * 0.333 = 3.33uS

JNE TIGHTL
10 * 0.333 = 3.33uS

69.264uS + 6.66uS = 75.924uS per loop

16.6mS / 75.924uS = 219.51 loop iterations

According to the actual count, we have 171 loop iterations (1368 / 8) is 97.465uS per loop iteration.  There should really be no discrepancy, the CPU is going to clock these instructions as designed, so the only thing I can think of is a slower CPU clock than the 3MHz we assume.

I can accept a little error based on the code that polls the status register before starting the critical loop, but it should not be that much.

Also, those MSX guys who claimed 3k bytes per "frame", where they talking about per *frame* for per *field*?  On the TI, we are actually talking per *field*, since a single NTSC 29.97Hz interlaced "frame" is made up of two "fields", one of the even scan lines and one for the odd scan lines.  Our timing loop is based on a single "field" time of 1/60th of a second.

So, if we are going to consider 30FPS animation, then we can double our results to 2736, 3072, and 3504 bytes per "frame", which is not too shabby.  30FPS will get you pretty smooth animation on a 256x192 screen.

Matthew

---

From: "Tursi" <[email-masked]>
Date: Thu, 12 Nov 2009 16:50:12 -0500

>> other module to fill in the correct value.

Remember, too, that that would have allowed the same object code to load 
on other machines where even the hardware was in different places, which 
is probably why they used REF instead of EQU for the hardware ports.

> I could not believe the results were *exactly* what you got!  Well, 
> good test for sure!  Now the only thing bugging me is that the speed 
> of the loop is not exactly what it should be based on how many times 
> the loop could be run in the 16.6mS frame time.
>

Good, glad to see that. And nobody sees any more obvious bugs in the 
code? :)

> I'm curious, if you have your console open could you check the CPU 
> clock?  Based on the timing of the loop, it seems like the CPU is 
> running at 2.66MHz instead of the assumed 3MHz.
> Basically, counting the clock cycles for the critical loop, we should 
> see about 219 iterations in the 16.6mS frame time.  The actual 
> iterations of the loop is about 171.
>

Hmm.. I'll check. I've wanted to measure that anyway to clear up other 
questions (though I was hoping to get out of doing the analyzer, hehe 
;) ). It'll take a little time to get to that.

> (14 + 4 + 8) * 0.333 = 8.658uS

I confirmed your math throughout, but I think you have an error here.

MOVB is 14 clock cycles. WR indirect adds 4 clock cycles. Symbolic adds 
8 clock cycles. You have that.

BUT, the VDP, even though it's on the 16-bit bus, is subject to the wait 
state generator, which according to Thierry's page adds 4 more cycles.

http://nouspikel.group.shef.ac.uk//ti99/wait.htm

That brings the time of the MOVB to (14+4+(8+4))= 30 cycles * 0.333 = 
9.999uS (might as well say 10).

To save rounding issues, I'll work in cycles till the last step. I 
already confirmed that math matches your original numbers. :)

So, 8 MOVBs is 30*8 = 240 cycles, plus 10 for DEC, plus 10 for JNE, 
gives us 260 cycles per loop.

260*.3333 = 86.6666 uS per loop.

16.6666mS / 86.6666 uS = 192.307 iterations per frame.

We get 171 iterations in the test.

> According to the actual count, we have 171 loop iterations (1368 / 8) 
> is 97.465uS per loop iteration.  There should really be no 
> discrepancy, the CPU is going to clock these instructions as designed, 
> so the only thing I can think of is a slower CPU clock than the 3MHz 
> we assume.
>

So, seems I still can't explain 21 loops. :) But we're getting close!

> I can accept a little error based on the code that polls the status 
> register before starting the critical loop, but it should not be that 
> much.
>

The overhead instructions for the test are the MOVB that reads the 
status register, the COC that tests it, the JNE that branches, and at 
the end, the last MOVB (though to a much lessor extent, but let's 
include it.)

The MOVB's are 14+(8+4)+0 = 26 cycles (times two, so 52 combined.)
The COC is comparing against 8-bit memory, so it's 14+(8+4)+0 = 26 
cycles.
The JNE is not taken in the loop that matters, so it's 8 cycles.
The total test overhead is 86 cycles, which is 28.6uS.
That's a one-time hit for the test, so technically we could work with an 
adjusted frame time of 16,638uS.
16638/86.6666 = 192.124 iterations -- which is good. The overhead costs 
less than 1/10th of a percent. We can dismiss it.

> Also, those MSX guys who claimed 3k bytes per "frame", where they 
> talking about per *frame* for per *field*?  On the TI, we are actually 
> talking per *field*, since a single NTSC 29.97Hz interlaced "frame" is 
> made up of two "fields", one of the even scan lines and one for the 
> odd scan lines.  Our timing loop is based on a single "field" time of 
> 1/60th of a second.
>

Although that is how NTSC video is created, it's not how the 9918 works. 
The 9918 actually outputs a single-field video signal, it's full 240P @ 
60hz (I'm not sure if it's the even or odd frame, but it's only one of 
them that it knows).

This actually screws up some modern video devices. For instance, my 
projector can't get a clean lock on the signal. It's not uncommon, 
either, most machines of the age did it. I have the same problem with my 
Atari 2600 and my Sega Genesis (and of course, the ColecoVision, but 
that's the same chip).

So in this case, talking about fields and talking about frames is the 
same thing.

> So, if we are going to consider 30FPS animation, then we can double 
> our results to 2736, 3072, and 3504 bytes per "frame", which is not 
> too shabby.  30FPS will get you pretty smooth animation on a 256x192 
> screen.
>

This is true, but it will visibly paint, since the display is updated 60 
times a second. That's why the desire to see what you can do in one 
frame. (Of course, seeing 30fps draw is still pretty hard ;) ).

---

From: "Jon P Vogel" <[email-masked]>
Date: Thu, 12 Nov 2009 17:09:10 -0600

From: "Tursi" <[email-masked]>

> Atari 2600 and my Sega Genesis (and of course, the ColecoVision, but

VCRs use this, also.  In fact, Toshiba TVs have a special video processing 
mode to detect this type of video.  <shameless plug>BTW, TI-99s work fine 
with Toshiba TVs.  So, run out and buy one today.  I suggest the 22" LCD 
model with built-in DVD player.</plug>

Regards,

Jon

---

From: "Matthew" <[email-masked]>
Date: Fri, 13 Nov 2009 00:19:08 -0000

> is probably why they used REF instead of EQU for the hardware ports.

Yeah, that was good fore thought, too bad they never needed to use it...

> ;) ). It'll take a little time to get to that.

Ha!  No way are you going to get out of using the analyzer! ;-)  Just crack the cover on your console, since we all know you don't keep the screws in it anyway, and test one of the clock input pins on the 9900.  You should be able to just use an O-scope for that.

> 9.999uS (might as well say 10).

That really sucks!  Why in the heck would the designers make 9918A subject to the wait state generator?  That's dumb.  They prevent the ROM and scratch pad RAM from activating the WSG, so why not all the memory mapped devices from >8000 to >9000 ??  Seems that would have been easier to block the whole 4K range.

However, what that tells me is, even the fastest variation of the MOV(B) instruction we have to write to the 9918A (MOV Rx,*Rx) is almost slower than the *maximum* delay required by the 9918A!

MOV R13,*R12 == (14 + 4) * 0.333 = 5.994uS

But, add the 4 clocks of the wait state: (14 + 4 + 4) * 0.333 = 7.326uS, and the 9918A is 2uS to 8uS (max) for the Graphics Modes I & II with all the sprites and such enabled.

> less than 1/10th of a percent. We can dismiss it.

That's what I concluded too, I just didn't take the time to nicely write it all up as you did. :-)  Nice work!

> 60hz (I'm not sure if it's the even or odd frame, but it's only one of 

That is something else I always wondered.  How do they always output only the odd or even field?  I assumed the odd field would always have to start 1 scan line lower than the even field to paint in between the even scan lines in order to achieve the 525 or so total scan lines?  I also assumed that the CRT did the scan line adjustment for every other field, but that must not be the case or the image would be jumping up and down 1 scan line every 1/16th of a second, no?

Matthew

---

From: "Tursi" <[email-masked]>
Date: Thu, 12 Nov 2009 19:41:44 -0500

> That really sucks!  Why in the heck would the designers make 9918A 
> subject to the wait state generator?  That's dumb.  They prevent the 
> ROM and scratch pad RAM from activating the WSG, so why not all the 
> memory mapped devices from >8000 to >9000 ??  Seems that would have 
> been easier to block the whole 4K range.
>

VDP is in the >9x00 range, eh? :)

Anyway, some bright engineer probably thought, "Well, it can't respond 
at full speed anyway, so we'll just have it slowed down, too." That, or 
just a bad side effect of poor planning during multiplexer 
implementation. We may never know. (Maybe we could ask the 9918 
developer? ;) )

> However, what that tells me is, even the fastest variation of the 
> MOV(B) instruction we have to write to the 9918A (MOV Rx,*Rx) is 
> almost slower than the *maximum* delay required by the 9918A!
> But, add the 4 clocks of the wait state: (14 + 4 + 4) * 0.333 = 
> 7.326uS, and the 9918A is 2uS to 8uS (max) for the Graphics Modes I & 
> II with all the sprites and such enabled.
>

Yeah! But... close isn't good enough. If you miss it, you still miss it, 
even if it was "almost". What that means is determining "reliable" is 
going to be hard, as we're right on the edge and edge cases could 
happen.

> That is something else I always wondered.  How do they always output 
> only the odd or even field?  I assumed the odd field would always have 
> to start 1 scan line lower than the even field to paint in between the 
> even scan lines in order to achieve the 525 or so total scan lines?  I 
> also assumed that the CRT did the scan line adjustment for every other 
> field, but that must not be the case or the image would be jumping up 
> and down 1 scan line every 1/16th of a second, no?
>

There's no position information in the stream, it's just a 1D stream of 
intensities (ignore color for the sake of simplicity) with the 
occasional mark for end of scanline and end of screen. So the only 
starting higher or lower is handled by the receiver.

However, there /is/ an indication at the top of the frame whether it's 
the even or the odd frame that helps the receiver do that alignment. 
Basically, one field seems to start out of phase by changing the sync 
pulses, affecting the timing in relation to the carrier. I don't 
understand it well enough to explain it, but this page gives a simple 
overview: 
http://www.poynton.com/notes/video/Four-field_NTSC_sequence/index.html

I suspect the 9918 always outputs a signal that is at 0 degrees with 
respect to the carrier (but not sure how to get that from the 
datasheet). A TV does not care, and neither do most encoders, but some 
that do fancy deinterlacing get upset when there's nothing to 
deinterlace. :)

---

From: "Tursi" <[email-masked]>
Date: Thu, 12 Nov 2009 21:17:30 -0500

> Ha!  No way are you going to get out of using the analyzer! ;-)  Just 
> crack the cover on your console, since we all know you don't keep the 
> screws in it anyway, and test one of the clock input pins on the 9900. 
> You should be able to just use an O-scope for that.
>

There are four screws in my case! ;)

All right.. so the analyzer (I don't have a scope) reports the clock 
frequency at PHI1/PHI2/PHI3/PHI4 (any of them, they are the same) is 
2,999,935Hz (+/- 5Hz). I'm not sure if there's a resolution limit on my 
hardware there or not, it's supposed to be able to measure at 500MHz, 
but it flips slightly between 2,999,930Hz and 2,999,940Hz. As it warmed 
up, the clock climbed slightly.. I saw 2,999,955 (+/- 5Hz again). I'm 
not sure who to suspect for the variance.. with the age, maybe it's 
possible the clock generators are a bit off? I think my console, at 
least, I'd put the actual clock rate at 2,999,950Hz. (Intronix LogicPort 
USB-based 34 channel analyzer).

I tested my QI machine, and it clocks at 3,000,040Hz. A second silver 
console got 3,000,100Hz!. And both of them had all their screws, damn 
it. ;) (Well, ok, only the QI did. ;) ) Figures, I kept the slowest 
console I own as my primary...

These results suggest to me that the clock is not a reliable 3MHz --  
even if my tester were a little off, I should see a consistent amount of 
'off'. I'm not sure if age is a factor in this kind of circuit, but if 
this is common among TIs, especially if the timing really is on the 
edge, that might explain why some consoles have trouble and some don't. 
I couldn't find a 9904 datasheet to see if it said anything about 
accuracy. But this is a variance of only 0.003%... it's hard to believe 
that would be out of reason. The clocks otherwise line up nicely.

So, does 2999930Hz explain the lost loops? No, not even close, it barely 
impacts the fractional part.

I hate you guys for this. ;) I'll start wiring up the data and address 
bus, then I need to try and figure out how to run a test of the actual 
opcodes... ;)

---

From: ti99_forever <[email-masked]>
Date: Thu, 12 Nov 2009 18:34:06 -0800 (PST)

Hmm - just like their owners, the older we get the slower we get...

From: Tursi <[email-masked]>
Subject: Re: [TI994A] Re: VDP throughput (was: Re: TMS9918 demo)
To: [email-masked]
Date: Thursday, November 12, 2009, 9:17 PM

  

frequency at PHI1/PHI2/PHI3/ PHI4 (any of them, they are the same) is 

console got 3,000,100Hz! . And both of them had all their screws, damn 

opcodes... ;)

---

From: mark wills <[email-masked]>
Date: Thu, 12 Nov 2009 19:57:26 -0800 (PST)

Anyone got a PAL TI to try this on?

I think the PAL VDP is clocked slower... It runs at 25 frames p/s, not 30...

Mark

>Sent: Thu, 12 November, 2009 14:54:13
>Peeking up from under his desk ;-)......... ......
>
>I am assuming that it is agreed then that the increase in speed is completely due to the shorter instruction ?  since this should apply across the board it makes me look at things a bit differently. ...  Anybody got a 9900 data book
> they want to sell or trade?
>
>
>
>
>
>
>
>
>
>
>
>--- On Wed, 11/11/09, Tursi <yahoogroup@harmless lion.com> wrote:
>
>
>>From: Tursi <yahoogroup@harmless lion.com>

---

From: "Tursi" <[email-masked]>
Date: Thu, 12 Nov 2009 23:52:12 -0500

Found the 9904 data sheet, it reports a clock tolerance of +/-0.005% --  
so we are in range with what I have measured. (+0.003% maximum variance)

An interesting note on the 9901 output pins -- high output on this 
device is only 2.0-2.4 volts! I was getting really random results till I 
read that in the datasheet.

One thing I see that's interesting, is that the READY line is pulled low 
for every memory access, between PHI2 and PHI3, in scratchpad. However, 
according to Thierry's page, the 9900 only samples the line at the 
beginning of PHI1, so this induces no delay, just interesting to see.

Since Minimem is my friend for this test, I made the test program fairly 
short, but to still contain all the necessary functions for us to 
examine:

Sorry on the 9C00 stuff.. I'm thinking about GROMs. I haven't had a 
proper night's sleep for a week and I'm getting pretty bagged.. this 
will have to be my last late night on this for a while ;)

I've inserted after the data column what the analyzer would show each 
address as. It would have been a little more clear with just 7 address 
lines, but that's fine.

   1                    AORG >8300              * assemble to scratchpad
   2  8300 02E0 80      LWPI >83E0              * use GPLWS
   2  8302 83E0 81
   3
   4  8304 0200 82      LI R0,>8300             * source address in 
scratchpad
   4  8306 8300 83
   5  8308 0201 84      LI R1,>8C00             * dest address VDP chip 
(for the indirect test)
   5  830A 8C00 85
   6  830C 0203 86      LI R3,>FFFF             * arbitrary
   6  830E FFFF 87
   7  8310 020C 88      LI R12,>0020      * need to trigger CRU pin to 
start the capture
   7  8312 0020 89
   8  8314 1D00 8A      SBO 0                   * trigger it!
   9
  10            * try to catch 2 cycles of each type!
  11            LP
  12  8316 D810 8B      MOVB *R0,@>8C00   * type 1
  12  8318 8C00 8C
  13  831A D810 8D      MOVB *R0,@>8C00
  13  831C 8C00 8E
  14
  15  831E D450 8F      MOVB *R0,*R1      * type 2
  16  8320 D450 90      MOVB *R0,*R1
  17
  18  8322 D440 91      MOVB R0,*R1             * type 3
  19  8324 D440 92      MOVB R0,*R1
  20
  21  8326 0603 93      DEC R3                  * test DEC
  22  8328 16F6 94      JNE LP
  23
  24  832A 10EA 95      JMP     >8300           * repeat test forever
  25
  26  832C 0000         END

I got a successful capture of this program running.. I captured all four 
phases of the clock, the trigger CRU pin, the CPU 'READY' line (to catch 
hold states) and the 8 least significant address lines at the CPU 
(meaning A7-A14, there is no A15 there ;) ). By comparing that with the 
listing, I can see what the CPU did.

The capture starts at the SBO 0. So from the capture data, here is what 
I see, line by line. I understand that PHI2 is the main clock, so 
counting relative to that.

   8  8314 1D00 8A      SBO 0                   * trigger it!
Address bus shows >8A for 6 cycles. It then shows >FC for 4 cycles, and 
 >10 for 2 cycles (this is the CRU operation). 1 cycle after the >10 on 
the address bus, the CRU line goes high as requested. SBO is supposed to 
take 12 cycles, and this is what we see.

  12  8316 D810 8B      MOVB *R0,@>8C00   * type 1
Address bus shows >8B for 4 cycles. We then see >f0 for 4 cycles (>83E0, 
correct for R0). Next we see >80 for 8 cycles (>8300). We then see >8C 
for 4 clocks (reading the immediate data) Next, we see >00 for 14 
clocks, including /two/ 4 cycle wait states including 4 non-wait state 
clocks in the middle, and 2 at the end. (Correct address for the VDP 
access). Total time is 34 cycles! Our previous estimate was 30 clocks on 
the expectation of a single VDP hold. Will come back to that.

  13  831A D810 8D      MOVB *R0,@>8C00
Duplicating the instruction gave no surprises - same pattern, 34 cycles.

  15  831E D450 8F      MOVB *R0,*R1      * type 2
Address bus shows >8F for 4 cycles, >F0 for 4 cycles (reading R0), >80 
for 4 cycles (reading >8300), >F1 for 4 cycles (reading R1), >00 for 14 
cycles (writing VDP, same pattern as above). Total time is 30 cycles.

  16  8320 D450 90      MOVB *R0,*R1
No surprises here, same pattern, 30 cycles.

  18  8322 D440 91      MOVB R0,*R1             * type 3
We've got >91 for 4 cycles, >F0 for 4 cycles (read R0), >F1 for 4 cycles 
(read R1), and the usual 14 cycle VDP access. Total time is 26 cycles.

  19  8324 D440 92      MOVB R0,*R1
No surprises, 26 cycles.

  21  8326 0603 93      DEC R3                  * test DEC
>93 for 4 cycles, >F3 for /six/ cycles - this covers the read and the 
>write. Total time is 10 cycles, as promised.

  22  8328 16F6 94      JNE LP
>94 is up for 10 cycles, as promised.

The VDP pattern surprised me at first... but I realized what's going on. 
We are too focused on writing to the VDP, we forgot something -- the 
9900 can't just write. MOV or MOVB is all the same, it always reads 
first. If you read, the wait state generator only hits you once and you 
lose 4 cycles, but if you write, the read-before-write means you get hit 
TWICE and it costs you /8/ cycles.

Based on this knowledge, we can now calculate the rest of the cycle 
time. The MOV takes 14+4+(8+4+4) = 34 cycles. 8 MOVs is 272 cycles. Plus 
10 for the DEC and 10 for the JNE makes 292 cycles per loop. 292 cycles 
* .333 = 97.236uS per loop. 16.6mS / 97.236uS = 171.39.... which matches 
observed.

Bloody hell, it's nice to get to the bottom of that.

Okay, now the fun stuff... you'll find nice hi-res pics of the test (and 
a screenshot of the capture data) at 
http://harmlesslion.com/temp/titest/  (note for the list: not 
indefinately).

Now to post this, and see if someone already figured out what we were 
missing... ;)

---

From: "Matthew" <[email-masked]>
Date: Fri, 13 Nov 2009 05:04:58 -0000

> impacts the fractional part.

Nope, that's not enough discrepancy to really even consider.  70Hz off of the exact 3MHz is well within tolerance IMHO.  We would need something in the range of 400KHz off (2.6MHz clock) to explain the instruction timing we are seeing.  As it is, even your console running at 3,000,100MHz will only get you 1 extra cycle in every 30,000 seconds over your main silver console.  And since you need 14 clocks for a useful instruction (MOV), that means you get an extra instruction every 30,000 * 14 = 420,000 seconds, or every 116.6 hours. :-)

> bus, then I need to try and figure out how to run a test of the actual 

Well, you can always send me your analyzer, I'd be glad to take to take it off your hands since it is such a pain in the butt... ;-)

Matthew

---

From: mark wills <[email-masked]>
Date: Thu, 12 Nov 2009 21:06:14 -0800 (PST)

That's hacking that is!!!

Well done, brilliant work!

>Sent: Fri, 13 November, 2009 5:52:12
>Subject: Re: [TI994A] Re: VDP throughput - Got it.
>
> >
>
>
>
>
>  >
>>      
> 
>>lose 4 cycles, but if you write, the read-before- write means you get hit 
>http://harmlesslion .com/temp/ titest/ (note for the list: not 
>>indefinately) .
>

---

From: "Tursi" <[email-masked]>
Date: Fri, 13 Nov 2009 00:04:37 -0500

>I think the PAL VDP is clocked slower... It runs at 25 frames p/s, not 

50 frames per second, but yes, slower. The MSX guys see the difference, 
too. This is pretty much non-disputed.

---

From: "Matthew" <[email-masked]>
Date: Fri, 13 Nov 2009 05:32:58 -0000

> Now to post this, and see if someone already figured out what we were 

Oh yeah, I figured that out already, just wanted to see if you could come up with the same result. ;-)  Just kidding.

That is *awesome* !!!  Good work!  Freaking read before write plus the wait state generator are going to forever cripple us!  So, there you go, even our fastest instruction (MOVB Rn,*Rm) is 8.658uS due to the two wait states, so we can *never* overrun the VDP in a stock 9900 console.

Now what we need to do is get creative with some other instruction that will let us write without reading first, and possibly without invoking the WSG (probably not possible though.)

That analyzer is pretty nice too!  I have looked at getting one of those, but aren't they like $400 bucks?  Seems to be well worth it though!

Matthew

---

From: "Tursi" <[email-masked]>
Date: Fri, 13 Nov 2009 00:47:05 -0500

> That is *awesome* !!!  Good work!  Freaking read before write plus the 
> wait state generator are going to forever cripple us!  So, there you 
> go, even our fastest instruction (MOVB Rn,*Rm) is 8.658uS due to the 
> two wait states, so we can *never* overrun the VDP in a stock 9900 
> console.
>

Huh. I can't find fault with the argument... it's really disappointing, 
though, since it proves we /are/ substantially slower than our Z80-based 
friends, at least to the VDP, and probably in normal RAM as well.

> Now what we need to do is get creative with some other instruction 
> that will let us write without reading first, and possibly without 
> invoking the WSG (probably not possible though.)
>

I think we're screwed on the wait state generator, unless we can find 
some edge case where it doesn't respond. I'd doubt it, though, 
especially with the huge windows TI gave the devices, lets the hardware 
be pretty straightforward. Of course Thierry describes how to turn the 
wait states completely off, but that's a hardware mod.

I'm not sure what we can do with other instructions, either. A 
write-only instruction would be so nice. ;) DMA hardware would, too.. 
there's so many /little/ things we could do to boost the console 
(Thierry proved we don't need /any/ wait states unless we are using the 
TI 32k card, for instance, everything else works at zero wait states, so 
imagine even that!) The CPU supports external DMA controllers, a little 
DMA controller would be awesome for moving memory, playing samples, etc 
(even nicer if we could interleave it). But... that's all wishlist. I 
would like to try and keep the base system, too, rather than make it 
something new.

Offhand I don't think we have anything. But maybe someone can find a 
creative hack....? It's a shame that the TI seems so solidly designed, 
there's very little we can exploit for more features.

> That analyzer is pretty nice too!  I have looked at getting one of 
> those, but aren't they like $400 bucks?  Seems to be well worth it 
> though!
>

Yeah, it is. I did the PS/2 adapter without anything like it, until 
right at the end where I got desperate on ONE keyboard that didn't work, 
and used the sound card to record the clock and data lines. That showed 
me the bug.

The next thing I worked on was attaching SD to the Jaguar, and I 
borrowed one of these analyzers from a friend to see what was going on. 
It took about 10 minutes with it to decide to get one.

---

From: "Matthew" <[email-masked]>
Date: Fri, 13 Nov 2009 05:59:54 -0000

> Now what we need to do is get creative with some other instruction that will let us write without reading first, and possibly without invoking the WSG (probably not possible though.)

To answer my own question, I wonder if this would work inside the critical section?  I'm going to try it tomorrow.  Granted it would only work for initializing VDP RAM with a fixed value (like clearing the screen), but LI should avoid the read before write, no?  LI is 12 clocks with no modifiers which is 3.996uS.

Matthew

* AORG >8320
WAITS1 MOVB @VDPSTA,R1
       COC @STAT,R1
       JNE WAITS1
       LWPI VDPWD
TIGHTL LI R0,>2000
       LI R0,>2000
       LI R0,>2000
       LI R0,>2000
       LI R0,>2000
       LI R0,>2000
       LI R0,>2000
       LI R0,>2000

* DEC R14
       DEC @>831C
       JNE TIGHTL
       LWPI >8300
       MOVB @VDPSTA,R1
       B @RESUME

---

From: mark wills <[email-masked]>
Date: Thu, 12 Nov 2009 22:05:38 -0800 (PST)

What we could do with is a 9995 based console. A halfway house between 4A and geneve; no Geneve functionality, just 4A, but with a 9995, tighter memory map to allow more RAM, and no wait state shenanigens!

Of course, the multiplexor would not be required at all ;-)

Basically, a 99/8 :-(

I'm sure a *largely* software compatible, greatly enhanced 4B could be built off a 9995, and say, 9938.

<dreeeeeeeeeem, dream dream dream, dreeeeeeeeem, dream dream dream.... >

*sigh*

M

>Sent: Fri, 13 November, 2009 6:47:05

---

From: mark wills <[email-masked]>
Date: Thu, 12 Nov 2009 22:09:19 -0800 (PST)

I was thinking EXACTLY the same thing! - Set the WP to point to VDPWA

Possible issue: LI is a 2-word instruction... ?

So you avoid the RBW, but you have an extra memory fetch cycle...?

Mark.

>Sent: Fri, 13 November, 2009 6:59:54
>Subject: [TI994A] Re: VDP throughput - Got it.
>
> >
>
>
>
>
>  >
>>      
>

---

From: "Tursi" <[email-masked]>
Date: Fri, 13 Nov 2009 02:00:56 -0500

> two wait states, so we can *never* overrun the VDP in a stock 9900 

No, wait, I knew something was bothering me... let's piece this out for 
sure. I want to just run through everything against the datasheet. I 
tested reads to be sure, since it's still set up.

READ from VDP:

MOV @>8800,R0    14+(8+4)+0 = 26 cycles = 8.65uS
MOV *R12,R0          14+(4+4)+0 = 22 cycles = 7.32uS

 MOV @>8800,R0
-First address for 8 clocks, 4 clocks on the immediate data, 8 clocks on 
the VDP write (4 clocks of wait state, 4 clocks active), 4 clocks to 
read R0, 2 clocks to write (I added the WE line to determine that). 
Total = 26 cycles = 8.6uS.

 MOV *R1,R0
-First address for 4 clocks, read R1 for 4 clocks, 8 clocks to read VDP 
(4 clocks of wait state, 4 clocks active), 4 clocks to read R0, 2 clocks 
to write. Total = 22 cycles = 7.3uS.

On a READ from VDP, the wait state will only be triggered once, meaing 
our fastest MOV is 22 cycles, or 7.3uS.

The Datasheet tells us that "the amount of time necessary for the CPU to 
transfer a byte of data to or from VRAM can vary from 2 to 8 uS". It 
then explains as such: it takes 2uS after the request before the VDP is 
ready to process. The VDP then waits for a CPU access window. In the 
worst case, active graphics 1 or 2, an access window occurs 
approximately every 6uS. The best case, excluding blanking, is text 
mode, where a window occurs approximately every 1.1uS.

The datasheet leads me to believe VDP reads and writes have 
approximately the same timing, so good.

VDP Writes - our fastest write is 8.65uS. This means that writes to the 
VDP at any speed should always be safe, as this is greater than the 
worst case access speed to the VDP. Confirmed theorhetically, just need 
some proof.

VDP Reads - our fastest read is 7.32uS. This is potentially close enough 
to the edge for tight loops to occasionally miss during graphics I or 
II. It's easy to add 4 cycles to make it safe by using the symbolic 
addressing mode instead of register indirect. They are safe in text 
(3.1uS max) and multicolor (3.5uS max) mode, however.

It's worth noting, with being on the edge there.. the CPU access window 
is not externally predictable, meaning it can come at /any/ time. You 
may be able to read a lot without ever hitting a glitch - the odds would 
appear to be that all else being equal, only about one in twelve reads 
might fail. (.68uS of bad time out of 8uS total possible time).

Outside of 16-bit RAM, both reads and writes are fully safe. However, a 
number of people have 16-bit RAM in their consoles (like meee), and it 
doesn't hurt much to support that in reads. ;) (And really.. how often 
do you need a tight read loop from VDP? Not that it never happens, but 
less often.)

All reads and writes are safe during blanking - either when the blank 
bit is set in register 1, or during vertical blank, defined as lasting 
4300uS after the interrupt is set. They are also safe during text and 
multicolor mode.

The datasheet often mentions, "with sprites", but gives no indication 
that disabling sprites gives more CPU access windows. I seem to recall a 
comment from the designer that it does not.

So there is still /one/ little gotcha there when reading, only. It's 
possible that the software which has been observed to screw up VDP 
accesses was interleaving reads and writes, and getting the address 
messed up? Definately we can do better than the NOP, adding 4 cycles by 
changing the addressing mode is much quicker than wasting 10 cycles on a 
NOP or 8 cycles on a SWPB (though you probably need that pretty much 
anyway), or even 6 cycles on an illegal instruction, and still leaves 
you very safe.

---

From: "Tursi" <[email-masked]>
Date: Fri, 13 Nov 2009 02:31:08 -0500

> To answer my own question, I wonder if this would work inside the 
> critical section?  I'm going to try it tomorrow.  Granted it would 
> only work for initializing VDP RAM with a fixed value (like clearing 
> the screen), but LI should avoid the read before write, no?  LI is 12 
> clocks with no modifiers which is 3.996uS.
>

Neat idea! Just to check that, I did LI R3,>FFFF (note: not involving 
the VDP this time, just scratchpad):

6 cycles on the opcode
2 cycles to read the immediate data
2 cycles to read R3 (or not.. see below)
2 cycles to write R3
Total = 12 cycles

So it still does read-before-write, just faster. I double-checked on the 
VDP, and it's interesting...
6 cycles on the opcode
2 cycles on the immediate data
2 cycles reading VDP
4 cycles of wait state
2 cycles of writing VDP
Total = 16 cycles

What's interesting is that the 2 cycles of "read" are not triggering a 
wait state, meaning that although the address is set, I suspect it's not 
triggering a memory cycle, so it is NOT actually reading, like you 
suspect. (I'm getting a little too tired to hook up that line and run it 
again... I have to type the hex every time as my Minimem isn't saving 
:) )

The single wait state seems to confirm that. That's only a 5uS write 
time.. while too fast for sure for graphics mode, it's great for every 
other mode. If you did it with self modifying code, you could get a 
pretty nice transfer going, I think! Thanks for suggesting that one. For 
instance, during blanking that should be able to approach 3k/frame @ 
60fps (fully unrolled).. is my math wrong there?

And NOW IT'S BEDTIME! :)

---

From: ti99_forever <[email-masked]>
Date: Fri, 13 Nov 2009 03:37:08 -0800 (PST)

It is at this point I'd like to find those programs that appear to "overrun" the VDP when run on a 32kx16 system... and have you put that on your analyzer.

--- On Fri, 11/13/09, Tursi <[email-masked]> wrote:

From: Tursi <[email-masked]>
Subject: Re: [TI994A] Re: VDP throughput - Got it.
To: [email-masked]
Date: Friday, November 13, 2009, 12:47 AM

  

      

something new.

me the bug.

---

From: "Matthew" <[email-masked]>
Date: Fri, 13 Nov 2009 15:42:08 -0000

> 60fps (fully unrolled).. is my math wrong there?

Well, I ran the test and it does over run the VDP.  And the VDP does *not* like to be over run! ;-)  The count came back 0A00 (2560), but the screen had garbage on it and the colors were all funky.  I don't know why exactly, since the VDP ports are all memory mapped to different addresses, but there was certainly something going on that the VDP does not like.

Personally I think I'll stick with the MOV(B) instructions since we know those should still be safe even with 16K in the console.  It is about the best we are going to get with our beloved stock 99/4A.

Matthew

---

From: "Tursi" <[email-masked]>
Date: Fri, 13 Nov 2009 12:16:43 -0500

> Well, I ran the test and it does over run the VDP.  And the VDP does 
> *not* like to be over run! ;-)  The count came back 0A00 (2560), but 
> the screen had garbage on it and the colors were all funky.  I don't 
> know why exactly, since the VDP ports are all memory mapped to 
> different addresses, but there was certainly something going on that 
> the VDP does not like.
> Personally I think I'll stick with the MOV(B) instructions since we 
> know those should still be safe even with 16K in the console.  It is 
> about the best we are going to get with our beloved stock 99/4A.
>

You won't overrun the VDP if you change to text or multicolor mode, or 
even set the blanking bit. Even this trick is too slow for that. ;) (Of 
course, if you set the blanking bit, you won't see anything, but it's 
good for doing a faster setup of VRAM).

I guess we've covered all the main bases now, though, except for those 
odd programs that do appear to cause an overrun. Unless we can locate 
and verify them, though, I guess we're done.

---

From: Marc Hull <[email-masked]>
Date: Fri, 13 Nov 2009 09:49:50 -0800 (PST)

The only program I know of  that creates an issue is Super Demon Attack.  And that is only on an overclocked console (mine at least.)  I have a feeling that it has more to do with timed loops and/or the ISR though because XB has issues on my overclocked console when using auto sprite motion.  

From: Tursi <[email-masked]>
Subject: Re: [TI994A] Re: VDP throughput - Got it.
To: [email-masked]
Date: Friday, November 13, 2009, 11:16 AM

---

From: "Tursi" <[email-masked]>
Date: Fri, 13 Nov 2009 14:54:06 -0500

>The only program I know of that creates an issue is Super Demon Attack. 
>And that is only on an overclocked console
>(mine at least.) I have a feeling that it has more to do with timed 
>loops and/or the ISR though because XB has issues on my
>overclocked console when using auto sprite motion.

Are we sure it's not just Super Demon Attack that's buggy? I used to get 
corrupted sprites on my /non/overclocked or accelerated console back in 
the day.. I always assumed it was just a bad dump.

Worth looking at real quick, anyway.

What kind of issues do you see in XB? If it's the ISR, autosprite motion 
overruns should in theory only affect motion, not patterns or anything 
like that.

---

From: Marc Hull <[email-masked]>
Date: Fri, 13 Nov 2009 13:21:19 -0800 (PST)

No, even the cart does it.  It's pretty unmistakable.

When you have a bunch of sprites on the screen at the same time (lowest number I saw it on was #16) then sprites begin to disappear and reappear else where.  Only when the faster crystal is used not when the 16 bit buss is active...

From: Tursi <[email-masked]>
Subject: Re: [TI994A] Re: VDP throughput - Got it.
To: [email-masked]
Date: Friday, November 13, 2009, 1:54 PM

  

like that.

---

From: Marc Hull <[email-masked]>
Date: Fri, 13 Nov 2009 13:24:17 -0800 (PST)

Sorry that didn't make much sense...

--- On Fri, 11/13/09, Marc Hull <[email-masked]> wrote:

From: Marc Hull <[email-masked]>
Subject: Re: [TI994A] Re: VDP throughput - Got it.
To: [email-masked]
Date: Friday, November 13, 2009, 3:21 PM

(Super Demon Attack)

  

(Extended BASIC)

--- On Fri, 11/13/09, Tursi <yahoogroup@harmless lion.com> wrote:

 

like that.

---

From: "jhwhite_delphi" <[email-masked]>
Date: Fri, 13 Nov 2009 23:45:33 -0000

I participated in VDP throughput discussions on the ti99-4a group.  Here are links to messages in several threads, some more applicable than others:

http://tech.groups.yahoo.com/group/ti99-4a/message/62592

http://tech.groups.yahoo.com/group/ti99-4a/message/45514

http://tech.groups.yahoo.com/group/ti99-4a/message/45358

http://tech.groups.yahoo.com/group/ti99-4a/message/45275

http://tech.groups.yahoo.com/group/ti99-4a/message/45212

http://tech.groups.yahoo.com/group/ti99-4a/message/41032

http://tech.groups.yahoo.com/group/ti99-4a/message/40072

http://tech.groups.yahoo.com/group/ti99-4a/message/40005

http://tech.groups.yahoo.com/group/ti99-4a/message/39936

http://tech.groups.yahoo.com/group/ti99-4a/message/15778

http://tech.groups.yahoo.com/group/ti99-4a/message/4336

About the read-before-write:

http://tech.groups.yahoo.com/group/ti99-4a/message/10256

Sorry that I came into this thread late.  It has been interesting reading.  Sorry, again, that I do not have time to reply to individual messages with applicable links into the "(b)others" group.  Note, I call my brothers "bothers".

Jeff White
[email-masked]