Jump to content
IGNORED

Conversion of Z80 code to TMS9900


Asmusr

Recommended Posts

Yes, these two/one instruction(s) are what I typically use for PUSH and POP. I prefer letting the stack grow towards lower addresses, since there is auto-increment, but not decrement, in the repertoire. It also means you can copy the value at TOS by just accessing *SP, since the stack pointer always points at top of stack.

If you write an operating system, or utilities for others to use, then you may want to check for stack overflow. If you write a specific program for yourself, and just push return links, not large data structures, to the stack, then it's not worth the overhead. If you do get a stack overflow in such a case, you have either severely underestimated the stack space you need, or you have created some bug which causes values to just PUSH, not POP.

 

Writing macros for the PUSH and POP functions reduce the risk you forget a "+", like in the example above. I frequently used macros for Branch with Link to Stack and ReTurn with Link from Stack, i.e. instructions including the push and branch for a call and pop and branch for a return.

  • Like 3
Link to comment
Share on other sites

  • 2 months later...
On 2/22/2021 at 1:32 AM, TheBF said:

I have never used the XOP instructions but that seems like a lot of code to do PUSH and POP plus the BLWP/RTWP overhead.

I suppose if the Assembler does not support macros this provides some abstraction. (?)

 

Push can be two instructions and pop can be one instruction on 9900. Could that work on your system?

 

 

Just re-reading your comment on never having used XOP instructions, I thought I would pass my latest use of them on, which might be of interest to the community.   Why I never thought of this before is surprising, and would have saved me months of debugging time over the years, but there you go.

 

For example, if you define an XOP as say DEBUG using code similar to 

DXOP	DEBUG,15

Then, in your programme code that needs to be debugged you can add the following:

  .
  .
  014E   0200 0003      	LI	R0,3
  0152   0201 0006      	LI	R1,6
  0156   8040           	C	R0,R1
  0158   2FE0 0208      	DEBUG	@TRACE_BUF
  015C   8001           	C	R1,R0
  015E   2FE0 0228      	DEBUG	@TRACE_BUF
  0162   0A10           	SLA	R0,1
  0164   2FE0 0248      	DEBUG	@TRACE_BUF
.
. 0200             TRACE_BUF: BSS  36			;Used to store the trace data
.

and the code in DEBUG(XOP) can produce, during execution, something such as this:

PC = 015C  ST = 1004
R0 =0003 R1 =0006 R2 =0088 R3 =0000 R4 =0500 R5 =7285 R6 =8D77 R7 =574D 
R8 =F2C0 R9 =01C6 R10=0204 R11=9044 R12=8000 R13=D411 R14=1C7B R15=0004

PC = 0162  ST = D004
R0 =0003 R1 =0006 R2 =0088 R3 =0000 R4 =0500 R5 =7285 R6 =8D77 R7 =574D 
R8 =F2C0 R9 =01C6 R10=0204 R11=9044 R12=8000 R13=D411 R14=1C7B R15=0004

PC = 0168  ST = C004
R0 =0006 R1 =0006 R2 =0088 R3 =0000 R4 =0500 R5 =7285 R6 =8D77 R7 =574D 
R8 =F2C0 R9 =01C6 R10=0204 R11=9044 R12=8000 R13=D411 R14=1C7B R15=0004

The DEBUG XOP 15 code is simply (the formatting code is left out but if anyone is interested I can post it),

 

                        ;
                        ; 	NOW SAVE THE TRACE DATA
                        ;
                  XOP15:      
  EE30   CECE           	MOV	R14,*R11+			;STORE PROGRAMME COUNTER FIRST
  EE32   CECF           	MOV	R15,*R11+			;STORE STATUS REGISTER
  EE34   0208 0010      	LI	R8,16			    ;16 REGISTERS
  EE38   CEFD     XOP_LOOP:	MOV	*R13+,*R11+			;COPY REGISTERS
  EE3A   0608           	DEC	R8
  EE3C   16FD           	JNE	XOP_LOOP
  EE3E   022D FFE0      	AI	R13,-32			    ;RESTOR WORKSPACE REGISTER LOCATION

 

