Shop OBEX P1 Docs P2 Docs Learn Events
Any way to extract S field of a register to another in a single instruction? — Parallax Forums

Any way to extract S field of a register to another in a single instruction?

What am I missing? If I use SETS D, S I think I need to clear the D register first, or if I do a AND S, #$1ff I destroy S.
Surely this is doable...
«1

Comments

  • roglohrogloh Posts: 5,150
    edited 2020-05-31 08:34
    Am just trying to optimize this sequence...and somehow eliminate the MOV a, #0 wcz - as I can always set Z in the ANDN later. This code has to check for zero transfer count as well as crossing a 512 byte boundary before the transfer takes place to prevent it. Taking 7 instructions right now and I reckon it could be shrunk somehow. Temporary register "a" is not used after this, but I need Z set to 1 and C=0 when I continue on and the addr1 & count registers get used so they need to remain intact.
    '..................................................................................................
    ' HYPER WRITES without latency
                                
                                                                ' a b c
    
                                                                ' W B R  (a) word write
                                                                ' O U E  (b) burst write
                                                                ' R R G  (c) register write
                                                                ' D S 
                                                                '   T
    w_flash_burst                                                 
                                tjz     count, #nowrite_lut     '   b     ensure transfer count is non-zero
                                mov     a, #0 wcz               '   b     zero out test reg and set z flag for later, c=0
                                sets    a, addr1                '   b     get 9 LSBs of flash address
                                add     a, count                '   b     add the count
                                sub     a, #1                   '   b     find the last address
                                andn    a, #$1ff                '   b     clear lower bits
                                tjnz    a, #sizeerror           '   b     exit if this wraps past 512 byte boundary    
    
  • Cluso99Cluso99 Posts: 18,069
    edited 2020-05-31 08:54
    There is no need to zero out a first, nor use sets. Saves an instruction.
    Also not sure about the 2 clock pipeline delay in setting a either.
                    mov     a, addr1
                    add     a, count
                    sub     a, #1
                    andn    a, #$1ff   wz  ' wz optional
                    tjnz    a, #sizeerror
    
    and this would work too
                    mov     a, addr1
                    add     a, count
                    sub     a, #1
                    testb   a, #9      wcz '
            if_c/nz jmp     #sizeerror
    
  • roglohrogloh Posts: 5,150
    edited 2020-05-31 09:29
    Unfortunately I don't think these will work Cluso. Addr1 can range from 0-$1ffffff, so its upper bits from bit9-bit24 are arbitrary. But I'm sure there is a way to shrink this code down somehow and still achieve the aims.

    The sets should not have pipeline problems if we are not executing from it.
  • I can probably do this and avoid the sets entirely but I still can't save an instruction this way.
                    tjz     count, #nowrite_lut
                    mov     a, addr1
                    and     a, #$1ff
                    add     a, count
                    sub     a, #1
                    andn    a, #$1ff   wcz  ' wz optional
                    tjnz    a, #sizeerror
    
  • evanhevanh Posts: 15,169
    edited 2020-05-31 09:59
    If D is reserved for this function then reusing SETS on it will only ever set the low 9 bits. So no need to keep clearing D beforehand. Oh, I see it explicitly looks for summing > 9 bits.

    MUXQ would work but still requires a SETQ setup sometime earlier. Not really any different to clearing D first.
  • rogloh wrote: »
    I can probably do this and avoid the sets entirely but I still can't save an instruction this way.
    		tjz	count, #nowrite_lut
    		mov	a, addr1
    		and	a, #$1ff
    		add	a, count
    		sub	a, #1
    		andn    a, #$1ff 	wcz  ' wz optional
    		tjnz    a, #sizeerror
    

    Is this any good?
    		tjz	count, #nowrite_lut
    		mov	a, addr1
    		add	a, count
    		sub	a, limit	wcz	'nc if too big
    	if_nc	jmp	#sizeerror
    
    'c, nz - opposite of what was wanted
    
    limit		long	#512			'check value
    
  • evanhevanh Posts: 15,169
    Combine those two
    		tjz	count, #nowrite_lut
    		mov	a, addr1
    		and	a, #$1ff
    		add	a, count
    		sub	a, #$1ff 	wcz  ' wz optional
    if_nc_and_nz	jmp	a, #sizeerror
    
  • roglohrogloh Posts: 5,150
    edited 2020-05-31 10:44
    Both @evanh and @TonyB_ almost get there but I need C=0 at the end when it falls through and continues. This would need another instruction to clear it. I was wondering if an alt instruction may help somehow or even reverse subtract? Or possibly a "tjns a, #sizeerror" based on evanh's approach?
  • Cluso99Cluso99 Posts: 18,069
    ALTI can do auto incrementing/decrementing so perhaps there's a combo here that can take care of the sub #1 at the same time???
  • Yeah I was hoping for something like that, or use addx or cmpsub somehow....too many choices. lol.

    The original 7 instruction code I show just seems too inefficient. The original footprint I had in place only checked zero and a total 512 byte limit but no 512 byte boundary crossing was 5 instructions and I'm trying to not grow it much to extend to cases where any transfer crosses a 512 byte boundary is identified and rejected.
  • evanhevanh Posts: 15,169
    edited 2020-05-31 11:00
    Bah! [deleted bad code]
  • roglohrogloh Posts: 5,150
    edited 2020-05-31 11:06
    I think that corrupts addr1 evanh or the register pointed to by addr1 perhaps. But I think alt something may help. We are on the right track.

    I would quite like the "andn a, #$1ff wcz" at the end though because it leaves the flags in the right condition.

    Update: there's also the FLES / FLE / FGE/ FGES stuff too. That might be something useful too.
  • evanhevanh Posts: 15,169
    edited 2020-05-31 11:08
    How about
    		tjz	count, #nowrite_lut
    		mov	a, addr1
    		and	a, #$1ff
    		sub	a, #$1ff
    		add	a, count 	wcz
    if_c_or_z	jmp	#sizeerror
    
  • Doesn't leave z=1 at the end.
  • evanhevanh Posts: 15,169
    Arg! I thought you only wanted C==0
  • evanhevanh Posts: 15,169
    What about "a" value. That's out by one as well. Does that matter?
  • I wish. LOL. The andn a, #$1ff wcz is good because it does multiple things in one go. I just reckon the above code could be 6 (or maybe even 5) instructions if I find the right magic sequence. 7 just feels too much. If I could get the S field in a single instruction (title of this thread) I'd be happy. Maybe alts can be used.

    @evanh. a is just a free temp register so it can be left in any state.
  • evanhevanh Posts: 15,169
    ALTS doesn't save any space, and ALTD and ALTR can only be used for indirection, sadly. Same story for ALTI: D and R fields are indirection only and S field is no space gain, afaics.

  • I was also looking at encod to see if the top bit is greater than 9 after addition, but it doesn't save against the andn a, #$1ff thing. I wonder if bit 9 of addr1 can be tested and xor'd with its original value somehow to see if it changes after adding count-1.
  • evanhevanh Posts: 15,169
    Actually, I have managed to do something with ALTS, namely incorporate the -1. This has an odd wrap around effect but maybe that's okay?
    		tjz	count, #nowrite_lut
    		alts	addr1, #$1ff
    		mov	a, #0-0
    		add	a, count
                    andn    a, #$1ff   wcz  ' wz optional
                    tjnz    a, #sizeerror
    
  • I think you might have it evanh! That wrap effect may be okay. I need to check.
  • Cluso99Cluso99 Posts: 18,069
    edited 2020-05-31 12:51
    Mov a, addr1
    And a, #$1ff
    Add a,count
    CMP a, #$201 or cmpr if you need the opposite c.

    This saves the sub.
  • evanhevanh Posts: 15,169
    Needs ##$201 :(

  • roglohrogloh Posts: 5,150
    edited 2020-05-31 12:59
    The cmp a, #$201 doesn't fit within the 9 bit S field of the instruction. You'd need another register to hold $201. No space saved vs 7 instructions. So far evanh's solution seems the best, but I wonder if it can be reduced to 5? There's a challenge.
  • evanhevanh Posts: 15,169
    Well, you can't eliminate the MOV. The ALTS absolutely needs it. That's why I'd initially said ALTS doesn't save space.
  • Yeah, I think this is as good as it gets. A great result as we can now test for flash line buffer write overruns with only one added instruction compared to what I had before. I'm going to use this evanh.
  • evanhevanh Posts: 15,169
    cool
  • evanh wrote: »
    Actually, I have managed to do something with ALTS, namely incorporate the -1. This has an odd wrap around effect but maybe that's okay?
    		tjz	count, #nowrite_lut
    		alts	addr1, #$1ff
    		mov	a, #0-0
    		add	a, count
                    andn    a, #$1ff   wcz  ' wz optional
                    tjnz    a, #sizeerror
    

    sizeerror is probably close by, but one issue with TJxx D,#S is that cannot jump from anywhere in COG RAM to anywhere in LUT RAM and vice-versa. Alternative:
    		tjz	count, #nowrite_lut
    		alts	addr1, #$1ff
    		mov	a, #0-0		wc	' nc
    		add	a, count
    		andn    a, #$1ff   	wz	' z if OK
    	if_nz	jmp	#sizeerror
    
  • Too funny. That is exactly what I had to do today. The tjnz didn't work out due to the LUTRAM jump but thankfully I already had Z set and could do this.
  • roglohrogloh Posts: 5,150
    edited 2020-07-01 07:13
    After running into a HyperFlash programming problem with burst writes I think this suggested code from the discussion with @TonyB_ and @evanh a month ago is broken unfortunately. Turns out I can't start on any 512 byte boundary in flash using it. Eg, if addr1 = 1024 and count was 2 it would fail, but it should be allowed. It should be such that it allows any count up to 512 in that case. I want it to abort out on count=0, as well as (count+(addr & $1ff))>512, and otherwise set Z=1, C=0 on success. I now need an alternative and I don't have any spare longs! Argh..
    		tjz	count, #nowrite_lut
    		alts	addr1, #$1ff
    		mov	a, #0-0		
    		add	a, count
    		andn    a, #$1ff   	wcz
    	if_nz	jmp	#sizeerror
    
Sign In or Register to comment.