ALTDS uses a D register for D/S field substitutions in the next instruction, while S/# modifies the D register's D and S fields and controls D/S substitution.
ALTDS D,S/#
D - a register whose D/S fields may be substituted for the next instructions' D/S fields
S/# - an 8-bit code: %ABBBCDDD
%A: 0 = don't substitute next instructions' D field with current D register's D field, 1 = substitute next instructions' D field with current D register's D field
%BBB: 000 = leave the current D register's D field the same, 0xx = add 1/2/3 to D field, 1xx = subtract 1/2/3/4 from D field
%C: 0 = don't substitute next instructions' S field with current D register's S field, 1 = substitute next instructions' S field with current D register's S field
%DDD: 000 = leave the current D register's S field the same, 0xx = add 1/2/3 to S field, 1xx = subtract 1/2/3/4 from S field
We've only got six bits specified for S/# in ALTDS, so we can use the three bits above to specify write-register alteration, with D[31:23] serving as the pointer for write redirection:
ALTDS D,S/#
S/# = %rrr_ddd_sss
rrr = same as ddd/sss, but uses D[31:23] as a write redirection pointer.
MOVI D,S/# can be used to set D[31:23]
Now we've got it all in one instruction!!!
This permits the additional possibilities of:
* redirecting the result
* redirecting the result to an unused register (maybe INx) to perform a pseudo NR
Therefore, might it be beneficial, and would it be easy to do the following ???
S/# = %RRRDDDSSS
where RRR, DDD and SSS mean:
000 = don't substitute next instructions S/D/R field, leave the current D registers S/D/I value the same
001 = substitute next instructions S/D/R field with the current D registers S/D/I field, then add 1 to the current D registers S/D/I value
010 = substitute next instructions S/D/R field with the current D registers S/D/I field, then add 2 to the current D registers S/D/I value
011 = substitute next instructions S/D/R field with the current D registers S/D/I field, then add 4 to the current D registers S/D/I value
100 = substitute next instructions S/D/R field with the current D registers S/D/I field, leave the current D registers S/D/I value the same
101 = substitute next instructions S/D/R field with the current D registers S/D/I field, then subtract 1 from the current D registers S/D/I value
110 = substitute next instructions S/D/R field with the current D registers S/D/I field, then subtract 2 from the current D registers S/D/I value
111 = substitute next instructions S/D/R field with the current D registers S/D/I field, then subtract 4 from the current D registers S/D/I value
1/2/4 covers byte/word/long in hub, and 1/2/4 longs in cog.
This permits the additional possibilities of:
* redirecting the result
* redirecting the result to an unused register (maybe INx) to perform a pseudo NR
Therefore, might it be beneficial, and would it be easy to do the following ???
S/# = %RRRDDDSSS
where RRR, DDD and SSS mean:
000 = don't substitute next instructions S/D/R field, leave the current D registers S/D/I value the same
001 = substitute next instructions S/D/R field with the current D registers S/D/I field, then add 1 to the current D registers S/D/I value
010 = substitute next instructions S/D/R field with the current D registers S/D/I field, then add 2 to the current D registers S/D/I value
011 = substitute next instructions S/D/R field with the current D registers S/D/I field, then add 4 to the current D registers S/D/I value
100 = substitute next instructions S/D/R field with the current D registers S/D/I field, leave the current D registers S/D/I value the same
101 = substitute next instructions S/D/R field with the current D registers S/D/I field, then subtract 1 from the current D registers S/D/I value
110 = substitute next instructions S/D/R field with the current D registers S/D/I field, then subtract 2 from the current D registers S/D/I value
111 = substitute next instructions S/D/R field with the current D registers S/D/I field, then subtract 4 from the current D registers S/D/I value
1/2/4 covers byte/word/long in hub, and 1/2/4 longs in cog.
I had forgotten about this! Yes, we'll have three 3-bit fields so that the result can be redirected, as well. Thanks for bringing this up.
Chip,
Would it be easy to add a special case of S=000_000_000 (effectively did nothing) to cancel the write back of the result?
This could have its own mnemonic "NR" meaning the next instruction would be equivalent to an NR effect. This makes up for the lost NR effect in the P1. So by using a pair of instructions we could set the Z and C flags without changing the destination.
Chip,
Would it be easy to add a special case of S=000_000_000 (effectively did nothing) to cancel the write back of the result?
This could have its own mnemonic "NR" meaning the next instruction would be equivalent to an NR effect. This makes up for the lost NR effect in the P1. So by using a pair of instructions we could set the Z and C flags without changing the destination.
Chip,
Would it be easy to add a special case of S=000_000_000 (effectively did nothing) to cancel the write back of the result?
This could have its own mnemonic "NR" meaning the next instruction would be equivalent to an NR effect. This makes up for the lost NR effect in the P1. So by using a pair of instructions we could set the Z and C flags without changing the destination.
Really solidly and simply. This new design has no hard-to-think-about details, so it's not difficult to know when sections of it are completed, which is a big stress reliever.
Really solidly and simply. This new design has no hard-to-think-about details, so it's not difficult to know when sections of it are completed, which is a big stress reliever.
That's great news. Simple designs are also simpler to explain and understand too.
mov count, #16
mov pntrs, initial
:loop altds pntrs, #%000_001_001
mov 0, 0
djnz count, #:loop
initial long $100<< 9 | $180
pntrs res 1
count res 1
I was wondering if that was the approach. If so, this would imply that just to manipulate D, you would always have to start with a 9-bit value that's shifted 9 bits.
Actually, the more I think about this, that's the only way to do this. ALTDS has to be able to write back to a single register (unless it's going to take additional clock cycles), which would mean that both D and S values would have to be in the same register.
Doing a slight variation of your solution, maybe something like:
setd indirect, dest
sets indirect, src
mov count, #16
:loop altds indirect, #%000_001_001
mov 0, 0
djnz count, #:loop
dest long $100
src long $180
indirect res 1
count res 1
You could have an ALTDS followed by another ALTDS, but the first one would affect the instruction following it which is another ALTDS and modify the destination and source addresses/operands of the second ALTDS. The modified second ALTDS would, in turn, modify the instruction following it, but that doesn't give you multiple levels of indirection.
You could have an ALTDS followed by another ALTDS, but the first one would affect the instruction following it which is another ALTDS and modify the destination and source addresses/operands of the second ALTDS. The modified second ALTDS would, in turn, modify the instruction following it, but that doesn't give you multiple levels of indirection.
That sounds to me like multiple levels of indirection. What am I missing?
From what I can tell, the following should copy the register pointed to by the register pointed to by ptr2ptr into result (result = **ptr2ptr):
You could have an ALTDS followed by another ALTDS, but the first one would affect the instruction following it which is another ALTDS and modify the destination and source addresses/operands of the second ALTDS. The modified second ALTDS would, in turn, modify the instruction following it, but that doesn't give you multiple levels of indirection.
That sounds to me like multiple levels of indirection. What am I missing?
From what I can tell, the following should copy the register pointed to by the register pointed to by ptr2ptr into result (result = **ptr2ptr):
But, more to Mike's point, I think he's saying that the you cannot do double indirection simply be using two consecutive ALTDSs. You must manipulate the indirect pointers to get them to work right.
Yes, you would have to manually increment/decrement the indirect registers. But this approach would be so much simpler to understand and would not require bit shifting, configuration bits, etc. It would also let @Electrodude do double indirection.
mov tmp, ptr2ptr ' tmp = ptr2ptr
shl tmp, #9 ' shift ptr2ptr into D field of tmp
altds tmp, #%000_100_000 ' use D field of tmp as D field of next instruction
altds 0-0, #%000_000_100 ' use S field of register pointed to by ptr2ptr (D of tmp)
' as S field of next instruction
mov result, 0-0 ' result = **(D of tmp) = **ptr2ptr
PS: And the only reason ALTDS saves an instruction here is because both the source and destination are in the same MOV instruction. If the operation is more complicated than a single instruction then an ADD srcptr / ADD destptr instruction pair will still be as quick.
But it does save space still, by not needing a separate pointer store, so there is that.
PPS: To be fair, this is not full indirection but rather a limited but common use case in Cog space. Won't most full indirection be in Hub space?
Oh, an ALTDS preceding an AUGD/AUGS could be fun. Would be nice to think that the three fields can fill the entire 23 immediate bits of the AUG instructions. But I guess the PTRA/PTRB registers are intended to fill this roll.
The first ALTDS would replace the "%000_000_100" in the second ALTDS. But you actually need to replace the d-field. Maybe something like this:
MOV reg2, #$100 ' pretend reg2 is at $0FF
MOV reg1, #reg2
SHL reg1, #9 ' reg1 contains %01_11111110_00000000
ALTDS addr1, #000_001_000 ' replaces next instruction's D with $0FF (which contains $100)
ALTDS 0-0, #000_000_001 ' replaces next instruction's S with $100
MOV dest, 0-0 ' becomes MOV dest, $100
A tidy up would be:
SETD reg1, #reg2 ' Cog pointer to Cog pointer preassigned, $FF placed in D operand of the ALTDS below. If traversing a table of Cog/LUT pointers then #reg2 wouldn't be an immediate operand.
NOP ' Dummy for SETD to write back before ALTDS is fetched.
reg1 ALTDS 0-0, #000_000_100 ' replaces next instruction's S from the assigned, in this case with $100
MOV dest, 0-0 ' becomes MOV dest, $100
reg2 LONG #$100
That's neat. I wasn't expecting this result of only a single ALTDS needed. Maybe my previous use wasn't so narrow after all.
Electrodude,
I think you've missed a little detail. The assignment of ptr2ptr into tmp fails because you are copying the contents of ptr2ptr rather than it's address.
And ALTDS is only capable of working with contents as it's source and writeback. That's why I've used the SETD instruction - to extract the address of reg2.
Interestingly, a real example of double indirection seems to not only need two ALTDS's but also the intermediary MOV as well. Also note I couldn't use self-modifying code for storing the pointers because they are applied as S operands. EDIT: All the earlier attempts, mine included, fail because of this need to work on the S operand.
mov total, #0
mov ptr2ptr, #raceptrtable
rep #(loopend-loop), #(racetablend-raceptrtable)
:loop
altds ptr2ptr, #000_000_001 ' apply ptr2ptr to next instruction then increment
mov ptr1, 0-0 ' use the applied pointer
altds ptr1, #000_000_100 ' apply ptr1 to next instruction
add total, 0-0 ' sum the list scores - ie: use the applied pointer
:loopend
total res 1
ptr1 res 1
ptr2ptr res 1
raceptrtable long $100,$10A,$11A,$12C,$138,$144 ' table of pointers to list of scores
racetablend
Err, I could save a long and have self modifying by changing the intermediate MOV to store into itself.
mov total, #0
mov ptr2ptr, #raceptrtable
rep #(:loopend-:loop), #(racetablend-raceptrtable)
:loop
altds ptr2ptr, #000_000_001 ' apply ptr2ptr to next instruction then increment
ptr1 sets ptr1, 0-0 ' store a table entry right in this instruction
altds ptr1, #000_000_100 ' apply ptr1 to next instruction
add total, 0-0 ' sum the list scores - ie: use the applied pointer
:loopend
total res 1
ptr2ptr res 1
raceptrtable long $100,$10A,$11A,$12C,$138,$144 ' table of pointers to list of scores
racetablend
Comments
ALTDS D,S/#
D - a register whose D/S fields may be substituted for the next instructions' D/S fields
S/# - an 8-bit code: %ABBBCDDD
%A: 0 = don't substitute next instructions' D field with current D register's D field, 1 = substitute next instructions' D field with current D register's D field
%BBB: 000 = leave the current D register's D field the same, 0xx = add 1/2/3 to D field, 1xx = subtract 1/2/3/4 from D field
%C: 0 = don't substitute next instructions' S field with current D register's S field, 1 = substitute next instructions' S field with current D register's S field
%DDD: 000 = leave the current D register's S field the same, 0xx = add 1/2/3 to S field, 1xx = subtract 1/2/3/4 from S field
In the linked post you discussed this... This permits the additional possibilities of:
* redirecting the result
* redirecting the result to an unused register (maybe INx) to perform a pseudo NR
Therefore, might it be beneficial, and would it be easy to do the following ???
S/# = %RRRDDDSSS
where RRR, DDD and SSS mean:
000 = don't substitute next instructions S/D/R field, leave the current D registers S/D/I value the same
001 = substitute next instructions S/D/R field with the current D registers S/D/I field, then add 1 to the current D registers S/D/I value
010 = substitute next instructions S/D/R field with the current D registers S/D/I field, then add 2 to the current D registers S/D/I value
011 = substitute next instructions S/D/R field with the current D registers S/D/I field, then add 4 to the current D registers S/D/I value
100 = substitute next instructions S/D/R field with the current D registers S/D/I field, leave the current D registers S/D/I value the same
101 = substitute next instructions S/D/R field with the current D registers S/D/I field, then subtract 1 from the current D registers S/D/I value
110 = substitute next instructions S/D/R field with the current D registers S/D/I field, then subtract 2 from the current D registers S/D/I value
111 = substitute next instructions S/D/R field with the current D registers S/D/I field, then subtract 4 from the current D registers S/D/I value
1/2/4 covers byte/word/long in hub, and 1/2/4 longs in cog.
I had forgotten about this! Yes, we'll have three 3-bit fields so that the result can be redirected, as well. Thanks for bringing this up.
Would it be easy to add a special case of S=000_000_000 (effectively did nothing) to cancel the write back of the result?
This could have its own mnemonic "NR" meaning the next instruction would be equivalent to an NR effect. This makes up for the lost NR effect in the P1. So by using a pair of instructions we could set the Z and C flags without changing the destination.
Good idea! I'll make it do that.
A versatile replacement for the indirect registers of the old P2.
How are things progressing?
Could the same effect be achieved by redirecting the D to INA? (ie the hidden ram behind it)
Yes, but you would need a register to be holding $1FA<<23. By using S=0 to do the same thing, A simple ALTDS 0,#0 could cancel the write.
Really solidly and simply. This new design has no hard-to-think-about details, so it's not difficult to know when sections of it are completed, which is a big stress reliever.
FYI - I LOVE the new LOCADDR/LINK being able to load PTRA/B and six additional high registers!
What is the value of altering both the D and S at the same time?
What is the value of altering the instruction bits?
What would happen if you alter S on an instruction like COGID (where S is part of the opcode)?
How would I go about moving data between two buffers? For instance:
I was wondering if that was the approach. If so, this would imply that just to manipulate D, you would always have to start with a 9-bit value that's shifted 9 bits.
Actually, the more I think about this, that's the only way to do this. ALTDS has to be able to write back to a single register (unless it's going to take additional clock cycles), which would mean that both D and S values would have to be in the same register.
Doing a slight variation of your solution, maybe something like:
You could have an ALTDS followed by another ALTDS, but the first one would affect the instruction following it which is another ALTDS and modify the destination and source addresses/operands of the second ALTDS. The modified second ALTDS would, in turn, modify the instruction following it, but that doesn't give you multiple levels of indirection.
That sounds to me like multiple levels of indirection. What am I missing?
From what I can tell, the following should copy the register pointed to by the register pointed to by ptr2ptr into result (result = **ptr2ptr):
EDIT: the above is wrong; the following is modified to replace the D instead of S field of the seconds ALTDS:
The first ALTDS would replace the "%000_000_100" in the second ALTDS. But you actually need to replace the d-field. Maybe something like this:
Yes, you would have to manually increment/decrement the indirect registers. But this approach would be so much simpler to understand and would not require bit shifting, configuration bits, etc. It would also let @Electrodude do double indirection.
Interestingly, ALTDS only saves one instruction in the loop. REP saves another though, so it becomes something like:
PS: And the only reason ALTDS saves an instruction here is because both the source and destination are in the same MOV instruction. If the operation is more complicated than a single instruction then an ADD srcptr / ADD destptr instruction pair will still be as quick.
But it does save space still, by not needing a separate pointer store, so there is that.
PPS: To be fair, this is not full indirection but rather a limited but common use case in Cog space. Won't most full indirection be in Hub space?
A tidy up would be:
That's neat. I wasn't expecting this result of only a single ALTDS needed. Maybe my previous use wasn't so narrow after all.
I think you've missed a little detail. The assignment of ptr2ptr into tmp fails because you are copying the contents of ptr2ptr rather than it's address.
And ALTDS is only capable of working with contents as it's source and writeback. That's why I've used the SETD instruction - to extract the address of reg2.