Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Pointer (Oshonsoft Basic Compiler)

DogFlu66

Member
Hello; I have a slightly special question.
For the Pic18F series I use a few machine instructions to obtain the memory address of a variable at runtime in a Basic oshonsoft program.
This is because I cannot obtain the address directly, but if I can pass it to a machine program and then recover it to a normal language variable at runtime.
I show the example:
Ejemplo.jpg

I have the problem for the 16 F series, I have not been able to find an equivalent in machine code.
For the 16F series I have only been able to pass memory addresses that are only 1Byte long.
 
GPR addresses are normally only 1 byte, because that's all you get in contiguous GPR's (in fact mostly less than that).

You simply need to set the correct bank, and then access it with the single byte address.

Some of the later devices (such as the 16F1827) do allow you to access GPR's contiguously, but I don't know if the BASIC compiler (or indeed C compilers) are capable of using it in that way.

Here's some assembler I wrote a decade ago, which clears a contiguous buffer in memory (240 bytes) on a 16F1827:

Code:
Clr_Buffer
                banksel    0x00                ; ensure bank 0
                movlw    Buff_Size
                movwf    count                ; set number of bytes to clear
                movlw    high Buff
                movwf    FSR0H                ; set buffer address
                movlw    low Buff
                movwf    FSR0L
BuffLoop        clrw
                movwi    FSR0++                ; clear each GPR in turn
                decfsz    count,    f            ; check if all cleared
                bra        BuffLoop
                return
 
I don't think Nigel has the gist.. The pic 16 has the same FSR. but access is with the indf register.
datasheet 2.4 said:
The INDF register is not a physical register. Addressing the INDF register will cause indirect addressing. Indirect addressing is possible by using the INDF register. Any instruction using the INDF register actually accesses data pointed to by the File Select Register(FSR). Reading INDF itself indirectly will produce 00h.Writing to the INDF register indirectly results in a no operation (although Status bits may be affected). An effective 9-bit address is obtained by concatenating the8-bit FSR and the IRP bit of the STATUS register, as shown in Figure 2-8.
The trouble here is the manipulation of the IRP bit to get the full address.

Also.. I believe MOVLW VARIABLE will store the address of the variable in W, but only within the scope of that bank.. So the actual location will be the RP pair and the value in W.

Banksel variable
movlw variable

status RP0 and RP1 and W should get you the address.
Indirect is just IRP and W.
 
Last edited:
I don't think Nigel has the gist.. The pic 16 has the same FSR. but access is with the indf register.
I believe I did?, just as you did, I said you need to select the correct bank for the GPR you want to address.

The code example I was posted was for full contiguous memory access, on enhanced PIC device, specifially the 16F1827.
 
Thanks for your time.
Only the FSR record recognizes me, I cannot use RFS0H, RFS0L, RFSH or RFSl.
In any case, I have detected a major problem, and that is that I cannot pass values greater than 1Byte. If I add a larger value when compiling into machine code, I get an error.

Note: I can only pass the address of the complete variable to the machine code.
 
Last edited:
I can assign an address to the variable when declaring it, this solves the problem, but I wanted to see if a more elegant solution could be obtained.

My knowledge of machine language is general.
 
Last edited:
I have detected a major problem, and that is that I cannot pass values greater than 1Byte.
That is the limit of the address range for earlier series PICs - the first ones only had something like 20 bytes RAM, so eight bits were plenty for that and the registers!

When that series got to more than 256 bytes used, the address was split to two independent sections, with the bank select bits setting a "window" in the memory space.

It works via a simple MMU, in a fashion, using two totally separate components to access the full address range.

There is no data address register or capability in the CPU for single-part addresses longer than 8 bits.


Compilers make the address range appear continuous, but that's by performing all the bank manipulation behind the scenes.

It's a very common method for increasing memory size to above the direct address limit of a CPU - eg. the original PC "Expanded memory" system, among other things.
 
Thanks for your time.
Only the FSR record recognizes me, I cannot use RFS0H, RFS0L, RFSH or RFSl.
In any case, I have detected a major problem, and that is that I cannot pass values greater than 1Byte. If I add a larger value when compiling into machine code, I get an error.

Note: I can only pass the address of the complete variable to the machine code.
If you pass the 1 byte address, and have a copy of RP0 and RP1.. The best way todo this is compile a C program doing the same thing and see how XC8 (Hitech) did it, as I can use pointers in that fashion in C on those devices.
 
Thanks.
I will review the code generated by C.
But as far as I know, when it is compiled, bank and memory are generated directly.

I'm not quite sure what you mean?, but a compiler produces assembler, or perhaps directly to machine code? - but it's the same thing - which WILL set the correct bank 'somewhere', and access the data byte with a machine code instruction. Depending on how clever the compiler is, it might not set the bank if it's already in the correct bank, but look for instructions writing to RP0 and RP1.

