How to Move memory

Basic and Machine Language

Moderator: Moderators

Post Reply
User avatar
nbla000
Salmon Run
Posts: 2582
Joined: Thu Oct 13, 2005 8:58 am
Location: Italy

How to Move memory

Post by nbla000 »

Hi to everybody, i came back from my holidays.... finally!!!

Now i'm working on some 2 part games (especially games that load characters in the first part via DATA & POKE) to single file and crunch them.

To do some work i need a short assembler routine to move some bytes from a location to another:
Example: move 74 bytes ($4a) from location $1b50 to $1c70

I've a Carlsson's routine used to move 8192 bytes ($2000) from location $2000 to $a000 but since my assembler is not so good, i don't know how to modify it for my purpose.

Code: Select all

1400   A2 20      LDX #$20     from $2000
1402   86 FC      STX $FC
1404   A9 A0      LDA #$A0     to   $A000
1406   85 FE      STA $FE
1408   A0 00      LDY #$00
140a   84 FB      STY $FB
140c   84 FD      STY $FD
140e   B1 FB      LDA ($FB),Y
1410   91 FD      STA ($FD),Y
1412   C8         INY
1413   D0 F9      BNE $140E
1415   E6 FC      INC $FC
1417   E6 FE      INC $FE
1419   CA         DEX
141a   D0 F2      BNE $140E
141c   4C 22 FD   JMP $FD22    RESET
so looking here on www.6502.org i've found this routine:

Code: Select all

; Move memory down
;
; FROM = source start address
;   TO = destination start address
; SIZE = number of bytes to move
;
MOVEDOWN LDY #0
         LDX SIZEH
         BEQ MD2
MD1      LDA (FROM),Y ; move a page at a time
         STA (TO),Y
         INY
         BNE MD1
         INC FROM+1
         INC TO+1
         DEX
         BNE MD1
MD2      LDX SIZEL
         BEQ MD4
MD3      LDA (FROM),Y ; move the remaining bytes
         STA (TO),Y
         INY
         DEX
         BNE MD3
MD4      RTS
so mixing with Carlsson's routine, i've transposed the 6502.org routine to the Vic-20, probably with errors:

Code: Select all

1100   A0 00      LDY #$00
1102   A6 00      LDX $00    <--- bytes to move HI
1104   F0 0E      BEQ $1114
1106   B1 FB      LDA ($FB),Y
1108   91 FD      STA ($FD),Y
110a   C8         INY
110b   D0 F9      BNE $1106
110d   E6 FC      INC $FC
110f   E6 FE      INC $FE
1111   CA         DEX
1112   D0 F2      BNE $1106
1114   A6 4A      LDX $4A        <--- bytes to move LO
1116   F0 08      BEQ $1120
1118   B1 FB      LDA ($FB),Y
111a   91 FD      STA ($FD),Y
111c   C8         INY
111d   CA         DEX
111e   D0 F8      BNE $1118
1120   60         RTS
i set the 74 bytes to move ($4a) in lines 1102 and 1114 but how to set the source ($1b50) and destination ($1c70) addresses?
User avatar
Mike
Herr VC
Posts: 4816
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

How about:

Code: Select all

     LDX #$4A
loop LDA $1B4F,X
     STA $1C6F,X
     DEX
     BNE loop
with fixed addresses and at most 256 bytes to copy, there's no need to use the full-fledged implementation with indirect addressing.

The begin of source and target have been decremented by 1, since X counts down from 74 to 1, and the loop exits as X becomes 0.

Greetings,

Michael
User avatar
nbla000
Salmon Run
Posts: 2582
Joined: Thu Oct 13, 2005 8:58 am
Location: Italy

Post by nbla000 »

Great, this routine is very short and practical to move some bytes (Max 256, $FF), thanks.

How to move more then 256 bytes?
User avatar
Mike
Herr VC
Posts: 4816
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: How to Move memory

Post by Mike »

nbla000 wrote:How to move more then 256 bytes?
In that case you must preface the copy routine to put the pointers to source and target into the corresponding ZP addresses:

