Store and restore attribute values

edited May 2012 in Development
I am needing ideas on how to write a machine code routine that will store/restore (more important to restore) attribute values to the 22528 area.

I am only wanting to store/restore a 16x16 section i.e. the AT 0,0 to 16,16 area of screen, 256 bytes I think?!

I heard you can use LDIR to make it easier, but I'm a bit lost...
Post edited by daveysludge on

Comments

  • edited May 2012
    I am needing ideas on how to write a machine code routine that will store/restore (more important to restore) attribute values to the 22528 area.

    I am only wanting to store/restore a 16x16 section i.e. the AT 0,0 to 16,16 area of screen, 256 bytes I think?!

    I heard you can use LDIR to make it easier, but I'm a bit lost...

    Hi davey,

    This should do it, though please note it's hurriedly cobbled together and almost time for my bed :-). 2 separate subroutines. Code is not perfect I'm sure but a quick test shows it works.
    org 32768
    	
    store_attributes
    	ld hl,22528		;start of attributes
    	ld de,attribute_buffer	;DEstination
    	ld b,16			;16 rows to save
    stlp	ld c,255		;c is decremented during ldi, so avoid flag effects by filling it up
    	ldi
    	ldi
    	ldi
    	ldi
    	ldi
    	ldi
    	ldi			;move a 16 byte row to the buffer
    	ldi
    	ldi
    	ldi
    	ldi
    	ldi
    	ldi
    	ldi
    	ldi
    	ldi
    	push bc
    	ld bc,16		;16 bytes is the distanc to the next row start
    	add hl,bc
    	pop bc			;get b back for the correct number of djnz
    	djnz stlp
    	ret
    	;
    restore_attributes
    	ld hl,attribute_buffer
    	ld de,22528
    	ld b,16
    ralp	ld c,255
    	ldi
    	ldi
    	ldi
    	ldi
    	ldi
    	ldi			;move 16 bytes from the buffer to the screen
    	ldi
    	ldi
    	ldi
    	ldi
    	ldi
    	ldi
    	ldi
    	ldi
    	ldi
    	ldi
    	push bc
    	ex de,hl		;we can only add to hl with 16 bit numbers
    	ld bc,16		;distance between rows
    	add hl,bc
    	ex de,hl		;put hl back to buffer, de back to screem
    	pop bc			;get b back for djnz
    	djnz ralp
    	ret
    	;
    attribute_buffer
    	defs	256		;define space 256 bytes = 0,0 to 16,16
    

    ldir would work fine for this, albeit more slowly (if you're writing a utility tho not a problem), I've just been using this recently so am in the habit.
  • edited May 2012
    Cheers mate, I'll give it a whirl! ;)
  • edited May 2012
    Since you've written than code for speed - i.e. unrolled the LDI loop - you missed the fact that you don't need to PUSH/POP BC when you update the screen address, but can instead just temporarily move B into A, since you don't use the accumulator in the loops.
  • edited May 2012
    bobs wrote: »
    Since you've written than code for speed - i.e. unrolled the LDI loop - you missed the fact that you don't need to PUSH/POP BC when you update the screen address, but can instead just temporarily move B into A, since you don't use the accumulator in the loops.

    Cheers Bob, yep much better using a. Using b for looping is so ingrained I forget I good the accumulator can be.
  • edited May 2012
    At the ATTR area is contigeous you could use Battle Bunny's amazing 9 byte Memory Move routine from BASIC.

    Paddy
  • edited May 2012
    At the ATTR area is contigeous you could use Battle Bunny's amazing 9 byte Memory Move routine from BASIC.

    Sma-a-a-all problem with that idea. If you're copying a 16x16 attribute block then the rows are not contiguous; there's a 16-byte gap between each row.

    PS.
    Just occurred to me. You could just copy a 32x16 block, which would be contiguous. As the other 16x16 attribute bytes haven't changed they wouldn't have any effect on the screen display. Of course, it would mean having to store an extra 16x16 bytes in the first place.
  • edited May 2012
    I eventually had to try out that idea, and including the adjacent 16x16 attribute block so that the save can be done in a single command works just as well as copying the discrete block, given a few minor caveats, namely: the source block should be on the left; the right-hand attributes shouldn't change between saving & restoring (as the restore will put back the old attributes); the top line should be in the range 0-6 (otherwise the bottom line will run into the printer buffer).

    I did assembler & BASIC versions (summarised below) and, as can be seen from this little RZX demo, there's no visible difference in the speed between them. Note that for the assembler version I put the address of the save area in S_TOP as that system variable isn't used when a program is running. The BASIC version doesn't need this as it just LETs the attributes to a string variable.
    ----- machine code version
         REM initialise: dd needs 512 bytes
         POKE 23660,FN g(dd): POKE 23661,FN h(dd)
         ...
         REM use: option: 0=put, 1=get
         RANDOMIZE row*64+col*2+option+USR pg
    
            org  65536-30
    
    PUTGET: call $2da2           ;FP-TO-BC
            srl  b
            rr   c
            ld   hl,22528
            ld   de,(23660)      ;(S-TOP)=dd
            jr   c,GET
    PUT:    add  hl,bc
            jr   COPY
    GET:    add  hl,bc
            ex   de,hl
    COPY:   ld   bc,512
            ldir
            call $2d2b           ;STACK-BC
            ret
    
    ----- BASIC version
         DEF FN p(a)=PEEK a+256*PEEK (a+1):
         DEF FN g(v)=v-FN h(v)*256: DEF FN h(v)=INT (v/256)
    
         REM initialise: dd needs 9 bytes
         DIM s$(512): POKE 23563,FN g(dd): POKE 23564,FN h(dd):
         LET attadd=22528+row*32+col
         FOR a=dd TO dd+8: READ b: POKE a,b: NEXT a:
         DATA CODE "A",CODE "$",14,0,FN g(attadd),FN h(attadd),0,2,CODE ")"
         ...
         REM use: put
         LET s$=a$
         REM use: get
         LET a$=s$
    
Sign In or Register to comment.