PDA

View Full Version : Adding data to an "array" in ASM



The Master
- 19th November 2009, 12:49
Hi, Im trying to write some of my PBP code in ASM. The bit im stuck on is setting values in an array. I know arrays dont really exist in ASM but i know its still possible to do what i want. After reading Mike's example in another thread (http://www.picbasic.co.uk/forum/showthread.php?t=11916) i can see that i can access the elements of an array by using +1, +2 etc. Thats fine when its being added to a constant value. In Mike's example "Led" appears to be the address of the first element in the array.

The array im working on at the moment uses a variable to decide which element to put data in. Heres the PBP version of the code


bOutData[bOutDataPos]=cControlCharOut 'Control character (a constant)
bOutDataPos=bOutDataPos+1
bOutData[bOutDataPos]=0 'Data length (always zero here)
bOutDataPos=bOutDataPos+1
bOutData[bOutDataPos]=aAddress 'Chip address (from variable aAddress)
bOutDataPos=bOutDataPos+1
bOutData[bOutDataPos]=cAction 'Action (another constant)
bOutDataPos=bOutDataPos+1


bOutData is an output buffer array. bOutDataPos gets incremented every time a byte is added to the array. The send routine elsewhere in the code then sends a byte, shifts all bytes up 1 place in the array then decrements bOutDataPos.

So, can anyone point me in the right direction here? I just need to know how to access the array elements based on the value in bOutDataPos

Jerson
- 20th November 2009, 08:18
This does the same thing in assembly

asm
movlw _bOutDataPos ; read the index to W
addwf _bOutData,w ; add base of the array and keep in W
movwf FSR ; move W to INDirect File register
movlw _cControlCharOut
movwf INDF
incf FSR ; move to the next location of array
clrw
movwf INDF
incf FSR ; move to the next location of array
movlw _aAddress
movwf INDF
incf FSR ; move to the next location of array
movlw _cAction
movwf INDF
incf FSR ; move to the next location of array
endasm

The Master
- 20th November 2009, 10:20
Thanks. That looks like exactly what i want. I wasnt sure if it was even possible with PICs.

Ive looked FSR and INDF up in the datasheet and i found something else interesting too.


POSTINC: accesses the FSR value, then automatically increments it by 1 afterwards

Bruce
- 20th November 2009, 21:07
The first part of this probably isn't working like you might expect.


movlw _bOutDataPos ; gets the "address" of bOutDataPos into W
addwf _bOutData,w ; adds the address + the "value" in bOutData
movwf FSR ; loads FSR with the wrong address


You want to add the base address of the array, which will never change, to the
offset value in bOutDataPos to get the address for each array element;


movf _bOutDataPos,W ; get the value of your index pointer in bOutDataPos
addlw _bOutData ; add the index to the base address of your array
movwf FSR ; load FSR with base address + offset


This will probably make it easier to follow;


Array VAR BYTE[8]
Index VAR BYTE
Address VAR BYTE

Action CON 10
ControlChar CON 20

CLEAR

Address = 15 ' address
Index = 0 ' starting Array Index position

Main:
Array[Index]=ControlChar
Index=Index+1
Array[Index]=0
Index=Index+1
Array[Index]=Address
Index=Index+1
Array[Index]=Action
Index=Index+1
GOTO Main

The code after Main would be something like this, which maintains your Index pointer.


asm
movf _Index, W ;get "offset" value from Index pointer
addlw _Array ;add it to Array[0] base address (result in W)
movwf FSR ;load pointer with base + offset
movlw _ControlChar ;load W with constant value in ControlChar
movwf INDF ;move it to Array[Index]
incf _Index, F ;inc Index pointer
movf _Index, W ;load new Index pointer value
addlw _Array ;add it to Array[0] base address
movwf FSR ;load pointer with base + offset
clrf INDF ;Clear Array[Index]
incf _Index, F ;inc Index pointer
movf _Index, W ;load new Index pointer value
addlw _Array ;add it to Array[0] base address
movwf FSR ;load pointer with base + offset
movf _Address, W ;get Address byte value
movwf INDF ;move it to Array[Index]
incf _Index, F ;inc Index pointer
movf _Index, W ;load new Index pointer value
addlw _Array ;add it to Array[0] base address
movwf FSR ;load pointer with base + offset
movlw _Action ;load W with Constant value in Action
movwf INDF ;move it to Array[Index]
incf _Index, F ;inc Index pointer
endasm
It could be made a bit smaller, and you could use incf FSR to increment the
pointer each time, but you could lose track of which array element you last
wrote to pretty quick.