Code: Select all

1400   A9 00      LDA #lo_byte of source
1402   85 FB      STA $FB
1404   A9 00      LDA #lo_byte of target
1406   85 FD      STA $FD
1408   A9 20      LDA #hi_byte of source
140A   85 FC      STA $FC
140C   A9 A0      LDA #hi_byte of target
140E   85 FE      STA $FE
If both low-bytes are the same, then of course you don't need to re-load the accumulator. If they're even 0, you then can do LDY #$00 beforehand, and store that value into the low-bytes.

Furthermore you must either supply the SIZE in immediate arguments,

Code: Select all

1102   A6 00      LDX $00    ; --> should be LDX #$00
1114   A6 4A      LDX $4A    ; --> should be LDX #$4A 
or set aside another pair of ZP addresses that are initialised beforehand.

You must take pre-cautions, if you're going to copy overlapping regions. When your target has a higher address than the source, then you must copy from the end of the source downwards! Otherwise you'll overwrite part of the source which has not yet been copied.

Michael
Thomas Hechelhammer
Vic 20 Dabbler
Posts: 79
Joined: Thu Jun 09, 2005 11:51 pm
Location: Germany

Re: How to Move memory

Post by Thomas Hechelhammer »

nbla000 wrote: so mixing with Carlsson's routine, i've transposed the 6502.org routine to the Vic-20, probably with errors:

Code: Select all


1102   A6 00      LDX $00    <--- bytes to move HI

1114   A6 4A      LDX $4A        <--- bytes to move LO
The A6 00 gets the byte which is already stored in Adress $0000.

For loading the X-Register with the value $00 you need the command LDX #$00 which is A2.

Here is the difference:

Code: Select all


1102   A6 00    LDX  $00 ; copys the value which is stored in $00 to reg X
1102   A2 00    LDX #$00 ; copys the value $00 to reg X
But there is a much easier method:

Code: Select all

start = where_the_block_starts_to_be_moved
end = start + bytes_to_be_moved
newend = newlocation + bytes_to_be_moved

LDA #$<start       ; low-byte startadress
STA $5F
LDA #$>start       ; high-byte
STA $60 
LDA #$<end +1      ; low-byte endadress + 1
STA $5A
LDA #$>end +1      ; high-byte
STA $5B
LDA #<new end +1   ; low-byte new endadress +1 
STA $58
LDA #>new end +1   ; high-byte
STA $59
JMP $C3BF          ; jump to blocktransfer and return with RTS
The blocktransfer is in the BASIC-ROM from $C3B8 to $C3FA and ends with an RTS.

-- Thomas
Last edited by Thomas Hechelhammer on Mon Sep 11, 2006 3:18 am, edited 1 time in total.
User avatar
nbla000
Salmon Run
Posts: 2582
Joined: Thu Oct 13, 2005 8:58 am
Location: Italy

Post by nbla000 »

Thanks so much to everybody.

I think that the definitive short routine for 256 byte is the mike method and for more bytes the Thomas method.

Thanks again.
User avatar
nbla000
Salmon Run
Posts: 2582
Joined: Thu Oct 13, 2005 8:58 am
Location: Italy

Post by nbla000 »

Whats wrong on this routine?
Using Thomas Routine i wish to move memory from $1300-1a2c to $1000
and start from the address $100d but doesn't work.

Code: Select all

1b00   A9 00      LDA #$00 low-byte start address $1300  
1b02   85 5F      STA $5F
1b04   A9 13      LDA #$13 high-byte start address $1300
1b06   85 60      STA $60
1b08   A9 2D      LDA #$2D low-byte end address +1 $1a2d
1b0a   85 5A      STA $5A
1b0c   A9 1A      LDA #$1A high-byte end address +1 $1a2d
1b0e   85 5B      STA $5B
1b10   A9 2D      LDA #$2D low-byte new end address +1 $172d
1b12   85 58      STA $58
1b14   A9 17      LDA #$17 high-byte new end address +1 $172d
1b16   85 59      STA $59
1b18   4C BF C3   JMP $C3BF execute move memory vic routine and returns
1b1b   4C 0D 10   JMP $100D Jump to decrunch routine
Thomas Hechelhammer
Vic 20 Dabbler
Posts: 79
Joined: Thu Jun 09, 2005 11:51 pm
Location: Germany

