Jump to content
IGNORED

TMS9900 assembly language tricks


retroclouds

Recommended Posts

21 hours ago, JasonACT said:

On real hardware, I don't think you ever get this far.  You certainly do in an emulator though.

If you want to make that assertion, then explain why not?

 

My knowledge of the system doesn't come from emulation, so I would like to know what you think I'm missing, especially if you're going to brag about schooling me ;)

 

  • Like 1
Link to comment
Share on other sites

43 minutes ago, Tursi said:

If you want to make that assertion, then explain why not?

 

My knowledge of the system doesn't come from emulation, so I would like to know what you think I'm missing, especially if you're going to brag about schooling me ;)

Why not?  Because, I ran it on real hardware, from the EA cart's option 5 and I was left with a green screen of death.  Then I ran it the same way in an emulator and it did what is expected, return you to the title screen.

 

But it was you who came along, dissected my post, and said it would run on real hardware, and it's not possible for software to do what I was saying it does.

Link to comment
Share on other sites

20 hours ago, apersson850 said:

From what I remember, the most vulnerable hardware to a software attack is the PSI, the TMS 9901. Since it has programmable IO pins, where you can set if they are outputs or inputs, you may turn two outputs agains each other, and set them to different levels.

What is also dangerous for the 9901 is when you connect a pin to e.g. a switch that closes to ground, and then reprogram that pin from input to output. I discussed those scenarios on Ninerpedia some time ago (in the scope of my knowledge).

 

https://www.ninerpedia.org/wiki/Programmable_Systems_Interface_TMS_9901#Safety_precautions

 

  • Like 1
Link to comment
Share on other sites

On 7/27/2023 at 11:54 AM, JasonACT said:

On real hardware, I don't think you ever get this far.  You certainly do in an emulator though.

Ah, that's not so certain. I see crashes on MAME that look identical to the real machine. The only thing that is not really well emulated are physical tolerances and thermal behavior.

Link to comment
Share on other sites

4 hours ago, JasonACT said:

Why not?  Because, I ran it on real hardware, from the EA cart's option 5 and I was left with a green screen of death.  Then I ran it the same way in an emulator and it did what is expected, return you to the title screen.

 

But it was you who came along, dissected my post, and said it would run on real hardware, and it's not possible for software to do what I was saying it does.

It's not an attack, dude. But it's not a schooling without an education. What is actually happening?

 

There's nothing that writing to those addresses /should/ do.

 

Link to comment
Share on other sites

Okay. Confirmed I can reproduce the issue on hardware using Easy Bug to enter the code (at >7000 instead of >A000, for simplicity.)

I can't reproduce any kind of lock up using MAME though.

 

I confirmed through variations that it's not a software lockup, or at least doesn't appear to be. Next instruction after BLWP does not seem to execute as you surmised. I left interrupts enabled, and also added an extra instruction that did not rely on a workspace.

 

I let it spin for a while and didn't notice anything abnormal with the thermal camera. GROMs in particular were near ambient, so they weren't experiencing any unusual load.

 

It is an interesting case though! Next step will be to drag the scope downstairs and see whether it's stuck on the READY line or cycling in some way. Hooking up the logic analyzer would be nice but mine can only do a very brief capture... might be able to catch it with a trigger though. That's going to have to wait a bit though.

 

Only theory I have is that maybe yes, after all, hitting the GROMs too fast can lock up the system. Originally I discounted that, since they have their READY line, and we know it's used for BLWP memory writes (otherwise the 32k wouldn't work), but, the GROM READY is a little weird both in how it works and how it's gated onto the CPU. GROMs are "not ready" /except/ when an access cycle is completed, then they go back to NOT ready again. The hardware only connects the READY line to the CPU during the GROM access cycle, and it disconnects it without waiting for the GROM to clear it (by my testing - it would have to anyway, else the CPU would get stuck in HOLD). So my theory is, if the next cycle comes around before the GROM has /actually/ finished its cycle, then the GROM may not see the new cycle start. If it doesn't, then it absolutely will never release the hold on the CPU. That would explain all the warnings that I discounted in my previous post. ;) Normal CPU access is too slow to be an issue, but back to back register writes probably isn't.

 

Should be possible to prove that, but that won't be today. Will take a note.

 

  • Like 4
Link to comment
Share on other sites

I'm in this for the knowledge, dude. So being wrong is great, but until we understand what's causing the lockup, we haven't learned anything yet. We've only learned that there is something to be learned. ;)

 

I don't have any copies of Dragon's Lair anyway.

 

 

  • Like 1
Link to comment
Share on other sites

Shame, they would make a good "for charity" auction item.

 

image.thumb.jpeg.049406cae27093997d369a56f2560bc7.jpeg

 

I'm guessing you'll never know, it appears the guy who did know wasn't a great communicator to TI's technical writer, based on this.

 