Edited by adel314
Additional comment
  • Like 5
Link to comment
Share on other sites

  • 3 years later...
On 5/13/2021 at 10:59 AM, adel314 said:

Just re-reading your comment on never having used XOP instructions, I thought I would pass my latest use of them on, which might be of interest to the community.   Why I never thought of this before is surprising, and would have saved me months of debugging time over the years, but there you go.

 

For example, if you define an XOP as say DEBUG using code similar to 

DXOP	DEBUG,15

Then, in your programme code that needs to be debugged you can add the following:

  .
  .
  014E   0200 0003      	LI	R0,3
  0152   0201 0006      	LI	R1,6
  0156   8040           	C	R0,R1
  0158   2FE0 0208      	DEBUG	@TRACE_BUF
  015C   8001           	C	R1,R0
  015E   2FE0 0228      	DEBUG	@TRACE_BUF
  0162   0A10           	SLA	R0,1
  0164   2FE0 0248      	DEBUG	@TRACE_BUF
.
. 0200             TRACE_BUF: BSS  36			;Used to store the trace data
.

and the code in DEBUG(XOP) can produce, during execution, something such as this:

PC = 015C  ST = 1004
R0 =0003 R1 =0006 R2 =0088 R3 =0000 R4 =0500 R5 =7285 R6 =8D77 R7 =574D 
R8 =F2C0 R9 =01C6 R10=0204 R11=9044 R12=8000 R13=D411 R14=1C7B R15=0004

PC = 0162  ST = D004
R0 =0003 R1 =0006 R2 =0088 R3 =0000 R4 =0500 R5 =7285 R6 =8D77 R7 =574D 
R8 =F2C0 R9 =01C6 R10=0204 R11=9044 R12=8000 R13=D411 R14=1C7B R15=0004

PC = 0168  ST = C004
R0 =0006 R1 =0006 R2 =0088 R3 =0000 R4 =0500 R5 =7285 R6 =8D77 R7 =574D 
R8 =F2C0 R9 =01C6 R10=0204 R11=9044 R12=8000 R13=D411 R14=1C7B R15=0004

The DEBUG XOP 15 code is simply (the formatting code is left out but if anyone is interested I can post it),

 

                        ;
                        ; 	NOW SAVE THE TRACE DATA
                        ;
                  XOP15:      
  EE30   CECE           	MOV	R14,*R11+			;STORE PROGRAMME COUNTER FIRST
  EE32   CECF           	MOV	R15,*R11+			;STORE STATUS REGISTER
  EE34   0208 0010      	LI	R8,16			    ;16 REGISTERS
  EE38   CEFD     XOP_LOOP:	MOV	*R13+,*R11+			;COPY REGISTERS
  EE3A   0608           	DEC	R8
  EE3C   16FD           	JNE	XOP_LOOP
  EE3E   022D FFE0      	AI	R13,-32			    ;RESTOR WORKSPACE REGISTER LOCATION

 

 

  • Like 1
Link to comment
Share on other sites

3 hours ago, adel314 said:

I have been using this small debugger for sometime now and have expanded it quite a bit, while keeping it compact.  For a full article on the debugger and source updated source listing you can go to my GitHub page, here: https://github.com/AlexanderAdelAU/DEBUGGING_TMS9900_USING_XOP

 

First time I've seen a really good use case of XOP. 

  • Like 5
Link to comment
Share on other sites

On 6/10/2024 at 7:14 AM, Vorticon said:

First time I've seen a really good use case of XOP. 

I know right?  Breakpoints sure...


Here are other uses of XOP inside Texas Instruments products:


 

Texas Instruments' XDS/22 XOPs

 

I disassembled  the 16 XOPs in the 34010 emulator XDS/22. Runs on a 9996 aka 9995. 

These all come from machines where all 16 XOPs are usable. 

 

My DXOP names for them below...


CALL

 

There's an XOP to allow a BLWP reentrancy:
 