Post by Thomas Hechelhammer »

You have overlapping memory. :cry:

So, you will need two different routines.

One which moves memory from higher to lower locations.
$2000-$4000 -> $1000-$3000 : start at $2000, copy to $1000 and then increment the counter

One which moves memory from lower to higher locations:
$2000-$4000 -> $3000-$5000 : start at $4000, copy to $5000 and then decrement the counter

If memory isn't overlapping: both routines will work.

The BASIC-routine is decrementing, this means it can only transfer memory from different blocks or, if blocks touch the same locations, from lower to higher locations.

So, for your issue, you need to transfer in an unused region in memory, then retransfer to the target or write your own routine with two 16-bit pointer in the Z-page.

-- Thomas
nippur72
de Lagash
Posts: 574
Joined: Thu Sep 07, 2006 8:35 am

Post by nippur72 »

resuming this old thread just to add that in the Basic ROM kernal there's already a memory move routine. It should work even if the areas are overlapped.

Code: Select all

; 'move bytes'-Routine
;    $5F/$60 Source Start adress
;    $5A/$5B Source End adress
;    $58/$59 Destination End adress 

.C:c3bf   38         SEC
.C:c3c0   A5 5A      LDA $5A
.C:c3c2   E5 5F      SBC $5F
.C:c3c4   85 22      STA $22
.C:c3c6   A8         TAY
.C:c3c7   A5 5B      LDA $5B
.C:c3c9   E5 60      SBC $60
.C:c3cb   AA         TAX
.C:c3cc   E8         INX
.C:c3cd   98         TYA
.C:c3ce   F0 23      BEQ $C3F3
.C:c3d0   A5 5A      LDA $5A
.C:c3d2   38         SEC
.C:c3d3   E5 22      SBC $22
.C:c3d5   85 5A      STA $5A
.C:c3d7   B0 03      BCS $C3DC
.C:c3d9   C6 5B      DEC $5B
.C:c3db   38         SEC
.C:c3dc   A5 58      LDA $58
.C:c3de   E5 22      SBC $22
.C:c3e0   85 58      STA $58
.C:c3e2   B0 08      BCS $C3EC
.C:c3e4   C6 59      DEC $59
.C:c3e6   90 04      BCC $C3EC
.C:c3e8   B1 5A      LDA ($5A),Y
.C:c3ea   91 58      STA ($58),Y
.C:c3ec   88         DEY
.C:c3ed   D0 F9      BNE $C3E8
.C:c3ef   B1 5A      LDA ($5A),Y
.C:c3f1   91 58      STA ($58),Y
.C:c3f3   C6 5B      DEC $5B
.C:c3f5   C6 59      DEC $59
.C:c3f7   CA         DEX
.C:c3f8   D0 F2      BNE $C3EC
.C:c3fa   60         RTS
has anyone ever used it?
User avatar
nbla000
Salmon Run
Posts: 2582
Joined: Thu Oct 13, 2005 8:58 am
Location: Italy

Post by nbla000 »

nippur72 wrote:It should work even if the areas are overlapped.
$C3bf is the last call of my previous code and if i'm not wrong in some cases it may overlap bytes, is exactly the problem that i had.
has anyone ever used it?
I often use this routine for my fixes works and other purpose, i use it on EasyLoad too if i'm not wrong.
Mega-Cart: the cartridge you plug in once and for all.
nippur72
de Lagash
Posts: 574
Joined: Thu Sep 07, 2006 8:35 am

Post by nippur72 »

nbla000 wrote:$C3bf is the last call of my previous code[...]
oops :roll: I should go to my eye doctor
Post Reply