LAC, LAS & LAT

Go To Last Post
11 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I wonder how the LAC, LAS and LAT instructions work.

I can imagine two possibilities. I think they simply combine 3 instructions into 1. They do a fetch of 8 bits, wiggle one of them, and store 8 bits. That would be a nice instruction but I don't think I need it bad enough to figure out how to get the compiler to use it.

The other possibility would be more interesting. It could set or clear one bit without touching the other 7 bits. I'm guessing this is not the case, but I'd like to find out.

I'm attaching a bit of the datasheet where it seems to use "AND" or "OR" to describe them, which makes me think the first description is the right one.

I'm interested because I've been looking at the USB description in the data sheet. The endpoint registers are interesting as they are in RAM. Even more interesting is the status register. It seems that the software needs to be able to clear at least one of the bits. To make it yet more interesting, some of the bits are cleared by writing a 1 to their bit position and others are cleared by writing a 0 to their bit position. This could be a typo, there seem to be several of them. But this is so bizarre, I think it is true.

I looked at the ASF and it seems to use macros LASR16..... and LACR16..... to do this. These turn into assembler code. I'm including a bit of the code but using
instead of you know what. I'm wondering if this use of LAC and LAS is really necessary.

// Load and Clear
#ifdef __GNUC__
#define LACR16(addr,msk) \
   __asm__ __volatile__ ( \
         "ldi r16, 1" "\n\t" \
         ".dc.w 0x9306" "\n\t"\
         ::"z" (addr), "M" (msk):"r16")
#else
#define LACR16(addr,msk) __lac((unsigned char)msk,(unsigned char*)addr)
#endif

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The procedure for clearing USB status flags was an error in the datasheet.

Atmel ATxmegaAU datasheet (revision D) wrote:
27. Updated “STATUS – Status register” on page 243. Updated Bit 5, 4, 4, 2 1: These flags are cleared by writing logical 0 to its bit location.

Curiously the AVR Instruction Set (revision I) lists LAC/LAS/LAT as single-cycle instructions whereas the the ATxmegaAU datasheet (revision D) counts two cycles.

Personally I suspect that the latter is accurate, and that the instruction performs separate read/writes. Probably they're intended primarily as a way of avoiding race conditions with regards to interrupts handlers without increasing latency.

As you yourself noted the obvious test would be to write to an unrelated bit of an interrupt acknowledgment register to see whether the other flags are affected. Just not the USB STATUS flags.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the reply. I particularly like to see that bit 2 is cleared by writing 0. That was the most bizarre one.

By the way, you are hopelessly out of date with revision D. That has been around for two months. There is now a revision E from January. Both revisions still show bit 2 cleared by writing a 1. The revision E filename I downloaded was: Atmel-8331-8-and-16-bit-AVR-Microcontroller-XMEGA-AU_Manual.pdf

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

doynax wrote:
the obvious test would be to write to an unrelated bit of an interrupt acknowledgment register to see whether the other flags are affected. Just not the USB STATUS flags.
The interrupt flag registers are part of the USB registers which are normal registers. They seem to work as expected.

It is the Endpoint "registers" that exist in RAM, and the Endpoint status register in particular that is a bit mysterious to me. I tried poking bits in this status register and it seems to act just like any other RAM location would.

I may have to plug this thing into a PC to do any further Endpoint testing.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

steve17 wrote:
The interrupt flag registers are part of the USB registers which are normal registers. They seem to work as expected.

It is the Endpoint "registers" that exist in RAM, and the Endpoint status register in particular that is a bit mysterious to me. I tried poking bits in this status register and it seems to act just like any other RAM location would.

My understanding is that the endpoint buffers are just normal SRAM which the USB controller may occasionally write through DMA.
The NACK flags are then used more-or-less as locks indicating who currently owns these buffers. Essentially you'd initialize an endpoint and clear NACK to hand over the buffer to the peripheral, then wait NACK to be raised and a result to be written back upon transaction completion. An exception is that some of the status flags (e.g. UNF/OVF) may be raised even while it is "locked".

As for LAC/LAS/LAT my proposed test would be to raise INT0IF of PORTA.INTFLAGS (say) and then LAC INT1IF instead. If the opcode is implemented as a regular read-modify-write then INT0IF would get reset by accident.

Curiously the CPU always has priority over regular DMA on the XMEGA, and presumably also over the more implicit USB DMA as well, so it seems likely that an internal read cycle followed back-to-back by a write in a two-cycle LAC/LAS/LAT cannot be interrupted by the USB controller. Thus guaranteeing atomicity for the endpoints and other SRAM.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm glad you mentioned the NACK use. That is how I saw them being used also, but it is good to get some confirmation. I don't get much from the datasheet.

