开发者

Want to configure a particular peripheral register in ARM9 based chip

I have verilog based verification envirnoment for ARM based chip. I have to write new tests in C++ to verifiy a peripheral. I have all ARM based GCC tools in place. I do not know how to make a particular peripheral register visible in C++ based test. I want to write to this register, want to wait for the interrupt from the peripheral and then want to read back status of another peripheral register.

I would like to to know how can it be done? Which documentation from ARM should I refer to. I tried and 开发者_开发百科find all documentations are for system developers I need the basic information. Regards Manish


You will eventually if not immediately want the ARM ARM (yes ARM twice, once for ARM the second one for Architectural Reference Manual, you can google it and find it for free as a download). Second you want the TRM, Technical Reference Manual for the specific core in your chip. ARM doesn't make chips they make processor cores that other people put in their chips so the company that has the chip may or may not have the TRM included in their documentation. If you have an arm core in verilog then I assume you purchased it and that means you have the specific TRM for the specific core that you purchased available, plus any add ons (like a cache for example).

You can take this with a grain of salt but I have done what you are doing for many years (testing in simulation and later on the real chip) now and my preference is to write my C code as if it were going to be running embedded on the arm. Well in this case perhaps you are running embedded on the arm.

Instead of something like this:


#define SOMEREG (*(volatile unsigned int *)0X12345678)

and then in your code


SOMEREG = 0xabc;

or


somevariable = SOMEREG;
somevariable |= 0x10;
SOMEREG = somevariable;

My C code uses external functions.


extern unsigned int GET32 ( unsigned int address );
extern void PUT32 ( unsigned int address, unsigned int data);

somevariable = GET32(0x12345678);
somevariable|=0x10;
PUT32(0x12345678,somevariable);

When running on the chip in or out of simulation:


.globl PUT32
PUT32:
   str r1,[r0]
   bx lr ;@ or mov pc,lr depending on architecture
.globl PUT16
PUT16:
   strh r1,[r0]
   bx lr
.globl GET32
GET32:
   ldr r0,[r0] ;@ I know what the ARM ARM says, this works
   bx lr
.globl GET16
GET16
   ldrh r0,[r0]
   bx lr

Say you name the file it putget.s

arm-something-as putget.s -o putget.o 

then link putget.o in with your C/C++ objects.

I have had gcc and pretty much every other compiler fail to get the *volatile thing to work 100%, usually right after you release your code to the manufacturing folks to take your tests and run them on the product is when it fails and you have to stop production and re-write or re-tune a bunch of code to get the compiler not confused again. The external function approach has worked 100% on all compilers, the only drawback is the performance when running embedded, but the benefits of abstraction across all interfaces and operating systems pays you back for that.

I assume you are doing one of two things, either you are running code on the simulated arm trying to talk to something tied to the simulated arm. Eventually I assume the code will be doing that so you will have to get into tools and linker issues, which there are many examples out there, some of my own as well, just like building a gcc cross compiler, trivial once shown the first time. If this is a peripheral that will eventually be tied to an arm, but for now is outside the core but inside the design, meaning it hopefully is memory mapped and is tied to the arms memory interface (amba, axi, etc).

for the first case you have to overcome the embedded hurdle, you will need to build bootable code, probably rom/flash based (read only) as that is likely how the arm/chip will boot, dealing with the linker scripts to separate the rom/ram. Here is my advice on that eventually if not now the hardware engineers will want to simulate the rom timing, which is painfully slow in simulation. Compile your program to run completely from ram (other than the exception table which is a separate topic), compile to a binary format that you are willing to write an ad hoc utility for reading, elf is easy, so is ihex and srec, none as easy as a plain old binary .bin. What you ultimately want to do is write some assembler that boots up on the virtual prom/flash, enables the instruction cache (if they have that implemented and working in simulation, if not then wait on that step) uses the ldm amd stm instructions in a loop to copy as many words at a time as you can to ram, then branch to ram. I have a host based utility that takes the .bin file creates an assembler program that includes the assembler that copies the binary to ram and embed the binary itself as .words in the assembler, then assemble and link that program to a format the simulation can use. Do not let the hardware engineers convince you that you have to re-build the verilog every time, you can use a $readmemh() or some other such thing in verilog to read a file at runtime and not have to re-compile the verilog to change the arm binary. You will want to write an ad hoc host based utility to convert your .bin or .elf or whatever to a file that the verilog can read, readmemh is trivial... So I am getting off on a tangent, use the put/get to talk to registers, you have to use the TRM and the ARM ARM to place the interrupt handler code somewhere, you have to enable the interrupt, most likely in more than one place in the arm as well as in the peripheral. The beauty of simulating is that you can watch your code execute and you can see the interrupt leave the peripheral and debug your code based on what you see, with a real chip you dont know if your code is failing to create the interrupt or if your code is failing to enable the interrupt or if the interrupt is working but you made a mistake in the interrupt handler, with a verilog simulator you can see all of this and you should strive to learn to read the waveforms and not rely on the hardware engineers to do it for you. modelsim or cadence or whomever can save the waveforms in .vcd format and you can use a free tool named gtkwave to view the waveforms. Dont let them convince you that they dont have any more licences available for you to look at stuff.

All of that is secondary, if this is an off core but on chip peripheral then you probably want to test that logic without the arm core first. If you dont know verilog, its easy you should just look at the code and you can figure it out. Software engineers can pick it up in a few days or a week if already experienced in languages, particularly C. Either way, the hardware engineer likely has a test bench for the peripheral, you create or have them create a test bench with a register that is similar to what you will see once connected to the arm, either directly on the arm bus or on a test bench interface that simplifies the arm bus. then use vpi, which is ugly but works (google foreign language interface as well as vpi) to connect C code on the host machine running the simulation. Do most of your work in C and verilog minimizing the vpi nightmare. Because this is compiled and linked to the simulation in a sense you do not want to have to re-build the sim every time you want to change your test program. So use something like sockets or some other IPC interface so that you can separate from the vpi code. Then write some host code that implements put32 and get32 (put8, put16, whatever functions you want to implement). so now you take your test program that can run on the arm if compiled that way and instead compile it on the lost linking it to the put/get/whatever abstraction layer. Now you can write programs that for now run on the host but interact with the peripheral in simulation as if it were real hardware and as if your host programs were embedded programs in the arm. the interrupt is likely trivial in this environment as all you have to do is either look for it in the waveforms or have the vpi code print something on the console when the signal changes states or something like that.

Oh, the reason for copying from rom to ram then running from ram is that on average your sim times will be significantly shorter, fives and tens of minutes instead of hours. simulating the peripheral by itself without the arm using a foreign language interface to bridge to/from the host, cuts your sim time from fives of minutes to seconds depending on what you are doing. If you use some sort of abstraction like my put/get you can write your peripheral code one time in one file, linking it different ways that one file/program/function can be used with the perhipheral only in simulation for quickly developing your code, then run with the arm in place in simulation adding the complexity of the arm exceptions and arm interrupt system, and later on the real chip as you were running on the simulated chip. and then later that code can hopefully be used as is in a driver or application space using mmap, etc.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