structure elements in assembly

Coding and general discussion relating to the compiler

Moderators: David Barker, Jerry Messina

Post Reply
janni
Posts: 51
Joined: Wed Aug 24, 2022 2:30 pm

structure elements in assembly

Post by janni » Tue Aug 30, 2022 3:00 pm

One may use structures in SF to access bits by name when one needs to know both the byte and bit name, like

Code: Select all

structure HTstateT	// HT state vector
   v as byte
   HTbroadc as v.0	// broadcast command
   HTsquawk as v.1	// squawk mode
  ...
end structure

dim HTstate as HTstateT 
and it has the advantage of preventing any mistakes by using the bit names with another variable but then how to access these bits in assembly? Declaring same bits again as constants just for occasional use in assembly would nullify the advantage and open way for other mistakes.

BTW, is there some fundamental reason that constant cannot be used directly as bit number designator?
Compiler protests against

Code: Select all

const bitnr=2

PORTA.bitnr=0
Though one may use

Code: Select all

PORTA.bits(bitnr)=0
it is somewhat less readable (and involves more typing :wink: ).

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: structure elements in assembly

Post by Jerry Messina » Wed Aug 31, 2022 1:04 pm

but then how to access these bits in assembly?
There's no direct way to since asm has no concept of a data structure like that. Heck, it doesn't even support 'port.pin'

Here are some examples of things you can do though:

Code: Select all

'device = 18F4520
'device = 18F24K40
device = 18F24K42
'device = 18F24Q10
'device = 18F97J94

//-------------------------------------------------------------------------------
// adapted from E:\_sfmodules\soft_spi\SSPI.bas
// these all work as they use PORT, LAT, and TRIS
//-------------------------------------------------------------------------------
#option SPORT_PIN = PORTC.4
dim FPORT as SPORT_PIN
dim FPORT_PIN as SPORT_PIN.SPORT_PIN@        // port bit

#option STRIS = GetTRIS(SPORT_PIN)
dim FTRIS as STRIS
dim FTRIS_PIN as STRIS.SPORT_PIN@            // tris bit

#option SLAT = GetLAT(SPORT_PIN)
dim FLAT as SLAT
dim FLAT_PIN as SLAT.SPORT_PIN@              // lat bit

// toggle pin
// this is a single instruction version of 'toggle(FPORT_PIN)' 
// standard toggle() does two instructions... btg LAT + set tris to output
// note: to use, you must make the pin an output first 
inline sub toggle_LAT()
   const SCK_PIN = SPORT_PIN@     // this syntax gets the bitno
   dim SCK_LAT as FLAT
   asm
      btg    SCK_LAT, SCK_PIN     // this toggles the LAT
   end asm
end sub

// compare the two (see asm result)
toggle_LAT()
toggle(FPORT_PIN)
Personally, I prefer to use the '.bits()' and '.booleans()' modifiers instead of just '.#'. It's a bit more typing but it's a lot more obvious to me what's going on.

Also, I typically do something like this to make it easier to move hdw around:

Code: Select all

dim LED as PORTC.bits(1)

LED = 1
LED = 0

janni
Posts: 51
Joined: Wed Aug 24, 2022 2:30 pm

Re: structure elements in assembly

Post by janni » Wed Aug 31, 2022 4:13 pm

Thank you, Jerry. I've learned most of these tricks browsing examples and libraries but GetTRIS() and GetLAT() operators are new to me.

It's so easy in SF to use names of simple variables and constants in assembly that I thought it'd be the same with structure elements but apparently it's not the case.

Using bits() may indeed let differentiate between bits and structure's or union's elements - I'll get used to it :) .

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: structure elements in assembly

Post by Jerry Messina » Thu Sep 01, 2022 12:36 pm

I guess the point I was trying to make is that if you create enough aliases and definitions there's almost always a way to create something that can be shared between the basic code and asm. Whether what you end up with is reasonable/easily understandable is up for debate.

I know where you're coming from... in most projects I've worked on speed (and data/code size) were very important.
It's a balancing act, though, since sometimes the architecture of the pic can make using asm a pain. Case in point: there's bound to be a device/layout where the asm in that toggle_LAT() sub above fails since it relies on the LAT register to be in the access bank (or the BSR to already be set to the proper bank).

What I usually do nowadays is to write the code in a straight-forward way and then look at the asm result to see if I really need to optimize it.
Many times just rewriting how the source is structured can make a real difference. I'm lucky in that I've been using SF long enough to know when it's likely to produce something that's going to be an issue, and what things to avoid. Doing that I've been able to avoid having to use asm in most cases.

Try it. You might be pleasantly surprised.

janni
Posts: 51
Joined: Wed Aug 24, 2022 2:30 pm

