Author |
Message |
James_Parsons
Joined: Sat Aug 03, 2013 11:02 pm Posts: 43
|
I have a program that needs to write to an address, but then increment the address, and write the next.
FF00: Some Data FF01: Some Data Etc.
The problem is how do i increment memory. I cant store the address in an 8-bit register as in:
LDAA #$ADDR STAA STUFF INCA
p.s. sorry if this is poorly written have to go in a few secs
_________________ intel 4004 countdown
:05000000DAF81C01000C :00000001FF
|
Tue Jan 14, 2014 7:43 pm |
|
![](./styles/serenity/theme/images/spacer.gif) |
Garth
Joined: Tue Dec 11, 2012 8:03 am Posts: 285 Location: California
|
You'd normally use either and indexed or an indirect addressing mode. Indexing is often most efficient. In 6502 or 65816 you would have for example, Code: LDX #0 loop: <put in the accumulator the data to store next> STA base_addr,X ; The accumulator's contents will get stored at base_addr plus X's contents. INX ; Increment X so the next indexed store will go to the next address higher. CPX #$40 ; Compare to how many you wanted to store. BNE loop ; If you haven't done that many yet, go back for another loop. On the 6502, the two index registers are 8-bit-only (unlike the 65816), and if you want to do more than 256 bytes, you might choose to get the value to store and then do something like: Code: STA (indirect_addr) ; The accumulator's value will get stored at the address pointed to by the _contents_ of indirect_addr. INC indirect_addr ; Increment low byte. BNE label ; If it carried, INC indirect_addr + 1 ; then increment high byte too. label: then test if necessary to see if you've gone as far as you wanted to. (The '816 allows incrementing the 16-bit address with a single INC instruction, unlike the 6502.) It looks like you have 6800 or 6809 code above. I've looked at their instruction sets many times over the years but never written any programming for them, so I won't try here.
_________________http://WilsonMinesCo.com/ lots of 6502 resources
|
Wed Jan 15, 2014 1:08 am |
|
![](./styles/serenity/theme/images/spacer.gif) |
BigEd
Joined: Wed Jan 09, 2013 6:54 pm Posts: 1783
|
On the 68xx you use the 16-bit X register, I think.
|
Wed Jan 15, 2014 8:42 am |
|
![](./styles/serenity/theme/images/spacer.gif) |
Dr Jefyll
Joined: Tue Jan 15, 2013 5:43 am Posts: 189
|
![Confused :?](./images/smilies/icon_e_confused.gif) OK, fasten your seatbelts. My Motorola skills are rusty but I'll give it a try! James, you've got some of the right stuff goin' on in the snippet you originally posted (above). But there's confusion between where you're writing to and what you're writing. IOW confusion between the address and the data. Ed is right -- X will be good for holding the address. And we'll stick with accumulator A for the data. Here's the 6800 version: Code: ;------------------------------------ ;want to achieve FF00: Some Data ; FF01: Some Data ; Etc. ;------------------------------------
LDX #$FF00 ;the first address is established explicitly by loading X LDAA SomeData ;get a byte of data STAA (X) ;store the byte to the address
INX ;the next address is gotten simply by incrementing X LDAA SomeData ;get a byte of data STAA (X) ;store the byte to the address
INX ;the next address is gotten simply by incrementing X LDAA SomeData ;get a byte of data STAA (X) ;store the byte to the address
; (and so on...)
On 6809 it can be streamlined to use fewer instructions! Code: LDX #$FF00 ;the first address is established explicitly by loading X LDAA SomeData ;get a byte of data STAA (X+) ;store the byte to the address and get the next address by incrementing X
LDAA SomeData ;get a byte of data STAA (X+) ;store the byte to the address and get the next address by incrementing X
LDAA SomeData ;get a byte of data STAA (X+) ;store the byte to the address and get the next address by incrementing X
; (and so on...)
The code is untested but should be at least close to correct! Cheers Jeff
|
Thu Jan 16, 2014 5:14 am |
|
![](./styles/serenity/theme/images/spacer.gif) |
barrym95838
Joined: Tue Dec 31, 2013 2:01 am Posts: 116 Location: Sacramento, CA, United States
|
As someone with 6800 experience, I can state that Jeff is correct, with the small caveat that (X) and (X+) are not standard Motorola assembler syntax; they should be replaced with ,X and ,X+ respectively (a leading zero is optional for most assemblers).
Mike
|
Fri Jan 17, 2014 3:54 am |
|
![](./styles/serenity/theme/images/spacer.gif) |
BigEd
Joined: Wed Jan 09, 2013 6:54 pm Posts: 1783
|
Here's a simulation of the beginning of Jeff's program. Note that LDAA here is plucking from some chosen addresses in direct page, most likely in reality you'd be doing either a block move or a block fill: http://visual6502.org/JSSim/expert-6800 ... 1&steps=54Programming card at http://www.textfiles.com/programming/CARDS/6800and programmer's model at http://www.sbprojects.com/sbasm/6800.phpCheers Ed
|
Fri Jan 17, 2014 12:21 pm |
|
![](./styles/serenity/theme/images/spacer.gif) |
barrym95838
Joined: Tue Dec 31, 2013 2:01 am Posts: 116 Location: Sacramento, CA, United States
|
BigEd wrote: ... most likely in reality you'd be doing either a block move or a block fill: ... The 6800 can block fill quite efficiently, due to the full-sized X register. Block moves are far less efficient, due to the missing Y register. You are forced to load and re-load the source and destination addresses into X inside the loop, or resort to the use of the S register, which is a dangerous practice (any interrupts that hit during the move are going to lightly sprinkle corrupted bytes into the data that you're trying to move, unless you are very diligent about its use). Later 8-bit Motorola products added the Y register (6809 and siblings). Mike [Edit: Self-modifying code is another option for the 6800 move loop, but I am not a fan of that technique.]
|
Fri Jan 17, 2014 3:23 pm |
|
![](./styles/serenity/theme/images/spacer.gif) |
Dr Jefyll
Joined: Tue Jan 15, 2013 5:43 am Posts: 189
|
barrym95838 wrote: (X) and (X+) are not standard Motorola assembler syntax; they should be replaced with ,X and ,X+ respectively See? I told you I was rusty! ![Wink ;)](./images/smilies/icon_e_wink.gif) (Actually, I never did learn proper assembler syntax. Back in the day, I assembled 6809 machine code by hand.) Thanks for the correction, Mike! Quote: Self-modifying code is another option for the 6800 move loop, but I am not a fan of that technique. I can sympathize with that, provided it's a well-informed decision being made. IOW, look at the pros & cons as with any other coding technique. The list of disadvantages is short but significant. Self-modifying code... - is non-reentrant
- needs to be clearly commented
- can't run entirely from ROM -- needs at least some RAM
We need to weigh those drawbacks against the advantages, which can be quite compelling -- such as a massive speed boost, or achieving something that's otherwise hideously clumsy or borderline impossible. Oops, are we off-topic now??? cheers, Jeff
|
Sun Jan 19, 2014 3:41 pm |
|
![](./styles/serenity/theme/images/spacer.gif) |
BigEd
Joined: Wed Jan 09, 2013 6:54 pm Posts: 1783
|
I can't find it now, but I'm pretty sure I read a story recently of an effort back in the day to write and debug a fast copy routine, where registers were loaded and then pushed - stack instructions being quite good value in clock cycles. So long as you use the stack pointer to point at the destination (not the source), and you have a little room at the end of the data, you can tolerate interrupts making use of the stack - they will write values which you will shortly overwrite when the interrupt routine returns.
|
Sun Jan 19, 2014 4:37 pm |
|
![](./styles/serenity/theme/images/spacer.gif) |
barrym95838
Joined: Tue Dec 31, 2013 2:01 am Posts: 116 Location: Sacramento, CA, United States
|
BigEd wrote: I can't find it now, but I'm pretty sure ... That sounds like an invitation for me to post some home-brewed 'test-cases' (untested) Code: ; MoveUp for the 6800: Non-interrupt-safe version. ; Move a block of num bytes _up_ from [source .. source + num - 1] ; to the block starting at dest. ; source, num and dest are direct-page 16-bit memory variables, and ; are preserved. A, B and X are not preserved. ; ssave holds the stack pointer value, so that it can be properly ; restored after the move. ; temp is used to calculate the ends of the blocks. ; IRQs are ignored for the duration of the move. ; Bad things will likely happen to the data if an NMI hits while ; the stack pointer is being used in this manner. ; A portion of the source will be forever lost if the destination ; block overlaps the beginning of the source block. Avoid this ; by using movedown instead. moveup: :d6 51 ldab num+1 :96 50 ldaa num :db 53 addb source+1 ;calculate initial source ptr :99 52 adca source :d7 57 stab temp+1 :97 56 staa temp :de 56 ldx temp ;init source ptr reg :d6 51 ldab num+1 :96 50 ldaa num :db 55 addb dest+1 ;calculate initial destination ptr :99 54 adca dest :d7 57 stab temp+1 :97 56 staa temp :9f 58 sts ssave ;save stack ptr :0f sei ;disable interrupts :9e 56 lds temp ;init destination ptr reg :34 des moveup2: :09 dex ;update source ptr reg :a6 00 ldaa 0,x ;load byte from source :36 psha ;store it in destination :9c 52 cpx source ;are we done yet? :26 f8 bne moveup2 ; no: repeat until done :9e 58 lds ssave ;restore stack ptr :0e cli ;enable interrupts :39 rts
It appears that you're correct: an NMI would write just below the destination 'cursor', so it would be harmless unless you had overlapping source and destination blocks, or sensitive data just below the beginning of the destination block. This version is safer, but much slower. Look at the difference in instruction count for the loop! Code: ; MoveUp for the 6800: Interrupt-safe version. ; moveup: :d6 51 ldab num+1 :96 50 ldaa num :db 53 addb source+1 ;calculate initial source ptr :99 52 adca source :d7 59 stab ssave+1 :97 58 staa ssave :d6 51 ldab num+1 :96 50 ldaa num :db 55 addb dest+1 ;calculate initial destination ptr :99 54 adca dest :d7 57 stab temp+1 :97 56 staa temp moveup2: :de 58 ldx ssave ;get source ptr :09 dex :a6 00 ldaa 0,x ;get byte from source :df 58 stx ssave ;update source ptr :de 56 ldx temp ;get destination ptr :09 dex :a7 00 staa 0,x ;store byte to destination :df 56 stx temp ;update destination ptr :9c 54 cpx dest ;are we done yet? :26 ee bne moveup2 ; no: repeat until done :39 rts
And now the same subroutine for the 6809: Code: ; 6809 Move memory up (1 byte to 64 KB) ; x = source start address ; y = destination start address ; d = number of bytes to move ; moveup: :30 8b leax d,x ;init source ptr :33 ab leau d,y ;init destination ptr :1f 02 tfr d,y ;save byte count moveup2: :a6 82 ldaa ,-x ;get byte from source :36 02 pshu a ;store byte to destination :31 3f leay -1,y ;are we done yet? :26 f7 bne moveup2 ; no: repeat until done :39 rts
If I'm not mistaken, the 6809 just kicked the 6800's @$$! Mike B. [Edit: noticed a bug in the 6809 example, and attempted a fix]
Last edited by barrym95838 on Tue Apr 28, 2020 11:18 pm, edited 2 times in total.
|
Sun Jan 19, 2014 5:27 pm |
|
![](./styles/serenity/theme/images/spacer.gif) |
Dr Jefyll
Joined: Tue Jan 15, 2013 5:43 am Posts: 189
|
BigEd wrote: So long as you use the stack pointer to point at the destination (not the source), and you have a little room at the end of the data, you can tolerate interrupts making use of the stack Brilliant! -- even though obvious in hindsight. The only thing I don't like about this idea is that I didn't think of it! barrym95838 wrote: the 6809 just kicked the 6800's @$$! Doesn't surprise me. I'm reminded of indirect-threaded Forth NEXT -- which, on 6809, requires just two instructions! (And the direct-threaded version is just one.) J.
|
Sun Jan 19, 2014 7:24 pm |
|
![](./styles/serenity/theme/images/spacer.gif) |
James_Parsons
Joined: Sat Aug 03, 2013 11:02 pm Posts: 43
|
Nowmy problem is that I need X to loop through a string, and write the X postiton of the string into memory
_________________ intel 4004 countdown
:05000000DAF81C01000C :00000001FF
|
Tue Jan 21, 2014 2:08 pm |
|
![](./styles/serenity/theme/images/spacer.gif) |
Dr Jefyll
Joined: Tue Jan 15, 2013 5:43 am Posts: 189
|
James_Parsons wrote: Nowmy problem is that I need X to loop through a string, and write the X postiton of the string into memory This begins to look like a school assignment. Or perhaps you have a project of your own you'd like to tell us about. In any case, it's best if you at least make a start on the problem yourself. Hint: the previous code example might be a good place to begin -- perhaps you could modify it, I mean. ![Geek :geek:](./images/smilies/icon_e_geek.gif) Have you gotten comfortable with the previous example? In particular, be certain you understand the distinction between address and data. Good luck, and be sure to show us how you're getting along! cheers Jeff
|
Tue Jan 21, 2014 3:04 pm |
|
![](./styles/serenity/theme/images/spacer.gif) |
barrym95838
Joined: Tue Dec 31, 2013 2:01 am Posts: 116 Location: Sacramento, CA, United States
|
James_Parsons wrote: Nowmy problem is that I need X to loop through a string, and write the X postiton of the string into memory It sounds like you need something akin to C's strcpy() ... What I would do on the 6800 is reserve two volatile 16-bit direct page pointer variables, then copy until a NUL was reached. For example: Code: strcpy: ; do { ldx str1 ldaa ,x ; a = *(str1++); inx stx str1 ldx str2 staa ,x ; *(str2++) = a; inx stx str2 cmpa #NUL ; /* if NUL is defined as zero, you can replace 'cmpa #NUL' with 'tsta' here */ bne strcpy ; } while (a != NUL); done: rts ; return ();
Sorry, I don't have time for comments right now ... maybe I'll edit some in tonight, if I'm up to it. The 6809 version has adequate register resources to avoid the use of direct page variables in this trivial case: Code: strcpy: ; do { ldaa ,x+ ; a = *(x++); staa ,y+ ; *(y++) = a; bne strcpy ; } while (a != 0); rts ; return ();
Mike [Edit: Sorry for pulling that end-around on you, Jeff (I didn't see your last post clearly before making mine). You are correct that learning is usually more rewarding with a minimum of help.]
Last edited by barrym95838 on Wed Jan 22, 2014 4:49 am, edited 1 time in total.
|
Tue Jan 21, 2014 4:16 pm |
|
![](./styles/serenity/theme/images/spacer.gif) |
Dr Jefyll
Joined: Tue Jan 15, 2013 5:43 am Posts: 189
|
barrym95838 wrote: Sorry for pulling that end-around on you, Jeff Not to worry, Mike -- I don't think you gave away the answer anyway. ![Smile :)](./images/smilies/icon_e_smile.gif) What you provided is a string move routine. James's problem is more of a search. James_Parsons wrote: I need X to loop through a string, and write the X postiton of the string into memory At least, I think it's a search -- are you looping in order to search for a Null at the end of the string, James? Perhaps you're looking for a specific character within the string. (I'm purely guessing.) And where in memory should X be written? There needs to be a complete description of what you're trying to accomplish! No offense, but you seem somewhat hurried and inattentive. That's the opposite of what you'll need for success with computer coding. So get the details straight and give yourself a chance! ![Uber Geek :ugeek:](./images/smilies/icon_e_ugeek.gif) Best of luck, and let us know how you're getting along. Jeff
|
Wed Jan 22, 2014 4:47 am |
|
|
Who is online |
Users browsing this forum: No registered users and 42 guests |
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot post attachments in this forum
|
|