How the slow clock affects timing of the much faster *CE is a mystery to me.  But the last sentence suggests they "just need a bit of time" to get back into ready mode.

  • Like 1
Link to comment
Share on other sites

2 minutes ago, JasonACT said:

Shame, they would make a good "for charity" auction item.

 

image.thumb.jpeg.049406cae27093997d369a56f2560bc7.jpeg

 

I'm guessing you'll never know, it appears the guy who did know wasn't a great communicator to TI's technical writer, based on this.

 

How the slow clock affects timing of the much faster *CE is a mystery to me.  But the last sentence suggests they "just need a bit of time" to get back into ready mode.

Yeah, that's starting to make a lot of sense. Unfortunately RL is being crazy, it'll probably be a few months till I can put the logical analyzer down and see the signals.

  • Like 4
Link to comment
Share on other sites

  • 3 weeks later...

Following up "code pools" in @apersson850's Pascal topic:

 

(This is from memory.. I'll consult the RX source later)


 

TI offered two other Pascals. The manuals say you can have Pcode or compiled code. 
 

Can the compiled code be moved in memory at runtime? After it's linked? I get the idea that the answer is yes. How?

 

Assembly language tricks!
 

A compiled process , procedure, or function under MPX (TI's Microprocessor Pascal Executive) will have a run-time frame (?) pointer to itself. All branches within the procedure or function,  and any local storage or constants, are addressed relative to that.

 

 

The frame pointer, R11,  is calculated by  the subroutine's first instructions:  

 

LI R4,>03xx * opcode for B *R11

X R4

BEGIN EQU $ * code label

 

Now R11 can be used to point to local data and local branches. 

A @CONST-BEGIN(R11),R0

B @SUB100-BEGIN(R11)

 

 

Subroutines are called through an intermediate routine:

 

BLWP @CALL$$

DATA MYSUB

 

It's possible that MYSUB  could be a pointer into a dynamic symbol table. Foundation for runtime movable code!

 

Another neat trick:

I *think* I got the idea that if R8 is the stack pointer, and R9 is CALL$$, then

 

BLWP R8

 

will allocate a workspace for the subroutine. In CALL$$ there might be

 

AI R8,>20

LI R9,CALL$$

 

to move the  stack pointer past the subroutine's new workspace. 


If R8 is the return stack pointer, R10 can point to a data stack. CALL$$ copies it:

 

MOV @R10*2(R13),R10

 

The subroutine can exit with

 

MOV R0,*R13 * my return value

RTWP

Less risk of stack PUSH/POP bugs: the subroutine doesn't have to balance  the caller's stack pointer (unless it really wants to). The caller can be responsible for that. (Or  the caller can just RTWP.) Think of PRINTF or variable length argument lists!
 

* push ARG1 local constant 

DECT R10
MOV @ARG1-BEGIN(R11),*R10
 

Subroutine can POP locally if it wants to use the stack:

 

MOV *R10+,R2 * pop

 

Personally, I like the data stack to grow upward so that PUSH uses the auto increment and POP uses DECT or MOV @-2(R10) etc. 

 

 

Linking Loader 

 

The DEF table contains 0-based offsets into a table of absolute addresses. REFS hold  the usual linked list until the corresponding DEF is found. 
 
Suppose that the DEF table defines SUBRT as 2. CALL$$  consults the dynamic symbol table and sees that entry 2 holds 0, ie SUBRT is not in memory.  It loads its segment and updates the symbol table so that there is now an absolute address in entry 2.

CALL$$ branches to the absolute address. 


When the heap manager needs to move code segments out of the way, or if a segment is unloaded (freeing up memory) it updates the DEF table accordingly. 


The Heap Manager might cooperate with CALL$$ to ensure that an active process or subroutine is never unloaded. And that the least-recently used segment is unloaded to make space. A process that exits is completely freed, except for shared libraries  (using SREF/DSEG/CSEG.)


An extension to this scheme uses memory mapping.  That is, a 4K page in address space is immediately remapped to another segment. (TI compilers for 990 created overlays for big programs.) 
 

The DEF table could hold two-word page-and-offset  values. Or it could require a scheme such that all DEFs must be 16-bit aligned, leaving 4 more bits for page number.  A 4K offset normally occupies 12 bits, now only 8, so you get 8 bits for  page number: adequate for 1 megabyte of segments. 

 

 

In the end, achieving PIC in this way, seems much more complicated than with position independent Pcode! But it's the compiler, not the programmer, which  writes all the yucky code.
 

 

 

  • Like 3
Link to comment
Share on other sites

The p-systems's approach is that it's the operating system's code handler that makes the brunt of the work when the user's program is running. The compiler will do some of it, since it generates the code file, and the code file is split up in the different segments. The compiler will generate inter-segment calls when appropriate, so the code handler will know in which segment to look for a procedure.

  • Like 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

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

×   Your previous content has been restored.   Clear editor

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

Loading...
  • Recently Browsing   0 members

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