DXOP CALL,n   (choose n)

CALL @MYSELF

 

CALL moves R13-15 to  a free workspace, then sets up R13-15 to emulate the re-entrant BLWP @MYSELF with RTWP.  

 

* GETC/PUTC do one-char serial I/O

* GETS,PUTS  do string input and output,

* GET#, GETHEX, PUT# do number in/out  conversion

 

Those types often appeared on single-board computers like the University board TM990/189 where they saved code space in a tiny debugger. 

 

* POPR, PUSHR for the return stack.  

 

When you POPR R11, it recognizes that you want to RT through R11 now, and does it for you.  
 

That caused me heaps confusion on the first rough disassembly. Why are there garbage instructions after POPR R11????


BTST is an elegant XOP.  Uses this sweet trick:

 

  BTST 2

  DATA SOMVAR

 

Operand "2" is assembled as a register, but it's used as the bit number to test. 
 

 code:


  DXOP BTST,12

XOP12 BTSTWS,BTST0

BTST0 S R13,R11    want the offset 

   MOV *R14+,R0    get pointer to user variable

  ANDI R15,>DFFF clear  EQ bit before test

  COC @BITSES(R11),*R0

  JNE BTST2

  ORI R15,>2000  set EQ bit 

BTST2  RTWP


(I recall maybe this isn't where I saw LST, maybe it just ORs the EQ bit into R15.) 


BITSES EQU $
H8000 DATA >8000

H4000 DATA >4000

H2000 DATA 2000

... and so on 

 

Back to the example:  test a bit in a user variable SOMVAR:

 

  BTST 2

  DATA SOMVAR

 

On entry to the XOP, R11 is set to the operand address. When the operand is a register, such as 2, then R11 is an offset from R13, the workspace pointer. R11-R13 is the word offset into the bits array.  
 

This surprised me because the operand doesn't get used as a memory address-- it's just a bit number, pre-multiplied by 2. 

 

GeneveOS

 

In contrast, GeneveOS wastes the potential of the system call XOP operand, by using it for library number.  E.g.  XOP @ONE,0 with R0 set to the subroutine number in library ONE. 
 

This use of @ONE to extend the number of call types is pointless:  Might as well just put the library# in the high byte of R0.

 

Then, syntax could be:

XOP R0,0 to use registers as it does now;

 

Or arguments could be anywhere:

 

  XOP @IOBLK,0

 

With

 

IOBLK BYTE n,0, ... your PAB here

 

(Where n is the GeneveOS FILE routines library.)

 

Whether you use @IOBLK or R0 as the operand, it's all the same to the XOP code which gets a pointer to the operand in R11. (Of course, GeneveOS assumes register access through*R13.)  
 

It's a waste of the operand.  
 

Texas Instruments also used exactly one XOP, named SVC or service call, where  the operand points to an opcode and subopcode. For instance, 0 is DSRLNK and subopcode is the file operation. 
 

SVC accesses the runtime from microprocessor Pascal, and was kept consistent across operating systems like DX10 and  TX990.  

 

 

Example:

 

  XOP @PAB,15

 

PAB 0,n,... LUNO, error flag, file flags,...,filename pointer

 

Usually defined as:

 

 DXOP SVC,15

 SVC @PAB


PAB here is very much like the 10-byte PAB on the 4A. (Family heritage!)


The XOP operand,  @PAB, begins with a 0, meaning to call DSRLNK, with the next byte n being the subopcode. (Subopcode equals the opcode in the 4A PAB.)  The rest  is your flags and options, including the LUNO, a file# you've mapped to a filename. 
 

Later code will reuse the PAB,  replacing @PAB+1 to with subopcodes like READ, WRITE, REWIND, CLOSE etc before another SVC @PAB. 
 

(An OPEN operation needs two SVC calls: one to associate LUNO #1 to your filename. Another to OPEN the file.)

 

 

 

OK I rambled long enough on what XOP can be used for. 

Edited by FarmerPotato
Edits
  • Like 4
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...