The Master
- 20th November 2009, 21:13
Ahh, I didnt notice that it was the wrong way round. It is right in my code though because i wrote it out myself instead of copy/paste (i remember better that way).

Heres how my code looks now. I think its all right


; Get the start address for the array
MOVLW _bOutData ; Set WREG to the start of the bOutData array
ADDWF _bOutDataPos,0 ; Add bOutDataPos to the address and store back in WREG
MOVWF FSR0 ; Copy WREG to the indirect file register

; Control character
MOVLW _cControlCharOut ; Copy the output control character to WREG
MOVWF POSTINC0 ; Copy WREG to bOutData[bOutDataPos] (specified by indirect file register) and increment FSR0
INCF _bOutDataPos ; Increment the array position

; Data length
MOVLW 0 ; Set WREG to 0
MOVWF POSTINC0 ; Copy WREG to bOutData[bOutDataPos]
INCF _bOutDataPos ; Increment the array position

; Chip address
MOVFF _aAddress,POSTINC0 ; Copy aAddress to bOutData[bOutDataPos]
INCF _bOutDataPos ; Increment the array position

; Action
MOVLW _cActionPing ; Copy the ping action character to WREG
MOVWF POSTINC0 ; Copy WREG to bOutData[bOutDataPos]
INCF _bOutDataPos ; Increment the array position

Bruce
- 20th November 2009, 23:04
Looks like you have it under control..;o}

I don't recommend using this particular syntax though ADDWF _bOutDataPos,0. I much
prefer being explicit with ADDWF _bOutDataPos,W. I can never remember if 0 or 1 is
specifying W or F, so it's a lot easier for me, at a later time, to review code with explicit
arguments.

The Master
- 20th November 2009, 23:54
Thats a very good point. Originally i saw it written how you said but the datasheet said it had to be 1 or 0. If typing W works too then i will do it that way. Thanks

rsocor01
- 21st November 2009, 02:05
Hi all,

Let me ask you a very stupid question here, but like they say if you don't ask you don't learn. This piece of code is very simple to do using PBP, so what is the purpose of complicating your life using ASM for this program? Using ASM saves programming space, but other than that why would you use it for this simple program?

Thank you for your answers,

Robert

The Master
- 21st November 2009, 14:18
Theres 2 reasons.

1) For a while now ive been wanting to learn ASM. By learning ASM a lot of things in other languages like PBP and even C are starting to make sense. I think its a very usefull thing to learn. It helps to understand how things are actually working inside the chip

2) Probably the most important one. This section of code is only part of a much bigger program. Its actually the same one from my other thread which is titled "PBP Using too many instructions". ASM uses a lot less instructions so i can finally add in the extra features that i wanted to do in PBP but couldnt because the code was running too slow.

The Master
- 21st November 2009, 17:58
Im having a bit of trouble getting this code working.

Heres some test code i wrote


MOVLW 38
MOVWF FSR0

MOVLW 57
MOVWF 38
MOVFF INDF0,TXREG


This code should set W to 38 then move that value to FSR0.

It then sets W to 57 (my test value) and moves W to memory location 38. Then it sends INDF0 over serial to the PC. I would expect INDF0 to reference memory location 38 and send 57 but it doesnt. I keep getting random values (a different one each time i reset the PIC asif its an uninitialized memory location). Its not a serial problem. MOVWF TXREG sends the correct value.

I know im writing data to memory location 38 and if i read FSR0 back it also says 38. Did i miss something obvious? It seems like both are accessing memory location 38 but in 2 different blocks of memory (im not sure if thats possible)

Darrel Taylor
- 21st November 2009, 21:11
FSR0 is a constant that equates to 0.
It's for use with the LFSR opcode, LFSR FSR0, 38

The address for the FSR0 is 2 bytes, FSR0L and FSR0H.
So with your example, it could be one of these ...
LFSR FSR0, 38

MOVLW 57
MOVWF 38
MOVFF INDF0,TXREG

... OR ...
MOVLW 38
MOVWF FSR0L
CLRF FSR0H

MOVLW 57
MOVWF 38
MOVFF INDF0,TXREG

hth,

The Master
- 22nd November 2009, 03:21
Thanks. Thats working perfectly now