I would try LAS/LAC but I don't know how to use AVR assembler or embed it in my C++ code. Maybe I could learn. What would be nifty is a C/C++ function that uses these instructions. That function would take arguments to specify the address of the byte to be fiddled with, and the "mask" or whatever else the LAS/LAC requires.

The datasheet describing the USB does not mention LAS and LAC. The fact that there are bits in the endpoint status register that allegedly can be cleared by writing a zero bit or a one bit seems to imply that all it takes to clear a bit and leave the other bits unchanged is a simple write of the proper mask. That is how certain peripheral registers work, as you know.

If that is how this status register works, then LAS and LAC aren't needed, and in fact I don't think they would work.

I've tried poking around in the endpoint status register and found it works just like any other RAM. Those "clear by writing one or zero" bits don't work that way. For instance, I assume when the datasheet says a bit is cleared by writing a zero then writing a one should not affect the bit, but it does.

Maybe for this register to work as advertised, the endpoint has to be used first by the USB module. I think that requires me to connect the USB to a host ocmputer.

Or maybe this magic only happens when LAS or LAC is used.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No, I'm fairly certain that the clear-by-writing-one description is just an error in the documentation. I had the same problem initially but everything seemed to work once I started manually clearing the bits. Plus when I peeked at the ASF it also seemed to clear the bits, albeit through LAC as you've noticed.

In any event I don't believe there's anything magical about these instructions. They're probably just used as a convenient way of twiddling the status bits without risking races against the USB controller or interrupts.
In my own little HID stack I ended up always overwriting the whole STATUS register and not caring about the previous value. Basically I didn't care about the error flags, and with automatic multi-packet transfers the TOGGLE bit always starts out set.

By the way, beware that the endpoint buffer block *must* be word-aligned!

steve17 wrote:
What would be nifty is a C/C++ function that uses these instructions. That function would take arguments to specify the address of the byte to be fiddled with, and the "mask" or whatever else the LAS/LAC requires.
What's wrong with the ASF macros in your original post?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

doynax wrote:
What's wrong with the ASF macros in your original post?
They would probably work. It's just that my eyes glaze over when I see macros and assembler code. ;) I may take a look at it.

One more thing though. The datasheet says LAC etc. are for RAM locations. I don't know what would happen if used on real hardware registers.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeah, I have everything suitably aligned. One thing I've not figured out is if the data buffer location given to the endpoint can be changed when the NACK bit is set, or whether once set it should never be changed.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

steve17 wrote:
One more thing though. The datasheet says LAC etc. are for RAM locations. I don't know what would happen if used on real hardware registers.
I should think that RAM in this context simply refers to the RAM address space, as opposed to the I/O address space. Still, I don't know for certain.

steve17 wrote:
Yeah, I have everything suitably aligned. One thing I've not figured out is if the data buffer location given to the endpoint can be changed when the NACK bit is set, or whether once set it should never be changed.
You mean the data address within the endpoint?

You're free to fiddle with any of the CNT/DATAPTR/AUXDATA registers while you're in possession of the endpoint. They just have to point to a proper buffer of the right length once you clear NACK to initiate another transfer.

Note that you cannot simply grab the endpoint at any time by raising NACK, you have to wait for it to be given back to you.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I tried the LAS-LAC instructions using macros like the one I included in my first post. They seem to work as advertised. That is, they can set or clear a bit in the status register, and presumably any RAM location, and the remaining bits are unaffected. It seems the second argument (msk) must be a constant known at compile time.

Of course I can't test what happens if the USB hardware and the software try to access the same RAM location at the same time. But it seems reasonable that it would be done sequentially, not simultaneously.

I suspect the datasheet description of the way bits in the status register can be cleared by writing ones or zeros is nonsense. I guess you feel the same way. One of these days, someone should send an e-mail to Atmel asking for an explanation.

The datasheet description of the transaction complete FIFO needs to be explained or corrected also. First of all, it calls FIFOWP and FIFORP write pointers and read pointers. They are actually indexes. Yeah, I know nobody but I care about misleading terminology. ;) I understand they are negative. By the way, I've never seen negative pointers. Probably something used in the fourth dimension. ;)

Then they say these pointers (translate to indexes) are relative to EPPTR (which is the address of the first endpoint configuration unless I'm off my rocker). Okay, that sort of makes sense. Then they say when these pointers (indexes, stupid) reach the FIFO size, they wrap to zero. Hmmm, really? If that is so, then the hardware would use the first byte of the first endpoint configuration as part of the FIFO, wouldn't it? What do you know about this?