Which 16F device are you using?.
 
To finish with the topic of this thread, I leave an example with the updated function to assign a pointer to a variable using a simple code in machine code. The function allows you to assign the pointer to any type of variable and even to functions. The example in this case only considers array, byte and string data collections. In any case, the string data in the most recent IDE updates now allows you to work with pointers natively in the language, but this will be for another thread.

Example:

'Pointer assignment from ASM Pic18
'By Cos, 2024/04/21, PSI Compiler Pic18, v5.45
'---------------------------------------------------
#define STRING_MAX_LENGTH = 70
'Include "_Pic18F26K22Library.bas"
'---------------------------------------------------
'Variables
Dim List(5) As Byte
Dim StrAisNMEA[5] As String
'Pointers
Dim P_List As Word
Dim P_StrAisNMEA As Word
'Pointer Assignment Pic18
ASM: LFSR 2, List
P_List = _PointerWord()
ASM: LFSR 2, StrAisNMEA
P_StrAisNMEA = _PointerWord()

While True
Wend

End
'Pointer assignment Pic18
Function _PointerWord() As Word
Symbol _Return_HB = _PointerWord.HB
Symbol _Return_LB = _PointerWord.LB
ASM: MOVFW FSR2H
ASM: MOVWF _Return_HB
ASM: MOVFW FSR2L
ASM: MOVWF _Return_LB
End Function

As can be seen in the window capture of the "Watch Variables" simulator, the variables P_List and P_StrAisNMEA contain the address of the first element of List and StrAisNMEA respectively.

Pointer ASM.jpg


Of course this is convenient to do at the beginning of the main and before activating the interrupts if they are used.
 
Last edited:
Hello; I have a slightly special question.
For the Pic18F series I use a few machine instructions to obtain the memory address of a variable at runtime in a Basic oshonsoft program.
This is because I cannot obtain the address directly, but if I can pass it to a machine program and then recover it to a normal language variable at runtime.
I show the example:
View attachment 142653
I have the problem for the 16 F series, I have not been able to find an equivalent in machine code.
For the 16F series I have only been able to pass memory addresses that are only 1Byte long.
After investigating a little more about this topic, I have been able to verify that there are some directives or macros to be able to perform this function from the assembler.

These directives allow access to different parts of a 16-bit or 24-bit memory address (in the case of some PIC18 microcontrollers). Here is a brief explanation of each:

low: Assembler directive that gets the low byte of a 16-bit address or value.
high: Assembler directive that gets the high byte of a 16-bit address or value.
upper: Assembler directive that gets the high byte of a 24-bit address or value (when using extended program memory on some PIC18 microcontrollers).

I leave an example to extract the memory address of a variable at runtime for families up to and including 18F.

'Obtaining the memory address of a variable
Dim m0(10) as Byte ' Define an array m0 of 10 bytes
Dim P_m0 as Word ' Define a Word variable P_m0 to store the address
Dim address As Word ' Define a Word variable address to use as temporary storage
Symbol address_LB = address.LB ' Create a symbol for the low byte of address
Symbol address_HB = address.HB ' Create a symbol for the high byte of address

'p_m0 = &m0
ASM: MOVLW low m0 ' Load the low byte of the address of m0 into WREG
ASM: MOVWF address_LB ' Move the value from WREG to the low byte of address
ASM: MOVLW high m0 ' Load the high byte of the address of m0 into WREG
ASM: MOVWF address_HB ' Move the value from WREG to the high byte of address

P_m0 = address ' Assign the full address stored in address to P_m0
 
Last edited:
GPR addresses are normally only 1 byte, because that's all you get in contiguous GPR's (in fact mostly less than that).

You simply need to set the correct bank, and then access it with the single byte address.

Some of the later devices (such as the 16F1827) do allow you to access GPR's contiguously, but I don't know if the BASIC compiler (or indeed C compilers) are capable of using it in that way.

Here's some assembler I wrote a decade ago, which clears a contiguous buffer in memory (240 bytes) on a 16F1827:

Code:
Clr_Buffer
                banksel    0x00                ; ensure bank 0
                movlw    Buff_Size
                movwf    count                ; set number of bytes to clear
                movlw    high Buff
                movwf    FSR0H                ; set buffer address
                movlw    low Buff
                movwf    FSR0L
BuffLoop        clrw
                movwi    FSR0++                ; clear each GPR in turn
                decfsz    count,    f            ; check if all cleared
                bra        BuffLoop
                return
Which is used in this example, but I didn't understand its application until now.
 

Latest threads

New Articles From Microcontroller Tips

Back
Top