MOVE Instruction of ASM in V2 MCU MCF52259

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

MOVE Instruction of ASM in V2 MCU MCF52259

2,758件の閲覧回数
flvloveu
Contributor II

Hello, there are some question about MOVE Instruction, that how to use (d16,An) and (d8,Ay,Xi*SF)? what is their function ?118842_118842.jpg360截图20151222102439869.jpg

ラベル(1)
タグ(2)
6 返答(返信)

2,268件の閲覧回数
TomE
Specialist II

> what is their function ?

Their basic function as assembly instruction addressing modes is to move data around.

Do you mean "HOW do they function" (technical details) or "WHAT are they good for"? They're very different questions. I don't know which one you meant.

You have pasted that table in from section "3.3.5.2 MOVE Instruction Execution Times" of the "MCF52259 ColdFire Integrated MCU Reference Manual".

That part only tells you the execution time of the instructions.

That's not the section that details how the instructions work. That isn't in this manual, but is in another one.

Read Chapter 3 from the top of the very first page. Look for references to other documents. Find, download and read them (actually it, there's one that details the instructions).

If you want to know "what programming and data constructs are they used for) then just disassemble something. The "Address Register Indirect with Displacement Mode" (d16,An) is used for absolutely everything.

As for the "Address Register Indirect with Index (8-Bit Displacement) Mode" (d8,Ay,Xi*SF), I have no idea. I think it is an "orphan" that happened to fit into the "one or two extension word restriction" imposed on the Coldfire that the more useful 68000 "Address Register Indirect with Index (Base Displacement) Mode" didn't survive.

For the "historical context" you should read up on the addressing modes of the 68000. Then read about the next evolution of that architecture, which was the 68020 and 68030, They had things like "Memory Indirect Postindexed ([bd,An],Xn.SIZE*SCALE.od)" and "Memory Indirect Preindexed ([bd,An.Xn.SIZE*SCALE],od)". They were cute and powerful and generally completely unused.

Tom

2,268件の閲覧回数
TomE
Specialist II

I wrote:

> As for the "Address Register Indirect with Index (8-Bit Displacement) Mode" (d8,Ay,Xi*SF),

>I have no idea. I think it is an "orphan"

It is a pretty busy "orphan". Disassembling a Coldfire bootstrap we have here that has 119k bytes of code in it consisting of about 34434 instructions:

$ m68k-elf-objdump -S boot.elf | grep "@.*:" | grep -v pc | wc
    385    1930   21752

$ m68k-elf-objdump -S boot.elf | grep "@.*:" | grep -v pc | less

800006d6:   2191 0c00       movel %a1@,%a0@(00000000,%d0:l:4)
800006f0:   2191 1c00       movel %a1@,%a0@(00000000,%d1:l:4)
8000070a:   2191 0c08       movel %a1@,%a0@(00000008,%d0:l:4)
8000073c:   2191 0c08       movel %a1@,%a0@(00000008,%d0:l:4)
8000083a:   81b6 1ccc       orl %d0,%fp@(ffffffcc,%d1:l:4)
80000840:   3031 0a00       movew %a1@(00000000,%d0:l:2),%d0
8000084a:   2d80 1ccc       movel %d0,%fp@(ffffffcc,%d1:l:4)
80000872:   1033 8800       moveb %a3@(00000000,%a0:l),%d0
8000087e:   1233 8800       moveb %a3@(00000000,%a0:l),%d1
8000088a:   1780 8800       moveb %d0,%a3@(00000000,%a0:l)
80000a20:   4870 aa00       pea %a0@(00000000,%a2:l:2)
80001316:   41f1 3c00       lea %a1@(00000000,%d3:l:4),%a0
8000131c:   47f0 5800       lea %a0@(00000000,%d5:l),%a3
80001346:   4872 0800       pea %a2@(00000000,%d0:l)
800013bc:   41f1 1c0c       lea %a1@(0000000c,%d1:l:4),%a0
800013c0:   41f0 5800       lea %a0@(00000000,%d5:l),%a0
8000168c:   52b6 0cec       addql #1,%fp@(ffffffec,%d0:l:4)
800016a2:   4ab6 0cec       tstl %fp@(ffffffec,%d0:l:4)
80001730:   4872 0800       pea %a2@(00000000,%d0:l)
80001a02:   3031 0a00       movew %a1@(00000000,%d0:l:2),%d0
80001a68:   41f1 2c00       lea %a1@(00000000,%d2:l:4),%a0
80001a6c:   43f3 2a01       lea %a3@(00000001,%d2:l:2),%a1
80001a70:   47f2 8800       lea %a2@(00000000,%a0:l),%a3
80001a80:   2032 9a00       movel %a2@(00000000,%a1:l:2),%d0
80002670:   2270 0800       moveal %a0@(00000000,%d0:l),%a1
8000268c:   cab0 0808       andl %a0@(00000008,%d0:l),%d5
8000269a:   b0b0 1c04       cmpl %a0@(00000004,%d1:l:4),%d0
800027d4:   c2b0 0808       andl %a0@(00000008,%d0:l),%d1
800027e8:   b2b0 0c04       cmpl %a0@(00000004,%d0:l:4),%d1
80002802:   2430 2800       movel %a0@(00000000,%d2:l),%d2
8000293e:   c2b0 0808       andl %a0@(00000008,%d0:l),%d1
80002952:   b2b0 0c04       cmpl %a0@(00000004,%d0:l:4),%d1

... And about another 350 like that.

The gcc compiler is making very good use of that instruction, most times just using it to add two registers together with a zero offset.

And as for the normal (and way more popular) indexed ones:

$ m68k-elf-objdump -S boot.elf | grep "@([0-9]*)" | wc
   5365   27050  238828

m68k-elf-objdump -S boot.elf | grep "@([0-9]*)" | less

800005ee:   4fef 000c       lea %sp@(12),%sp
80000690:   2f2e 0008       movel %fp@(8),%sp@-
800006ae:   262e 0008       movel %fp@(8),%d3
800006b2:   206a 0146       moveal %a2@(326),%a0
800006ba:   2028 0004       movel %a0@(4),%d0
800006d0:   43ee 0010       lea %fp@(16),%a1
800006da:   43ee 0014       lea %fp@(20),%a1
800006e0:   2828 0004       movel %a0@(4),%d4
800006e4:   2228 0004       movel %a0@(4),%d1
800006f4:   85a8 0188       orl %d2,%a0@(392)
80000702:   43ee 000c       lea %fp@(12),%a1
80000706:   2141 0004       movel %d1,%a0@(4)
8000071c:   41ea 014a       lea %a2@(330),%a0
80000722:   2028 0004       movel %a0@(4),%d0
80000726:   2548 0146       movel %a0,%a2@(326)
80000730:   2028 0004       movel %a0@(4),%d0
80000734:   43ee 000c       lea %fp@(12),%a1
80000740:   85a8 018c       orl %d2,%a0@(396)
80000744:   2141 0004       movel %d1,%a0@(4)
80000772:   20aa 0146       movel %a2@(326),%a0@
80000778:   2548 0146       movel %a0,%a2@(326)
8000077c:   42a8 0004       clrl %a0@(4)

Count of normal "move" and "movea" instructions, and 26 "movec" ones:

$ m68k-elf-objdump -S boot.elf | grep "move" | wc
  13940   65080  620299

Tom

0 件の賞賛
返信

2,268件の閲覧回数
flvloveu
Contributor II

Hi Tom,

     Thanks for the answer. Actually, I don't know how they work and what they are  good for in my question.

     As your suggestion , I find a document named "ColdFire Family Programmer’s Reference Manual" at the head of Chapter 3.Now , I see it is Address Register Indirect with Displacement Mode. I try to execute "move (2,a0),d0", but ,a error occur. Anything I was wrong?

     pastedImage_0.png

pastedImage_2.png

David

0 件の賞賛
返信

2,268件の閲覧回数
TomE
Specialist II

Now you know how the CPU instructions work.

What you now have is a very different problem.

The assembly syntax shown in the Programmer's Manual is only one way of representing that instruction to an assembler.

The people who write assemblers don't seem to take much notice of the manuals. They seem to "know better" and have their own favourite ways of representing parts of the assembly instruction.

So it may be "move" or "movel" or "move.l" or "move_l" and "2" or "$2" or "#2", and "a0" or "%a0".

I'm using gcc and it seems to prefer things like "movew %a0@(4),%d2".

So you now have to read the manual for the Assembly Manual that you're using to see how they expect assembly code to be written.

But then you're trying to write assembly code and then present it to a C Compiler.

Different C compilers have different ways of accepting Assembly code, often with even more complicated coding. You then have to tell the system which C Variable you want in which Assembly Register. it is useless putting assembly in C code if you can't have them work on each others variables.

I hope you're not just typing "move (2, a0), d0)" into a file and trying to compile it like that as that isn't "Valid C". That has to be wrapped in "asm("move ..."); or something special. And something non-standard (and different for each different compiler).

What compiler are you using? If you're using the Freescale one, then you should read all the documentation for it. You should then post in the CW forum with questions on its use if you can't work it out.

You should also look through sample code for examples on how to use assembly in the system you're using.

This Forum isn't Twitter, so you should be providing FAR more context and sample code than you're doing.

Why are you trying to use assembly code in "fpgaCAN.c" which looks like a CAN driver? There shouldn't be any need to write assembly, and the compiler can usually do a better job converting C code to assembly that you could anyway.

Tom

0 件の賞賛
返信

2,268件の閲覧回数
flvloveu
Contributor II

Hi Tom,

     Thanks for the examples and the kindly answer.

     You are right.As your suspect, I had used "asm {}" in a C file and I use the CodeWarrior 7.2 .So, it seems the Compiler is not spported to this instruction.

     >>Why are you trying to use assembly code in "fpgaCAN.c" which looks like a CAN driver?

     Yes, it is in a CAN  interrupt . More important thing is that I am learning assembly language of Freescale, so that , I can handle some bad conditions that the code  can run more faster.

      In conclusion,  I know more about  assembly and instructions and I can use some basic instructions to finish some code instead with C.

     pastedImage_0.png

A new question , if I want to rewrite codes "CANRXMSG *pCurrentMsgBuf = &(CANstruct.RxBuffer[CANstruct.usRxBufHead]);" CANstruct is a global variable , how can I do?

Now I write them as :

         pastedImage_1.png

   I think I use a bad method to get the pointer.

    

    

     Thanks again.

    David

0 件の賞賛
返信

2,268件の閲覧回数
TomE
Specialist II

You've got an 80MHz CPU. The fastest CAN port is 1MHz and takes between 50 and 110 bits to deliver a message. So the maximum message arrival rate is one every 2,800 CPU instructions.

So why do you need to try and make it a bit faster when the CPU has that much speed?

You can probably save a lot of time somewhere else in your code if you need it.

Writing maintainable code is far more important that writing something "just a bit quicker". If I was your boss I wouldn't let you write assembly code in that function.

If you must have assembly you should write it as a separate standalone assembly code file, not using the "asm" construct.

Your code is a little inefficient. You should be using more registers and you shouldn't be using address registers for data operation as they're more restricted in what they can do. The first thing your code should do is a "moveml" to free up registers for efficient use.

I can't see that the compiler would do that bad a job, UNLESS you've got it configured in "debug mode" which generates unoptimised code so it is easy to single-step. You should let it generate "release" code with a high level of optimisation and compare that with your assembly.

It may be that CW isn't that good, even if you configure it properly.

Can you provide a stand-alone (main() plus function calls) program with the internals of the interrupt handler written in C. I'll compile it with gcc and we'll then see if it can do any better?

I've just done that for the part of the code that moves and merges the extended ID and the code from gcc ends up like this:

#define CAN_MSG_IDX_IDE 0x80000000

if (pReg->CAN_MSG_ID_REG & CAN_MSG_IDX_IDE)

{

pMsg->ulMsgId = ((pReg->CAN_MSG_ID_REG & 0x3ff) << 18) |

                 ((pReg->CAN_MSG_ID_REG & 0x1ffff800) >> 11);

16:   2211            movel %a1@,%d1

18:   2f02            movel %d2,sp@-

1a:   4a81            tst %d1

1c:   6d18            blts 36

36:   2001            movel %d1,%d0

38:   740b            moveq #11,%d2

3a:   0280 1fff f800  andil #536868864,%d0

40:   0281 0000 03ff  andil #1023,%d1

46:   e4a8            lsrl %d2,%d0

48:   143c 0012       moveb #18,%d2

4c:   e5a9            lsll %d2,%d1

4e:   740f            moveq #15,%d2

50:   8081            orl %d1,%d0

52:   2140 0004       movel %d0,%a0@(4)

So that's 9 instructions, doing the same as your code does in 10. The "moveq #15" in there is just setting up for masking the DLC.

It would be better to move that operation out of the interrupt routine and perform that operation in the mainline code though. The interrupt routine should do the bare minimum.

What you do need is to declare a static inline assembly function that can contains the "byterev.l" instruction (ONLY) to do the byte swap for you. That SHOULD already be a part of a provided library for the ColdFire chips. I'd look to see if one has already been provided in CW before writing one yourself.

On Linux systems, the header file "netinet/in.h" defines macros ntohs(), htons(), ntohl() and htonl() to perform byte swapping from "network order" to "host order". On a big-endian coldfire these do nothing (the bytes are already in "network order"). See if you can find equivalent definitions in CW. in Linux these are defined in terms of a "__bswap_32()". There should be more standard definitions in an "endian.h" header file. You might have a "byteswap.h" header.

Here's one from the Linux distribution. That's for gcc. You need an equivalent for CW:

http://lxr.free-electrons.com/source/arch/m68k/include/asm/swab.h?v=3.4

Here's where that question has come up before - simply searching the community for "byterev":

Re: Link Error : Undefined : mcf5xxx_byterev

Re: Swapping bytes &amp; ASR/ASL

Re: Coldfire SEC and SKHA Benchmarks

It would be more efficient to fix the FPGA CAN implementation to give you the data in the right order so you don't have to fix it in your code though. It looks like someone bolted a little-endian CAN implementation onto a big-endian CPU. That's never a good idea. But you'll notice in the "SKHA" post above that Freescale did exactly that in the MCF5235!

EDIT:

Thinking some more about this, what order are the data bytes in the FPGA? The "standard" order for them in two 32-bit registers is "[ 0 | 1 | 2 | 3 ] [ 4 | 5 | 6 | 7 ]", which matches the byte order in the big-endian Coldfire chip. Is the FPGA providing them in this order and you're swapping to little-endian, or is it weirdly providing them as "[ 3 | 2 | 1 | 0 ] [ 7 | 6 | 5 | 4 ]" and you're swapping them back to native big-endian?

CAN Data shouldn't be considered as a stream of 8 bytes. It is a stream of 64 BITS. Breaking those bits into smaller fields (1, 2, 3, 4, 8, 16 and 32 bits are common) can be done on any bit boundary, so leaving the data in the original 32-bit order (or 64 bits on a 64-bit CPU) can make the final data extraction more efficient. If you swap them into "little endian byte order" you'll later have to swap them back to extract the fields.

Tom

0 件の賞賛
返信