Re: structure elements in assembly

Post by janni » Thu Sep 01, 2022 8:04 pm

Jerry Messina wrote:
Thu Sep 01, 2022 12:36 pm
What I usually do nowadays is to write the code in a straight-forward way and then look at the asm result to see if I really need to optimize it.
Many times just rewriting how the source is structured can make a real difference.
Yep, my approach exactly. I love it when I don't need to use assembly :) . I use it almost exclusively in ISRs (and math libraries where it's a must). And with newer 8bit PIC processors with 128 levels deep call stack one doesn't even have to be careful about calls in ISR :D .

Still, I'm working on an application where servicing interrupts is so frequent that it takes up to 75% of execution time and every instruction cycle counts. So here's a new question: is there a way to force compiler to include a subroutine called only from assembly besides calling it somewhere in Basic?

P.S. Somehow I cannot convince the forum server to send me an e-mail when new post appears in subscribed topic :( .

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: structure elements in assembly

Post by Jerry Messina » Thu Sep 01, 2022 11:12 pm

is there a way to force compiler to include a subroutine called only from assembly besides calling it somewhere in Basic?
I don't think so... the compiler has to see a reference to it somewhere otherwise it doesn't include it, and inside an asm block it's basically invisible. That goes for subs, data, consts, etc.

Putting a call to it outside your main 'while(true)' loop should do it. It won't ever execute the call but that'll make it visible.

janni
Posts: 51
Joined: Wed Aug 24, 2022 2:30 pm

Re: structure elements in assembly

Post by janni » Fri Sep 02, 2022 12:24 pm

Jerry Messina wrote:
Thu Sep 01, 2022 11:12 pm
Putting a call to it outside your main 'while(true)' loop should do it. It won't ever execute the call but that'll make it visible.
So I figured though I prefer placing the dummy call in subroutines that call (or jump to) the 'invisible' ones. The final effect is sometimes funny, like

Code: Select all

...
?I000111_F005_001161_P000090 ; L#MK EXIT_INTR_HANDLER()
    RETFIE 1
?I000112_F005_001162_P000090 ; L#MK HT_SIOrecr()                // force compiler to include HT_SIOrecr & RStimoP
    RCALL PROC_HT_SIORECR_39
?I000113_F005_001163_P000090 ; L#MK RStimoP()
    BRA PROC_RSTIMOP_31
where a jump was placed instead of a call like the compiler knew it didn't matter :) .

Still, it would be nice to have an option of including a routine in compilation even if it's not directly called from Basic. In compilers that allow for indirect calls it is obviously necessary, but even though SF doesn't have the possibility of calling a routine by address it should not be that hard to implement the possibility of adding routines to compilation process.

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: structure elements in assembly

Post by Jerry Messina » Fri Sep 02, 2022 2:32 pm

There's an existing way to get the code included w/out changing the way things work.

If you want to mark a section of code to delete, include the following macros in your code:

Code: Select all

//
//-----------------------------------------------------------------------------
// BEGIN_SB_COMMENT_BLOCK()
// END_SB_COMMENT_BLOCK()
//   these macros can be used to mark a section of code with SB_COMMENT_BLOCK_BEGIN
//   and SB_COMMENT_BLOCK_END markers, which will allow the ICC code generator to 
//   comment out and remove the code between BLOCK_BEGIN and BLOCK_END
// for internal use
//-----------------------------------------------------------------------------
//
private macro BEGIN_SB_COMMENT_BLOCK()
    asm-
SB_COMMENT_BLOCK_BEGIN:
    end asm  
end macro

private macro END_SB_COMMENT_BLOCK()
    asm-
SB_COMMENT_BLOCK_END:
    end asm  
end macro
and then place macro calls around the code that references the object:

Code: Select all

BEGIN_SB_COMMENT_BLOCK()
addressof(sub1)
END_SB_COMMENT_BLOCK()

janni
Posts: 51
Joined: Wed Aug 24, 2022 2:30 pm

Re: structure elements in assembly

Post by janni » Fri Sep 02, 2022 3:26 pm

Works like a charm, thanks again :D .

BTW, was going to ask that for some time - is there a difference between asm and asm- keywords?

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: structure elements in assembly

Post by Jerry Messina » Sat Sep 03, 2022 12:17 pm

'ASM' will reset the code generator's internal BSR tracking and may generate a MOVLB instruction as a result.
'ASM-' skips that and leaves the banking alone.

janni
Posts: 51
Joined: Wed Aug 24, 2022 2:30 pm

Re: structure elements in assembly

Post by janni » Sat Sep 03, 2022 1:58 pm

Ouch, that's serious difference. Thanks.

Post Reply