- prepare OpenOCD for branching, created ./trunk/
git-svn-id: svn://svn.berlios.de/openocd/trunk@64 b42882b7-edfa-0310-969c-e2dbd0fdcd60
This commit is contained in:
commit
8b4e882a16
|
@ -0,0 +1,340 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Library General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Library General
|
||||||
|
Public License instead of this License.
|
|
@ -0,0 +1,7 @@
|
||||||
|
2005-07-03 Dominic Rath <Dominic.Rath@gmx.net>
|
||||||
|
|
||||||
|
* First public release
|
||||||
|
|
||||||
|
2005-10-27 Dominic Rath <Dominic.Rath@gmx.net>
|
||||||
|
|
||||||
|
* First release of new codebase
|
|
@ -0,0 +1,194 @@
|
||||||
|
Prerequisites
|
||||||
|
=============
|
||||||
|
|
||||||
|
When building with support for FTDI FT2232 based devices, you need at least
|
||||||
|
one of the following libraries:
|
||||||
|
|
||||||
|
- libftdi (http://www.intra2net.com/opensource/ftdi/)
|
||||||
|
- libftd2xx (http://www.ftdichip.com/Drivers/D2XX.htm)
|
||||||
|
|
||||||
|
Basic Installation
|
||||||
|
==================
|
||||||
|
|
||||||
|
OpenOCD is distributed without autotools generated files, i.e. without a
|
||||||
|
configure script. Run ./bootstrap in the openocd directory to have all
|
||||||
|
necessary files generated.
|
||||||
|
|
||||||
|
You have to explicitly enable desired JTAG interfaces during configure:
|
||||||
|
|
||||||
|
./configure --enable-parport --enable-ftdi2232 --enable-ftd2xx \
|
||||||
|
--enable-amtjtagaccel
|
||||||
|
|
||||||
|
Under Windows/Cygwin, only the ftd2xx driver is supported for FT2232 based
|
||||||
|
devices. You have to specify the location of the FTDI driver package with the
|
||||||
|
--with-ftd2xx=/full/path/name option.
|
||||||
|
|
||||||
|
Under Linux you can choose to build the parport driver with support for
|
||||||
|
/dev/parportN instead of the default access with direct port I/O using
|
||||||
|
--enable-parport_ppdev. This has the advantage of running OpenOCD without root
|
||||||
|
privileges at the expense of a slight performance decrease.
|
||||||
|
|
||||||
|
These are generic installation instructions.
|
||||||
|
|
||||||
|
The `configure' shell script attempts to guess correct values for
|
||||||
|
various system-dependent variables used during compilation. It uses
|
||||||
|
those values to create a `Makefile' in each directory of the package.
|
||||||
|
It may also create one or more `.h' files containing system-dependent
|
||||||
|
definitions. Finally, it creates a shell script `config.status' that
|
||||||
|
you can run in the future to recreate the current configuration, a file
|
||||||
|
`config.cache' that saves the results of its tests to speed up
|
||||||
|
reconfiguring, and a file `config.log' containing compiler output
|
||||||
|
(useful mainly for debugging `configure').
|
||||||
|
|
||||||
|
If you need to do unusual things to compile the package, please try
|
||||||
|
to figure out how `configure' could check whether to do them, and mail
|
||||||
|
diffs or instructions to the address given in the `README' so they can
|
||||||
|
be considered for the next release. If at some point `config.cache'
|
||||||
|
contains results you don't want to keep, you may remove or edit it.
|
||||||
|
|
||||||
|
The file `configure.in' is used to create `configure' by a program
|
||||||
|
called `autoconf'. You only need `configure.in' if you want to change
|
||||||
|
it or regenerate `configure' using a newer version of `autoconf'.
|
||||||
|
|
||||||
|
The simplest way to compile this package is:
|
||||||
|
|
||||||
|
1. `cd' to the directory containing the package's source code and type
|
||||||
|
`./configure' to configure the package for your system. If you're
|
||||||
|
using `csh' on an old version of System V, you might need to type
|
||||||
|
`sh ./configure' instead to prevent `csh' from trying to execute
|
||||||
|
`configure' itself.
|
||||||
|
|
||||||
|
Running `configure' takes a while. While running, it prints some
|
||||||
|
messages telling which features it is checking for.
|
||||||
|
|
||||||
|
2. Type `make' to compile the package.
|
||||||
|
|
||||||
|
3. Type `make install' to install the programs and any data files and
|
||||||
|
documentation.
|
||||||
|
|
||||||
|
4. You can remove the program binaries and object files from the
|
||||||
|
source code directory by typing `make clean'.
|
||||||
|
|
||||||
|
Compilers and Options
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Some systems require unusual options for compilation or linking that
|
||||||
|
the `configure' script does not know about. You can give `configure'
|
||||||
|
initial values for variables by setting them in the environment. Using
|
||||||
|
a Bourne-compatible shell, you can do that on the command line like
|
||||||
|
this:
|
||||||
|
CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
|
||||||
|
|
||||||
|
Or on systems that have the `env' program, you can do it like this:
|
||||||
|
env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
|
||||||
|
|
||||||
|
Compiling For Multiple Architectures
|
||||||
|
====================================
|
||||||
|
|
||||||
|
You can compile the package for more than one kind of computer at the
|
||||||
|
same time, by placing the object files for each architecture in their
|
||||||
|
own directory. To do this, you must use a version of `make' that
|
||||||
|
supports the `VPATH' variable, such as GNU `make'. `cd' to the
|
||||||
|
directory where you want the object files and executables to go and run
|
||||||
|
the `configure' script. `configure' automatically checks for the
|
||||||
|
source code in the directory that `configure' is in and in `..'.
|
||||||
|
|
||||||
|
If you have to use a `make' that does not supports the `VPATH'
|
||||||
|
variable, you have to compile the package for one architecture at a time
|
||||||
|
in the source code directory. After you have installed the package for
|
||||||
|
one architecture, use `make distclean' before reconfiguring for another
|
||||||
|
architecture.
|
||||||
|
|
||||||
|
Installation Names
|
||||||
|
==================
|
||||||
|
|
||||||
|
By default, `make install' will install the package's files in
|
||||||
|
`/usr/local/bin', `/usr/local/man', etc. You can specify an
|
||||||
|
installation prefix other than `/usr/local' by giving `configure' the
|
||||||
|
option `--prefix=PATH'.
|
||||||
|
|
||||||
|
You can specify separate installation prefixes for
|
||||||
|
architecture-specific files and architecture-independent files. If you
|
||||||
|
give `configure' the option `--exec-prefix=PATH', the package will use
|
||||||
|
PATH as the prefix for installing programs and libraries.
|
||||||
|
Documentation and other data files will still use the regular prefix.
|
||||||
|
|
||||||
|
If the package supports it, you can cause programs to be installed
|
||||||
|
with an extra prefix or suffix on their names by giving `configure' the
|
||||||
|
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||||
|
|
||||||
|
Optional Features
|
||||||
|
=================
|
||||||
|
|
||||||
|
Some packages pay attention to `--enable-FEATURE' options to
|
||||||
|
`configure', where FEATURE indicates an optional part of the package.
|
||||||
|
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
||||||
|
is something like `gnu-as' or `x' (for the X Window System). The
|
||||||
|
`README' should mention any `--enable-' and `--with-' options that the
|
||||||
|
package recognizes.
|
||||||
|
|
||||||
|
For packages that use the X Window System, `configure' can usually
|
||||||
|
find the X include and library files automatically, but if it doesn't,
|
||||||
|
you can use the `configure' options `--x-includes=DIR' and
|
||||||
|
`--x-libraries=DIR' to specify their locations.
|
||||||
|
|
||||||
|
Specifying the System Type
|
||||||
|
==========================
|
||||||
|
|
||||||
|
There may be some features `configure' can not figure out
|
||||||
|
automatically, but needs to determine by the type of host the package
|
||||||
|
will run on. Usually `configure' can figure that out, but if it prints
|
||||||
|
a message saying it can not guess the host type, give it the
|
||||||
|
`--host=TYPE' option. TYPE can either be a short name for the system
|
||||||
|
type, such as `sun4', or a canonical name with three fields:
|
||||||
|
CPU-COMPANY-SYSTEM
|
||||||
|
|
||||||
|
See the file `config.sub' for the possible values of each field. If
|
||||||
|
`config.sub' isn't included in this package, then this package doesn't
|
||||||
|
need to know the host type.
|
||||||
|
|
||||||
|
If you are building compiler tools for cross-compiling, you can also
|
||||||
|
use the `--target=TYPE' option to select the type of system they will
|
||||||
|
produce code for and the `--build=TYPE' option to select the type of
|
||||||
|
system on which you are compiling the package.
|
||||||
|
|
||||||
|
Sharing Defaults
|
||||||
|
================
|
||||||
|
|
||||||
|
If you want to set default values for `configure' scripts to share,
|
||||||
|
you can create a site shell script called `config.site' that gives
|
||||||
|
default values for variables like `CC', `cache_file', and `prefix'.
|
||||||
|
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
||||||
|
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||||
|
`CONFIG_SITE' environment variable to the location of the site script.
|
||||||
|
A warning: not all `configure' scripts look for a site script.
|
||||||
|
|
||||||
|
Operation Controls
|
||||||
|
==================
|
||||||
|
|
||||||
|
`configure' recognizes the following options to control how it
|
||||||
|
operates.
|
||||||
|
|
||||||
|
`--cache-file=FILE'
|
||||||
|
Use and save the results of the tests in FILE instead of
|
||||||
|
`./config.cache'. Set FILE to `/dev/null' to disable caching, for
|
||||||
|
debugging `configure'.
|
||||||
|
|
||||||
|
`--help'
|
||||||
|
Print a summary of the options to `configure', and exit.
|
||||||
|
|
||||||
|
`--quiet'
|
||||||
|
`--silent'
|
||||||
|
`-q'
|
||||||
|
Do not print messages saying which checks are being made.
|
||||||
|
|
||||||
|
`--srcdir=DIR'
|
||||||
|
Look for the package's source code in directory DIR. Usually
|
||||||
|
`configure' can determine that directory automatically.
|
||||||
|
|
||||||
|
`--version'
|
||||||
|
Print the version of Autoconf used to generate the `configure'
|
||||||
|
script, and exit.
|
||||||
|
|
||||||
|
`configure' also accepts some other, not widely useful, options.
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
# not a GNU package. You can remove this line, if
|
||||||
|
# have all needed files, that a GNU package needs
|
||||||
|
AUTOMAKE_OPTIONS = foreign 1.4
|
||||||
|
|
||||||
|
SUBDIRS = src
|
|
@ -0,0 +1,49 @@
|
||||||
|
openocd
|
||||||
|
|
||||||
|
Free and Open On-Chip Debugging, In-System Programming
|
||||||
|
and Boundary-Scan Testing
|
||||||
|
Copyright (c) 2004, 2005 Dominic Rath
|
||||||
|
|
||||||
|
The debugger uses an IEEE 1149-1 compliant JTAG TAP bus master to access on-chip
|
||||||
|
debug functionality available on ARM7 and ARM9 based microcontrollers /
|
||||||
|
system-on-chip solutions.
|
||||||
|
|
||||||
|
User interaction is realized through a telnet command line interface and a gdb
|
||||||
|
(The GNU Debugger) remote protocol server.
|
||||||
|
|
||||||
|
Initially, support for two JTAG TAP bus master interfaces with public hardware
|
||||||
|
schematics will be included, but support of additional hardware is an expressed
|
||||||
|
goal.
|
||||||
|
|
||||||
|
1. JTAG hardware
|
||||||
|
|
||||||
|
Currently, openocd contains support for Wiggler-compatible paralell port
|
||||||
|
dongles and a USB interface based on the FTDI FT2232, called USBJTAG-1.
|
||||||
|
A new version of the USB interface, USB-JTAG v1.2, is available with complete
|
||||||
|
schematics (http://www.fh-augsburg.de/~hhoegl/proj/volksmikro/usb-jtag/050910/).
|
||||||
|
|
||||||
|
It was tested using Amontec's (www.amontec.com) Chameleon POD in it's
|
||||||
|
Wiggler configuration, but homemade wigglers should work just as well.
|
||||||
|
In order to use the reset functionality (warm-reset, debug from reset, reset
|
||||||
|
and init), the choosen Wiggler has to connect the nSRST line.
|
||||||
|
|
||||||
|
USBJTAG-1 is based on a FTDI DLP2232M module and a few additional parts.
|
||||||
|
Schematics are freely available. USB-JTAG v1.2 doesn't use the DLP2232M, but
|
||||||
|
has the FTDI chip soldered directly on the PCB. There are two drivers for these
|
||||||
|
modules implemented, one using the open source libftdi, the other using FTDI's
|
||||||
|
proprietary FTD2XX library.
|
||||||
|
|
||||||
|
2. Supported cores
|
||||||
|
|
||||||
|
This version of openocd supports the following cores:
|
||||||
|
|
||||||
|
- ARM7TDMI
|
||||||
|
- ARM9TDMI
|
||||||
|
|
||||||
|
Support for cores with MMUs (ARM720t, ARM920t) is currently being merged.
|
||||||
|
|
||||||
|
3. Licensing
|
||||||
|
|
||||||
|
openocd is licensed under the terms of the GNU General Public License, see the
|
||||||
|
file COPYING for details.
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
- Additional cores. ARM9E(J)-S, ARM7TDMI-S, TI925, ...
|
||||||
|
- Testing.
|
||||||
|
- Additional jtag interfaces. Currently, only Wiggler style interfaces and
|
||||||
|
USBJTAG-1 are supported.
|
||||||
|
- Testing.
|
||||||
|
- Handle endianess. The configuration variable is there, but that's about it.
|
||||||
|
Currently, only little-endian targets and little-endian hosts are supported.
|
|
@ -0,0 +1,4 @@
|
||||||
|
aclocal \
|
||||||
|
&& autoheader \
|
||||||
|
&& automake --gnu --add-missing \
|
||||||
|
&& autoconf
|
|
@ -0,0 +1,112 @@
|
||||||
|
AC_INIT(configure.in)
|
||||||
|
|
||||||
|
AC_SEARCH_LIBS([ioperm], [ioperm])
|
||||||
|
|
||||||
|
AC_CANONICAL_HOST
|
||||||
|
|
||||||
|
build_bitbang=no
|
||||||
|
is_cygwin=no
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(parport,
|
||||||
|
AS_HELP_STRING([--enable-parport], [Enable building the pc parallel port driver]),
|
||||||
|
[build_parport=$enableval], [build_parport=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(parport_ppdev,
|
||||||
|
AS_HELP_STRING([--enable-parport_ppdev], [Enable use of ppdev (/dev/parportN) for parport]),
|
||||||
|
[parport_use_ppdev=$enableval], [parport_use_ppdev=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(ftdi2232,
|
||||||
|
AS_HELP_STRING([--enable-ftdi2232], [Enable building the libftdi ft2232c driver]),
|
||||||
|
[build_ftdi2232=$enableval], [build_ftdi2232=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(ftd2xx,
|
||||||
|
AS_HELP_STRING([--enable-ftd2xx], [Enable building the ftd2xx ft2232c driver]),
|
||||||
|
[build_ftd2xx=$enableval], [build_ftd2xx=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(amtjtagaccel,
|
||||||
|
AS_HELP_STRING([--enable-amtjtagaccel], [Enable building the Amontec JTAG-Accelerator driver]),
|
||||||
|
[build_amtjtagaccel=$enableval], [build_amtjtagaccel=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(ep93xx,
|
||||||
|
AS_HELP_STRING([--enable-ep93xx], [Enable building support for EP93xx based SBCs]),
|
||||||
|
[build_ep93xx=$enableval], [build_ep93xx=no])
|
||||||
|
|
||||||
|
AC_ARG_WITH(ftd2xx,
|
||||||
|
[AS_HELP_STRING(--with-ftd2xx,
|
||||||
|
[Where libftd2xx can be found <default=search>])],
|
||||||
|
[],
|
||||||
|
with_ftd2xx=search)
|
||||||
|
|
||||||
|
if test $build_parport = yes; then
|
||||||
|
build_bitbang=yes
|
||||||
|
AC_DEFINE(BUILD_PARPORT, 1, [1 if you want parport.])
|
||||||
|
else
|
||||||
|
AC_DEFINE(BUILD_PARPORT, 0, [0 if you don't want parport.])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test $build_ep93xx = yes; then
|
||||||
|
build_bitbang=yes
|
||||||
|
AC_DEFINE(BUILD_EP93XX, 1, [1 if you want ep93xx.])
|
||||||
|
else
|
||||||
|
AC_DEFINE(BUILD_EP93XX, 0, [0 if you don't want ep93xx.])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test $parport_use_ppdev = yes; then
|
||||||
|
AC_DEFINE(PARPORT_USE_PPDEV, 1, [1 if you want parport to use ppdev.])
|
||||||
|
else
|
||||||
|
AC_DEFINE(PARPORT_USE_PPDEV, 0, [0 if you don't want parport to use ppdev.])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test $build_bitbang = yes; then
|
||||||
|
AC_DEFINE(BUILD_BITBANG, 1, [1 if you want a bitbang interface.])
|
||||||
|
else
|
||||||
|
AC_DEFINE(BUILD_BITBANG, 0, [0 if you don't want a bitbang interface.])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test $build_ftdi2232 = yes; then
|
||||||
|
AC_DEFINE(BUILD_FTDI2232, 1, [1 if you want libftdi ft2232.])
|
||||||
|
else
|
||||||
|
AC_DEFINE(BUILD_FTDI2232, 0, [0 if you don't want libftdi ft2232.])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test $build_ftd2xx = yes; then
|
||||||
|
AC_DEFINE(BUILD_FTD2XX, 1, [1 if you want ftd2xx ft2232.])
|
||||||
|
else
|
||||||
|
AC_DEFINE(BUILD_FTD2XX, 0, [0 if you don't want ftd2xx ft2232.])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test $build_amtjtagaccel = yes; then
|
||||||
|
AC_DEFINE(BUILD_AMTJTAGACCEL, 1, [1 if you want the Amontec JTAG-Accelerator driver.])
|
||||||
|
else
|
||||||
|
AC_DEFINE(BUILD_AMTJTAGACCEL, 0, [0 if you don't want the Amontec JTAG-Accelerator driver.])
|
||||||
|
fi
|
||||||
|
|
||||||
|
case $host in
|
||||||
|
*-*-cygwin*)
|
||||||
|
is_cygwin=yes
|
||||||
|
AC_DEFINE(IS_CYGWIN, 1, [1 if building for Cygwin.])
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_DEFINE(IS_CYGWIN, 0, [0 if not building for Cygwin.])
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
AM_CONFIG_HEADER(config.h)
|
||||||
|
AM_INIT_AUTOMAKE(openocd, 0.1)
|
||||||
|
|
||||||
|
AM_CONDITIONAL(PARPORT, test $build_parport = yes)
|
||||||
|
AM_CONDITIONAL(EP93XX, test $build_ep93xx = yes)
|
||||||
|
AM_CONDITIONAL(BITBANG, test $build_bitbang = yes)
|
||||||
|
AM_CONDITIONAL(FTDI2232, test $build_ftdi2232 = yes)
|
||||||
|
AM_CONDITIONAL(FTD2XX, test $build_ftd2xx = yes)
|
||||||
|
AM_CONDITIONAL(AMTJTAGACCEL, test $build_amtjtagaccel = yes)
|
||||||
|
AM_CONDITIONAL(IS_CYGWIN, test $is_cygwin = yes)
|
||||||
|
AM_CONDITIONAL(FTD2XXDIR, test $with_ftd2xx != search)
|
||||||
|
|
||||||
|
AC_LANG_C
|
||||||
|
AC_PROG_CC
|
||||||
|
AC_PROG_RANLIB
|
||||||
|
|
||||||
|
AC_SUBST(WITH_FTD2XX, $with_ftd2xx)
|
||||||
|
|
||||||
|
AC_OUTPUT(Makefile src/Makefile src/helper/Makefile src/jtag/Makefile src/xsvf/Makefile src/target/Makefile src/server/Makefile src/flash/Makefile)
|
|
@ -0,0 +1,26 @@
|
||||||
|
#daemon configuration
|
||||||
|
telnet_port 4444
|
||||||
|
gdb_port 3333
|
||||||
|
|
||||||
|
#interface
|
||||||
|
interface ftdi2232
|
||||||
|
jtag_speed 0
|
||||||
|
#use combined on interfaces or targets that can't set TRST/SRST separately
|
||||||
|
reset_config trst_and_srst srst_pulls_trst
|
||||||
|
|
||||||
|
#jtag scan chain
|
||||||
|
#format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE)
|
||||||
|
jtag_device 4 0x1 0xf 0xe
|
||||||
|
|
||||||
|
#target configuration
|
||||||
|
daemon_startup reset
|
||||||
|
#target <type> <startup mode>
|
||||||
|
#target arm7tdmi <reset mode> <chainpos> <endianness> <variant>
|
||||||
|
target arm7tdmi little run_and_halt 0 arm7tdmi-s_r4
|
||||||
|
target_script 0 reset h2294_init.script
|
||||||
|
run_and_halt_time 0 30
|
||||||
|
working_area 0 0x40000000 0x40000 nobackup
|
||||||
|
|
||||||
|
#flash configuration
|
||||||
|
flash bank lpc2000 0x0 0x40000 0 0 lpc2000_v1 0 14765 calc_checksum
|
||||||
|
flash bank cfi 0x80000000 0x400000 2 2 0
|
|
@ -0,0 +1,29 @@
|
||||||
|
#daemon configuration
|
||||||
|
telnet_port 4444
|
||||||
|
gdb_port 3333
|
||||||
|
|
||||||
|
#interface
|
||||||
|
interface ftd2xx
|
||||||
|
ftd2xx_device_desc "Amontec JTAGkey A"
|
||||||
|
ftd2xx_layout jtagkey
|
||||||
|
ftd2xx_vid_pid 0x0403 0xcff8
|
||||||
|
jtag_speed 2
|
||||||
|
#use combined on interfaces or targets that can't set TRST/SRST separately
|
||||||
|
reset_config trst_and_srst srst_pulls_trst
|
||||||
|
|
||||||
|
#jtag scan chain
|
||||||
|
#format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE)
|
||||||
|
jtag_device 4 0x1 0xf 0xe
|
||||||
|
|
||||||
|
#target configuration
|
||||||
|
daemon_startup reset
|
||||||
|
#target <type> <startup mode>
|
||||||
|
#target arm7tdmi <reset mode> <chainpos> <endianness> <variant>
|
||||||
|
target arm7tdmi little run_and_halt 0 arm7tdmi-s_r4
|
||||||
|
target_script 0 reset h2294_init.script
|
||||||
|
run_and_halt_time 0 30
|
||||||
|
working_area 0 0x40000000 0x40000 nobackup
|
||||||
|
|
||||||
|
#flash configuration
|
||||||
|
flash bank lpc2000 0x0 0x40000 0 0 lpc2000_v1 0 14765 calc_checksum
|
||||||
|
flash bank cfi 0x80000000 0x400000 2 2 0
|
|
@ -0,0 +1,28 @@
|
||||||
|
#daemon configuration
|
||||||
|
telnet_port 4444
|
||||||
|
gdb_port 3333
|
||||||
|
|
||||||
|
#interface
|
||||||
|
interface parport
|
||||||
|
parport_port 0x378
|
||||||
|
parport_cable wiggler
|
||||||
|
jtag_speed 0
|
||||||
|
#use combined on interfaces or targets that can't set TRST/SRST separately
|
||||||
|
reset_config trst_and_srst srst_pulls_trst
|
||||||
|
|
||||||
|
#jtag scan chain
|
||||||
|
#format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE)
|
||||||
|
jtag_device 4 0x1 0xf 0xe
|
||||||
|
|
||||||
|
#target configuration
|
||||||
|
daemon_startup reset
|
||||||
|
#target <type> <startup mode>
|
||||||
|
#target arm7tdmi <reset mode> <chainpos> <endianness> <variant>
|
||||||
|
target arm7tdmi little run_and_halt 0 arm7tdmi-s_r4
|
||||||
|
target_script 0 reset h2294_init.script
|
||||||
|
run_and_halt_time 0 30
|
||||||
|
working_area 0 0x40000000 0x40000 nobackup
|
||||||
|
|
||||||
|
#flash configuration
|
||||||
|
flash bank lpc2000 0x0 0x40000 0 0 lpc2000_v1 0 14765 calc_checksum
|
||||||
|
flash bank cfi 0x80000000 0x400000 2 2 0
|
|
@ -0,0 +1,28 @@
|
||||||
|
#daemon configuration
|
||||||
|
telnet_port 4444
|
||||||
|
gdb_port 3333
|
||||||
|
|
||||||
|
#interface
|
||||||
|
interface ftd2xx
|
||||||
|
ftd2xx_device_desc "Amontec JTAGkey A"
|
||||||
|
ftd2xx_layout "jtagkey"
|
||||||
|
ftd2xx_vid_pid 0x0403 0xcff8
|
||||||
|
jtag_speed 1
|
||||||
|
#use combined on interfaces or targets that can't set TRST/SRST separately
|
||||||
|
reset_config trst_and_srst
|
||||||
|
|
||||||
|
#jtag scan chain
|
||||||
|
#format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE)
|
||||||
|
jtag_device 4 0x1 0xf 0xe
|
||||||
|
|
||||||
|
#target configuration
|
||||||
|
daemon_startup reset
|
||||||
|
#target <type> <endianess> <reset mode>
|
||||||
|
target arm9tdmi little reset_halt 0 arm920t
|
||||||
|
working_area 0 0x200000 0x4000 backup
|
||||||
|
run_and_halt_time 0 5000
|
||||||
|
|
||||||
|
#flash configuration
|
||||||
|
#flash bank <driver> <base> <size> <chip_width> <bus_width> [driver_options ...]
|
||||||
|
flash bank cfi 0x10000000 0x800000 2 2 0
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#daemon configuration
|
||||||
|
telnet_port 4444
|
||||||
|
gdb_port 3333
|
||||||
|
|
||||||
|
#interface
|
||||||
|
interface parport
|
||||||
|
parport_cable chameleon
|
||||||
|
jtag_speed 0
|
||||||
|
|
||||||
|
#jtag scan chain
|
||||||
|
# format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE)
|
||||||
|
jtag_device 5 0x01 0x1f 0x01
|
|
@ -0,0 +1,40 @@
|
||||||
|
bin_PROGRAMS = openocd
|
||||||
|
openocd_SOURCES = openocd.c
|
||||||
|
|
||||||
|
# set the include path found by configure
|
||||||
|
INCLUDES = -I$(top_srcdir)/src/helper \
|
||||||
|
-I$(top_srcdir)/src/jtag -I$(top_srcdir)/src/target -I$(top_srcdir)/src/xsvf -I$(top_srcdir)/src/server \
|
||||||
|
-I$(top_srcdir)/src/flash $(all_includes)
|
||||||
|
|
||||||
|
# the library search path.
|
||||||
|
openocd_LDFLAGS = $(all_libraries)
|
||||||
|
SUBDIRS = helper jtag xsvf target server flash
|
||||||
|
|
||||||
|
if FTDI2232
|
||||||
|
FTDI2232LIB = -lftdi
|
||||||
|
else
|
||||||
|
FTDI2232LIB =
|
||||||
|
endif
|
||||||
|
|
||||||
|
if IS_CYGWIN
|
||||||
|
if FTD2XXDIR
|
||||||
|
FTD2XXLDADD = @WITH_FTD2XX@/FTD2XX.lib
|
||||||
|
else
|
||||||
|
FTD2XXLDADD = -lftd2xx
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
FTD2XXLDADD = -lftd2xx
|
||||||
|
endif
|
||||||
|
|
||||||
|
if FTD2XX
|
||||||
|
FTD2XXLIB = $(FTD2XXLDADD)
|
||||||
|
else
|
||||||
|
FTD2XXLIB =
|
||||||
|
endif
|
||||||
|
|
||||||
|
openocd_LDADD = $(top_builddir)/src/xsvf/libxsvf.a \
|
||||||
|
$(top_builddir)/src/target/libtarget.a $(top_builddir)/src/jtag/libjtag.a \
|
||||||
|
$(top_builddir)/src/helper/libhelper.a \
|
||||||
|
$(top_builddir)/src/server/libserver.a $(top_builddir)/src/helper/libhelper.a \
|
||||||
|
$(top_builddir)/src/flash/libflash.a $(top_builddir)/src/target/libtarget.a \
|
||||||
|
$(FTDI2232LIB) $(FTD2XXLIB)
|
|
@ -0,0 +1,5 @@
|
||||||
|
INCLUDES = -I$(top_srcdir)/src/helper -I$(top_srcdir)/src/jtag -I$(top_srcdir)/src/target $(all_includes)
|
||||||
|
METASOURCES = AUTO
|
||||||
|
noinst_LIBRARIES = libflash.a
|
||||||
|
libflash_a_SOURCES = flash.c lpc2000.c cfi.c at91sam7.c str7x.c
|
||||||
|
noinst_HEADERS = flash.h lpc2000.h cfi.h at91sam7.h str7x.h
|
|
@ -0,0 +1,632 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2006 by Magnus Lundin *
|
||||||
|
* lundin@mlu.mine.nu *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
There are some things to notice
|
||||||
|
|
||||||
|
* AT91SAM7S64 is tested
|
||||||
|
* All AT91SAM7Sxx and AT91SAM7Xxx should work but is not tested
|
||||||
|
* All parameters are identified from onchip configuartion registers
|
||||||
|
*
|
||||||
|
* The flash controller handles erases automatically on a page (128/265 byte) basis
|
||||||
|
* Only an EraseAll command is supported by the controller
|
||||||
|
* Partial erases can be implemented in software by writing one 0xFFFFFFFF word to
|
||||||
|
* some location in every page in the region to be erased
|
||||||
|
*
|
||||||
|
* Lock regions (sectors) are 32 or 64 pages
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "at91sam7.h"
|
||||||
|
|
||||||
|
#include "flash.h"
|
||||||
|
#include "target.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "binarybuffer.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int at91sam7_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||||
|
int at91sam7_erase(struct flash_bank_s *bank, int first, int last);
|
||||||
|
int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||||
|
int at91sam7_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
|
||||||
|
int at91sam7_probe(struct flash_bank_s *bank);
|
||||||
|
int at91sam7_erase_check(struct flash_bank_s *bank);
|
||||||
|
int at91sam7_protect_check(struct flash_bank_s *bank);
|
||||||
|
int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||||
|
|
||||||
|
u32 at91sam7_get_flash_status(flash_bank_t *bank);
|
||||||
|
void at91sam7_set_flash_mode(flash_bank_t *bank,int mode);
|
||||||
|
u8 at91sam7_wait_status_busy(flash_bank_t *bank, int timeout);
|
||||||
|
int at91sam7_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
|
||||||
|
flash_driver_t at91sam7_flash =
|
||||||
|
{
|
||||||
|
.name = "at91sam7",
|
||||||
|
.register_commands = at91sam7_register_commands,
|
||||||
|
.flash_bank_command = at91sam7_flash_bank_command,
|
||||||
|
.erase = at91sam7_erase,
|
||||||
|
.protect = at91sam7_protect,
|
||||||
|
.write = at91sam7_write,
|
||||||
|
.probe = at91sam7_probe,
|
||||||
|
.erase_check = at91sam7_erase_check,
|
||||||
|
.protect_check = at91sam7_protect_check,
|
||||||
|
.info = at91sam7_info
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
char * EPROC[8]= {"Unknown","ARM946-E","ARM7TDMI","Unknown","ARM920T","ARM926EJ-S","Unknown","Unknown"};
|
||||||
|
long NVPSIZ[16] = {
|
||||||
|
0,
|
||||||
|
0x2000, /* 8K */
|
||||||
|
0x4000, /* 16K */
|
||||||
|
0x8000, /* 32K */
|
||||||
|
-1,
|
||||||
|
0x10000, /* 64K */
|
||||||
|
-1,
|
||||||
|
0x20000, /* 128K */
|
||||||
|
-1,
|
||||||
|
0x40000, /* 256K */
|
||||||
|
0x80000, /* 512K */
|
||||||
|
-1,
|
||||||
|
0x100000, /* 1024K */
|
||||||
|
-1,
|
||||||
|
0x200000, /* 2048K */
|
||||||
|
-1
|
||||||
|
};
|
||||||
|
|
||||||
|
long SRAMSIZ[16] = {
|
||||||
|
-1,
|
||||||
|
0x0400, /* 1K */
|
||||||
|
0x0800, /* 2K */
|
||||||
|
-1,
|
||||||
|
0x1c000, /* 112K */
|
||||||
|
0x1000, /* 4K */
|
||||||
|
0x14000, /* 80K */
|
||||||
|
0x28000, /* 160K */
|
||||||
|
0x2000, /* 8K */
|
||||||
|
0x4000, /* 16K */
|
||||||
|
0x8000, /* 32K */
|
||||||
|
0x10000, /* 64K */
|
||||||
|
0x20000, /* 128K */
|
||||||
|
0x40000, /* 256K */
|
||||||
|
0x18000, /* 96K */
|
||||||
|
0x80000, /* 512K */
|
||||||
|
};
|
||||||
|
|
||||||
|
u32 at91sam7_get_flash_status(flash_bank_t *bank)
|
||||||
|
{
|
||||||
|
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||||
|
target_t *target = at91sam7_info->target;
|
||||||
|
long fsr;
|
||||||
|
|
||||||
|
target->type->read_memory(target, MC_FSR, 4, 1, (u8 *)&fsr);
|
||||||
|
|
||||||
|
return fsr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup the timimg registers for nvbits or normal flash */
|
||||||
|
void at91sam7_set_flash_mode(flash_bank_t *bank,int mode)
|
||||||
|
{
|
||||||
|
u32 fmcn, fmr;
|
||||||
|
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||||
|
target_t *target = at91sam7_info->target;
|
||||||
|
|
||||||
|
if (mode != at91sam7_info->flashmode) {
|
||||||
|
/* mainf contains the number of main clocks in approx 500uS */
|
||||||
|
if (mode==1)
|
||||||
|
/* main clocks in 1uS */
|
||||||
|
fmcn = (at91sam7_info->mainf>>9)+1;
|
||||||
|
else
|
||||||
|
/* main clocks in 1.5uS */
|
||||||
|
fmcn = (at91sam7_info->mainf>>9)+(at91sam7_info->mainf>>10)+1;
|
||||||
|
DEBUG("fmcn: %i", fmcn);
|
||||||
|
fmr = fmcn<<16;
|
||||||
|
target->type->write_memory(target, MC_FSR, 4, 1, (u8 *)&fmr);
|
||||||
|
at91sam7_info->flashmode = mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 at91sam7_wait_status_busy(flash_bank_t *bank, int timeout)
|
||||||
|
{
|
||||||
|
u32 status;
|
||||||
|
|
||||||
|
while ((!((status = at91sam7_get_flash_status(bank)) & 0x01)) && (timeout-- > 0))
|
||||||
|
{
|
||||||
|
DEBUG("status: 0x%x", status);
|
||||||
|
usleep(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG("status: 0x%x", status);
|
||||||
|
|
||||||
|
if (status&0x0C)
|
||||||
|
{
|
||||||
|
ERROR("status register: 0x%x", status);
|
||||||
|
if (status & 0x4)
|
||||||
|
ERROR("Lock Error Bit Detected, Operation Abort");
|
||||||
|
if (status & 0x8)
|
||||||
|
ERROR("Invalid command and/or bad keyword, Operation Abort");
|
||||||
|
if (status & 0x10)
|
||||||
|
ERROR("Security Bit Set, Operation Abort");
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int at91sam7_flash_command(struct flash_bank_s *bank,u8 cmd,u16 pagen)
|
||||||
|
{
|
||||||
|
u32 fcr;
|
||||||
|
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||||
|
target_t *target = at91sam7_info->target;
|
||||||
|
|
||||||
|
fcr = (0x5A<<24) | (pagen<<8) | cmd;
|
||||||
|
target->type->write_memory(target, MC_FCR, 4, 1, (u8 *)&fcr);
|
||||||
|
DEBUG("Flash command: 0x%x, pagenumber:", fcr, pagen);
|
||||||
|
|
||||||
|
if (at91sam7_wait_status_busy(bank, 10)&0x0C)
|
||||||
|
{
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read device id register, main clock frequency register and fill in driver info structure */
|
||||||
|
int at91sam7_read_part_info(struct flash_bank_s *bank)
|
||||||
|
{
|
||||||
|
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||||
|
target_t *target = at91sam7_info->target;
|
||||||
|
unsigned long cidr, mcfr, status;
|
||||||
|
|
||||||
|
if (at91sam7_info->target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read and parse chip identification register */
|
||||||
|
target->type->read_memory(target, DBGU_CIDR, 4, 1, (u8 *)&cidr);
|
||||||
|
|
||||||
|
if (cidr == 0)
|
||||||
|
{
|
||||||
|
WARNING("Cannot identify target as an AT91SAM");
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
at91sam7_info->cidr = cidr;
|
||||||
|
at91sam7_info->cidr_ext = (cidr>>31)&0x0001;
|
||||||
|
at91sam7_info->cidr_nvptyp = (cidr>>28)&0x0007;
|
||||||
|
at91sam7_info->cidr_arch = (cidr>>20)&0x00FF;
|
||||||
|
at91sam7_info->cidr_sramsiz = (cidr>>16)&0x000F;
|
||||||
|
at91sam7_info->cidr_nvpsiz2 = (cidr>>12)&0x000F;
|
||||||
|
at91sam7_info->cidr_nvpsiz = (cidr>>8)&0x000F;
|
||||||
|
at91sam7_info->cidr_eproc = (cidr>>5)&0x0007;
|
||||||
|
at91sam7_info->cidr_version = cidr&0x001F;
|
||||||
|
bank->size = NVPSIZ[at91sam7_info->cidr_nvpsiz];
|
||||||
|
|
||||||
|
DEBUG("nvptyp: 0x%3.3x, arch: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x", at91sam7_info->cidr_nvptyp, at91sam7_info->cidr_arch );
|
||||||
|
|
||||||
|
/* Read main clock freqency register */
|
||||||
|
target->type->read_memory(target, CKGR_MCFR, 4, 1, (u8 *)&mcfr);
|
||||||
|
if (mcfr&0x10000)
|
||||||
|
{
|
||||||
|
at91sam7_info->mainrdy = 1;
|
||||||
|
at91sam7_info->mainf = mcfr&0xFFFF;
|
||||||
|
at91sam7_info->usec_clocks = mcfr>>9;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
at91sam7_info->mainrdy = 0;
|
||||||
|
at91sam7_info->mainf = 0;
|
||||||
|
at91sam7_info->usec_clocks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = at91sam7_get_flash_status(bank);
|
||||||
|
at91sam7_info->lockbits = status>>16;
|
||||||
|
at91sam7_info->securitybit = (status>>4)&0x01;
|
||||||
|
|
||||||
|
if (at91sam7_info->cidr_arch == 0x70 ) {
|
||||||
|
at91sam7_info->num_nvmbits = 2;
|
||||||
|
at91sam7_info->nvmbits = (status>>8)&0x03;
|
||||||
|
bank->base = 0x100000;
|
||||||
|
bank->bus_width = 4;
|
||||||
|
if (bank->size==0x40000) /* AT91SAM7S256 */
|
||||||
|
{
|
||||||
|
at91sam7_info->num_lockbits = 16;
|
||||||
|
at91sam7_info->pagesize = 256;
|
||||||
|
at91sam7_info->pages_in_lockregion = 64;
|
||||||
|
at91sam7_info->num_pages = 16*64;
|
||||||
|
}
|
||||||
|
if (bank->size==0x20000) /* AT91SAM7S128 */
|
||||||
|
{
|
||||||
|
at91sam7_info->num_lockbits = 8;
|
||||||
|
at91sam7_info->pagesize = 256;
|
||||||
|
at91sam7_info->pages_in_lockregion = 64;
|
||||||
|
at91sam7_info->num_pages = 8*64;
|
||||||
|
}
|
||||||
|
if (bank->size==0x10000) /* AT91SAM7S64 */
|
||||||
|
{
|
||||||
|
at91sam7_info->num_lockbits = 16;
|
||||||
|
at91sam7_info->pagesize = 128;
|
||||||
|
at91sam7_info->pages_in_lockregion = 32;
|
||||||
|
at91sam7_info->num_pages = 16*32;
|
||||||
|
}
|
||||||
|
if (bank->size==0x08000) /* AT91SAM7S321/32 */
|
||||||
|
{
|
||||||
|
at91sam7_info->num_lockbits = 8;
|
||||||
|
at91sam7_info->pagesize = 128;
|
||||||
|
at91sam7_info->pages_in_lockregion = 32;
|
||||||
|
at91sam7_info->num_pages = 8*32;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (at91sam7_info->cidr_arch == 0x71 ) {
|
||||||
|
at91sam7_info->num_nvmbits = 2;
|
||||||
|
at91sam7_info->nvmbits = (status>>8)&0x03;
|
||||||
|
bank->base = 0x100000;
|
||||||
|
bank->bus_width = 4;
|
||||||
|
if (bank->size==0x40000) /* AT91SAM7XC256 */
|
||||||
|
{
|
||||||
|
at91sam7_info->num_lockbits = 16;
|
||||||
|
at91sam7_info->pagesize = 256;
|
||||||
|
at91sam7_info->pages_in_lockregion = 64;
|
||||||
|
at91sam7_info->num_pages = 16*64;
|
||||||
|
}
|
||||||
|
if (bank->size==0x20000) /* AT91SAM7XC128 */
|
||||||
|
{
|
||||||
|
at91sam7_info->num_lockbits = 8;
|
||||||
|
at91sam7_info->pagesize = 256;
|
||||||
|
at91sam7_info->pages_in_lockregion = 64;
|
||||||
|
at91sam7_info->num_pages = 8*64;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (at91sam7_info->cidr_arch == 0x75 ) {
|
||||||
|
at91sam7_info->num_nvmbits = 3;
|
||||||
|
at91sam7_info->nvmbits = (status>>8)&0x07;
|
||||||
|
bank->base = 0x100000;
|
||||||
|
bank->bus_width = 4;
|
||||||
|
if (bank->size==0x40000) /* AT91SAM7X256 */
|
||||||
|
{
|
||||||
|
at91sam7_info->num_lockbits = 16;
|
||||||
|
at91sam7_info->pagesize = 256;
|
||||||
|
at91sam7_info->pages_in_lockregion = 64;
|
||||||
|
at91sam7_info->num_pages = 16*64;
|
||||||
|
}
|
||||||
|
if (bank->size==0x20000) /* AT91SAM7X128 */
|
||||||
|
{
|
||||||
|
at91sam7_info->num_lockbits = 8;
|
||||||
|
at91sam7_info->pagesize = 256;
|
||||||
|
at91sam7_info->pages_in_lockregion = 64;
|
||||||
|
at91sam7_info->num_pages = 8*64;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (at91sam7_info->cidr_arch != 0x70 )
|
||||||
|
{
|
||||||
|
WARNING("at91sam7 flash only tested for AT91SAM7Sxx series");
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int at91sam7_erase_check(struct flash_bank_s *bank)
|
||||||
|
{
|
||||||
|
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||||
|
target_t *target = at91sam7_info->target;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!at91sam7_info->working_area_size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int at91sam7_protect_check(struct flash_bank_s *bank)
|
||||||
|
{
|
||||||
|
u32 status;
|
||||||
|
|
||||||
|
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||||
|
target_t *target = at91sam7_info->target;
|
||||||
|
|
||||||
|
if (at91sam7_info->cidr == 0)
|
||||||
|
{
|
||||||
|
at91sam7_read_part_info(bank);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (at91sam7_info->cidr == 0)
|
||||||
|
{
|
||||||
|
WARNING("Cannot identify target as an AT91SAM");
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = at91sam7_get_flash_status(bank);
|
||||||
|
at91sam7_info->lockbits = status>>16;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int at91sam7_register_commands(struct command_context_s *cmd_ctx)
|
||||||
|
{
|
||||||
|
command_t *at91sam7_cmd = register_command(cmd_ctx, NULL, "cfi", NULL, COMMAND_ANY, NULL);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||||
|
{
|
||||||
|
at91sam7_flash_bank_t *at91sam7_info;
|
||||||
|
|
||||||
|
if (argc < 6)
|
||||||
|
{
|
||||||
|
WARNING("incomplete flash_bank at91sam7 configuration");
|
||||||
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
at91sam7_info = malloc(sizeof(at91sam7_flash_bank_t));
|
||||||
|
bank->driver_priv = at91sam7_info;
|
||||||
|
|
||||||
|
at91sam7_info->target = get_target_by_num(strtoul(args[5], NULL, 0));
|
||||||
|
if (!at91sam7_info->target)
|
||||||
|
{
|
||||||
|
ERROR("no target '%i' configured", args[5]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* part wasn't probed for info yet */
|
||||||
|
at91sam7_info->cidr = 0;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int at91sam7_erase(struct flash_bank_s *bank, int first, int last)
|
||||||
|
{
|
||||||
|
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||||
|
|
||||||
|
if (at91sam7_info->target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (at91sam7_info->cidr == 0)
|
||||||
|
{
|
||||||
|
at91sam7_read_part_info(bank);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (at91sam7_info->cidr == 0)
|
||||||
|
{
|
||||||
|
WARNING("Cannot identify target as an AT91SAM");
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((first < 0) || (last < first) || (last >= at91sam7_info->num_lockbits))
|
||||||
|
{
|
||||||
|
return ERROR_FLASH_SECTOR_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((first == 0) && (last == (at91sam7_info->num_lockbits-1)))
|
||||||
|
{
|
||||||
|
return at91sam7_flash_command(bank, EA, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
WARNING("Can only erase the whole flash area, pages are autoerased on write");
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||||
|
{
|
||||||
|
u32 cmd, pagen, status;
|
||||||
|
int lockregion;
|
||||||
|
|
||||||
|
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||||
|
target_t *target = at91sam7_info->target;
|
||||||
|
|
||||||
|
if (at91sam7_info->target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((first < 0) || (last < first) || (last >= at91sam7_info->num_lockbits))
|
||||||
|
{
|
||||||
|
return ERROR_FLASH_SECTOR_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (at91sam7_info->cidr == 0)
|
||||||
|
{
|
||||||
|
at91sam7_read_part_info(bank);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (at91sam7_info->cidr == 0)
|
||||||
|
{
|
||||||
|
WARNING("Cannot identify target as an AT91SAM");
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure the flash controller timing */
|
||||||
|
at91sam7_set_flash_mode(bank,1);
|
||||||
|
|
||||||
|
for (lockregion=first;lockregion<=last;lockregion++)
|
||||||
|
{
|
||||||
|
pagen = lockregion*at91sam7_info->pages_in_lockregion;
|
||||||
|
if (set)
|
||||||
|
cmd = SLB;
|
||||||
|
else
|
||||||
|
cmd = CLB;
|
||||||
|
if (at91sam7_flash_command(bank, cmd, pagen) != ERROR_OK)
|
||||||
|
{
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status = at91sam7_get_flash_status(bank);
|
||||||
|
at91sam7_info->lockbits = status>>16;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int at91sam7_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||||
|
{
|
||||||
|
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||||
|
target_t *target = at91sam7_info->target;
|
||||||
|
u32 dst_min_alignment, wcount, bytes_remaining = count;
|
||||||
|
u32 first_page, last_page, pagen, buffer_pos;
|
||||||
|
u32 fcr;
|
||||||
|
|
||||||
|
if (at91sam7_info->target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (at91sam7_info->cidr == 0)
|
||||||
|
{
|
||||||
|
at91sam7_read_part_info(bank);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (at91sam7_info->cidr == 0)
|
||||||
|
{
|
||||||
|
WARNING("Cannot identify target as an AT91SAM");
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset + count > bank->size)
|
||||||
|
return ERROR_FLASH_DST_OUT_OF_BANK;
|
||||||
|
|
||||||
|
dst_min_alignment = at91sam7_info->pagesize;
|
||||||
|
|
||||||
|
if (offset % dst_min_alignment)
|
||||||
|
{
|
||||||
|
WARNING("offset 0x%x breaks required alignment 0x%x", offset, dst_min_alignment);
|
||||||
|
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset + count > bank->size)
|
||||||
|
return ERROR_FLASH_DST_OUT_OF_BANK;
|
||||||
|
|
||||||
|
if (at91sam7_info->cidr_arch == 0)
|
||||||
|
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||||
|
|
||||||
|
first_page = offset/dst_min_alignment;
|
||||||
|
last_page = CEIL(offset + count, dst_min_alignment);
|
||||||
|
|
||||||
|
DEBUG("first_page: %i, last_page: %i, count %i", first_page, last_page, count);
|
||||||
|
|
||||||
|
/* Configure the flash controller timing */
|
||||||
|
at91sam7_set_flash_mode(bank,2);
|
||||||
|
|
||||||
|
for (pagen=first_page; pagen<last_page; pagen++) {
|
||||||
|
if (bytes_remaining<dst_min_alignment)
|
||||||
|
count = bytes_remaining;
|
||||||
|
else
|
||||||
|
count = dst_min_alignment;
|
||||||
|
bytes_remaining -= count;
|
||||||
|
|
||||||
|
/* Write one block to the PageWriteBuffer */
|
||||||
|
buffer_pos = (pagen-first_page)*dst_min_alignment;
|
||||||
|
wcount = CEIL(count,4);
|
||||||
|
target->type->write_memory(target, bank->base, 4, wcount, buffer+buffer_pos);
|
||||||
|
|
||||||
|
/* Send Write Page command to Flash Controller */
|
||||||
|
if (at91sam7_flash_command(bank, WP, pagen) != ERROR_OK)
|
||||||
|
{
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
DEBUG("Flash command: 0x%x, pagenumber:", fcr, pagen);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int at91sam7_probe(struct flash_bank_s *bank)
|
||||||
|
{
|
||||||
|
/* we can't probe on an at91sam7
|
||||||
|
* if this is an at91sam7, it has the configured flash
|
||||||
|
*/
|
||||||
|
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||||
|
|
||||||
|
if (at91sam7_info->cidr == 0)
|
||||||
|
{
|
||||||
|
at91sam7_read_part_info(bank);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (at91sam7_info->cidr == 0)
|
||||||
|
{
|
||||||
|
WARNING("Cannot identify target as an AT91SAM");
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||||
|
{
|
||||||
|
int printed;
|
||||||
|
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||||
|
|
||||||
|
if (at91sam7_info->cidr == 0)
|
||||||
|
{
|
||||||
|
at91sam7_read_part_info(bank);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (at91sam7_info->cidr == 0)
|
||||||
|
{
|
||||||
|
printed = snprintf(buf, buf_size, "Cannot identify target as an AT91SAM\n");
|
||||||
|
buf += printed;
|
||||||
|
buf_size -= printed;
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
printed = snprintf(buf, buf_size, "\nat91sam7 information:\n");
|
||||||
|
buf += printed;
|
||||||
|
buf_size -= printed;
|
||||||
|
|
||||||
|
printed = snprintf(buf, buf_size, "cidr: 0x%8.8x, arch: 0x%4.4x, eproc: %s, version:0x%3.3x, flashsize: 0x%8.8x\n", at91sam7_info->cidr, at91sam7_info->cidr_arch, EPROC[at91sam7_info->cidr_eproc], at91sam7_info->cidr_version, bank->size);
|
||||||
|
buf += printed;
|
||||||
|
buf_size -= printed;
|
||||||
|
|
||||||
|
printed = snprintf(buf, buf_size, "main clock(estimated): %ikHz \n", at91sam7_info->mainf*2);
|
||||||
|
buf += printed;
|
||||||
|
buf_size -= printed;
|
||||||
|
|
||||||
|
if (at91sam7_info->num_lockbits>0) {
|
||||||
|
printed = snprintf(buf, buf_size, "pagesize: %i, lockbits: %i 0x%4.4x, pages in lock region: %i \n", at91sam7_info->pagesize, at91sam7_info->num_lockbits, at91sam7_info->lockbits,at91sam7_info->num_pages/at91sam7_info->num_lockbits);
|
||||||
|
buf += printed;
|
||||||
|
buf_size -= printed;
|
||||||
|
}
|
||||||
|
|
||||||
|
printed = snprintf(buf, buf_size, "securitybit: %i, nvmbits: 0x%1.1x\n", at91sam7_info->securitybit, at91sam7_info->nvmbits);
|
||||||
|
buf += printed;
|
||||||
|
buf_size -= printed;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2006 by Magnus Lundin *
|
||||||
|
* lundinªmlu.mine.nu *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef AT91SAM7_H
|
||||||
|
#define AT91SAM7_H
|
||||||
|
|
||||||
|
#include "flash.h"
|
||||||
|
#include "target.h"
|
||||||
|
|
||||||
|
typedef struct at91sam7_flash_bank_s
|
||||||
|
{
|
||||||
|
struct target_s *target;
|
||||||
|
u32 working_area;
|
||||||
|
u32 working_area_size;
|
||||||
|
|
||||||
|
/* chip id register */
|
||||||
|
u32 cidr;
|
||||||
|
u16 cidr_ext;
|
||||||
|
u16 cidr_nvptyp;
|
||||||
|
u16 cidr_arch;
|
||||||
|
u16 cidr_sramsiz;
|
||||||
|
u16 cidr_nvpsiz;
|
||||||
|
u16 cidr_nvpsiz2;
|
||||||
|
u16 cidr_eproc;
|
||||||
|
u16 cidr_version;
|
||||||
|
|
||||||
|
/* flash geometry */
|
||||||
|
u16 num_pages;
|
||||||
|
u16 pagesize;
|
||||||
|
u16 pages_in_lockregion;
|
||||||
|
u8 num_erase_regions;
|
||||||
|
u32 *erase_region_info;
|
||||||
|
|
||||||
|
/* nv memory bits */
|
||||||
|
u16 num_lockbits;
|
||||||
|
u16 lockbits;
|
||||||
|
u16 num_nvmbits;
|
||||||
|
u16 nvmbits;
|
||||||
|
u8 securitybit;
|
||||||
|
u8 flashmode; /* 0: not init, 1: fmcn for nvbits (1uS), 2: fmcn for flash (1.5uS) */
|
||||||
|
|
||||||
|
/* main clock status */
|
||||||
|
u8 mainrdy;
|
||||||
|
u16 mainf;
|
||||||
|
u16 usec_clocks;
|
||||||
|
|
||||||
|
} at91sam7_flash_bank_t;
|
||||||
|
|
||||||
|
/* AT91SAM7 control registers */
|
||||||
|
#define DBGU_CIDR 0xFFFFF240
|
||||||
|
#define CKGR_MCFR 0xFFFFFC24
|
||||||
|
#define MC_FMR 0xFFFFFF60
|
||||||
|
#define MC_FCR 0xFFFFFF64
|
||||||
|
#define MC_FSR 0xFFFFFF68
|
||||||
|
|
||||||
|
/* Flash Controller Commands */
|
||||||
|
#define WP 0x01
|
||||||
|
#define SLB 0x02
|
||||||
|
#define WPL 0x03
|
||||||
|
#define CLB 0x04
|
||||||
|
#define EA 0x08
|
||||||
|
#define SGPB 0x0B
|
||||||
|
#define CGPB 0x0D
|
||||||
|
#define SSB 0x0F
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* AT91SAM7_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,86 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef CFI_H
|
||||||
|
#define CFI_H
|
||||||
|
|
||||||
|
#include "flash.h"
|
||||||
|
#include "target.h"
|
||||||
|
|
||||||
|
typedef struct cfi_flash_bank_s
|
||||||
|
{
|
||||||
|
struct target_s *target;
|
||||||
|
working_area_t *write_algorithm;
|
||||||
|
working_area_t *erase_check_algorithm;
|
||||||
|
|
||||||
|
char qry[3];
|
||||||
|
|
||||||
|
/* identification string */
|
||||||
|
u16 pri_id;
|
||||||
|
u16 pri_addr;
|
||||||
|
u16 alt_id;
|
||||||
|
u16 alt_addr;
|
||||||
|
|
||||||
|
/* device-system interface */
|
||||||
|
u8 vcc_min;
|
||||||
|
u8 vcc_max;
|
||||||
|
u8 vpp_min;
|
||||||
|
u8 vpp_max;
|
||||||
|
u8 word_write_timeout_typ;
|
||||||
|
u8 buf_write_timeout_typ;
|
||||||
|
u8 block_erase_timeout_typ;
|
||||||
|
u8 chip_erase_timeout_typ;
|
||||||
|
u8 word_write_timeout_max;
|
||||||
|
u8 buf_write_timeout_max;
|
||||||
|
u8 block_erase_timeout_max;
|
||||||
|
u8 chip_erase_timeout_max;
|
||||||
|
|
||||||
|
/* flash geometry */
|
||||||
|
u8 dev_size;
|
||||||
|
u16 interface_desc;
|
||||||
|
u16 max_buf_write_size;
|
||||||
|
u8 num_erase_regions;
|
||||||
|
u32 *erase_region_info;
|
||||||
|
|
||||||
|
void *pri_ext;
|
||||||
|
void *alt_ext;
|
||||||
|
} cfi_flash_bank_t;
|
||||||
|
|
||||||
|
/* Intel primary extended query table
|
||||||
|
* as defined for the Advanced+ Boot Block Flash Memory (C3)
|
||||||
|
* and used by the linux kernel cfi driver (as of 2.6.14)
|
||||||
|
*/
|
||||||
|
typedef struct cfi_intel_pri_ext_s
|
||||||
|
{
|
||||||
|
char pri[3];
|
||||||
|
u8 major_version;
|
||||||
|
u8 minor_version;
|
||||||
|
u32 feature_support;
|
||||||
|
u8 suspend_cmd_support;
|
||||||
|
u16 blk_status_reg_mask;
|
||||||
|
u8 vcc_optimal;
|
||||||
|
u8 vpp_optimal;
|
||||||
|
u8 num_protection_fields;
|
||||||
|
u16 prot_reg_addr;
|
||||||
|
u8 fact_prot_reg_size;
|
||||||
|
u8 user_prot_reg_size;
|
||||||
|
u8 extra[0];
|
||||||
|
} cfi_intel_pri_ext_t;
|
||||||
|
|
||||||
|
#endif /* CFI_H */
|
|
@ -0,0 +1,556 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "flash.h"
|
||||||
|
#include "command.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "target.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/* command handlers */
|
||||||
|
int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int handle_flash_banks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int handle_flash_protect_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
|
||||||
|
/* flash drivers
|
||||||
|
*/
|
||||||
|
extern flash_driver_t lpc2000_flash;
|
||||||
|
extern flash_driver_t cfi_flash;
|
||||||
|
extern flash_driver_t at91sam7_flash;
|
||||||
|
extern flash_driver_t str7x_flash;
|
||||||
|
|
||||||
|
flash_driver_t *flash_drivers[] =
|
||||||
|
{
|
||||||
|
&lpc2000_flash,
|
||||||
|
&cfi_flash,
|
||||||
|
&at91sam7_flash,
|
||||||
|
&str7x_flash,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
flash_bank_t *flash_banks;
|
||||||
|
static command_t *flash_cmd;
|
||||||
|
|
||||||
|
int flash_register_commands(struct command_context_s *cmd_ctx)
|
||||||
|
{
|
||||||
|
flash_cmd = register_command(cmd_ctx, NULL, "flash", NULL, COMMAND_ANY, NULL);
|
||||||
|
|
||||||
|
register_command(cmd_ctx, flash_cmd, "bank", handle_flash_bank_command, COMMAND_CONFIG, NULL);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int flash_init(struct command_context_s *cmd_ctx)
|
||||||
|
{
|
||||||
|
if (flash_banks)
|
||||||
|
{
|
||||||
|
register_command(cmd_ctx, flash_cmd, "banks", handle_flash_banks_command, COMMAND_EXEC,
|
||||||
|
"list configured flash banks ");
|
||||||
|
register_command(cmd_ctx, flash_cmd, "info", handle_flash_info_command, COMMAND_EXEC,
|
||||||
|
"print info about flash bank <num>");
|
||||||
|
register_command(cmd_ctx, flash_cmd, "probe", handle_flash_probe_command, COMMAND_EXEC,
|
||||||
|
"identify flash bank <num>");
|
||||||
|
register_command(cmd_ctx, flash_cmd, "erase_check", handle_flash_erase_check_command, COMMAND_EXEC,
|
||||||
|
"check erase state of sectors in flash bank <num>");
|
||||||
|
register_command(cmd_ctx, flash_cmd, "protect_check", handle_flash_protect_check_command, COMMAND_EXEC,
|
||||||
|
"check protection state of sectors in flash bank <num>");
|
||||||
|
register_command(cmd_ctx, flash_cmd, "erase", handle_flash_erase_command, COMMAND_EXEC,
|
||||||
|
"erase sectors at <bank> <first> <last>");
|
||||||
|
register_command(cmd_ctx, flash_cmd, "write", handle_flash_write_command, COMMAND_EXEC,
|
||||||
|
"write binary <bank> <file> <offset>");
|
||||||
|
register_command(cmd_ctx, flash_cmd, "protect", handle_flash_protect_command, COMMAND_EXEC,
|
||||||
|
"set protection of sectors at <bank> <first> <last> <on|off>");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_bank_t *get_flash_bank_by_num(int num)
|
||||||
|
{
|
||||||
|
flash_bank_t *p;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (p = flash_banks; p; p = p->next)
|
||||||
|
{
|
||||||
|
if (i++ == num)
|
||||||
|
{
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flash_bank <driver> <base> <size> <chip_width> <bus_width> [driver_options ...]
|
||||||
|
*/
|
||||||
|
int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int found = 0;
|
||||||
|
|
||||||
|
if (argc < 5)
|
||||||
|
{
|
||||||
|
WARNING("incomplete flash_bank configuration");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; flash_drivers[i]; i++)
|
||||||
|
{
|
||||||
|
if (strcmp(args[0], flash_drivers[i]->name) == 0)
|
||||||
|
{
|
||||||
|
flash_bank_t *p, *c;
|
||||||
|
|
||||||
|
/* register flash specific commands */
|
||||||
|
if (flash_drivers[i]->register_commands(cmd_ctx) != ERROR_OK)
|
||||||
|
{
|
||||||
|
ERROR("couldn't register '%s' commands", args[0]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
c = malloc(sizeof(flash_bank_t));
|
||||||
|
c->driver = flash_drivers[i];
|
||||||
|
c->driver_priv = NULL;
|
||||||
|
c->base = strtoul(args[1], NULL, 0);
|
||||||
|
c->size = strtoul(args[2], NULL, 0);
|
||||||
|
c->chip_width = strtoul(args[3], NULL, 0);
|
||||||
|
c->bus_width = strtoul(args[4], NULL, 0);
|
||||||
|
c->next = NULL;
|
||||||
|
|
||||||
|
if (flash_drivers[i]->flash_bank_command(cmd_ctx, cmd, args, argc, c) != ERROR_OK)
|
||||||
|
{
|
||||||
|
ERROR("'%s' driver rejected flash bank at 0x%8.8x", args[0], c->base);
|
||||||
|
free(c);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* put flash bank in linked list */
|
||||||
|
if (flash_banks)
|
||||||
|
{
|
||||||
|
/* find last flash bank */
|
||||||
|
for (p = flash_banks; p && p->next; p = p->next);
|
||||||
|
if (p)
|
||||||
|
p->next = c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
flash_banks = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no matching flash driver found */
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
ERROR("flash driver '%s' not found", args[0]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle_flash_banks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
flash_bank_t *p;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (!flash_banks)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "no flash banks configured");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (p = flash_banks; p; p = p->next)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "#%i: %s at 0x%8.8x, size 0x%8.8x, buswidth %i, chipwidth %i",
|
||||||
|
i++, p->driver->name, p->base, p->size, p->bus_width, p->chip_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
flash_bank_t *p;
|
||||||
|
int i = 0;
|
||||||
|
int j = 0;
|
||||||
|
|
||||||
|
if (argc != 1)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "usage: flash info <num>");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (p = flash_banks; p; p = p->next)
|
||||||
|
{
|
||||||
|
if (i++ == strtoul(args[0], NULL, 0))
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
|
||||||
|
command_print(cmd_ctx, "#%i: %s at 0x%8.8x, size 0x%8.8x, buswidth %i, chipwidth %i",
|
||||||
|
i, p->driver->name, p->base, p->size, p->bus_width, p->chip_width);
|
||||||
|
for (j = 0; j < p->num_sectors; j++)
|
||||||
|
{
|
||||||
|
char *erase_state, *protect_state;
|
||||||
|
|
||||||
|
if (p->sectors[j].is_erased == 0)
|
||||||
|
erase_state = "not erased";
|
||||||
|
else if (p->sectors[j].is_erased == 1)
|
||||||
|
erase_state = "erased";
|
||||||
|
else
|
||||||
|
erase_state = "erase state unknown";
|
||||||
|
|
||||||
|
if (p->sectors[j].is_protected == 0)
|
||||||
|
protect_state = "not protected";
|
||||||
|
else if (p->sectors[j].is_protected == 1)
|
||||||
|
protect_state = "protected";
|
||||||
|
else
|
||||||
|
protect_state = "protection state unknown";
|
||||||
|
|
||||||
|
command_print(cmd_ctx, "\t#%i: 0x%8.8x (0x%xkB) %s, %s",
|
||||||
|
j, p->sectors[j].offset, p->sectors[j].size,
|
||||||
|
erase_state, protect_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
p->driver->info(p, buf, 1024);
|
||||||
|
command_print(cmd_ctx, "%s", buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
flash_bank_t *p;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if (argc != 1)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "usage: flash probe <num>");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
if ((retval = p->driver->probe(p)) == ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "flash '%s' found at 0x%8.8x", p->driver->name, p->base);
|
||||||
|
}
|
||||||
|
else if (retval == ERROR_FLASH_BANK_INVALID)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "probing failed for flash bank '#%s' at 0x%8.8x",
|
||||||
|
args[0], p->base);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "unknown error when probing flash bank '#%s' at 0x%8.8x",
|
||||||
|
args[0], p->base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
flash_bank_t *p;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if (argc != 1)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "usage: flash erase_check <num>");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
if ((retval = p->driver->erase_check(p)) == ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "successfully checked erase state", p->driver->name, p->base);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "unknown error when checking erase state of flash bank #%s at 0x%8.8x",
|
||||||
|
args[0], p->base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
flash_bank_t *p;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if (argc != 1)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "usage: flash protect_check <num>");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
if ((retval = p->driver->protect_check(p)) == ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "successfully checked protect state");
|
||||||
|
}
|
||||||
|
else if (retval == ERROR_FLASH_OPERATION_FAILED)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "checking protection state failed (possibly unsupported) by flash #%s at 0x%8.8x", args[0], p->base);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "unknown error when checking protection state of flash bank '#%s' at 0x%8.8x", args[0], p->base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
if (argc > 2)
|
||||||
|
{
|
||||||
|
int first = strtoul(args[1], NULL, 0);
|
||||||
|
int last = strtoul(args[2], NULL, 0);
|
||||||
|
int retval;
|
||||||
|
flash_bank_t *p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||||
|
if (!p)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((retval = p->driver->erase(p, first, last)) != ERROR_OK)
|
||||||
|
{
|
||||||
|
switch (retval)
|
||||||
|
{
|
||||||
|
case ERROR_TARGET_NOT_HALTED:
|
||||||
|
command_print(cmd_ctx, "can't work with this flash while target is running");
|
||||||
|
break;
|
||||||
|
case ERROR_INVALID_ARGUMENTS:
|
||||||
|
command_print(cmd_ctx, "usage: flash_erase <bank> <first> <last>");
|
||||||
|
break;
|
||||||
|
case ERROR_FLASH_BANK_INVALID:
|
||||||
|
command_print(cmd_ctx, "no '%s' flash found at 0x%8.8x", p->driver->name, p->base);
|
||||||
|
break;
|
||||||
|
case ERROR_FLASH_OPERATION_FAILED:
|
||||||
|
command_print(cmd_ctx, "flash erase error");
|
||||||
|
break;
|
||||||
|
case ERROR_FLASH_SECTOR_INVALID:
|
||||||
|
command_print(cmd_ctx, "sector number(s) invalid");
|
||||||
|
break;
|
||||||
|
case ERROR_OK:
|
||||||
|
command_print(cmd_ctx, "erased flash sectors %i to %i", first, last);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
command_print(cmd_ctx, "unknown error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "usage: flash erase <bank> <first> <last>");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle_flash_protect_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
if (argc > 3)
|
||||||
|
{
|
||||||
|
int first = strtoul(args[1], NULL, 0);
|
||||||
|
int last = strtoul(args[2], NULL, 0);
|
||||||
|
int set;
|
||||||
|
int retval;
|
||||||
|
flash_bank_t *p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||||
|
if (!p)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(args[3], "on") == 0)
|
||||||
|
set = 1;
|
||||||
|
else if (strcmp(args[3], "off") == 0)
|
||||||
|
set = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "usage: flash protect <bank> <first> <last> <on|off>");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((retval = p->driver->protect(p, set, first, last)) != ERROR_OK)
|
||||||
|
{
|
||||||
|
switch (retval)
|
||||||
|
{
|
||||||
|
case ERROR_TARGET_NOT_HALTED:
|
||||||
|
command_print(cmd_ctx, "can't work with this flash while target is running");
|
||||||
|
break;
|
||||||
|
case ERROR_INVALID_ARGUMENTS:
|
||||||
|
command_print(cmd_ctx, "usage: flash protect <bank> <first> <last> <on|off>");
|
||||||
|
break;
|
||||||
|
case ERROR_FLASH_BANK_INVALID:
|
||||||
|
command_print(cmd_ctx, "no '%s' flash found at 0x%8.8x", p->driver->name, p->base);
|
||||||
|
break;
|
||||||
|
case ERROR_FLASH_OPERATION_FAILED:
|
||||||
|
command_print(cmd_ctx, "flash program error");
|
||||||
|
break;
|
||||||
|
case ERROR_FLASH_SECTOR_INVALID:
|
||||||
|
command_print(cmd_ctx, "sector number(s) invalid");
|
||||||
|
break;
|
||||||
|
case ERROR_OK:
|
||||||
|
command_print(cmd_ctx, "protection of flash sectors %i to %i turned %s", first, last, args[3]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
command_print(cmd_ctx, "unknown error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "usage: flash protect <bank> <first> <last> <on|off>");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
FILE *binary;
|
||||||
|
u32 offset;
|
||||||
|
struct stat binary_stat;
|
||||||
|
u32 binary_size;
|
||||||
|
u8 *buffer;
|
||||||
|
u32 buf_cnt;
|
||||||
|
int retval;
|
||||||
|
flash_bank_t *p;
|
||||||
|
|
||||||
|
if (argc < 3)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "usage: flash write <bank> <file> <offset>");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = strtoul(args[2], NULL, 0);
|
||||||
|
p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||||
|
if (!p)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat(args[1], &binary_stat) == -1)
|
||||||
|
{
|
||||||
|
ERROR("couldn't stat() %s: %s", args[1], strerror(errno));
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_ISDIR(binary_stat.st_mode))
|
||||||
|
{
|
||||||
|
ERROR("%s is a directory", args[1]);
|
||||||
|
command_print(cmd_ctx,"%s is a directory", args[1]);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (binary_stat.st_size == 0){
|
||||||
|
ERROR("Empty file %s", args[1]);
|
||||||
|
command_print(cmd_ctx,"Empty file %s", args[1]);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(binary = fopen(args[1], "r")))
|
||||||
|
{
|
||||||
|
ERROR("couldn't open %s: %s", args[1], strerror(errno));
|
||||||
|
command_print(cmd_ctx, "couldn't open %s", args[1]);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
binary_size = binary_stat.st_size;
|
||||||
|
buffer = malloc(binary_size);
|
||||||
|
buf_cnt = fread(buffer, 1, binary_size, binary);
|
||||||
|
|
||||||
|
if ((retval = p->driver->write(p, buffer, offset, buf_cnt)) != ERROR_OK)
|
||||||
|
{
|
||||||
|
switch (retval)
|
||||||
|
{
|
||||||
|
case ERROR_TARGET_NOT_HALTED:
|
||||||
|
command_print(cmd_ctx, "can't work with this flash while target is running");
|
||||||
|
break;
|
||||||
|
case ERROR_INVALID_ARGUMENTS:
|
||||||
|
command_print(cmd_ctx, "usage: flash write <bank> <file> <offset>");
|
||||||
|
break;
|
||||||
|
case ERROR_FLASH_BANK_INVALID:
|
||||||
|
command_print(cmd_ctx, "no '%s' flash found at 0x%8.8x", p->driver->name, p->base);
|
||||||
|
break;
|
||||||
|
case ERROR_FLASH_OPERATION_FAILED:
|
||||||
|
command_print(cmd_ctx, "flash program error");
|
||||||
|
break;
|
||||||
|
case ERROR_FLASH_DST_BREAKS_ALIGNMENT:
|
||||||
|
command_print(cmd_ctx, "offset breaks required alignment");
|
||||||
|
break;
|
||||||
|
case ERROR_FLASH_DST_OUT_OF_BANK:
|
||||||
|
command_print(cmd_ctx, "destination is out of flash bank (offset and/or file too large)");
|
||||||
|
break;
|
||||||
|
case ERROR_FLASH_SECTOR_NOT_ERASED:
|
||||||
|
command_print(cmd_ctx, "destination sector(s) not erased");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
command_print(cmd_ctx, "unknown error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(buffer);
|
||||||
|
fclose(binary);
|
||||||
|
|
||||||
|
command_print(cmd_ctx, "wrote file %s to flash bank %i at offset 0x%8.8x", args[1], strtoul(args[0], NULL, 0), strtoul(args[2], NULL, 0));
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef FLASH_H
|
||||||
|
#define FLASH_H
|
||||||
|
|
||||||
|
#include "target.h"
|
||||||
|
|
||||||
|
typedef struct flash_sector_s
|
||||||
|
{
|
||||||
|
u32 offset;
|
||||||
|
u32 size;
|
||||||
|
int is_erased;
|
||||||
|
int is_protected;
|
||||||
|
} flash_sector_t;
|
||||||
|
|
||||||
|
struct flash_bank_s;
|
||||||
|
|
||||||
|
typedef struct flash_driver_s
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
int (*register_commands)(struct command_context_s *cmd_ctx);
|
||||||
|
int (*flash_bank_command)(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||||
|
int (*erase)(struct flash_bank_s *bank, int first, int last);
|
||||||
|
int (*protect)(struct flash_bank_s *bank, int set, int first, int last);
|
||||||
|
int (*write)(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
|
||||||
|
int (*probe)(struct flash_bank_s *bank);
|
||||||
|
int (*erase_check)(struct flash_bank_s *bank);
|
||||||
|
int (*protect_check)(struct flash_bank_s *bank);
|
||||||
|
int (*info)(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||||
|
} flash_driver_t;
|
||||||
|
|
||||||
|
typedef struct flash_bank_s
|
||||||
|
{
|
||||||
|
flash_driver_t *driver;
|
||||||
|
void *driver_priv;
|
||||||
|
u32 base;
|
||||||
|
u32 size;
|
||||||
|
int chip_width;
|
||||||
|
int bus_width;
|
||||||
|
int num_sectors;
|
||||||
|
flash_sector_t *sectors;
|
||||||
|
struct flash_bank_s *next;
|
||||||
|
} flash_bank_t;
|
||||||
|
|
||||||
|
extern int flash_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
extern int flash_init(struct command_context_s *cmd_ctx);
|
||||||
|
|
||||||
|
extern flash_bank_t *get_flash_bank_by_num(int num);
|
||||||
|
|
||||||
|
#define ERROR_FLASH_BANK_INVALID (-900)
|
||||||
|
#define ERROR_FLASH_SECTOR_INVALID (-901)
|
||||||
|
#define ERROR_FLASH_OPERATION_FAILED (-902)
|
||||||
|
#define ERROR_FLASH_DST_OUT_OF_BANK (-903)
|
||||||
|
#define ERROR_FLASH_DST_BREAKS_ALIGNMENT (-904)
|
||||||
|
#define ERROR_FLASH_BUSY (-905)
|
||||||
|
#define ERROR_FLASH_SECTOR_NOT_ERASED (-906)
|
||||||
|
#define ERROR_FLASH_BANK_NOT_PROBED (-907)
|
||||||
|
|
||||||
|
#endif /* FLASH_H */
|
|
@ -0,0 +1,685 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "lpc2000.h"
|
||||||
|
|
||||||
|
#include "flash.h"
|
||||||
|
#include "target.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "armv4_5.h"
|
||||||
|
#include "algorithm.h"
|
||||||
|
#include "binarybuffer.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* flash programming support for Philips LPC2xxx devices
|
||||||
|
* currently supported devices:
|
||||||
|
* variant 1 (lpc2000_v1):
|
||||||
|
* - 2104|5|6
|
||||||
|
* - 2114|9
|
||||||
|
* - 2124|9
|
||||||
|
* - 2194
|
||||||
|
* - 2212|4
|
||||||
|
* - 2292|4
|
||||||
|
*
|
||||||
|
* variant 2 (lpc2000_v2):
|
||||||
|
* - 213x
|
||||||
|
* - 214x
|
||||||
|
*/
|
||||||
|
|
||||||
|
int lpc2000_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||||
|
int lpc2000_erase(struct flash_bank_s *bank, int first, int last);
|
||||||
|
int lpc2000_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||||
|
int lpc2000_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
|
||||||
|
int lpc2000_probe(struct flash_bank_s *bank);
|
||||||
|
int lpc2000_erase_check(struct flash_bank_s *bank);
|
||||||
|
int lpc2000_protect_check(struct flash_bank_s *bank);
|
||||||
|
int lpc2000_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||||
|
|
||||||
|
int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
|
||||||
|
flash_driver_t lpc2000_flash =
|
||||||
|
{
|
||||||
|
.name = "lpc2000",
|
||||||
|
.register_commands = lpc2000_register_commands,
|
||||||
|
.flash_bank_command = lpc2000_flash_bank_command,
|
||||||
|
.erase = lpc2000_erase,
|
||||||
|
.protect = lpc2000_protect,
|
||||||
|
.write = lpc2000_write,
|
||||||
|
.probe = lpc2000_probe,
|
||||||
|
.erase_check = lpc2000_erase_check,
|
||||||
|
.protect_check = lpc2000_protect_check,
|
||||||
|
.info = lpc2000_info
|
||||||
|
};
|
||||||
|
|
||||||
|
int lpc2000_register_commands(struct command_context_s *cmd_ctx)
|
||||||
|
{
|
||||||
|
command_t *lpc2000_cmd = register_command(cmd_ctx, NULL, "lpc2000", NULL, COMMAND_ANY, NULL);
|
||||||
|
|
||||||
|
register_command(cmd_ctx, lpc2000_cmd, "part_id", lpc2000_handle_part_id_command, COMMAND_EXEC,
|
||||||
|
"print part id of lpc2000 flash bank <num>");
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lpc2000_build_sector_list(struct flash_bank_s *bank)
|
||||||
|
{
|
||||||
|
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
|
||||||
|
|
||||||
|
if (lpc2000_info->variant == 1)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
u32 offset = 0;
|
||||||
|
|
||||||
|
/* variant 1 has different layout for 128kb and 256kb flashes */
|
||||||
|
if (bank->size == 128 * 1024)
|
||||||
|
{
|
||||||
|
bank->num_sectors = 16;
|
||||||
|
bank->sectors = malloc(sizeof(flash_sector_t) * 16);
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
bank->sectors[i].offset = offset;
|
||||||
|
bank->sectors[i].size = 8 * 1024;
|
||||||
|
offset += bank->sectors[i].size;
|
||||||
|
bank->sectors[i].is_erased = -1;
|
||||||
|
bank->sectors[i].is_protected = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (bank->size == 256 * 1024)
|
||||||
|
{
|
||||||
|
bank->num_sectors = 18;
|
||||||
|
bank->sectors = malloc(sizeof(flash_sector_t) * 18);
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
bank->sectors[i].offset = offset;
|
||||||
|
bank->sectors[i].size = 8 * 1024;
|
||||||
|
offset += bank->sectors[i].size;
|
||||||
|
bank->sectors[i].is_erased = -1;
|
||||||
|
bank->sectors[i].is_protected = 1;
|
||||||
|
}
|
||||||
|
for (i = 8; i < 10; i++)
|
||||||
|
{
|
||||||
|
bank->sectors[i].offset = offset;
|
||||||
|
bank->sectors[i].size = 64 * 1024;
|
||||||
|
offset += bank->sectors[i].size;
|
||||||
|
bank->sectors[i].is_erased = -1;
|
||||||
|
bank->sectors[i].is_protected = 1;
|
||||||
|
}
|
||||||
|
for (i = 10; i < 18; i++)
|
||||||
|
{
|
||||||
|
bank->sectors[i].offset = offset;
|
||||||
|
bank->sectors[i].size = 8 * 1024;
|
||||||
|
offset += bank->sectors[i].size;
|
||||||
|
bank->sectors[i].is_erased = -1;
|
||||||
|
bank->sectors[i].is_protected = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR("BUG: unknown bank->size encountered");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (lpc2000_info->variant == 2)
|
||||||
|
{
|
||||||
|
int num_sectors;
|
||||||
|
int i;
|
||||||
|
u32 offset = 0;
|
||||||
|
|
||||||
|
/* variant 2 has a uniform layout, only number of sectors differs */
|
||||||
|
switch (bank->size)
|
||||||
|
{
|
||||||
|
case 32 * 1024:
|
||||||
|
num_sectors = 8;
|
||||||
|
break;
|
||||||
|
case 64 * 1024:
|
||||||
|
num_sectors = 9;
|
||||||
|
break;
|
||||||
|
case 128 * 1024:
|
||||||
|
num_sectors = 11;
|
||||||
|
break;
|
||||||
|
case 256 * 1024:
|
||||||
|
num_sectors = 15;
|
||||||
|
break;
|
||||||
|
case 500 * 1024:
|
||||||
|
num_sectors = 27;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("BUG: unknown bank->size encountered");
|
||||||
|
exit(-1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bank->num_sectors = num_sectors;
|
||||||
|
bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
|
||||||
|
|
||||||
|
for (i = 0; i < num_sectors; i++)
|
||||||
|
{
|
||||||
|
if ((i >= 0) && (i < 8))
|
||||||
|
{
|
||||||
|
bank->sectors[i].offset = offset;
|
||||||
|
bank->sectors[i].size = 4 * 1024;
|
||||||
|
offset += bank->sectors[i].size;
|
||||||
|
bank->sectors[i].is_erased = -1;
|
||||||
|
bank->sectors[i].is_protected = 1;
|
||||||
|
}
|
||||||
|
if ((i >= 8) && (i < 22))
|
||||||
|
{
|
||||||
|
bank->sectors[i].offset = offset;
|
||||||
|
bank->sectors[i].size = 32 * 1024;
|
||||||
|
offset += bank->sectors[i].size;
|
||||||
|
bank->sectors[i].is_erased = -1;
|
||||||
|
bank->sectors[i].is_protected = 1;
|
||||||
|
}
|
||||||
|
if ((i >= 22) && (i < 27))
|
||||||
|
{
|
||||||
|
bank->sectors[i].offset = offset;
|
||||||
|
bank->sectors[i].size = 4 * 1024;
|
||||||
|
offset += bank->sectors[i].size;
|
||||||
|
bank->sectors[i].is_erased = -1;
|
||||||
|
bank->sectors[i].is_protected = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR("BUG: unknown lpc2000_info->variant encountered");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* call LPC2000 IAP function
|
||||||
|
* uses 172 bytes working area
|
||||||
|
* 0x0 to 0x7: jump gate (BX to thumb state, b -2 to wait)
|
||||||
|
* 0x8 to 0x1f: command parameter table
|
||||||
|
* 0x20 to 0x2b: command result table
|
||||||
|
* 0x2c to 0xac: stack (only 128b needed)
|
||||||
|
*/
|
||||||
|
int lpc2000_iap_call(flash_bank_t *bank, int code, u32 param_table[5], u32 result_table[2])
|
||||||
|
{
|
||||||
|
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
|
||||||
|
target_t *target = lpc2000_info->target;
|
||||||
|
mem_param_t mem_params[2];
|
||||||
|
reg_param_t reg_params[5];
|
||||||
|
armv4_5_algorithm_t armv4_5_info;
|
||||||
|
u32 status_code;
|
||||||
|
|
||||||
|
/* regrab previously allocated working_area, or allocate a new one */
|
||||||
|
if (!lpc2000_info->iap_working_area)
|
||||||
|
{
|
||||||
|
u8 jump_gate[8];
|
||||||
|
|
||||||
|
/* make sure we have a working area */
|
||||||
|
if (target_alloc_working_area(target, 172, &lpc2000_info->iap_working_area) != ERROR_OK)
|
||||||
|
{
|
||||||
|
ERROR("no working area specified, can't write LPC2000 internal flash");
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write IAP code to working area */
|
||||||
|
buf_set_u32(jump_gate, 0, 32, ARMV4_5_BX(12));
|
||||||
|
buf_set_u32(jump_gate, 32, 32, 0xeafffffe);
|
||||||
|
target->type->write_memory(target, lpc2000_info->iap_working_area->address, 4, 2, (u8*)jump_gate);
|
||||||
|
}
|
||||||
|
|
||||||
|
armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
|
||||||
|
armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
|
||||||
|
armv4_5_info.core_state = ARMV4_5_STATE_ARM;
|
||||||
|
|
||||||
|
/* command parameter table */
|
||||||
|
init_mem_param(&mem_params[0], lpc2000_info->iap_working_area->address + 8, 4 * 6, PARAM_OUT);
|
||||||
|
buf_set_u32(mem_params[0].value, 0, 32, code);
|
||||||
|
buf_set_u32(mem_params[0].value, 32, 32, param_table[0]);
|
||||||
|
buf_set_u32(mem_params[0].value, 64, 32, param_table[1]);
|
||||||
|
buf_set_u32(mem_params[0].value, 96, 32, param_table[2]);
|
||||||
|
buf_set_u32(mem_params[0].value, 128, 32, param_table[3]);
|
||||||
|
buf_set_u32(mem_params[0].value, 160, 32, param_table[4]);
|
||||||
|
|
||||||
|
init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
|
||||||
|
buf_set_u32(reg_params[0].value, 0, 32, lpc2000_info->iap_working_area->address + 0x8);
|
||||||
|
|
||||||
|
/* command result table */
|
||||||
|
init_mem_param(&mem_params[1], lpc2000_info->iap_working_area->address + 0x20, 4 * 3, PARAM_IN);
|
||||||
|
|
||||||
|
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
||||||
|
buf_set_u32(reg_params[1].value, 0, 32, lpc2000_info->iap_working_area->address + 0x20);
|
||||||
|
|
||||||
|
/* IAP entry point */
|
||||||
|
init_reg_param(®_params[2], "r12", 32, PARAM_OUT);
|
||||||
|
buf_set_u32(reg_params[2].value, 0, 32, 0x7ffffff1);
|
||||||
|
|
||||||
|
/* IAP stack */
|
||||||
|
init_reg_param(®_params[3], "r13_svc", 32, PARAM_OUT);
|
||||||
|
buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xac);
|
||||||
|
|
||||||
|
/* return address */
|
||||||
|
init_reg_param(®_params[4], "lr_svc", 32, PARAM_OUT);
|
||||||
|
buf_set_u32(reg_params[4].value, 0, 32, lpc2000_info->iap_working_area->address + 0x4);
|
||||||
|
|
||||||
|
target->type->run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, lpc2000_info->iap_working_area->address + 0x4, 10000, &armv4_5_info);
|
||||||
|
|
||||||
|
status_code = buf_get_u32(mem_params[1].value, 0, 32);
|
||||||
|
result_table[0] = buf_get_u32(mem_params[1].value, 32, 32);
|
||||||
|
result_table[1] = buf_get_u32(mem_params[1].value, 64, 32);
|
||||||
|
|
||||||
|
destroy_mem_param(&mem_params[0]);
|
||||||
|
destroy_mem_param(&mem_params[1]);
|
||||||
|
|
||||||
|
destroy_reg_param(®_params[0]);
|
||||||
|
destroy_reg_param(®_params[1]);
|
||||||
|
destroy_reg_param(®_params[2]);
|
||||||
|
destroy_reg_param(®_params[3]);
|
||||||
|
destroy_reg_param(®_params[4]);
|
||||||
|
|
||||||
|
return status_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lpc2000_iap_blank_check(struct flash_bank_s *bank, int first, int last)
|
||||||
|
{
|
||||||
|
u32 param_table[5];
|
||||||
|
u32 result_table[2];
|
||||||
|
int status_code;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if ((first < 0) || (last > bank->num_sectors))
|
||||||
|
return ERROR_FLASH_SECTOR_INVALID;
|
||||||
|
|
||||||
|
for (i = first; i <= last; i++)
|
||||||
|
{
|
||||||
|
/* check single sector */
|
||||||
|
param_table[0] = param_table[1] = i;
|
||||||
|
status_code = lpc2000_iap_call(bank, 53, param_table, result_table);
|
||||||
|
|
||||||
|
switch (status_code)
|
||||||
|
{
|
||||||
|
case ERROR_FLASH_OPERATION_FAILED:
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
case LPC2000_CMD_SUCCESS:
|
||||||
|
bank->sectors[i].is_erased = 1;
|
||||||
|
break;
|
||||||
|
case LPC2000_SECTOR_NOT_BLANK:
|
||||||
|
bank->sectors[i].is_erased = 0;
|
||||||
|
break;
|
||||||
|
case LPC2000_INVALID_SECTOR:
|
||||||
|
bank->sectors[i].is_erased = 0;
|
||||||
|
break;
|
||||||
|
case LPC2000_BUSY:
|
||||||
|
return ERROR_FLASH_BUSY;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("BUG: unknown LPC2000 status code");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flash_bank lpc2000 <base> <size> 0 0 <lpc_variant> <target#> <cclk> [calc_checksum]
|
||||||
|
*/
|
||||||
|
int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||||
|
{
|
||||||
|
lpc2000_flash_bank_t *lpc2000_info;
|
||||||
|
|
||||||
|
if (argc < 8)
|
||||||
|
{
|
||||||
|
WARNING("incomplete flash_bank lpc2000 configuration");
|
||||||
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
lpc2000_info = malloc(sizeof(lpc2000_flash_bank_t));
|
||||||
|
bank->driver_priv = lpc2000_info;
|
||||||
|
|
||||||
|
if (strcmp(args[5], "lpc2000_v1") == 0)
|
||||||
|
{
|
||||||
|
lpc2000_info->variant = 1;
|
||||||
|
lpc2000_info->cmd51_dst_boundary = 512;
|
||||||
|
lpc2000_info->cmd51_can_256b = 0;
|
||||||
|
lpc2000_info->cmd51_can_8192b = 1;
|
||||||
|
}
|
||||||
|
else if (strcmp(args[5], "lpc2000_v2") == 0)
|
||||||
|
{
|
||||||
|
lpc2000_info->variant = 2;
|
||||||
|
lpc2000_info->cmd51_dst_boundary = 256;
|
||||||
|
lpc2000_info->cmd51_can_256b = 1;
|
||||||
|
lpc2000_info->cmd51_can_8192b = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR("unknown LPC2000 variant");
|
||||||
|
free(lpc2000_info);
|
||||||
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
lpc2000_info->target = get_target_by_num(strtoul(args[6], NULL, 0));
|
||||||
|
if (!lpc2000_info->target)
|
||||||
|
{
|
||||||
|
ERROR("no target '%s' configured", args[6]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
lpc2000_info->iap_working_area = NULL;
|
||||||
|
lpc2000_info->cclk = strtoul(args[7], NULL, 0);
|
||||||
|
lpc2000_info->calc_checksum = 0;
|
||||||
|
lpc2000_build_sector_list(bank);
|
||||||
|
|
||||||
|
|
||||||
|
if (argc >= 9)
|
||||||
|
{
|
||||||
|
if (strcmp(args[8], "calc_checksum") == 0)
|
||||||
|
lpc2000_info->calc_checksum = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lpc2000_erase(struct flash_bank_s *bank, int first, int last)
|
||||||
|
{
|
||||||
|
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
|
||||||
|
u32 param_table[5];
|
||||||
|
u32 result_table[2];
|
||||||
|
int status_code;
|
||||||
|
|
||||||
|
if (lpc2000_info->target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((first < 0) || (last < first) || (last >= bank->num_sectors))
|
||||||
|
{
|
||||||
|
return ERROR_FLASH_SECTOR_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
param_table[0] = first;
|
||||||
|
param_table[1] = last;
|
||||||
|
param_table[2] = lpc2000_info->cclk;
|
||||||
|
|
||||||
|
/* Prepare sectors */
|
||||||
|
status_code = lpc2000_iap_call(bank, 50, param_table, result_table);
|
||||||
|
switch (status_code)
|
||||||
|
{
|
||||||
|
case ERROR_FLASH_OPERATION_FAILED:
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
case LPC2000_CMD_SUCCESS:
|
||||||
|
break;
|
||||||
|
case LPC2000_INVALID_SECTOR:
|
||||||
|
return ERROR_FLASH_SECTOR_INVALID;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WARNING("lpc2000 prepare sectors returned %i", status_code);
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Erase sectors */
|
||||||
|
status_code = lpc2000_iap_call(bank, 52, param_table, result_table);
|
||||||
|
switch (status_code)
|
||||||
|
{
|
||||||
|
case ERROR_FLASH_OPERATION_FAILED:
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
case LPC2000_CMD_SUCCESS:
|
||||||
|
break;
|
||||||
|
case LPC2000_INVALID_SECTOR:
|
||||||
|
return ERROR_FLASH_SECTOR_INVALID;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WARNING("lpc2000 erase sectors returned %i", status_code);
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lpc2000_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||||
|
{
|
||||||
|
/* can't protect/unprotect on the lpc2000 */
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lpc2000_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||||
|
{
|
||||||
|
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
|
||||||
|
target_t *target = lpc2000_info->target;
|
||||||
|
u32 dst_min_alignment;
|
||||||
|
u32 bytes_remaining = count;
|
||||||
|
u32 bytes_written = 0;
|
||||||
|
int first_sector = 0;
|
||||||
|
int last_sector = 0;
|
||||||
|
u32 param_table[5];
|
||||||
|
u32 result_table[2];
|
||||||
|
int status_code;
|
||||||
|
int i;
|
||||||
|
working_area_t *download_area;
|
||||||
|
|
||||||
|
if (lpc2000_info->target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate a working area */
|
||||||
|
if (target_alloc_working_area(target, 4096, &download_area) != ERROR_OK)
|
||||||
|
{
|
||||||
|
ERROR("no working area specified, can't write LPC2000 internal flash");
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset + count > bank->size)
|
||||||
|
return ERROR_FLASH_DST_OUT_OF_BANK;
|
||||||
|
|
||||||
|
if (lpc2000_info->cmd51_can_256b)
|
||||||
|
dst_min_alignment = 256;
|
||||||
|
else
|
||||||
|
dst_min_alignment = 512;
|
||||||
|
|
||||||
|
if (offset % dst_min_alignment)
|
||||||
|
{
|
||||||
|
WARNING("offset 0x%x breaks required alignment 0x%x", offset, dst_min_alignment);
|
||||||
|
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < bank->num_sectors; i++)
|
||||||
|
{
|
||||||
|
if (offset >= bank->sectors[i].offset)
|
||||||
|
first_sector = i;
|
||||||
|
if (offset + CEIL(count, dst_min_alignment) * dst_min_alignment > bank->sectors[i].offset)
|
||||||
|
last_sector = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector);
|
||||||
|
|
||||||
|
/* check if exception vectors should be flashed */
|
||||||
|
if ((offset == 0) && (count >= 0x20) && lpc2000_info->calc_checksum)
|
||||||
|
{
|
||||||
|
u32 checksum = 0;
|
||||||
|
int i = 0;
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
DEBUG("0x%2.2x: 0x%8.8x", i * 4, buf_get_u32(buffer + (i * 4), 0, 32));
|
||||||
|
if (i != 5)
|
||||||
|
checksum += buf_get_u32(buffer + (i * 4), 0, 32);
|
||||||
|
}
|
||||||
|
checksum = 0 - checksum;
|
||||||
|
DEBUG("checksum: 0x%8.8x", checksum);
|
||||||
|
buf_set_u32(buffer + 0x14, 0, 32, checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (bytes_remaining > 0)
|
||||||
|
{
|
||||||
|
u32 thisrun_bytes;
|
||||||
|
if (bytes_remaining >= 4096)
|
||||||
|
thisrun_bytes = 4096;
|
||||||
|
else if (bytes_remaining >= 1024)
|
||||||
|
thisrun_bytes = 1024;
|
||||||
|
else if ((bytes_remaining >= 512) || (!lpc2000_info->cmd51_can_256b))
|
||||||
|
thisrun_bytes = 512;
|
||||||
|
else
|
||||||
|
thisrun_bytes = 256;
|
||||||
|
|
||||||
|
/* Prepare sectors */
|
||||||
|
param_table[0] = first_sector;
|
||||||
|
param_table[1] = last_sector;
|
||||||
|
status_code = lpc2000_iap_call(bank, 50, param_table, result_table);
|
||||||
|
switch (status_code)
|
||||||
|
{
|
||||||
|
case ERROR_FLASH_OPERATION_FAILED:
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
case LPC2000_CMD_SUCCESS:
|
||||||
|
break;
|
||||||
|
case LPC2000_INVALID_SECTOR:
|
||||||
|
return ERROR_FLASH_SECTOR_INVALID;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WARNING("lpc2000 prepare sectors returned %i", status_code);
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_remaining >= thisrun_bytes)
|
||||||
|
{
|
||||||
|
if (target_write_buffer(lpc2000_info->target, download_area->address, thisrun_bytes, buffer + bytes_written) != ERROR_OK)
|
||||||
|
{
|
||||||
|
target_free_working_area(target, download_area);
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u8 *last_buffer = malloc(thisrun_bytes);
|
||||||
|
int i;
|
||||||
|
memcpy(last_buffer, buffer + bytes_written, bytes_remaining);
|
||||||
|
for (i = bytes_remaining; i < thisrun_bytes; i++)
|
||||||
|
last_buffer[i] = 0xff;
|
||||||
|
target_write_buffer(lpc2000_info->target, download_area->address, thisrun_bytes, last_buffer);
|
||||||
|
free(last_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG("writing 0x%x bytes to address 0x%x", thisrun_bytes, bank->base + offset + bytes_written);
|
||||||
|
|
||||||
|
/* Write data */
|
||||||
|
param_table[0] = bank->base + offset + bytes_written;
|
||||||
|
param_table[1] = download_area->address;
|
||||||
|
param_table[2] = thisrun_bytes;
|
||||||
|
param_table[3] = lpc2000_info->cclk;
|
||||||
|
status_code = lpc2000_iap_call(bank, 51, param_table, result_table);
|
||||||
|
switch (status_code)
|
||||||
|
{
|
||||||
|
case ERROR_FLASH_OPERATION_FAILED:
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
case LPC2000_CMD_SUCCESS:
|
||||||
|
break;
|
||||||
|
case LPC2000_INVALID_SECTOR:
|
||||||
|
return ERROR_FLASH_SECTOR_INVALID;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WARNING("lpc2000 returned %i", status_code);
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_remaining > thisrun_bytes)
|
||||||
|
bytes_remaining -= thisrun_bytes;
|
||||||
|
else
|
||||||
|
bytes_remaining = 0;
|
||||||
|
bytes_written += thisrun_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
target_free_working_area(target, download_area);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lpc2000_probe(struct flash_bank_s *bank)
|
||||||
|
{
|
||||||
|
/* we can't probe on an lpc2000
|
||||||
|
* if this is an lpc2xxx, it has the configured flash
|
||||||
|
*/
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lpc2000_erase_check(struct flash_bank_s *bank)
|
||||||
|
{
|
||||||
|
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
|
||||||
|
|
||||||
|
if (lpc2000_info->target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lpc2000_iap_blank_check(bank, 0, bank->num_sectors - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lpc2000_protect_check(struct flash_bank_s *bank)
|
||||||
|
{
|
||||||
|
/* sectors are always protected */
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lpc2000_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||||
|
{
|
||||||
|
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
|
||||||
|
|
||||||
|
snprintf(buf, buf_size, "lpc2000 flash driver variant: %i, clk: %i", lpc2000_info->variant, lpc2000_info->cclk);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
flash_bank_t *bank;
|
||||||
|
u32 param_table[5];
|
||||||
|
u32 result_table[2];
|
||||||
|
int status_code;
|
||||||
|
lpc2000_flash_bank_t *lpc2000_info;
|
||||||
|
|
||||||
|
if (argc < 1)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "usage: lpc2000 part_id <num>");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||||
|
if (!bank)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
lpc2000_info = bank->driver_priv;
|
||||||
|
if (lpc2000_info->target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((status_code = lpc2000_iap_call(bank, 54, param_table, result_table)) != 0x0)
|
||||||
|
{
|
||||||
|
if (status_code == ERROR_FLASH_OPERATION_FAILED)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "no sufficient working area specified, can't access LPC2000 IAP interface");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
command_print(cmd_ctx, "lpc2000 IAP returned status code %i", status_code);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "lpc2000 part id: 0x%8.8x", result_table[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef LPC2000_H
|
||||||
|
#define LPC2000_H
|
||||||
|
|
||||||
|
#include "flash.h"
|
||||||
|
#include "target.h"
|
||||||
|
|
||||||
|
typedef struct lpc2000_flash_bank_s
|
||||||
|
{
|
||||||
|
int variant;
|
||||||
|
struct target_s *target;
|
||||||
|
struct working_area_s *iap_working_area;
|
||||||
|
u32 cclk;
|
||||||
|
int cmd51_dst_boundary;
|
||||||
|
int cmd51_can_256b;
|
||||||
|
int cmd51_can_8192b;
|
||||||
|
int calc_checksum;
|
||||||
|
} lpc2000_flash_bank_t;
|
||||||
|
|
||||||
|
enum lpc2000_status_codes
|
||||||
|
{
|
||||||
|
LPC2000_CMD_SUCCESS = 0,
|
||||||
|
LPC2000_INVALID_COMMAND = 1,
|
||||||
|
LPC2000_SRC_ADDR_ERROR = 2,
|
||||||
|
LPC2000_DST_ADDR_ERROR = 3,
|
||||||
|
LPC2000_SRC_ADDR_NOT_MAPPED = 4,
|
||||||
|
LPC2000_DST_ADDR_NOT_MAPPED = 5,
|
||||||
|
LPC2000_COUNT_ERROR = 6,
|
||||||
|
LPC2000_INVALID_SECTOR = 7,
|
||||||
|
LPC2000_SECTOR_NOT_BLANK = 8,
|
||||||
|
LPC2000_SECTOR_NOT_PREPARED = 9,
|
||||||
|
LPC2000_COMPARE_ERROR = 10,
|
||||||
|
LPC2000_BUSY = 11
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* LPC2000_H */
|
|
@ -0,0 +1,469 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "str7x.h"
|
||||||
|
#include "flash.h"
|
||||||
|
#include "target.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "armv4_5.h"
|
||||||
|
#include "algorithm.h"
|
||||||
|
#include "binarybuffer.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
str7x_mem_layout_t mem_layout[] = {
|
||||||
|
{0x00000000, 0x02000, 0x01},
|
||||||
|
{0x00002000, 0x02000, 0x01},
|
||||||
|
{0x00004000, 0x02000, 0x01},
|
||||||
|
{0x00006000, 0x02000, 0x01},
|
||||||
|
{0x00008000, 0x08000, 0x01},
|
||||||
|
{0x00010000, 0x10000, 0x01},
|
||||||
|
{0x00020000, 0x10000, 0x01},
|
||||||
|
{0x00030000, 0x10000, 0x01},
|
||||||
|
{0x000C0000, 0x02000, 0x10},
|
||||||
|
{0x000C2000, 0x02000, 0x10},
|
||||||
|
{0,0},
|
||||||
|
};
|
||||||
|
|
||||||
|
int str7x_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||||
|
int str7x_erase(struct flash_bank_s *bank, int first, int last);
|
||||||
|
int str7x_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||||
|
int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
|
||||||
|
int str7x_probe(struct flash_bank_s *bank);
|
||||||
|
int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int str7x_protect_check(struct flash_bank_s *bank);
|
||||||
|
int str7x_erase_check(struct flash_bank_s *bank);
|
||||||
|
int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||||
|
|
||||||
|
flash_driver_t str7x_flash =
|
||||||
|
{
|
||||||
|
.name = "str7x",
|
||||||
|
.register_commands = str7x_register_commands,
|
||||||
|
.flash_bank_command = str7x_flash_bank_command,
|
||||||
|
.erase = str7x_erase,
|
||||||
|
.protect = str7x_protect,
|
||||||
|
.write = str7x_write,
|
||||||
|
.probe = str7x_probe,
|
||||||
|
.erase_check = str7x_erase_check,
|
||||||
|
.protect_check = str7x_protect_check,
|
||||||
|
.info = str7x_info
|
||||||
|
};
|
||||||
|
|
||||||
|
int str7x_register_commands(struct command_context_s *cmd_ctx)
|
||||||
|
{
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int str7x_get_flash_adr(struct flash_bank_s *bank, u32 reg)
|
||||||
|
{
|
||||||
|
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||||
|
return (str7x_info->flash_base|reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
int str7x_build_block_list(struct flash_bank_s *bank)
|
||||||
|
{
|
||||||
|
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
int num_sectors;
|
||||||
|
|
||||||
|
switch (bank->size)
|
||||||
|
{
|
||||||
|
case 16 * 1024:
|
||||||
|
num_sectors = 2;
|
||||||
|
break;
|
||||||
|
case 64 * 1024:
|
||||||
|
num_sectors = 5;
|
||||||
|
break;
|
||||||
|
case 128 * 1024:
|
||||||
|
num_sectors = 6;
|
||||||
|
break;
|
||||||
|
case 256 * 1024:
|
||||||
|
num_sectors = 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("BUG: unknown bank->size encountered");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( str7x_info->bank1 == 1 )
|
||||||
|
{
|
||||||
|
num_sectors += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
bank->num_sectors = num_sectors;
|
||||||
|
bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
|
||||||
|
|
||||||
|
for (i = 0; i < num_sectors; i++)
|
||||||
|
{
|
||||||
|
bank->sectors[i].offset = mem_layout[i].sector_start;
|
||||||
|
bank->sectors[i].size = mem_layout[i].sector_size;
|
||||||
|
bank->sectors[i].is_erased = -1;
|
||||||
|
bank->sectors[i].is_protected = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flash bank str7x <base> <size> 0 0 <str71_variant> <target#>
|
||||||
|
*/
|
||||||
|
int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||||
|
{
|
||||||
|
str7x_flash_bank_t *str7x_info;
|
||||||
|
|
||||||
|
if (argc < 7)
|
||||||
|
{
|
||||||
|
WARNING("incomplete flash_bank str7x configuration");
|
||||||
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
str7x_info = malloc(sizeof(str7x_flash_bank_t));
|
||||||
|
bank->driver_priv = str7x_info;
|
||||||
|
|
||||||
|
if (strcmp(args[5], "STR71x") == 0)
|
||||||
|
{
|
||||||
|
str7x_info->bank1 = 1;
|
||||||
|
str7x_info->flash_base = 0x40000000;
|
||||||
|
}
|
||||||
|
else if (strcmp(args[5], "STR73x") == 0)
|
||||||
|
{
|
||||||
|
str7x_info->bank1 = 0;
|
||||||
|
str7x_info->flash_base = 0x80000000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR("unknown STR7x variant");
|
||||||
|
free(str7x_info);
|
||||||
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
str7x_info->target = get_target_by_num(strtoul(args[6], NULL, 0));
|
||||||
|
if (!str7x_info->target)
|
||||||
|
{
|
||||||
|
ERROR("no target '%i' configured", args[6]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
str7x_build_block_list(bank);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 str7x_status(struct flash_bank_s *bank)
|
||||||
|
{
|
||||||
|
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||||
|
target_t *target = str7x_info->target;
|
||||||
|
u32 retval;
|
||||||
|
|
||||||
|
target->type->read_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&retval);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 str7x_result(struct flash_bank_s *bank)
|
||||||
|
{
|
||||||
|
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||||
|
target_t *target = str7x_info->target;
|
||||||
|
u32 retval;
|
||||||
|
|
||||||
|
target->type->read_memory(target, str7x_get_flash_adr(bank, FLASH_ER), 4, 1, (u8*)&retval);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int str7x_blank_check(struct flash_bank_s *bank, int first, int last)
|
||||||
|
{
|
||||||
|
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||||
|
target_t *target = str7x_info->target;
|
||||||
|
u8 *buffer;
|
||||||
|
int i;
|
||||||
|
int nBytes;
|
||||||
|
|
||||||
|
if ((first < 0) || (last > bank->num_sectors))
|
||||||
|
return ERROR_FLASH_SECTOR_INVALID;
|
||||||
|
|
||||||
|
if (str7x_info->target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = malloc(256);
|
||||||
|
|
||||||
|
for (i = first; i <= last; i++)
|
||||||
|
{
|
||||||
|
bank->sectors[i].is_erased = 1;
|
||||||
|
|
||||||
|
target->type->read_memory(target, bank->base + bank->sectors[i].offset, 4, 256/4, buffer);
|
||||||
|
|
||||||
|
for (nBytes = 0; nBytes < 256; nBytes++)
|
||||||
|
{
|
||||||
|
if (buffer[nBytes] != 0xFF)
|
||||||
|
{
|
||||||
|
bank->sectors[i].is_erased = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int str7x_protect_check(struct flash_bank_s *bank)
|
||||||
|
{
|
||||||
|
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||||
|
target_t *target = str7x_info->target;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if (str7x_info->target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
target->type->read_memory(target, str7x_get_flash_adr(bank, FLASH_NVWPAR), 4, 1, (u8*)&retval);
|
||||||
|
|
||||||
|
for (i = 0; i < bank->num_sectors; i++)
|
||||||
|
{
|
||||||
|
if (retval & (mem_layout[i].reg_offset << i))
|
||||||
|
bank->sectors[i].is_protected = 0;
|
||||||
|
else
|
||||||
|
bank->sectors[i].is_protected = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int str7x_erase(struct flash_bank_s *bank, int first, int last)
|
||||||
|
{
|
||||||
|
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||||
|
target_t *target = str7x_info->target;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
u32 cmd;
|
||||||
|
u32 retval;
|
||||||
|
u32 erase_blocks;
|
||||||
|
|
||||||
|
if (str7x_info->target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
erase_blocks = 0;
|
||||||
|
|
||||||
|
for (i = first; i <= last; i++)
|
||||||
|
erase_blocks |= (mem_layout[i].reg_offset << i);
|
||||||
|
|
||||||
|
cmd = FLASH_SER;
|
||||||
|
target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
|
||||||
|
|
||||||
|
cmd = erase_blocks;
|
||||||
|
target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR1), 4, 1, (u8*)&cmd);
|
||||||
|
|
||||||
|
cmd = FLASH_SER|FLASH_WMS;
|
||||||
|
target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
|
||||||
|
|
||||||
|
while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
|
||||||
|
usleep(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = str7x_result(bank);
|
||||||
|
|
||||||
|
if (retval & FLASH_ERER)
|
||||||
|
return ERROR_FLASH_SECTOR_NOT_ERASED;
|
||||||
|
else if (retval & FLASH_WPF)
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
|
||||||
|
for (i = first; i <= last; i++)
|
||||||
|
bank->sectors[i].is_erased = 1;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int str7x_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||||
|
{
|
||||||
|
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||||
|
target_t *target = str7x_info->target;
|
||||||
|
int i;
|
||||||
|
u32 cmd;
|
||||||
|
u32 retval;
|
||||||
|
u32 protect_blocks;
|
||||||
|
|
||||||
|
if (str7x_info->target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
protect_blocks = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
if( set )
|
||||||
|
{
|
||||||
|
for (i = first; i <= last; i++)
|
||||||
|
protect_blocks &= ~(mem_layout[i].reg_offset << i);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = FLASH_SPR;
|
||||||
|
target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
|
||||||
|
|
||||||
|
cmd = str7x_get_flash_adr(bank, FLASH_NVWPAR);
|
||||||
|
target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_AR), 4, 1, (u8*)&cmd);
|
||||||
|
|
||||||
|
cmd = protect_blocks;
|
||||||
|
target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, (u8*)&cmd);
|
||||||
|
|
||||||
|
cmd = FLASH_SPR|FLASH_WMS;
|
||||||
|
target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
|
||||||
|
|
||||||
|
while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
|
||||||
|
usleep(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = str7x_result(bank);
|
||||||
|
|
||||||
|
if (retval & FLASH_ERER)
|
||||||
|
return ERROR_FLASH_SECTOR_NOT_ERASED;
|
||||||
|
else if (retval & FLASH_WPF)
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||||
|
{
|
||||||
|
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||||
|
target_t *target = str7x_info->target;
|
||||||
|
u32 dwords_remaining = (count / 8);
|
||||||
|
u32 bytes_remaining = (count & 0x00000007);
|
||||||
|
u32 address = bank->base + offset;
|
||||||
|
u32 *wordbuffer = (u32*)buffer;
|
||||||
|
u32 bytes_written = 0;
|
||||||
|
u32 cmd;
|
||||||
|
u32 retval;
|
||||||
|
|
||||||
|
if (str7x_info->target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset + count > bank->size)
|
||||||
|
return ERROR_FLASH_DST_OUT_OF_BANK;
|
||||||
|
|
||||||
|
while (dwords_remaining > 0)
|
||||||
|
{
|
||||||
|
// command
|
||||||
|
cmd = FLASH_DWPG;
|
||||||
|
target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
|
||||||
|
|
||||||
|
// address
|
||||||
|
cmd = address;
|
||||||
|
target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_AR), 4, 1, (u8*)&cmd);
|
||||||
|
|
||||||
|
// data byte 1
|
||||||
|
cmd = wordbuffer[bytes_written/4];
|
||||||
|
target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, (u8*)&cmd);
|
||||||
|
bytes_written += 4;
|
||||||
|
|
||||||
|
// data byte 2
|
||||||
|
cmd = wordbuffer[bytes_written/4];
|
||||||
|
target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, (u8*)&cmd);
|
||||||
|
bytes_written += 4;
|
||||||
|
|
||||||
|
/* start programming cycle */
|
||||||
|
cmd = FLASH_DWPG|FLASH_WMS;
|
||||||
|
target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
|
||||||
|
|
||||||
|
while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
|
||||||
|
usleep(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = str7x_result(bank);
|
||||||
|
|
||||||
|
if (retval & FLASH_PGER)
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
else if (retval & FLASH_WPF)
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
|
||||||
|
dwords_remaining--;
|
||||||
|
address += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
while( bytes_remaining > 0 )
|
||||||
|
{
|
||||||
|
// command
|
||||||
|
cmd = FLASH_WPG;
|
||||||
|
target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
|
||||||
|
|
||||||
|
// address
|
||||||
|
cmd = address;
|
||||||
|
target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_AR), 4, 1, (u8*)&cmd);
|
||||||
|
|
||||||
|
// data byte
|
||||||
|
cmd = buffer[bytes_written];
|
||||||
|
target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, (u8*)&cmd);
|
||||||
|
|
||||||
|
/* start programming cycle */
|
||||||
|
cmd = FLASH_WPG|FLASH_WMS;
|
||||||
|
target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
|
||||||
|
|
||||||
|
while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
|
||||||
|
usleep(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = str7x_result(bank);
|
||||||
|
|
||||||
|
if (retval & FLASH_PGER)
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
else if (retval & FLASH_WPF)
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
|
||||||
|
address++;
|
||||||
|
bytes_remaining--;
|
||||||
|
bytes_written++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int str7x_probe(struct flash_bank_s *bank)
|
||||||
|
{
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int str7x_erase_check(struct flash_bank_s *bank)
|
||||||
|
{
|
||||||
|
return str7x_blank_check(bank, 0, bank->num_sectors - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||||
|
{
|
||||||
|
snprintf(buf, buf_size, "str7x flash driver info" );
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef STR7X_H
|
||||||
|
#define STR7X_H
|
||||||
|
|
||||||
|
#include "flash.h"
|
||||||
|
#include "target.h"
|
||||||
|
|
||||||
|
typedef struct str7x_flash_bank_s
|
||||||
|
{
|
||||||
|
int bank1;
|
||||||
|
struct target_s *target;
|
||||||
|
u32 flash_base;
|
||||||
|
} str7x_flash_bank_t;
|
||||||
|
|
||||||
|
enum str7x_status_codes
|
||||||
|
{
|
||||||
|
STR7X_CMD_SUCCESS = 0,
|
||||||
|
STR7X_INVALID_COMMAND = 1,
|
||||||
|
STR7X_SRC_ADDR_ERROR = 2,
|
||||||
|
STR7X_DST_ADDR_ERROR = 3,
|
||||||
|
STR7X_SRC_ADDR_NOT_MAPPED = 4,
|
||||||
|
STR7X_DST_ADDR_NOT_MAPPED = 5,
|
||||||
|
STR7X_COUNT_ERROR = 6,
|
||||||
|
STR7X_INVALID_SECTOR = 7,
|
||||||
|
STR7X_SECTOR_NOT_BLANK = 8,
|
||||||
|
STR7X_SECTOR_NOT_PREPARED = 9,
|
||||||
|
STR7X_COMPARE_ERROR = 10,
|
||||||
|
STR7X_BUSY = 11
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Flash registers */
|
||||||
|
|
||||||
|
#define FLASH_CR0 0x00100000
|
||||||
|
#define FLASH_CR1 0x00100004
|
||||||
|
#define FLASH_DR0 0x00100008
|
||||||
|
#define FLASH_DR1 0x0010000C
|
||||||
|
#define FLASH_AR 0x00100010
|
||||||
|
#define FLASH_ER 0x00100014
|
||||||
|
#define FLASH_NVWPAR 0x0010DFB0
|
||||||
|
#define FLASH_NVAPR0 0x0010DFB8
|
||||||
|
#define FLASH_NVAPR1 0x0010DFBC
|
||||||
|
|
||||||
|
/* FLASH_CR0 register bits */
|
||||||
|
|
||||||
|
#define FLASH_WMS 0x80000000
|
||||||
|
#define FLASH_SUSP 0x40000000
|
||||||
|
#define FLASH_WPG 0x20000000
|
||||||
|
#define FLASH_DWPG 0x10000000
|
||||||
|
#define FLASH_SER 0x08000000
|
||||||
|
#define FLASH_SPR 0x01000000
|
||||||
|
#define FLASH_BER 0x04000000
|
||||||
|
#define FLASH_MER 0x02000000
|
||||||
|
#define FLASH_BSYA1 0x00000002
|
||||||
|
#define FLASH_BSYA2 0x00000004
|
||||||
|
|
||||||
|
/* FLASH_CR1 regsiter bits */
|
||||||
|
|
||||||
|
#define FLASH_B1S 0x02000000
|
||||||
|
#define FLASH_B0S 0x01000000
|
||||||
|
#define FLASH_B1F1 0x00020000
|
||||||
|
#define FLASH_B1F0 0x00010000
|
||||||
|
#define FLASH_B0F7 0x00000080
|
||||||
|
#define FLASH_B0F6 0x00000040
|
||||||
|
#define FLASH_B0F5 0x00000020
|
||||||
|
#define FLASH_B0F4 0x00000010
|
||||||
|
#define FLASH_B0F3 0x00000008
|
||||||
|
#define FLASH_B0F2 0x00000004
|
||||||
|
#define FLASH_B0F1 0x00000002
|
||||||
|
#define FLASH_B0F0 0x00000001
|
||||||
|
|
||||||
|
/* FLASH_ER register bits */
|
||||||
|
|
||||||
|
#define FLASH_WPF 0x00000100
|
||||||
|
#define FLASH_RESER 0x00000080
|
||||||
|
#define FLASH_SEQER 0x00000040
|
||||||
|
#define FLASH_10ER 0x00000008
|
||||||
|
#define FLASH_PGER 0x00000004
|
||||||
|
#define FLASH_ERER 0x00000002
|
||||||
|
#define FLASH_ERR 0x00000001
|
||||||
|
|
||||||
|
typedef struct str7x_mem_layout_s {
|
||||||
|
u32 sector_start;
|
||||||
|
u32 sector_size;
|
||||||
|
u32 reg_offset;
|
||||||
|
} str7x_mem_layout_t;
|
||||||
|
|
||||||
|
#endif /* STR7X_H */
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
INCLUDES = $(all_includes)
|
||||||
|
METASOURCES = AUTO
|
||||||
|
noinst_LIBRARIES = libhelper.a
|
||||||
|
libhelper_a_SOURCES = binarybuffer.c configuration.c log.c interpreter.c command.c time_support.c
|
||||||
|
noinst_HEADERS = binarybuffer.h configuration.h types.h log.h command.h \
|
||||||
|
interpreter.h time_support.h
|
|
@ -0,0 +1,246 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2004, 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#include "binarybuffer.h"
|
||||||
|
|
||||||
|
int buf_set_u32(u8* buffer, unsigned int first, unsigned int num, u32 value);
|
||||||
|
u32 buf_get_u32(u8* buffer, unsigned int first, unsigned int num);
|
||||||
|
u32 flip_u32(u32 value, unsigned int num);
|
||||||
|
|
||||||
|
const unsigned char bit_reverse_table256[] =
|
||||||
|
{
|
||||||
|
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
|
||||||
|
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
|
||||||
|
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
|
||||||
|
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
|
||||||
|
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
|
||||||
|
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
|
||||||
|
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
|
||||||
|
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
|
||||||
|
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
|
||||||
|
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
|
||||||
|
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
|
||||||
|
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
|
||||||
|
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
|
||||||
|
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
|
||||||
|
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
|
||||||
|
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
|
int buf_set_u32(u8* buffer, unsigned int first, unsigned int num, u32 value)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (!buffer)
|
||||||
|
return ERROR_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
|
for (i=first; i<first+num; i++)
|
||||||
|
{
|
||||||
|
if (((value >> (i-first))&1) == 1)
|
||||||
|
buffer[i/8] |= 1 << (i%8);
|
||||||
|
else
|
||||||
|
buffer[i/8] &= ~(1 << (i%8));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 buf_get_u32(u8* buffer, unsigned int first, unsigned int num)
|
||||||
|
{
|
||||||
|
u32 result = 0;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (!buffer)
|
||||||
|
{
|
||||||
|
ERROR("buffer not initialized");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=first; i<first+num; i++)
|
||||||
|
{
|
||||||
|
if (((buffer[i/8]>>(i%8))&1) == 1)
|
||||||
|
result |= 1 << (i-first);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8* buf_cpy(u8 *from, u8 *to, int size)
|
||||||
|
{
|
||||||
|
int num_bytes = CEIL(size, 8);
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (from == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < num_bytes; i++)
|
||||||
|
to[i] = from[i];
|
||||||
|
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
|
||||||
|
int buf_cmp(u8 *buf1, u8 *buf2, int size)
|
||||||
|
{
|
||||||
|
int num_bytes = CEIL(size, 8);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!buf1 || !buf2)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
for (i = 0; i < num_bytes; i++)
|
||||||
|
{
|
||||||
|
if (buf1[i] != buf2[i])
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int buf_cmp_mask(u8 *buf1, u8 *buf2, u8 *mask, int size)
|
||||||
|
{
|
||||||
|
int num_bytes = CEIL(size, 8);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < num_bytes; i++)
|
||||||
|
{
|
||||||
|
if ((buf1[i] & mask[i]) != (buf2[i] & mask[i]))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8* buf_set_ones(u8 *buf, int count)
|
||||||
|
{
|
||||||
|
int num_bytes = CEIL(count, 8);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < num_bytes; i++)
|
||||||
|
{
|
||||||
|
if (count >= 8)
|
||||||
|
buf[i] = 0xff;
|
||||||
|
else
|
||||||
|
buf[i] = (1 << count) - 1;
|
||||||
|
|
||||||
|
count -= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8* buf_set_buf(u8 *src, int src_start, u8 *dst, int dst_start, int len)
|
||||||
|
{
|
||||||
|
int src_idx = src_start, dst_idx = dst_start;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
if (((src[src_idx/8] >> (src_idx % 8)) & 1) == 1)
|
||||||
|
dst[dst_idx/8] |= 1 << (dst_idx%8);
|
||||||
|
else
|
||||||
|
dst[dst_idx/8] &= ~(1 << (dst_idx%8));
|
||||||
|
dst_idx++;
|
||||||
|
src_idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 flip_u32(u32 value, unsigned int num)
|
||||||
|
{
|
||||||
|
u32 c;
|
||||||
|
|
||||||
|
c = (bit_reverse_table256[value & 0xff] << 24) |
|
||||||
|
(bit_reverse_table256[(value >> 8) & 0xff] << 16) |
|
||||||
|
(bit_reverse_table256[(value >> 16) & 0xff] << 8) |
|
||||||
|
(bit_reverse_table256[(value >> 24) & 0xff]);
|
||||||
|
|
||||||
|
if (num < 32)
|
||||||
|
c = c >> (32 - num);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* buf_to_char(u8 *buf, int size)
|
||||||
|
{
|
||||||
|
int char_len = CEIL(size, 8) * 2;
|
||||||
|
char *char_buf = malloc(char_len + 1);
|
||||||
|
int i;
|
||||||
|
int bits_left = size;
|
||||||
|
|
||||||
|
char_buf[char_len] = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < CEIL(size, 8); i++)
|
||||||
|
{
|
||||||
|
if (bits_left < 8)
|
||||||
|
{
|
||||||
|
buf[i] &= ((1 << bits_left) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((buf[i] & 0x0f) >= 0) && ((buf[i] & 0x0f) <= 9))
|
||||||
|
char_buf[char_len - 2*i - 1] = '0' + (buf[i] & 0xf);
|
||||||
|
else
|
||||||
|
char_buf[char_len - 2*i - 1] = 'a' + (buf[i] & 0xf) - 10;
|
||||||
|
|
||||||
|
if (((buf[i] & 0xf0) >> 4 >= 0) && ((buf[i] & 0xf0) >> 4 <= 9))
|
||||||
|
char_buf[char_len - 2*i - 2] = '0' + ((buf[i] & 0xf0) >> 4);
|
||||||
|
else
|
||||||
|
char_buf[char_len - 2*i - 2] = 'a' + ((buf[i] & 0xf0) >> 4) - 10;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return char_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int char_to_buf(char *buf, int len, u8 *bin_buf, int buf_size)
|
||||||
|
{
|
||||||
|
int bin_len = CEIL(len, 2);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (buf_size < CEIL(bin_len, 8))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (len % 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < strlen(buf); i++)
|
||||||
|
{
|
||||||
|
u32 tmp;
|
||||||
|
sscanf(buf + 2*i, "%2x", &tmp);
|
||||||
|
bin_buf[i] = tmp & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bin_len * 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
int buf_to_u32_handler(u8 *in_buf, void *priv)
|
||||||
|
{
|
||||||
|
u32 *dest = priv;
|
||||||
|
|
||||||
|
*dest = buf_get_u32(in_buf, 0, 32);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2004, 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef BINARYBUFFER_H
|
||||||
|
#define BINARYBUFFER_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
/* support functions to access arbitrary bits in a byte array
|
||||||
|
* flip_u32 inverses the bit order inside a 32-bit word (31..0 -> 0..31)
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern int buf_set_u32(u8* buffer, unsigned int first, unsigned int num, u32 value);
|
||||||
|
extern u32 buf_get_u32(u8* buffer, unsigned int first, unsigned int num);
|
||||||
|
|
||||||
|
extern u32 flip_u32(u32 value, unsigned int num);
|
||||||
|
|
||||||
|
extern int buf_cmp(u8 *buf1, u8 *buf2, int size);
|
||||||
|
extern int buf_cmp_mask(u8 *buf1, u8 *buf2, u8 *mask, int size);
|
||||||
|
extern u8* buf_cpy(u8 *from, u8 *to, int size);
|
||||||
|
|
||||||
|
extern u8* buf_set_ones(u8 *buf, int count);
|
||||||
|
extern u8* buf_set_buf(u8 *src, int src_start, u8 *dst, int dst_start, int len);
|
||||||
|
|
||||||
|
extern char* buf_to_char(u8 *buf, int size);
|
||||||
|
extern int char_to_buf(char *buf, int len, u8 *bin_buf, int buf_size);
|
||||||
|
|
||||||
|
extern int buf_to_u32_handler(u8 *in_buf, void *priv);
|
||||||
|
|
||||||
|
#define CEIL(m, n) ((m + n - 1) / n)
|
||||||
|
|
||||||
|
#endif /* BINARYBUFFER_H */
|
|
@ -0,0 +1,508 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* part of this file is taken from libcli (libcli.sourceforge.net) *
|
||||||
|
* Copyright (C) David Parrish (david@dparrish.com) *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
|
||||||
|
int build_unique_lenghts(command_context_t *context, command_t *commands)
|
||||||
|
{
|
||||||
|
command_t *c, *p;
|
||||||
|
|
||||||
|
/* iterate through all commands */
|
||||||
|
for (c = commands; c; c = c->next)
|
||||||
|
{
|
||||||
|
/* find out how many characters are required to uniquely identify a command */
|
||||||
|
for (c->unique_len = 1; c->unique_len <= strlen(c->name); c->unique_len++)
|
||||||
|
{
|
||||||
|
int foundmatch = 0;
|
||||||
|
|
||||||
|
/* for every command, see if the current length is enough */
|
||||||
|
for (p = commands; p; p = p->next)
|
||||||
|
{
|
||||||
|
/* ignore the command itself */
|
||||||
|
if (c == p)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* compare commands up to the current length */
|
||||||
|
if (strncmp(p->name, c->name, c->unique_len) == 0)
|
||||||
|
foundmatch++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* when none of the commands matched, we've found the minimum length required */
|
||||||
|
if (!foundmatch)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if the current command has children, build the unique lengths for them */
|
||||||
|
if (c->children)
|
||||||
|
build_unique_lenghts(context, c->children);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
command_t* register_command(command_context_t *context, command_t *parent, char *name, int (*handler)(struct command_context_s *context, char* name, char** args, int argc), enum command_mode mode, char *help)
|
||||||
|
{
|
||||||
|
command_t *c, *p;
|
||||||
|
|
||||||
|
if (!context || !name)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
c = malloc(sizeof(command_t));
|
||||||
|
|
||||||
|
c->name = strdup(name);
|
||||||
|
c->parent = parent;
|
||||||
|
c->children = NULL;
|
||||||
|
c->handler = handler;
|
||||||
|
c->mode = mode;
|
||||||
|
if (help)
|
||||||
|
c->help = strdup(help);
|
||||||
|
else
|
||||||
|
c->help = NULL;
|
||||||
|
c->unique_len = 0;
|
||||||
|
c->next = NULL;
|
||||||
|
|
||||||
|
/* place command in tree */
|
||||||
|
if (parent)
|
||||||
|
{
|
||||||
|
if (parent->children)
|
||||||
|
{
|
||||||
|
/* find last child */
|
||||||
|
for (p = parent->children; p && p->next; p = p->next);
|
||||||
|
if (p)
|
||||||
|
p->next = c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parent->children = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (context->commands)
|
||||||
|
{
|
||||||
|
/* find last command */
|
||||||
|
for (p = context->commands; p && p->next; p = p->next);
|
||||||
|
if (p)
|
||||||
|
p->next = c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context->commands = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update unique lengths */
|
||||||
|
build_unique_lenghts(context, (parent) ? parent : context->commands);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int unregister_command(command_context_t *context, char *name)
|
||||||
|
{
|
||||||
|
command_t *c, *p = NULL, *c2;
|
||||||
|
|
||||||
|
if ((!context) || (!name))
|
||||||
|
return ERROR_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
|
/* find command */
|
||||||
|
for (c = context->commands; c; c = c->next)
|
||||||
|
{
|
||||||
|
if (strcmp(name, c->name) == 0)
|
||||||
|
{
|
||||||
|
/* unlink command */
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
p->next = c->next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context->commands = c->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unregister children */
|
||||||
|
if (c->children)
|
||||||
|
{
|
||||||
|
for (c2 = c->children; c2; c2 = c2->next)
|
||||||
|
{
|
||||||
|
free(c2->name);
|
||||||
|
if (c2->help)
|
||||||
|
free(c2->help);
|
||||||
|
free(c2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* delete command */
|
||||||
|
free(c->name);
|
||||||
|
if (c->help)
|
||||||
|
free(c->help);
|
||||||
|
free(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remember the last command for unlinking */
|
||||||
|
p = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_line(char *line, char *words[], int max_words)
|
||||||
|
{
|
||||||
|
int nwords = 0;
|
||||||
|
char *p = line;
|
||||||
|
char *word_start = line;
|
||||||
|
int inquote = 0;
|
||||||
|
|
||||||
|
while (nwords < max_words - 1)
|
||||||
|
{
|
||||||
|
/* check if we reached
|
||||||
|
* a terminating NUL
|
||||||
|
* a matching closing quote character " or '
|
||||||
|
* we're inside a word but not a quote, and the current character is whitespace
|
||||||
|
*/
|
||||||
|
if (!*p || *p == inquote || (word_start && !inquote && isspace(*p)))
|
||||||
|
{
|
||||||
|
/* we're inside a word or quote, and reached its end*/
|
||||||
|
if (word_start)
|
||||||
|
{
|
||||||
|
int len = p - word_start;
|
||||||
|
|
||||||
|
/* copy the word */
|
||||||
|
memcpy(words[nwords] = malloc(len + 1), word_start, len);
|
||||||
|
/* add terminating NUL */
|
||||||
|
words[nwords++][len] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we're done parsing the line */
|
||||||
|
if (!*p)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* skip over trailing quote or whitespace*/
|
||||||
|
if (inquote || isspace(*p))
|
||||||
|
p++;
|
||||||
|
|
||||||
|
inquote = 0;
|
||||||
|
word_start = 0;
|
||||||
|
}
|
||||||
|
else if (*p == '"' || *p == '\'')
|
||||||
|
{
|
||||||
|
/* we've reached the beginning of a quote */
|
||||||
|
inquote = *p++;
|
||||||
|
word_start = p;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* we've reached the beginning of a new word */
|
||||||
|
if (!word_start)
|
||||||
|
word_start = p;
|
||||||
|
|
||||||
|
/* normal character, skip */
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nwords;
|
||||||
|
}
|
||||||
|
|
||||||
|
void command_print(command_context_t *context, char *format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
char *buffer = NULL;
|
||||||
|
int n, size = 0;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
|
||||||
|
/* process format string */
|
||||||
|
/* TODO: possible bug. va_list is undefined after the first call to vsnprintf */
|
||||||
|
while (!buffer || (n = vsnprintf(buffer, size, format, ap)) >= size)
|
||||||
|
{
|
||||||
|
/* increase buffer until it fits the whole string */
|
||||||
|
if (!(p = realloc(buffer, size += 4096)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
buffer = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vsnprintf failed */
|
||||||
|
if (n < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
p = buffer;
|
||||||
|
|
||||||
|
/* process lines in buffer */
|
||||||
|
do {
|
||||||
|
char *next = strchr(p, '\n');
|
||||||
|
|
||||||
|
if (next)
|
||||||
|
*next++ = 0;
|
||||||
|
|
||||||
|
if (context->output_handler)
|
||||||
|
context->output_handler(context, p);
|
||||||
|
|
||||||
|
p = next;
|
||||||
|
} while (p);
|
||||||
|
|
||||||
|
if (buffer)
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
int find_and_run_command(command_context_t *context, command_t *commands, char *words[], int num_words, int start_word)
|
||||||
|
{
|
||||||
|
command_t *c;
|
||||||
|
|
||||||
|
for (c = commands; c; c = c->next)
|
||||||
|
{
|
||||||
|
if (strncasecmp(c->name, words[start_word], c->unique_len))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strncasecmp(c->name, words[start_word], strlen(words[start_word])))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((c->mode == context->mode) || (c->mode == COMMAND_ANY))
|
||||||
|
{
|
||||||
|
if (!c->children)
|
||||||
|
{
|
||||||
|
if (!c->handler)
|
||||||
|
{
|
||||||
|
command_print(context, "No handler for command");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return c->handler(context, c->name, words + start_word + 1, num_words - start_word - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (start_word == num_words - 1)
|
||||||
|
{
|
||||||
|
command_print(context, "Incomplete command");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return find_and_run_command(context, c->children, words, num_words, start_word + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
command_print(context, "Command %s not found", words[start_word]);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int command_run_line(command_context_t *context, char *line)
|
||||||
|
{
|
||||||
|
int nwords;
|
||||||
|
char *words[128] = {0};
|
||||||
|
int retval;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if ((!context) || (!line))
|
||||||
|
return ERROR_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
|
/* skip preceding whitespace */
|
||||||
|
while (isspace(*line))
|
||||||
|
line++;
|
||||||
|
|
||||||
|
/* empty line, ignore */
|
||||||
|
if (!*line)
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
if (context->echo)
|
||||||
|
{
|
||||||
|
command_print(context, "%s", line);
|
||||||
|
}
|
||||||
|
|
||||||
|
nwords = parse_line(line, words, sizeof(words) / sizeof(words[0]));
|
||||||
|
|
||||||
|
if (nwords > 0)
|
||||||
|
retval = find_and_run_command(context, context->commands, words, nwords, 0);
|
||||||
|
else
|
||||||
|
return ERROR_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
|
for (i = 0; i < nwords; i++)
|
||||||
|
free(words[i]);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int command_run_file(command_context_t *context, FILE *file, enum command_mode mode)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
int old_command_mode;
|
||||||
|
char buffer[4096];
|
||||||
|
|
||||||
|
old_command_mode = context->mode;
|
||||||
|
context->mode = mode;
|
||||||
|
|
||||||
|
while (fgets(buffer, 4096, file))
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
char *cmd, *end;
|
||||||
|
|
||||||
|
/* stop processing line after a comment (#, !) or a LF, CR were encountered */
|
||||||
|
if ((p = strpbrk(buffer, "#!\r\n")))
|
||||||
|
*p = 0;
|
||||||
|
|
||||||
|
/* skip over leading whitespace */
|
||||||
|
cmd = buffer;
|
||||||
|
while (isspace(*cmd))
|
||||||
|
cmd++;
|
||||||
|
|
||||||
|
/* empty (all whitespace) line? */
|
||||||
|
if (!*cmd)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* search the end of the current line, ignore trailing whitespace */
|
||||||
|
for (p = end = cmd; *p; p++)
|
||||||
|
if (!isspace(*p))
|
||||||
|
end = p;
|
||||||
|
|
||||||
|
/* terminate end */
|
||||||
|
*++end = 0;
|
||||||
|
if (strcasecmp(cmd, "quit") == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* run line */
|
||||||
|
if (command_run_line(context, cmd) == ERROR_COMMAND_CLOSE_CONNECTION)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->mode = old_command_mode;
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void command_print_help_line(command_context_t* context, struct command_s *command, int indent)
|
||||||
|
{
|
||||||
|
command_t *c;
|
||||||
|
char indents[32] = {0};
|
||||||
|
char *help = "no help available";
|
||||||
|
char name_buf[64];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < indent; i+=2)
|
||||||
|
{
|
||||||
|
indents[i*2] = ' ';
|
||||||
|
indents[i*2+1] = '-';
|
||||||
|
}
|
||||||
|
indents[i*2] = 0;
|
||||||
|
|
||||||
|
if ((command->mode == COMMAND_EXEC) || (command->mode == COMMAND_ANY))
|
||||||
|
{
|
||||||
|
if (command->help)
|
||||||
|
help = command->help;
|
||||||
|
|
||||||
|
snprintf(name_buf, 64, command->name);
|
||||||
|
strncat(name_buf, indents, 64);
|
||||||
|
command_print(context, "%20s\t%s", name_buf, help);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command->children)
|
||||||
|
{
|
||||||
|
for (c = command->children; c; c = c->next)
|
||||||
|
{
|
||||||
|
command_print_help_line(context, c, indent + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int command_print_help(command_context_t* context, char* name, char** args, int argc)
|
||||||
|
{
|
||||||
|
command_t *c;
|
||||||
|
|
||||||
|
for (c = context->commands; c; c = c->next)
|
||||||
|
{
|
||||||
|
command_print_help_line(context, c, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, char* line), void *priv)
|
||||||
|
{
|
||||||
|
context->output_handler = output_handler;
|
||||||
|
context->output_handler_priv = priv;
|
||||||
|
}
|
||||||
|
|
||||||
|
command_context_t* copy_command_context(command_context_t* context)
|
||||||
|
{
|
||||||
|
command_context_t* copy_context = malloc(sizeof(command_context_t));
|
||||||
|
|
||||||
|
*copy_context = *context;
|
||||||
|
|
||||||
|
return copy_context;
|
||||||
|
}
|
||||||
|
|
||||||
|
int command_done(command_context_t *context)
|
||||||
|
{
|
||||||
|
free(context);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
command_context_t* command_init()
|
||||||
|
{
|
||||||
|
command_context_t* context = malloc(sizeof(command_context_t));
|
||||||
|
|
||||||
|
context->mode = COMMAND_EXEC;
|
||||||
|
context->commands = NULL;
|
||||||
|
context->current_target = 0;
|
||||||
|
context->echo = 0;
|
||||||
|
context->output_handler = NULL;
|
||||||
|
context->output_handler_priv = NULL;
|
||||||
|
|
||||||
|
register_command(context, NULL, "help", command_print_help,
|
||||||
|
COMMAND_EXEC, "display this help");
|
||||||
|
|
||||||
|
register_command(context, NULL, "sleep", handle_sleep_command,
|
||||||
|
COMMAND_ANY, "sleep for <n> milliseconds");
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sleep command sleeps for <n> miliseconds
|
||||||
|
* this is useful in target startup scripts
|
||||||
|
*/
|
||||||
|
int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
unsigned long duration = 0;
|
||||||
|
|
||||||
|
if (argc == 1)
|
||||||
|
{
|
||||||
|
duration = strtoul(args[0], NULL, 0);
|
||||||
|
usleep(duration * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef COMMAND_H
|
||||||
|
#define COMMAND_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
enum command_mode
|
||||||
|
{
|
||||||
|
COMMAND_EXEC,
|
||||||
|
COMMAND_CONFIG,
|
||||||
|
COMMAND_ANY,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct command_context_s
|
||||||
|
{
|
||||||
|
enum command_mode mode;
|
||||||
|
struct command_s *commands;
|
||||||
|
int current_target;
|
||||||
|
int echo;
|
||||||
|
int (*output_handler)(struct command_context_s *context, char* line);
|
||||||
|
void *output_handler_priv;
|
||||||
|
} command_context_t;
|
||||||
|
|
||||||
|
typedef struct command_s
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
struct command_s *parent;
|
||||||
|
struct command_s *children;
|
||||||
|
int (*handler)(struct command_context_s *context, char* name, char** args, int argc);
|
||||||
|
enum command_mode mode;
|
||||||
|
char *help;
|
||||||
|
int unique_len;
|
||||||
|
struct command_s *next;
|
||||||
|
} command_t;
|
||||||
|
|
||||||
|
extern command_t* register_command(command_context_t *context, command_t *parent, char *name, int (*handler)(struct command_context_s *context, char* name, char** args, int argc), enum command_mode mode, char *help);
|
||||||
|
extern int unregister_command(command_context_t *context, char *name);
|
||||||
|
extern void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, char* line), void *priv);
|
||||||
|
extern command_context_t* copy_command_context(command_context_t* context);
|
||||||
|
extern command_context_t* command_init();
|
||||||
|
extern int command_done(command_context_t *context);
|
||||||
|
extern void command_print(command_context_t *context, char *format, ...);
|
||||||
|
extern int command_run_line(command_context_t *context, char *line);
|
||||||
|
extern int command_run_file(command_context_t *context, FILE *file, enum command_mode mode);
|
||||||
|
|
||||||
|
|
||||||
|
#define ERROR_COMMAND_CLOSE_CONNECTION (-600)
|
||||||
|
|
||||||
|
#endif /* COMMAND_H */
|
|
@ -0,0 +1,131 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2004, 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "command.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
|
char* config_file_name;
|
||||||
|
|
||||||
|
static int help_flag;
|
||||||
|
|
||||||
|
static struct option long_options[] =
|
||||||
|
{
|
||||||
|
{"help", no_argument, &help_flag, 1},
|
||||||
|
|
||||||
|
{"debug", optional_argument, 0, 'd'},
|
||||||
|
{"file", required_argument, 0, 'f'},
|
||||||
|
{"log_output", required_argument, 0, 'l'},
|
||||||
|
|
||||||
|
{0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
int configuration_output_handler(struct command_context_s *context, char* line)
|
||||||
|
{
|
||||||
|
INFO(line);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_cmdline_args(struct command_context_s *cmd_ctx, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
char command_buffer[128];
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* getopt_long stores the option index here. */
|
||||||
|
int option_index = 0;
|
||||||
|
|
||||||
|
c = getopt_long(argc, argv, "hd::l:f:", long_options, &option_index);
|
||||||
|
|
||||||
|
/* Detect the end of the options. */
|
||||||
|
if (c == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 'h': /* --help | -h */
|
||||||
|
help_flag = 1;
|
||||||
|
break;
|
||||||
|
case 'f': /* --file | -f */
|
||||||
|
config_file_name = optarg;
|
||||||
|
break;
|
||||||
|
case 'd': /* --debug | -d */
|
||||||
|
if (optarg)
|
||||||
|
snprintf(command_buffer, 128, "debug_level %s", optarg);
|
||||||
|
else
|
||||||
|
snprintf(command_buffer, 128, "debug_level 3");
|
||||||
|
command_run_line(cmd_ctx, command_buffer);
|
||||||
|
break;
|
||||||
|
case 'l': /* --log_output | -l */
|
||||||
|
if (optarg)
|
||||||
|
{
|
||||||
|
snprintf(command_buffer, 128, "log_output %s", optarg);
|
||||||
|
command_run_line(cmd_ctx, command_buffer);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (help_flag)
|
||||||
|
{
|
||||||
|
printf("Open On-Chip Debugger\n(c) 2005 by Dominic Rath\n\n");
|
||||||
|
printf("--help | -h\tdisplay this help\n");
|
||||||
|
printf("--file | -f\tuse configuration file <name>\n");
|
||||||
|
printf("--debug | -d\tset debug level <0-3>\n");
|
||||||
|
printf("--log_output | -l\tredirect log output to file <name>\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_config_file(struct command_context_s *cmd_ctx)
|
||||||
|
{
|
||||||
|
FILE *config_file;
|
||||||
|
|
||||||
|
if (!config_file_name)
|
||||||
|
config_file_name = "openocd.cfg";
|
||||||
|
|
||||||
|
config_file = fopen(config_file_name, "r");
|
||||||
|
if (!config_file)
|
||||||
|
{
|
||||||
|
ERROR("couldn't open config file");
|
||||||
|
return ERROR_NO_CONFIG_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
command_run_file(cmd_ctx, config_file, COMMAND_CONFIG);
|
||||||
|
|
||||||
|
fclose(config_file);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2004, 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef CONFIGURATION_H
|
||||||
|
#define CONFIGURATION_H
|
||||||
|
|
||||||
|
#include "command.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
extern int parse_cmdline_args(struct command_context_s *cmd_ctx, int argc, char *argv[]);
|
||||||
|
extern int parse_config_file(struct command_context_s *cmd_ctx);
|
||||||
|
extern int configuration_output_handler(struct command_context_s *context, char* line);
|
||||||
|
|
||||||
|
extern char* config_file_name;
|
||||||
|
#endif /* CONFIGURATION_H */
|
|
@ -0,0 +1,237 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "interpreter.h"
|
||||||
|
|
||||||
|
#include "binarybuffer.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
var_t *variables = NULL;
|
||||||
|
|
||||||
|
int handle_var_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int handle_field_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int handle_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
|
||||||
|
int interpreter_register_commands(struct command_context_s *cmd_ctx)
|
||||||
|
{
|
||||||
|
register_command(cmd_ctx, NULL, "var", handle_var_command,
|
||||||
|
COMMAND_ANY, "allocate, display or delete variable <name> [num_fields|'del'] [size1] ...");
|
||||||
|
register_command(cmd_ctx, NULL, "field", handle_field_command,
|
||||||
|
COMMAND_ANY, "display/modify variable field <var> <field> [value|'flip']");
|
||||||
|
register_command(cmd_ctx, NULL, "script", handle_script_command,
|
||||||
|
COMMAND_ANY, "execute commands from <file>");
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
var_t* get_var_by_num(int num)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
var_t *var = variables;
|
||||||
|
|
||||||
|
if (var)
|
||||||
|
{
|
||||||
|
if (num == count)
|
||||||
|
return var;
|
||||||
|
while (var->next)
|
||||||
|
{
|
||||||
|
var = var->next;
|
||||||
|
count++;
|
||||||
|
if (num == count)
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
var_t* get_var_by_name(char *name)
|
||||||
|
{
|
||||||
|
var_t *var = variables;
|
||||||
|
|
||||||
|
if (var)
|
||||||
|
{
|
||||||
|
if (strcmp(var->name, name) == 0)
|
||||||
|
return var;
|
||||||
|
while (var->next)
|
||||||
|
{
|
||||||
|
var = var->next;
|
||||||
|
if (strcmp(var->name, name) == 0)
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
var_t* get_var_by_namenum(char *namenum)
|
||||||
|
{
|
||||||
|
if ((namenum[0] >= '0') && (namenum[0] <= '9'))
|
||||||
|
return get_var_by_num(strtol(namenum, NULL, 0));
|
||||||
|
else
|
||||||
|
return get_var_by_name(namenum);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int field_le_to_host(u8 *buffer, void *priv)
|
||||||
|
{
|
||||||
|
var_field_t *field = priv;
|
||||||
|
field->value = buf_get_u32(buffer, 0, field->num_bits);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle_var_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
var_t **last_var_p = &variables;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (argc >= 2)
|
||||||
|
{
|
||||||
|
while (*last_var_p)
|
||||||
|
{
|
||||||
|
if (strcmp((*last_var_p)->name, args[0]) == 0)
|
||||||
|
{
|
||||||
|
if (strcmp(args[1], "del") == 0)
|
||||||
|
{
|
||||||
|
var_t *next = (*last_var_p)->next;
|
||||||
|
free ((*last_var_p)->fields);
|
||||||
|
free (*last_var_p);
|
||||||
|
*last_var_p = next;
|
||||||
|
command_print(cmd_ctx, "variable %s deleted", args[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
command_print(cmd_ctx, "variable of that name already exists");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
last_var_p = &((*last_var_p)->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((args[0][0] >= 0) && (args[0][0] <= 9))
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "invalid name specified (first character may not be a number)");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
*last_var_p = malloc(sizeof(var_t));
|
||||||
|
(*last_var_p)->name = strdup(args[0]);
|
||||||
|
(*last_var_p)->num_fields = argc - 1;
|
||||||
|
(*last_var_p)->next = NULL;
|
||||||
|
|
||||||
|
(*last_var_p)->fields = malloc(sizeof(var_field_t) * (*last_var_p)->num_fields);
|
||||||
|
for (i = 0; i < (*last_var_p)->num_fields; i++)
|
||||||
|
{
|
||||||
|
(*last_var_p)->fields[i].num_bits = strtol(args[1+i], NULL, 0);
|
||||||
|
(*last_var_p)->fields[i].value = 0x0;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc == 1)
|
||||||
|
{
|
||||||
|
var_t *var = get_var_by_namenum(args[0]);
|
||||||
|
if (var)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
command_print(cmd_ctx, "%s (%i fields):", var->name, var->num_fields);
|
||||||
|
for (i = 0; i < (var->num_fields); i++)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "0x%x (/%i)", var->fields[i].value, var->fields[i].num_bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "variable %s doesn't exist", args[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc == 0)
|
||||||
|
{
|
||||||
|
var_t *var = variables;
|
||||||
|
int count = 0;
|
||||||
|
while (var)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "%i: %s (%i fields)", count, var->name, var->num_fields);
|
||||||
|
var = var->next;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle_field_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (argc < 2)
|
||||||
|
command_print(cmd_ctx, "usage: field <var> <field> [value|'flip']");
|
||||||
|
|
||||||
|
if (argc >= 2)
|
||||||
|
{
|
||||||
|
var_t *var = get_var_by_namenum(args[0]);
|
||||||
|
int field_num = strtol(args[1], NULL, 0);
|
||||||
|
if (!var)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "variable %s doesn't exist", args[0]);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
if (field_num >= var->num_fields)
|
||||||
|
command_print(cmd_ctx, "variable field %i is out of bounds (max. %i)", field_num, var->num_fields - 1);
|
||||||
|
if ((var) && (field_num < var->num_fields))
|
||||||
|
{
|
||||||
|
if (argc > 2)
|
||||||
|
{
|
||||||
|
if (strcmp(args[2], "flip") == 0)
|
||||||
|
var->fields[field_num].value = flip_u32(var->fields[field_num].value, var->fields[field_num].num_bits);
|
||||||
|
else
|
||||||
|
var->fields[field_num].value = strtoul(args[2], NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
command_print(cmd_ctx, "%s(%i): 0x%x (/%i)", var->name, field_num, var->fields[field_num].value, var->fields[field_num].num_bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
FILE *script_file;
|
||||||
|
int echo;
|
||||||
|
|
||||||
|
if (argc != 1)
|
||||||
|
command_print(cmd_ctx, "usage: script <file>");
|
||||||
|
|
||||||
|
script_file = fopen(args[0], "r");
|
||||||
|
if (!script_file)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "couldn't open script file %s", args[0]);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo = cmd_ctx->echo;
|
||||||
|
cmd_ctx->echo = 1;
|
||||||
|
|
||||||
|
command_run_file(cmd_ctx, script_file, COMMAND_EXEC);
|
||||||
|
|
||||||
|
cmd_ctx->echo = echo;
|
||||||
|
|
||||||
|
fclose(script_file);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef INTERPRETER_H
|
||||||
|
#define INTERPRETER_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "command.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
typedef struct var_field_s
|
||||||
|
{
|
||||||
|
int num_bits;
|
||||||
|
u32 value;
|
||||||
|
} var_field_t;
|
||||||
|
|
||||||
|
typedef struct var_s
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
int num_fields;
|
||||||
|
var_field_t *fields;
|
||||||
|
struct var_s *next;
|
||||||
|
} var_t;
|
||||||
|
|
||||||
|
extern var_t *variables;
|
||||||
|
|
||||||
|
extern int field_le_to_host(u8 *buffer, void *priv);
|
||||||
|
|
||||||
|
extern var_t* get_var_by_namenum(char *namenum);
|
||||||
|
extern int interpreter_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
|
||||||
|
#endif /* INTERPRETER_H */
|
|
@ -0,0 +1,134 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "log.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
int debug_level = -1;
|
||||||
|
|
||||||
|
static FILE* log_output;
|
||||||
|
|
||||||
|
static char *log_strings[4] =
|
||||||
|
{
|
||||||
|
"Error: ",
|
||||||
|
"Warning:",
|
||||||
|
"Info: ",
|
||||||
|
"Debug: ",
|
||||||
|
};
|
||||||
|
|
||||||
|
void log_printf(enum log_levels level, const char *file, int line, const char *function, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
char buffer[512];
|
||||||
|
|
||||||
|
if (level > debug_level)
|
||||||
|
return;
|
||||||
|
|
||||||
|
va_start(args, format);
|
||||||
|
vsnprintf(buffer, 512, format, args);
|
||||||
|
|
||||||
|
fprintf(log_output, "%s %s:%d %s(): %s\n", log_strings[level], file, line, function, buffer);
|
||||||
|
fflush(log_output);
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void short_log_printf(enum log_levels level, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
char buffer[512];
|
||||||
|
|
||||||
|
if (level > debug_level)
|
||||||
|
return;
|
||||||
|
|
||||||
|
va_start(args, format);
|
||||||
|
vsnprintf(buffer, 512, format, args);
|
||||||
|
|
||||||
|
fprintf(log_output, "%s %s\n", log_strings[level], buffer);
|
||||||
|
fflush(log_output);
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* change the current debug level on the fly
|
||||||
|
* 0: only ERRORS
|
||||||
|
* 1: + WARNINGS
|
||||||
|
* 2: + INFORMATIONAL MSGS
|
||||||
|
* 3: + DEBUG MSGS
|
||||||
|
*/
|
||||||
|
int handle_debug_level_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
if (argc == 0)
|
||||||
|
command_print(cmd_ctx, "debug_level: %i", debug_level);
|
||||||
|
|
||||||
|
if (argc > 0)
|
||||||
|
debug_level = strtoul(args[0], NULL, 0);
|
||||||
|
|
||||||
|
if (debug_level < 0)
|
||||||
|
debug_level = 0;
|
||||||
|
|
||||||
|
if (debug_level > 3)
|
||||||
|
debug_level = 3;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle_log_output_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
if (argc == 1)
|
||||||
|
{
|
||||||
|
FILE* file = fopen(args[0], "w");
|
||||||
|
|
||||||
|
if (file)
|
||||||
|
{
|
||||||
|
log_output = file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int log_register_commands(struct command_context_s *cmd_ctx)
|
||||||
|
{
|
||||||
|
register_command(cmd_ctx, NULL, "log_output", handle_log_output_command,
|
||||||
|
COMMAND_ANY, "redirect logging to <file> (default: stderr)");
|
||||||
|
register_command(cmd_ctx, NULL, "debug_level", handle_debug_level_command,
|
||||||
|
COMMAND_ANY, "adjust debug level <0-3>");
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int log_init(struct command_context_s *cmd_ctx)
|
||||||
|
{
|
||||||
|
/* set defaults for daemon configuration, if not set by cmdline or cfgfile */
|
||||||
|
if (debug_level == -1)
|
||||||
|
debug_level = LOG_INFO;
|
||||||
|
|
||||||
|
if (log_output == NULL)
|
||||||
|
{
|
||||||
|
log_output = stderr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef ERROR_H
|
||||||
|
#define ERROR_H
|
||||||
|
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
/* logging priorities
|
||||||
|
* LOG_ERROR - fatal errors, that are likely to cause program abort
|
||||||
|
* LOG_WARNING - non-fatal errors, that may be resolved later
|
||||||
|
* LOG_INFO - state information, etc.
|
||||||
|
* LOG_DEBUG - debug statements, execution trace
|
||||||
|
*/
|
||||||
|
enum log_levels
|
||||||
|
{
|
||||||
|
LOG_ERROR = 0,
|
||||||
|
LOG_WARNING = 1,
|
||||||
|
LOG_INFO = 2,
|
||||||
|
LOG_DEBUG = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void log_printf(enum log_levels level, const char *file, int line,
|
||||||
|
const char *function, const char *format, ...);
|
||||||
|
extern int log_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
extern int log_init(struct command_context_s *cmd_ctx);
|
||||||
|
|
||||||
|
extern int debug_level;
|
||||||
|
|
||||||
|
#define DEBUG(expr ...) \
|
||||||
|
do { \
|
||||||
|
log_printf (LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, expr); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define INFO(expr ...) \
|
||||||
|
do { \
|
||||||
|
log_printf (LOG_INFO, __FILE__, __LINE__, __FUNCTION__, expr); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define WARNING(expr ...) \
|
||||||
|
do { \
|
||||||
|
log_printf (LOG_WARNING, __FILE__, __LINE__, __FUNCTION__, expr); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define ERROR(expr ...) \
|
||||||
|
do { \
|
||||||
|
log_printf (LOG_ERROR, __FILE__, __LINE__, __FUNCTION__, expr); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define SDEBUG(expr ...) \
|
||||||
|
do { \
|
||||||
|
short_log_printf (LOG_DEBUG, expr); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define SINFO(expr ...) \
|
||||||
|
do { \
|
||||||
|
short_log_printf (LOG_INFO, expr); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define SWARNING(expr ...) \
|
||||||
|
do { \
|
||||||
|
short_log_printf (LOG_WARNING, expr); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define SERROR(expr ...) \
|
||||||
|
do { \
|
||||||
|
short_log_printf (LOG_ERROR, expr); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/* general failures
|
||||||
|
* error codes < 100
|
||||||
|
*/
|
||||||
|
#define ERROR_OK (0)
|
||||||
|
#define ERROR_INVALID_ARGUMENTS (-1)
|
||||||
|
#define ERROR_NO_CONFIG_FILE (-2)
|
||||||
|
#define ERROR_BUF_TOO_SMALL (-3)
|
||||||
|
|
||||||
|
#endif /* ERROR_H */
|
|
@ -0,0 +1,82 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2006 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "time_support.h"
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y);
|
||||||
|
int timeval_add(struct timeval *result, struct timeval *x, struct timeval *y);
|
||||||
|
int timeval_add_time(struct timeval *result, int sec, int usec);
|
||||||
|
|
||||||
|
/* calculate difference between two struct timeval values */
|
||||||
|
int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
|
||||||
|
{
|
||||||
|
if (x->tv_usec < y->tv_usec)
|
||||||
|
{
|
||||||
|
int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
|
||||||
|
y->tv_usec -= 1000000 * nsec;
|
||||||
|
y->tv_sec += nsec;
|
||||||
|
}
|
||||||
|
if (x->tv_usec - y->tv_usec > 1000000) {
|
||||||
|
int nsec = (x->tv_usec - y->tv_usec) / 1000000;
|
||||||
|
y->tv_usec += 1000000 * nsec;
|
||||||
|
y->tv_sec -= nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
result->tv_sec = x->tv_sec - y->tv_sec;
|
||||||
|
result->tv_usec = x->tv_usec - y->tv_usec;
|
||||||
|
|
||||||
|
/* Return 1 if result is negative. */
|
||||||
|
return x->tv_sec < y->tv_sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add two struct timeval values */
|
||||||
|
int timeval_add(struct timeval *result, struct timeval *x, struct timeval *y)
|
||||||
|
{
|
||||||
|
result->tv_sec = x->tv_sec + y->tv_sec;
|
||||||
|
|
||||||
|
result->tv_usec = x->tv_usec + y->tv_usec;
|
||||||
|
|
||||||
|
while (result->tv_usec > 1000000)
|
||||||
|
{
|
||||||
|
result->tv_usec -= 1000000;
|
||||||
|
result->tv_sec++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int timeval_add_time(struct timeval *result, int sec, int usec)
|
||||||
|
{
|
||||||
|
result->tv_sec += sec;
|
||||||
|
result->tv_usec += usec;
|
||||||
|
|
||||||
|
while (result->tv_usec > 1000000)
|
||||||
|
{
|
||||||
|
result->tv_usec -= 1000000;
|
||||||
|
result->tv_sec++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2006 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef TIME_SUPPORT_H
|
||||||
|
#define TIME_SUPPORT_H
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
extern int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y);
|
||||||
|
extern int timeval_add(struct timeval *result, struct timeval *x, struct timeval *y);
|
||||||
|
extern int timeval_add_time(struct timeval *result, int sec, int usec);
|
||||||
|
|
||||||
|
#endif /* TIME_SUPPORT_H */
|
|
@ -0,0 +1,36 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2004, 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TYPES_H
|
||||||
|
#define TYPES_H
|
||||||
|
|
||||||
|
#ifndef u8
|
||||||
|
typedef unsigned char u8;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef u16
|
||||||
|
typedef unsigned short u16;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef u32
|
||||||
|
typedef unsigned int u32;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* TYPES_H */
|
|
@ -0,0 +1,50 @@
|
||||||
|
|
||||||
|
if FTD2XXDIR
|
||||||
|
FTD2XXINC = -I@WITH_FTD2XX@/
|
||||||
|
else
|
||||||
|
FTD2XXINC =
|
||||||
|
endif
|
||||||
|
|
||||||
|
INCLUDES = -I$(top_srcdir)/src/helper $(FTD2XXINC) $(all_includes)
|
||||||
|
METASOURCES = AUTO
|
||||||
|
noinst_LIBRARIES = libjtag.a
|
||||||
|
|
||||||
|
if BITBANG
|
||||||
|
BITBANGFILES = bitbang.c
|
||||||
|
else
|
||||||
|
BITBANGFILES =
|
||||||
|
endif
|
||||||
|
|
||||||
|
if PARPORT
|
||||||
|
PARPORTFILES = parport.c
|
||||||
|
else
|
||||||
|
PARPORTFILES =
|
||||||
|
endif
|
||||||
|
|
||||||
|
if FTDI2232
|
||||||
|
FTDI2232FILES = ftdi2232.c
|
||||||
|
else
|
||||||
|
FTDI2232FILES =
|
||||||
|
endif
|
||||||
|
|
||||||
|
if FTD2XX
|
||||||
|
FTD2XXFILES = ftd2xx.c
|
||||||
|
else
|
||||||
|
FTD2XXFILES =
|
||||||
|
endif
|
||||||
|
|
||||||
|
if AMTJTAGACCEL
|
||||||
|
AMTJTAGACCELFILES = amt_jtagaccel.c
|
||||||
|
else
|
||||||
|
AMTJTAGACCELFILES =
|
||||||
|
endif
|
||||||
|
|
||||||
|
if EP93XX
|
||||||
|
EP93XXFILES = ep93xx.c
|
||||||
|
else
|
||||||
|
EP93XXFILES =
|
||||||
|
endif
|
||||||
|
|
||||||
|
libjtag_a_SOURCES = jtag.c $(BITBANGFILES) $(PARPORTFILES) $(FTDI2232FILES) $(FTD2XXFILES) $(AMTJTAGACCELFILES) $(EP93XXFILES)
|
||||||
|
|
||||||
|
noinst_HEADERS = bitbang.h jtag.h
|
|
@ -0,0 +1,510 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "config.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "jtag.h"
|
||||||
|
|
||||||
|
/* system includes */
|
||||||
|
#include <sys/io.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#if PARPORT_USE_PPDEV == 1
|
||||||
|
#include <linux/parport.h>
|
||||||
|
#include <linux/ppdev.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* configuration */
|
||||||
|
unsigned long amt_jtagaccel_port;
|
||||||
|
|
||||||
|
/* interface variables
|
||||||
|
*/
|
||||||
|
static u8 aw_control_rst = 0x00;
|
||||||
|
static u8 aw_control_fsm = 0x10;
|
||||||
|
static u8 aw_control_baudrate = 0x20;
|
||||||
|
|
||||||
|
static int rtck_enabled = 0;
|
||||||
|
|
||||||
|
#if PARPORT_USE_PPDEV == 1
|
||||||
|
static int device_handle;
|
||||||
|
int addr_mode = IEEE1284_MODE_EPP | IEEE1284_ADDR ;
|
||||||
|
int data_mode = IEEE1284_MODE_EPP | IEEE1284_DATA ;
|
||||||
|
#define AMT_AW(val) do { ioctl(device_handle, PPSETMODE, &addr_mode); write(device_handle, &val, 1); } while (0)
|
||||||
|
#define AMT_AR(val) do { ioctl(device_handle, PPSETMODE, &addr_mode); read(device_handle, &val, 1); } while (0)
|
||||||
|
#define AMT_DW(val) do { ioctl(device_handle, PPSETMODE, &data_mode); write(device_handle, &val, 1); } while (0)
|
||||||
|
#define AMT_DR(val) do { ioctl(device_handle, PPSETMODE, &data_mode); read(device_handle, &val, 1); } while (0)
|
||||||
|
#else
|
||||||
|
#define AMT_AW(val) do { outb(val, amt_jtagaccel_port + 3); } while (0)
|
||||||
|
#define AMT_AR(val) do { val = inb(amt_jtagaccel_port + 3); } while (0)
|
||||||
|
#define AMT_DW(val) do { outb(val, amt_jtagaccel_port + 4); } while (0)
|
||||||
|
#define AMT_DR(val) do { val = inb(amt_jtagaccel_port + 4); } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int amt_jtagaccel_execute_queue(void);
|
||||||
|
int amt_jtagaccel_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
int amt_jtagaccel_speed(int speed);
|
||||||
|
int amt_jtagaccel_init(void);
|
||||||
|
int amt_jtagaccel_quit(void);
|
||||||
|
|
||||||
|
int amt_jtagaccel_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int amt_jtagaccel_handle_rtck_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
|
||||||
|
/* tap_move[i][j]: tap movement command to go from state i to state j
|
||||||
|
* 0: Test-Logic-Reset
|
||||||
|
* 1: Run-Test/Idle
|
||||||
|
* 2: Shift-DR
|
||||||
|
* 3: Pause-DR
|
||||||
|
* 4: Shift-IR
|
||||||
|
* 5: Pause-IR
|
||||||
|
*/
|
||||||
|
u8 amt_jtagaccel_tap_move[6][6][2] =
|
||||||
|
{
|
||||||
|
/* TLR RTI SD PD SI PI */
|
||||||
|
{{0x1f, 0x00}, {0x0f, 0x00}, {0x8a, 0x04}, {0x0a, 0x00}, {0x06, 0x00}, {0x96, 0x00}}, /* TLR */
|
||||||
|
{{0x1f, 0x00}, {0x00, 0x00}, {0x85, 0x08}, {0x05, 0x00}, {0x8b, 0x08}, {0x0b, 0x00}}, /* RTI */
|
||||||
|
{{0x1f, 0x00}, {0x0d, 0x00}, {0x00, 0x00}, {0x01, 0x00}, {0x8f, 0x09}, {0x8f, 0x01}}, /* SD */
|
||||||
|
{{0x1f, 0x00}, {0x0c, 0x00}, {0x08, 0x00}, {0x00, 0x00}, {0x8f, 0x09}, {0x8f, 0x01}}, /* PD */
|
||||||
|
{{0x1f, 0x00}, {0x0d, 0x00}, {0x07, 0x00}, {0x97, 0x00}, {0x00, 0x00}, {0x01, 0x00}}, /* SI */
|
||||||
|
{{0x1f, 0x00}, {0x0c, 0x00}, {0x07, 0x00}, {0x97, 0x00}, {0x08, 0x00}, {0x00, 0x00}}, /* PI */
|
||||||
|
};
|
||||||
|
|
||||||
|
jtag_interface_t amt_jtagaccel_interface =
|
||||||
|
{
|
||||||
|
.name = "amt_jtagaccel",
|
||||||
|
|
||||||
|
.execute_queue = amt_jtagaccel_execute_queue,
|
||||||
|
|
||||||
|
.support_statemove = 0,
|
||||||
|
|
||||||
|
.speed = amt_jtagaccel_speed,
|
||||||
|
.register_commands = amt_jtagaccel_register_commands,
|
||||||
|
.init = amt_jtagaccel_init,
|
||||||
|
.quit = amt_jtagaccel_quit,
|
||||||
|
};
|
||||||
|
|
||||||
|
int amt_jtagaccel_register_commands(struct command_context_s *cmd_ctx)
|
||||||
|
{
|
||||||
|
register_command(cmd_ctx, NULL, "parport_port", amt_jtagaccel_handle_parport_port_command,
|
||||||
|
COMMAND_CONFIG, NULL);
|
||||||
|
register_command(cmd_ctx, NULL, "rtck", amt_jtagaccel_handle_rtck_command,
|
||||||
|
COMMAND_CONFIG, NULL);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void amt_jtagaccel_reset(int trst, int srst)
|
||||||
|
{
|
||||||
|
if (trst == 1)
|
||||||
|
aw_control_rst |= 0x4;
|
||||||
|
else if (trst == 0)
|
||||||
|
aw_control_rst &= ~0x4;
|
||||||
|
|
||||||
|
if (srst == 1)
|
||||||
|
aw_control_rst |= 0x1;
|
||||||
|
else if (srst == 0)
|
||||||
|
aw_control_rst &= ~0x1;
|
||||||
|
|
||||||
|
AMT_AW(aw_control_rst);
|
||||||
|
}
|
||||||
|
|
||||||
|
int amt_jtagaccel_speed(int speed)
|
||||||
|
{
|
||||||
|
aw_control_baudrate &= 0xf0;
|
||||||
|
aw_control_baudrate |= speed & 0x0f;
|
||||||
|
AMT_AW(aw_control_baudrate);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void amt_jtagaccel_end_state(state)
|
||||||
|
{
|
||||||
|
if (tap_move_map[state] != -1)
|
||||||
|
end_state = state;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR("BUG: %i is not a valid end state", state);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void amt_wait_scan_busy()
|
||||||
|
{
|
||||||
|
int timeout = 4096;
|
||||||
|
u8 ar_status;
|
||||||
|
|
||||||
|
AMT_AR(ar_status);
|
||||||
|
while (((ar_status) & 0x80) && (timeout-- > 0))
|
||||||
|
AMT_AR(ar_status);
|
||||||
|
|
||||||
|
if (ar_status & 0x80)
|
||||||
|
{
|
||||||
|
ERROR("amt_jtagaccel timed out while waiting for end of scan, rtck was %s", (rtck_enabled) ? "enabled" : "disabled");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void amt_jtagaccel_state_move(void)
|
||||||
|
{
|
||||||
|
u8 aw_scan_tms_5;
|
||||||
|
u8 tms_scan[2];
|
||||||
|
|
||||||
|
tms_scan[0] = amt_jtagaccel_tap_move[tap_move_map[cur_state]][tap_move_map[end_state]][0];
|
||||||
|
tms_scan[1] = amt_jtagaccel_tap_move[tap_move_map[cur_state]][tap_move_map[end_state]][1];
|
||||||
|
|
||||||
|
aw_scan_tms_5 = 0x40 | (tms_scan[0] & 0x1f);
|
||||||
|
AMT_AW(aw_scan_tms_5);
|
||||||
|
if (jtag_speed > 3 || rtck_enabled)
|
||||||
|
amt_wait_scan_busy();
|
||||||
|
|
||||||
|
if (tms_scan[0] & 0x80)
|
||||||
|
{
|
||||||
|
aw_scan_tms_5 = 0x40 | (tms_scan[1] & 0x1f);
|
||||||
|
AMT_AW(aw_scan_tms_5);
|
||||||
|
if (jtag_speed > 3 || rtck_enabled)
|
||||||
|
amt_wait_scan_busy();
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_state = end_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void amt_jtagaccel_runtest(int num_cycles)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
u8 aw_scan_tms_5;
|
||||||
|
u8 aw_scan_tms_1to4;
|
||||||
|
|
||||||
|
enum tap_state saved_end_state = end_state;
|
||||||
|
|
||||||
|
/* only do a state_move when we're not already in RTI */
|
||||||
|
if (cur_state != TAP_RTI)
|
||||||
|
{
|
||||||
|
amt_jtagaccel_end_state(TAP_RTI);
|
||||||
|
amt_jtagaccel_state_move();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (num_cycles - i >= 5)
|
||||||
|
{
|
||||||
|
aw_scan_tms_5 = 0x40;
|
||||||
|
AMT_AW(aw_scan_tms_5);
|
||||||
|
i += 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_cycles - i > 0)
|
||||||
|
{
|
||||||
|
aw_scan_tms_1to4 = 0x80 | ((num_cycles - i - 1) & 0x3) << 4;
|
||||||
|
AMT_AW(aw_scan_tms_1to4);
|
||||||
|
}
|
||||||
|
|
||||||
|
amt_jtagaccel_end_state(saved_end_state);
|
||||||
|
if (cur_state != end_state)
|
||||||
|
amt_jtagaccel_state_move();
|
||||||
|
}
|
||||||
|
|
||||||
|
void amt_jtagaccel_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
|
||||||
|
{
|
||||||
|
int bits_left = scan_size;
|
||||||
|
int bit_count = 0;
|
||||||
|
enum tap_state saved_end_state = end_state;
|
||||||
|
u8 aw_tdi_option;
|
||||||
|
u8 dw_tdi_scan;
|
||||||
|
u8 dr_tdo;
|
||||||
|
u8 aw_tms_scan;
|
||||||
|
u8 tms_scan[2];
|
||||||
|
|
||||||
|
if (ir_scan)
|
||||||
|
amt_jtagaccel_end_state(TAP_SI);
|
||||||
|
else
|
||||||
|
amt_jtagaccel_end_state(TAP_SD);
|
||||||
|
|
||||||
|
amt_jtagaccel_state_move();
|
||||||
|
amt_jtagaccel_end_state(saved_end_state);
|
||||||
|
|
||||||
|
/* handle unaligned bits at the beginning */
|
||||||
|
if ((scan_size - 1) % 8)
|
||||||
|
{
|
||||||
|
aw_tdi_option = 0x30 | (((scan_size - 1) % 8) - 1);
|
||||||
|
AMT_AW(aw_tdi_option);
|
||||||
|
|
||||||
|
dw_tdi_scan = buf_get_u32(buffer, bit_count, (scan_size - 1) % 8) & 0xff;
|
||||||
|
AMT_DW(dw_tdi_scan);
|
||||||
|
if (jtag_speed > 3 || rtck_enabled)
|
||||||
|
amt_wait_scan_busy();
|
||||||
|
|
||||||
|
if ((type == SCAN_IN) || (type == SCAN_IO))
|
||||||
|
{
|
||||||
|
AMT_DR(dr_tdo);
|
||||||
|
dr_tdo = dr_tdo >> (8 - ((scan_size - 1) % 8));
|
||||||
|
buf_set_u32(buffer, bit_count, (scan_size - 1) % 8, dr_tdo);
|
||||||
|
}
|
||||||
|
|
||||||
|
bit_count += (scan_size - 1) % 8;
|
||||||
|
bits_left -= (scan_size - 1) % 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (bits_left - 1 >= 8)
|
||||||
|
{
|
||||||
|
dw_tdi_scan = buf_get_u32(buffer, bit_count, 8) & 0xff;
|
||||||
|
AMT_DW(dw_tdi_scan);
|
||||||
|
if (jtag_speed > 3 || rtck_enabled)
|
||||||
|
amt_wait_scan_busy();
|
||||||
|
|
||||||
|
if ((type == SCAN_IN) || (type == SCAN_IO))
|
||||||
|
{
|
||||||
|
AMT_DR(dr_tdo);
|
||||||
|
buf_set_u32(buffer, bit_count, 8, dr_tdo);
|
||||||
|
}
|
||||||
|
|
||||||
|
bit_count += 8;
|
||||||
|
bits_left -= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
tms_scan[0] = amt_jtagaccel_tap_move[tap_move_map[cur_state]][tap_move_map[end_state]][0];
|
||||||
|
tms_scan[1] = amt_jtagaccel_tap_move[tap_move_map[cur_state]][tap_move_map[end_state]][1];
|
||||||
|
aw_tms_scan = 0x40 | (tms_scan[0] & 0x1f) | (buf_get_u32(buffer, bit_count, 1) << 5);
|
||||||
|
AMT_AW(aw_tms_scan);
|
||||||
|
if (jtag_speed > 3 || rtck_enabled)
|
||||||
|
amt_wait_scan_busy();
|
||||||
|
|
||||||
|
if ((type == SCAN_IN) || (type == SCAN_IO))
|
||||||
|
{
|
||||||
|
AMT_DR(dr_tdo);
|
||||||
|
dr_tdo = dr_tdo >> 7;
|
||||||
|
buf_set_u32(buffer, bit_count, 1, dr_tdo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tms_scan[0] & 0x80)
|
||||||
|
{
|
||||||
|
aw_tms_scan = 0x40 | (tms_scan[1] & 0x1f);
|
||||||
|
AMT_AW(aw_tms_scan);
|
||||||
|
if (jtag_speed > 3 || rtck_enabled)
|
||||||
|
amt_wait_scan_busy();
|
||||||
|
}
|
||||||
|
cur_state = end_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
int amt_jtagaccel_execute_queue(void)
|
||||||
|
{
|
||||||
|
jtag_command_t *cmd = jtag_command_queue; /* currently processed command */
|
||||||
|
int scan_size;
|
||||||
|
enum scan_type type;
|
||||||
|
u8 *buffer;
|
||||||
|
|
||||||
|
while (cmd)
|
||||||
|
{
|
||||||
|
switch (cmd->type)
|
||||||
|
{
|
||||||
|
case JTAG_END_STATE:
|
||||||
|
#ifdef _DEBUG_JTAG_IO_
|
||||||
|
DEBUG("end_state: %i", cmd->cmd.end_state->end_state);
|
||||||
|
#endif
|
||||||
|
if (cmd->cmd.end_state->end_state != -1)
|
||||||
|
amt_jtagaccel_end_state(cmd->cmd.end_state->end_state);
|
||||||
|
break;
|
||||||
|
case JTAG_RESET:
|
||||||
|
#ifdef _DEBUG_JTAG_IO_
|
||||||
|
DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);
|
||||||
|
#endif
|
||||||
|
if (cmd->cmd.reset->trst == 1)
|
||||||
|
{
|
||||||
|
cur_state = TAP_TLR;
|
||||||
|
}
|
||||||
|
amt_jtagaccel_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
|
||||||
|
break;
|
||||||
|
case JTAG_RUNTEST:
|
||||||
|
#ifdef _DEBUG_JTAG_IO_
|
||||||
|
DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state);
|
||||||
|
#endif
|
||||||
|
if (cmd->cmd.runtest->end_state != -1)
|
||||||
|
amt_jtagaccel_end_state(cmd->cmd.runtest->end_state);
|
||||||
|
amt_jtagaccel_runtest(cmd->cmd.runtest->num_cycles);
|
||||||
|
break;
|
||||||
|
case JTAG_STATEMOVE:
|
||||||
|
#ifdef _DEBUG_JTAG_IO_
|
||||||
|
DEBUG("statemove end in %i", cmd->cmd.statemove->end_state);
|
||||||
|
#endif
|
||||||
|
if (cmd->cmd.statemove->end_state != -1)
|
||||||
|
amt_jtagaccel_end_state(cmd->cmd.statemove->end_state);
|
||||||
|
amt_jtagaccel_state_move();
|
||||||
|
break;
|
||||||
|
case JTAG_SCAN:
|
||||||
|
#ifdef _DEBUG_JTAG_IO_
|
||||||
|
DEBUG("scan end in %i", cmd->cmd.scan->end_state);
|
||||||
|
#endif
|
||||||
|
if (cmd->cmd.scan->end_state != -1)
|
||||||
|
amt_jtagaccel_end_state(cmd->cmd.scan->end_state);
|
||||||
|
scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
|
||||||
|
type = jtag_scan_type(cmd->cmd.scan);
|
||||||
|
amt_jtagaccel_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
|
||||||
|
if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
|
||||||
|
return ERROR_JTAG_QUEUE_FAILED;
|
||||||
|
if (buffer)
|
||||||
|
free(buffer);
|
||||||
|
break;
|
||||||
|
case JTAG_SLEEP:
|
||||||
|
#ifdef _DEBUG_JTAG_IO_
|
||||||
|
DEBUG("sleep", cmd->cmd.sleep->us);
|
||||||
|
#endif
|
||||||
|
jtag_sleep(cmd->cmd.sleep->us);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("BUG: unknown JTAG command type encountered");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
cmd = cmd->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int amt_jtagaccel_init(void)
|
||||||
|
{
|
||||||
|
#if PARPORT_USE_PPDEV == 1
|
||||||
|
char buffer[256];
|
||||||
|
int i = 0;
|
||||||
|
u8 control_port;
|
||||||
|
#else
|
||||||
|
u8 status_port;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if PARPORT_USE_PPDEV == 1
|
||||||
|
if (device_handle > 0)
|
||||||
|
{
|
||||||
|
ERROR("device is already opened");
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buffer, 256, "/dev/parport%d", amt_jtagaccel_port);
|
||||||
|
device_handle = open(buffer, O_RDWR);
|
||||||
|
|
||||||
|
if (device_handle < 0)
|
||||||
|
{
|
||||||
|
ERROR("cannot open device. check it exists and that user read and write rights are set");
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = ioctl(device_handle, PPCLAIM);
|
||||||
|
if (i < 0)
|
||||||
|
{
|
||||||
|
ERROR("cannot claim device");
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = IEEE1284_MODE_EPP;
|
||||||
|
i = ioctl(device_handle, PPSETMODE, & i);
|
||||||
|
if (i < 0)
|
||||||
|
{
|
||||||
|
ERROR(" cannot set compatible mode to device");
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
control_port = 0x00;
|
||||||
|
i = ioctl(device_handle, PPWCONTROL, &control_port);
|
||||||
|
|
||||||
|
control_port = 0x04;
|
||||||
|
i = ioctl(device_handle, PPWCONTROL, &control_port);
|
||||||
|
|
||||||
|
#else
|
||||||
|
if (amt_jtagaccel_port == 0)
|
||||||
|
{
|
||||||
|
amt_jtagaccel_port = 0x378;
|
||||||
|
WARNING("No parport port specified, using default '0x378' (LPT1)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioperm(amt_jtagaccel_port, 5, 1) != 0) {
|
||||||
|
ERROR("missing privileges for direct i/o");
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* prepare epp port */
|
||||||
|
/* clear timeout */
|
||||||
|
status_port = inb(amt_jtagaccel_port + 1);
|
||||||
|
outb(status_port | 0x1, amt_jtagaccel_port + 1);
|
||||||
|
|
||||||
|
/* reset epp port */
|
||||||
|
outb(0x00, amt_jtagaccel_port + 2);
|
||||||
|
outb(0x04, amt_jtagaccel_port + 2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* enable JTAG port */
|
||||||
|
aw_control_fsm |= 0x04;
|
||||||
|
AMT_AW(aw_control_fsm);
|
||||||
|
|
||||||
|
amt_jtagaccel_speed(jtag_speed);
|
||||||
|
|
||||||
|
if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
|
||||||
|
aw_control_rst &= ~0x8;
|
||||||
|
else
|
||||||
|
aw_control_rst |= 0x8;
|
||||||
|
|
||||||
|
if (jtag_reset_config & RESET_SRST_PUSH_PULL)
|
||||||
|
aw_control_rst &= ~0x2;
|
||||||
|
else
|
||||||
|
aw_control_rst |= 0x2;
|
||||||
|
|
||||||
|
amt_jtagaccel_reset(0, 0);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int amt_jtagaccel_quit(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int amt_jtagaccel_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
if (argc == 0)
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
/* only if the port wasn't overwritten by cmdline */
|
||||||
|
if (amt_jtagaccel_port == 0)
|
||||||
|
amt_jtagaccel_port = strtoul(args[0], NULL, 0);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int amt_jtagaccel_handle_rtck_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
if (argc == 0)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "amt_jtagaccel RTCK feature %s", (rtck_enabled) ? "enabled" : "disabled");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (strcmp(args[0], "enabled") == 0)
|
||||||
|
{
|
||||||
|
rtck_enabled = 1;
|
||||||
|
|
||||||
|
/* set RTCK enable bit */
|
||||||
|
aw_control_fsm |= 0x02;
|
||||||
|
AMT_AW(aw_control_fsm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
|
@ -0,0 +1,219 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "bitbang.h"
|
||||||
|
|
||||||
|
/* project specific includes */
|
||||||
|
#include "log.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "jtag.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
/* system includes */
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
bitbang_interface_t *bitbang_interface;
|
||||||
|
|
||||||
|
int bitbang_execute_queue(void);
|
||||||
|
|
||||||
|
void bitbang_end_state(enum tap_state state)
|
||||||
|
{
|
||||||
|
if (tap_move_map[state] != -1)
|
||||||
|
end_state = state;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR("BUG: %i is not a valid end state", state);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitbang_state_move(void) {
|
||||||
|
|
||||||
|
int i=0, tms=0;
|
||||||
|
u8 tms_scan = TAP_MOVE(cur_state, end_state);
|
||||||
|
|
||||||
|
for (i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
tms = (tms_scan >> i) & 1;
|
||||||
|
bitbang_interface->write(0, tms, 0);
|
||||||
|
bitbang_interface->write(1, tms, 0);
|
||||||
|
}
|
||||||
|
bitbang_interface->write(0, tms, 0);
|
||||||
|
|
||||||
|
cur_state = end_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitbang_runtest(int num_cycles)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
enum tap_state saved_end_state = end_state;
|
||||||
|
|
||||||
|
/* only do a state_move when we're not already in RTI */
|
||||||
|
if (cur_state != TAP_RTI)
|
||||||
|
{
|
||||||
|
bitbang_end_state(TAP_RTI);
|
||||||
|
bitbang_state_move();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* execute num_cycles */
|
||||||
|
bitbang_interface->write(0, 0, 0);
|
||||||
|
for (i = 0; i < num_cycles; i++)
|
||||||
|
{
|
||||||
|
bitbang_interface->write(1, 0, 0);
|
||||||
|
bitbang_interface->write(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* finish in end_state */
|
||||||
|
bitbang_end_state(saved_end_state);
|
||||||
|
if (cur_state != end_state)
|
||||||
|
bitbang_state_move();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitbang_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
|
||||||
|
{
|
||||||
|
enum tap_state saved_end_state = end_state;
|
||||||
|
int bit_cnt;
|
||||||
|
|
||||||
|
if (ir_scan)
|
||||||
|
bitbang_end_state(TAP_SI);
|
||||||
|
else
|
||||||
|
bitbang_end_state(TAP_SD);
|
||||||
|
|
||||||
|
bitbang_state_move();
|
||||||
|
bitbang_end_state(saved_end_state);
|
||||||
|
|
||||||
|
for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++)
|
||||||
|
{
|
||||||
|
if ((buffer[bit_cnt/8] >> (bit_cnt % 8)) & 0x1) {
|
||||||
|
bitbang_interface->write(0, (bit_cnt==scan_size-1) ? 1 : 0, 1);
|
||||||
|
bitbang_interface->write(1, (bit_cnt==scan_size-1) ? 1 : 0, 1);
|
||||||
|
} else {
|
||||||
|
bitbang_interface->write(0, (bit_cnt==scan_size-1) ? 1 : 0, 0);
|
||||||
|
bitbang_interface->write(1, (bit_cnt==scan_size-1) ? 1 : 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type != SCAN_OUT)
|
||||||
|
{
|
||||||
|
if (bitbang_interface->read())
|
||||||
|
buffer[(bit_cnt)/8] |= 1 << ((bit_cnt) % 8);
|
||||||
|
else
|
||||||
|
buffer[(bit_cnt)/8] &= ~(1 << ((bit_cnt) % 8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Exit1 -> Pause */
|
||||||
|
bitbang_interface->write(0, 0, 0);
|
||||||
|
bitbang_interface->write(1, 0, 0);
|
||||||
|
|
||||||
|
if (ir_scan)
|
||||||
|
cur_state = TAP_PI;
|
||||||
|
else
|
||||||
|
cur_state = TAP_PD;
|
||||||
|
|
||||||
|
if (cur_state != end_state)
|
||||||
|
bitbang_state_move();
|
||||||
|
}
|
||||||
|
|
||||||
|
int bitbang_execute_queue(void)
|
||||||
|
{
|
||||||
|
jtag_command_t *cmd = jtag_command_queue; /* currently processed command */
|
||||||
|
int scan_size;
|
||||||
|
enum scan_type type;
|
||||||
|
u8 *buffer;
|
||||||
|
|
||||||
|
if (!bitbang_interface)
|
||||||
|
{
|
||||||
|
ERROR("BUG: Bitbang interface called, but not yet initialized");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (cmd)
|
||||||
|
{
|
||||||
|
switch (cmd->type)
|
||||||
|
{
|
||||||
|
case JTAG_END_STATE:
|
||||||
|
#ifdef _DEBUG_JTAG_IO_
|
||||||
|
DEBUG("end_state: %i", cmd->cmd.end_state->end_state);
|
||||||
|
#endif
|
||||||
|
if (cmd->cmd.end_state->end_state != -1)
|
||||||
|
bitbang_end_state(cmd->cmd.end_state->end_state);
|
||||||
|
break;
|
||||||
|
case JTAG_RESET:
|
||||||
|
#ifdef _DEBUG_JTAG_IO_
|
||||||
|
DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);
|
||||||
|
#endif
|
||||||
|
if (cmd->cmd.reset->trst == 1)
|
||||||
|
{
|
||||||
|
cur_state = TAP_TLR;
|
||||||
|
}
|
||||||
|
bitbang_interface->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
|
||||||
|
break;
|
||||||
|
case JTAG_RUNTEST:
|
||||||
|
#ifdef _DEBUG_JTAG_IO_
|
||||||
|
DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state);
|
||||||
|
#endif
|
||||||
|
if (cmd->cmd.runtest->end_state != -1)
|
||||||
|
bitbang_end_state(cmd->cmd.runtest->end_state);
|
||||||
|
bitbang_runtest(cmd->cmd.runtest->num_cycles);
|
||||||
|
break;
|
||||||
|
case JTAG_STATEMOVE:
|
||||||
|
#ifdef _DEBUG_JTAG_IO_
|
||||||
|
DEBUG("statemove end in %i", cmd->cmd.statemove->end_state);
|
||||||
|
#endif
|
||||||
|
if (cmd->cmd.statemove->end_state != -1)
|
||||||
|
bitbang_end_state(cmd->cmd.statemove->end_state);
|
||||||
|
bitbang_state_move();
|
||||||
|
break;
|
||||||
|
case JTAG_SCAN:
|
||||||
|
#ifdef _DEBUG_JTAG_IO_
|
||||||
|
DEBUG("scan end in %i", cmd->cmd.scan->end_state);
|
||||||
|
#endif
|
||||||
|
if (cmd->cmd.scan->end_state != -1)
|
||||||
|
bitbang_end_state(cmd->cmd.scan->end_state);
|
||||||
|
scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
|
||||||
|
type = jtag_scan_type(cmd->cmd.scan);
|
||||||
|
bitbang_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
|
||||||
|
if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
|
||||||
|
return ERROR_JTAG_QUEUE_FAILED;
|
||||||
|
if (buffer)
|
||||||
|
free(buffer);
|
||||||
|
break;
|
||||||
|
case JTAG_SLEEP:
|
||||||
|
#ifdef _DEBUG_JTAG_IO_
|
||||||
|
DEBUG("sleep", cmd->cmd.sleep->us);
|
||||||
|
#endif
|
||||||
|
jtag_sleep(cmd->cmd.sleep->us);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("BUG: unknown JTAG command type encountered");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
cmd = cmd->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef BITBANG_H
|
||||||
|
#define BITBANG_H
|
||||||
|
|
||||||
|
typedef struct bitbang_interface_s
|
||||||
|
{
|
||||||
|
/* low level callbacks (for bitbang)
|
||||||
|
*/
|
||||||
|
int (*read)(void);
|
||||||
|
void (*write)(int tck, int tms, int tdi);
|
||||||
|
void (*reset)(int trst, int srst);
|
||||||
|
} bitbang_interface_t;
|
||||||
|
|
||||||
|
extern bitbang_interface_t *bitbang_interface;
|
||||||
|
|
||||||
|
extern int bitbang_execute_queue(void);
|
||||||
|
|
||||||
|
#endif /* BITBANG_H */
|
|
@ -0,0 +1,236 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "config.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "jtag.h"
|
||||||
|
#include "bitbang.h"
|
||||||
|
|
||||||
|
#define TDO_BIT 1
|
||||||
|
#define TDI_BIT 2
|
||||||
|
#define TCK_BIT 4
|
||||||
|
#define TMS_BIT 8
|
||||||
|
#define TRST_BIT 16
|
||||||
|
#define SRST_BIT 32
|
||||||
|
#define VCC_BIT 64
|
||||||
|
|
||||||
|
/* system includes */
|
||||||
|
#include <sys/io.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
static u8 output_value = 0x0;
|
||||||
|
static int dev_mem_fd;
|
||||||
|
static void *gpio_controller;
|
||||||
|
static volatile u8 *gpio_data_register;
|
||||||
|
static volatile u8 *gpio_data_direction_register;
|
||||||
|
|
||||||
|
/* low level command set
|
||||||
|
*/
|
||||||
|
int ep93xx_read(void);
|
||||||
|
void ep93xx_write(int tck, int tms, int tdi);
|
||||||
|
void ep93xx_reset(int trst, int srst);
|
||||||
|
|
||||||
|
int ep93xx_speed(int speed);
|
||||||
|
int ep93xx_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
int ep93xx_init(void);
|
||||||
|
int ep93xx_quit(void);
|
||||||
|
|
||||||
|
struct timespec ep93xx_zzzz;
|
||||||
|
|
||||||
|
jtag_interface_t ep93xx_interface =
|
||||||
|
{
|
||||||
|
.name = "ep93xx",
|
||||||
|
|
||||||
|
.execute_queue = bitbang_execute_queue,
|
||||||
|
|
||||||
|
.support_statemove = 0,
|
||||||
|
|
||||||
|
.speed = ep93xx_speed,
|
||||||
|
.register_commands = ep93xx_register_commands,
|
||||||
|
.init = ep93xx_init,
|
||||||
|
.quit = ep93xx_quit,
|
||||||
|
};
|
||||||
|
|
||||||
|
bitbang_interface_t ep93xx_bitbang =
|
||||||
|
{
|
||||||
|
.read = ep93xx_read,
|
||||||
|
.write = ep93xx_write,
|
||||||
|
.reset = ep93xx_reset
|
||||||
|
};
|
||||||
|
|
||||||
|
int ep93xx_read(void)
|
||||||
|
{
|
||||||
|
return !!(*gpio_data_register & TDO_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ep93xx_write(int tck, int tms, int tdi)
|
||||||
|
{
|
||||||
|
if (tck)
|
||||||
|
output_value |= TCK_BIT;
|
||||||
|
else
|
||||||
|
output_value &= TCK_BIT;
|
||||||
|
|
||||||
|
if (tms)
|
||||||
|
output_value |= TMS_BIT;
|
||||||
|
else
|
||||||
|
output_value &= TMS_BIT;
|
||||||
|
|
||||||
|
if (tdi)
|
||||||
|
output_value |= TDI_BIT;
|
||||||
|
else
|
||||||
|
output_value &= TDI_BIT;
|
||||||
|
|
||||||
|
*gpio_data_register = output_value;
|
||||||
|
nanosleep(ep93xx_zzzz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (1) assert or (0) deassert reset lines */
|
||||||
|
void ep93xx_reset(int trst, int srst)
|
||||||
|
{
|
||||||
|
if (trst == 0)
|
||||||
|
output_value |= TRST_BIT;
|
||||||
|
else if (trst == 1)
|
||||||
|
output_value &= TRST_BIT;
|
||||||
|
|
||||||
|
if (srst == 0)
|
||||||
|
output_value |= SRST_BIT;
|
||||||
|
else if (srst == 1)
|
||||||
|
output_value &= SRST_BIT;
|
||||||
|
|
||||||
|
*gpio_data_register = output_value;
|
||||||
|
nanosleep(ep93xx_zzzz);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ep93xx_speed(int speed)
|
||||||
|
{
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ep93xx_register_commands(struct command_context_s *cmd_ctx)
|
||||||
|
{
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_gonk_mode(void)
|
||||||
|
{
|
||||||
|
void *syscon;
|
||||||
|
u32 devicecfg;
|
||||||
|
|
||||||
|
syscon = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
|
||||||
|
MAP_SHARED, dev_mem_fd, 0x80930000);
|
||||||
|
if (syscon == MAP_FAILED) {
|
||||||
|
perror("mmap");
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
devicecfg = *((volatile int *)(syscon + 0x80));
|
||||||
|
*((volatile int *)(syscon + 0xc0)) = 0xaa;
|
||||||
|
*((volatile int *)(syscon + 0x80)) = devicecfg | 0x08000000;
|
||||||
|
|
||||||
|
munmap(syscon, 4096);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ep93xx_init(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
bitbang_interface = &ep93xx_bitbang;
|
||||||
|
|
||||||
|
ep93xx_zzzz.tv_sec = 0;
|
||||||
|
ep93xx_zzzz.tv_nsec = 10000000;
|
||||||
|
|
||||||
|
dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
|
||||||
|
if (dev_mem_fd < 0) {
|
||||||
|
perror("open");
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_controller = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
|
||||||
|
MAP_SHARED, dev_mem_fd, 0x80840000);
|
||||||
|
if (gpio_controller == MAP_FAILED) {
|
||||||
|
perror("mmap");
|
||||||
|
close(dev_mem_fd);
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = set_gonk_mode();
|
||||||
|
if (ret != ERROR_OK) {
|
||||||
|
munmap(gpio_controller, 4096);
|
||||||
|
close(dev_mem_fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* Use GPIO port A. */
|
||||||
|
gpio_data_register = gpio_controller + 0x00;
|
||||||
|
gpio_data_direction_register = gpio_controller + 0x10;
|
||||||
|
|
||||||
|
|
||||||
|
/* Use GPIO port B. */
|
||||||
|
gpio_data_register = gpio_controller + 0x04;
|
||||||
|
gpio_data_direction_register = gpio_controller + 0x14;
|
||||||
|
|
||||||
|
/* Use GPIO port C. */
|
||||||
|
gpio_data_register = gpio_controller + 0x08;
|
||||||
|
gpio_data_direction_register = gpio_controller + 0x18;
|
||||||
|
|
||||||
|
/* Use GPIO port D. */
|
||||||
|
gpio_data_register = gpio_controller + 0x0c;
|
||||||
|
gpio_data_direction_register = gpio_controller + 0x1c;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Use GPIO port C. */
|
||||||
|
gpio_data_register = gpio_controller + 0x08;
|
||||||
|
gpio_data_direction_register = gpio_controller + 0x18;
|
||||||
|
|
||||||
|
printf("gpio_data_register = %08x\n", gpio_data_register);
|
||||||
|
printf("gpio_data_direction_reg = %08x\n", gpio_data_direction_register);
|
||||||
|
/*
|
||||||
|
* Configure bit 0 (TDO) as an input, and bits 1-5 (TDI, TCK
|
||||||
|
* TMS, TRST, SRST) as outputs. Drive TDI and TCK low, and
|
||||||
|
* TMS/TRST/SRST high.
|
||||||
|
*/
|
||||||
|
output_value = TMS_BIT | TRST_BIT | SRST_BIT | VCC_BIT;
|
||||||
|
*gpio_data_register = output_value;
|
||||||
|
nanosleep(ep93xx_zzzz);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configure the direction register. 1 = output, 0 = input.
|
||||||
|
*/
|
||||||
|
*gpio_data_direction_register =
|
||||||
|
TDI_BIT | TCK_BIT | TMS_BIT | TRST_BIT | SRST_BIT | VCC_BIT;
|
||||||
|
|
||||||
|
nanosleep(ep93xx_zzzz);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ep93xx_quit(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,630 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2004 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/* project specific includes */
|
||||||
|
#include "log.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "jtag.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
/* system includes */
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <usb.h>
|
||||||
|
#include <ftdi.h>
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/* enable this to debug io latency
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
#define _DEBUG_USB_IO_
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int ftdi2232_execute_queue(void);
|
||||||
|
|
||||||
|
int ftdi2232_speed(int speed);
|
||||||
|
int ftdi2232_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
int ftdi2232_init(void);
|
||||||
|
int ftdi2232_quit(void);
|
||||||
|
|
||||||
|
enum { FTDI2232_TRST = 0x10, FTDI2232_SRST = 0x40 };
|
||||||
|
static u8 discrete_output = 0x0 | FTDI2232_TRST | FTDI2232_SRST;
|
||||||
|
static struct ftdi_context ftdic;
|
||||||
|
|
||||||
|
static u8 *ftdi2232_buffer = NULL;
|
||||||
|
static int ftdi2232_buffer_size = 0;
|
||||||
|
static int ftdi2232_read_pointer = 0;
|
||||||
|
static int ftdi2232_expect_read = 0;
|
||||||
|
#define FTDI2232_BUFFER_SIZE 131072
|
||||||
|
#define BUFFER_ADD ftdi2232_buffer[ftdi2232_buffer_size++]
|
||||||
|
#define BUFFER_READ ftdi2232_buffer[ftdi2232_read_pointer++]
|
||||||
|
|
||||||
|
#define FTDI2232_SAVE_SIZE 1024
|
||||||
|
|
||||||
|
int ftdi2232_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
|
||||||
|
static u16 ftdi2232_vid = 0x0403;
|
||||||
|
static u16 ftdi2232_pid = 0x6010;
|
||||||
|
|
||||||
|
jtag_interface_t ftdi2232_interface =
|
||||||
|
{
|
||||||
|
|
||||||
|
.name = "ftdi2232",
|
||||||
|
|
||||||
|
.execute_queue = ftdi2232_execute_queue,
|
||||||
|
|
||||||
|
.support_statemove = 1,
|
||||||
|
|
||||||
|
.speed = ftdi2232_speed,
|
||||||
|
.register_commands = ftdi2232_register_commands,
|
||||||
|
.init = ftdi2232_init,
|
||||||
|
.quit = ftdi2232_quit,
|
||||||
|
};
|
||||||
|
|
||||||
|
int ftdi2232_speed(int speed)
|
||||||
|
{
|
||||||
|
u8 buf[3];
|
||||||
|
|
||||||
|
buf[0] = 0x86; /* command "set divisor" */
|
||||||
|
buf[1] = speed & 0xff; /* valueL (0=6MHz, 1=3MHz, 2=1.5MHz, ...*/
|
||||||
|
buf[2] = (speed >> 8) & 0xff; /* valueH */
|
||||||
|
|
||||||
|
DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
|
||||||
|
ftdi_write_data(&ftdic, buf, 3);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ftdi2232_register_commands(struct command_context_s *cmd_ctx)
|
||||||
|
{
|
||||||
|
register_command(cmd_ctx, NULL, "ftdi2232_vid_pid", ftdi2232_handle_vid_pid_command,
|
||||||
|
COMMAND_CONFIG, NULL);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ftdi2232_end_state(state)
|
||||||
|
{
|
||||||
|
if (tap_move_map[state] != -1)
|
||||||
|
end_state = state;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR("BUG: %i is not a valid end state", state);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ftdi2232_read_scan(enum scan_type type, u8* buffer, int scan_size)
|
||||||
|
{
|
||||||
|
int num_bytes = ((scan_size + 7) / 8);
|
||||||
|
int bits_left = scan_size;
|
||||||
|
int cur_byte = 0;
|
||||||
|
|
||||||
|
while(num_bytes-- > 1)
|
||||||
|
{
|
||||||
|
buffer[cur_byte] = BUFFER_READ;
|
||||||
|
cur_byte++;
|
||||||
|
bits_left -= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[cur_byte] = 0x0;
|
||||||
|
|
||||||
|
if (bits_left > 1)
|
||||||
|
{
|
||||||
|
buffer[cur_byte] = BUFFER_READ >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[cur_byte] = (buffer[cur_byte] | ((BUFFER_READ & 0x02) << 6)) >> (8 - bits_left);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ftdi2232_debug_dump_buffer(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < ftdi2232_buffer_size; i++)
|
||||||
|
{
|
||||||
|
printf("%2.2x ", ftdi2232_buffer[i]);
|
||||||
|
if (i % 16 == 15)
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ftdi2232_send_and_recv(jtag_command_t *first, jtag_command_t *last)
|
||||||
|
{
|
||||||
|
jtag_command_t *cmd;
|
||||||
|
u8 *buffer;
|
||||||
|
int scan_size;
|
||||||
|
enum scan_type type;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
BUFFER_ADD = 0x87; /* send immediate command */
|
||||||
|
|
||||||
|
if (ftdi2232_buffer_size > FTDI2232_SAVE_SIZE)
|
||||||
|
{
|
||||||
|
ERROR("BUG: ftdi2232_buffer grew beyond %i byte (%i) - this is going to fail", FTDI2232_SAVE_SIZE, ftdi2232_buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _DEBUG_USB_IO_
|
||||||
|
DEBUG("write buffer (size %i):", ftdi2232_buffer_size);
|
||||||
|
ftdi2232_debug_dump_buffer();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((retval = ftdi_write_data(&ftdic, ftdi2232_buffer, ftdi2232_buffer_size)) < 0)
|
||||||
|
{
|
||||||
|
ERROR("ftdi_write_data returned %i", retval);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ftdi2232_expect_read)
|
||||||
|
{
|
||||||
|
int timeout = 100;
|
||||||
|
ftdi2232_buffer_size = 0;
|
||||||
|
|
||||||
|
while ((ftdi2232_buffer_size < ftdi2232_expect_read) && timeout)
|
||||||
|
{
|
||||||
|
ftdi2232_buffer_size += ftdi_read_data(&ftdic, ftdi2232_buffer + ftdi2232_buffer_size, FTDI2232_BUFFER_SIZE - ftdi2232_buffer_size);
|
||||||
|
timeout--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ftdi2232_expect_read != ftdi2232_buffer_size)
|
||||||
|
{
|
||||||
|
ERROR("ftdi2232_expect_read (%i) != ftdi2232_buffer_size (%i) (%i retries)", ftdi2232_expect_read, ftdi2232_buffer_size, 100 - timeout);
|
||||||
|
ftdi2232_debug_dump_buffer();
|
||||||
|
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _DEBUG_USB_IO_
|
||||||
|
DEBUG("read buffer (%i retries): %i bytes", 100 - timeout, ftdi2232_buffer_size);
|
||||||
|
ftdi2232_debug_dump_buffer();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ftdi2232_expect_read = 0;
|
||||||
|
ftdi2232_read_pointer = 0;
|
||||||
|
|
||||||
|
cmd = first;
|
||||||
|
while (cmd != last)
|
||||||
|
{
|
||||||
|
switch (cmd->type)
|
||||||
|
{
|
||||||
|
case JTAG_SCAN:
|
||||||
|
type = jtag_scan_type(cmd->cmd.scan);
|
||||||
|
if (type != SCAN_OUT)
|
||||||
|
{
|
||||||
|
scan_size = jtag_scan_size(cmd->cmd.scan);
|
||||||
|
buffer = calloc(CEIL(scan_size, 8), 1);
|
||||||
|
ftdi2232_read_scan(type, buffer, scan_size);
|
||||||
|
jtag_read_buffer(buffer, cmd->cmd.scan);
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cmd = cmd->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
ftdi2232_buffer_size = 0;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ftdi2232_add_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
|
||||||
|
{
|
||||||
|
int num_bytes = (scan_size + 7) / 8;
|
||||||
|
int bits_left = scan_size;
|
||||||
|
int cur_byte = 0;
|
||||||
|
int last_bit;
|
||||||
|
|
||||||
|
/* command "Clock Data to TMS/CS Pin (no Read)" */
|
||||||
|
BUFFER_ADD = 0x4b;
|
||||||
|
/* scan 7 bit */
|
||||||
|
BUFFER_ADD = 0x6;
|
||||||
|
/* TMS data bits */
|
||||||
|
if (ir_scan)
|
||||||
|
{
|
||||||
|
BUFFER_ADD = TAP_MOVE(cur_state, TAP_SI);
|
||||||
|
cur_state = TAP_SI;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BUFFER_ADD = TAP_MOVE(cur_state, TAP_SD);
|
||||||
|
cur_state = TAP_SD;
|
||||||
|
}
|
||||||
|
//DEBUG("added TMS scan (no read)");
|
||||||
|
|
||||||
|
/* add command for complete bytes */
|
||||||
|
if (num_bytes > 1)
|
||||||
|
{
|
||||||
|
if (type == SCAN_IO)
|
||||||
|
{
|
||||||
|
/* Clock Data Bytes In and Out LSB First */
|
||||||
|
BUFFER_ADD = 0x39;
|
||||||
|
//DEBUG("added TDI bytes (io %i)", num_bytes);
|
||||||
|
}
|
||||||
|
else if (type == SCAN_OUT)
|
||||||
|
{
|
||||||
|
/* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */
|
||||||
|
BUFFER_ADD = 0x19;
|
||||||
|
//DEBUG("added TDI bytes (o)");
|
||||||
|
}
|
||||||
|
else if (type == SCAN_IN)
|
||||||
|
{
|
||||||
|
/* Clock Data Bytes In on +ve Clock Edge LSB First (no Write) */
|
||||||
|
BUFFER_ADD = 0x28;
|
||||||
|
//DEBUG("added TDI bytes (i %i)", num_bytes);
|
||||||
|
}
|
||||||
|
BUFFER_ADD = (num_bytes-2) & 0xff;
|
||||||
|
BUFFER_ADD = ((num_bytes-2) >> 8) & 0xff;
|
||||||
|
}
|
||||||
|
if (type != SCAN_IN)
|
||||||
|
{
|
||||||
|
/* add complete bytes */
|
||||||
|
while(num_bytes-- > 1)
|
||||||
|
{
|
||||||
|
BUFFER_ADD = buffer[cur_byte];
|
||||||
|
cur_byte++;
|
||||||
|
bits_left -= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (type == SCAN_IN)
|
||||||
|
{
|
||||||
|
bits_left -= 8 * (num_bytes - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the most signifcant bit is scanned during TAP movement */
|
||||||
|
if (type != SCAN_IN)
|
||||||
|
last_bit = (buffer[cur_byte] >> (bits_left - 1)) & 0x1;
|
||||||
|
else
|
||||||
|
last_bit = 0;
|
||||||
|
|
||||||
|
/* process remaining bits but the last one */
|
||||||
|
if (bits_left > 1)
|
||||||
|
{
|
||||||
|
if (type == SCAN_IO)
|
||||||
|
{
|
||||||
|
/* Clock Data Bits In and Out LSB First */
|
||||||
|
BUFFER_ADD = 0x3b;
|
||||||
|
//DEBUG("added TDI bits (io) %i", bits_left - 1);
|
||||||
|
}
|
||||||
|
else if (type == SCAN_OUT)
|
||||||
|
{
|
||||||
|
/* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */
|
||||||
|
BUFFER_ADD = 0x1b;
|
||||||
|
//DEBUG("added TDI bits (o)");
|
||||||
|
}
|
||||||
|
else if (type == SCAN_IN)
|
||||||
|
{
|
||||||
|
/* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */
|
||||||
|
BUFFER_ADD = 0x2a;
|
||||||
|
//DEBUG("added TDI bits (i %i)", bits_left - 1);
|
||||||
|
}
|
||||||
|
BUFFER_ADD = bits_left - 2;
|
||||||
|
if (type != SCAN_IN)
|
||||||
|
BUFFER_ADD = buffer[cur_byte];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* move from Shift-IR/DR to end state */
|
||||||
|
if (type != SCAN_OUT)
|
||||||
|
{
|
||||||
|
/* Clock Data to TMS/CS Pin with Read */
|
||||||
|
BUFFER_ADD = 0x6b;
|
||||||
|
//DEBUG("added TMS scan (read)");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Clock Data to TMS/CS Pin (no Read) */
|
||||||
|
BUFFER_ADD = 0x4b;
|
||||||
|
//DEBUG("added TMS scan (no read)");
|
||||||
|
}
|
||||||
|
BUFFER_ADD = 0x6;
|
||||||
|
BUFFER_ADD = TAP_MOVE(cur_state, end_state) | (last_bit << 7);
|
||||||
|
cur_state = end_state;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int ftdi2232_predict_scan_out(int scan_size, enum scan_type type)
|
||||||
|
{
|
||||||
|
int predicted_size = 6;
|
||||||
|
if (type == SCAN_IN) /* only from device to host */
|
||||||
|
{
|
||||||
|
predicted_size += (CEIL(scan_size, 8) > 1) ? 3 : 0;
|
||||||
|
predicted_size += ((scan_size - 1) % 8) ? 2 : 0;
|
||||||
|
}
|
||||||
|
else /* host to device, or bidirectional */
|
||||||
|
{
|
||||||
|
predicted_size += (CEIL(scan_size, 8) > 1) ? (CEIL(scan_size, 8) + 3 - 1) : 0;
|
||||||
|
predicted_size += ((scan_size - 1) % 8) ? 3 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return predicted_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ftdi2232_predict_scan_in(int scan_size, enum scan_type type)
|
||||||
|
{
|
||||||
|
int predicted_size = 0;
|
||||||
|
|
||||||
|
if (type != SCAN_OUT)
|
||||||
|
{
|
||||||
|
/* complete bytes */
|
||||||
|
predicted_size += (CEIL(scan_size, 8) > 1) ? (CEIL(scan_size, 8) - 1) : 0;
|
||||||
|
/* remaining bits - 1 */
|
||||||
|
predicted_size += ((scan_size - 1) % 8) ? 1 : 0;
|
||||||
|
/* last bit (from TMS scan) */
|
||||||
|
predicted_size += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//DEBUG("scan_size: %i, predicted_size: %i", scan_size, predicted_size);
|
||||||
|
|
||||||
|
return predicted_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ftdi2232_execute_queue()
|
||||||
|
{
|
||||||
|
jtag_command_t *cmd = jtag_command_queue; /* currently processed command */
|
||||||
|
jtag_command_t *first_unsent = cmd; /* next command that has to be sent */
|
||||||
|
u8 *buffer;
|
||||||
|
int scan_size; /* size of IR or DR scan */
|
||||||
|
enum scan_type type;
|
||||||
|
int i;
|
||||||
|
int predicted_size = 0;
|
||||||
|
int require_send = 0;
|
||||||
|
|
||||||
|
ftdi2232_buffer_size = 0;
|
||||||
|
ftdi2232_expect_read = 0;
|
||||||
|
|
||||||
|
while (cmd)
|
||||||
|
{
|
||||||
|
switch(cmd->type)
|
||||||
|
{
|
||||||
|
case JTAG_END_STATE:
|
||||||
|
if (cmd->cmd.end_state->end_state != -1)
|
||||||
|
ftdi2232_end_state(cmd->cmd.end_state->end_state);
|
||||||
|
break;
|
||||||
|
case JTAG_RESET:
|
||||||
|
/* only send the maximum buffer size that FT2232C can handle */
|
||||||
|
predicted_size = 3;
|
||||||
|
if (ftdi2232_buffer_size + predicted_size + 1 > FTDI2232_SAVE_SIZE)
|
||||||
|
{
|
||||||
|
ftdi2232_send_and_recv(first_unsent, cmd);
|
||||||
|
require_send = 0;
|
||||||
|
first_unsent = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd->cmd.reset->trst == 1)
|
||||||
|
{
|
||||||
|
cur_state = TAP_TLR;
|
||||||
|
discrete_output &= ~FTDI2232_TRST;
|
||||||
|
}
|
||||||
|
else if (cmd->cmd.reset->trst == 0)
|
||||||
|
{
|
||||||
|
discrete_output |= FTDI2232_TRST;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd->cmd.reset->srst == 1)
|
||||||
|
discrete_output &= ~FTDI2232_SRST;
|
||||||
|
else if (cmd->cmd.reset->srst == 0)
|
||||||
|
discrete_output |= FTDI2232_SRST;
|
||||||
|
/* command "set data bits low byte" */
|
||||||
|
BUFFER_ADD = 0x80;
|
||||||
|
/* value (TMS=1,TCK=0, TDI=0, TRST/SRST */
|
||||||
|
BUFFER_ADD = 0x08 | discrete_output;
|
||||||
|
/* dir (output=1), TCK/TDI/TMS=out, TDO=in, TRST/SRST=out */
|
||||||
|
BUFFER_ADD = 0x0b | FTDI2232_SRST | FTDI2232_TRST;
|
||||||
|
require_send = 1;
|
||||||
|
break;
|
||||||
|
case JTAG_RUNTEST:
|
||||||
|
/* only send the maximum buffer size that FT2232C can handle */
|
||||||
|
predicted_size = 0;
|
||||||
|
if (cur_state != TAP_RTI)
|
||||||
|
predicted_size += 3;
|
||||||
|
predicted_size += 3 * CEIL(cmd->cmd.runtest->num_cycles, 7);
|
||||||
|
if ((cmd->cmd.runtest->end_state != -1) && (cmd->cmd.runtest->end_state != TAP_RTI))
|
||||||
|
predicted_size += 3;
|
||||||
|
if ((cmd->cmd.runtest->end_state == -1) && (end_state != TAP_RTI))
|
||||||
|
predicted_size += 3;
|
||||||
|
if (ftdi2232_buffer_size + predicted_size + 1 > FTDI2232_SAVE_SIZE)
|
||||||
|
{
|
||||||
|
ftdi2232_send_and_recv(first_unsent, cmd);
|
||||||
|
require_send = 0;
|
||||||
|
first_unsent = cmd;
|
||||||
|
}
|
||||||
|
if (cur_state != TAP_RTI)
|
||||||
|
{
|
||||||
|
/* command "Clock Data to TMS/CS Pin (no Read)" */
|
||||||
|
BUFFER_ADD = 0x4b;
|
||||||
|
/* scan 7 bit */
|
||||||
|
BUFFER_ADD = 0x6;
|
||||||
|
/* TMS data bits */
|
||||||
|
BUFFER_ADD = TAP_MOVE(cur_state, TAP_RTI);
|
||||||
|
cur_state = TAP_RTI;
|
||||||
|
require_send = 1;
|
||||||
|
}
|
||||||
|
i = cmd->cmd.runtest->num_cycles;
|
||||||
|
while (i > 0)
|
||||||
|
{
|
||||||
|
/* command "Clock Data to TMS/CS Pin (no Read)" */
|
||||||
|
BUFFER_ADD = 0x4b;
|
||||||
|
/* scan 7 bit */
|
||||||
|
BUFFER_ADD = (i > 7) ? 6 : (i - 1);
|
||||||
|
/* TMS data bits */
|
||||||
|
BUFFER_ADD = 0x0;
|
||||||
|
cur_state = TAP_RTI;
|
||||||
|
i -= (i > 7) ? 7 : i;
|
||||||
|
//DEBUG("added TMS scan (no read)");
|
||||||
|
}
|
||||||
|
if (cmd->cmd.runtest->end_state != -1)
|
||||||
|
ftdi2232_end_state(cmd->cmd.runtest->end_state);
|
||||||
|
if (cur_state != end_state)
|
||||||
|
{
|
||||||
|
/* command "Clock Data to TMS/CS Pin (no Read)" */
|
||||||
|
BUFFER_ADD = 0x4b;
|
||||||
|
/* scan 7 bit */
|
||||||
|
BUFFER_ADD = 0x6;
|
||||||
|
/* TMS data bits */
|
||||||
|
BUFFER_ADD = TAP_MOVE(cur_state, end_state);
|
||||||
|
cur_state = end_state;
|
||||||
|
//DEBUG("added TMS scan (no read)");
|
||||||
|
}
|
||||||
|
require_send = 1;
|
||||||
|
break;
|
||||||
|
case JTAG_STATEMOVE:
|
||||||
|
/* only send the maximum buffer size that FT2232C can handle */
|
||||||
|
predicted_size = 3;
|
||||||
|
if (ftdi2232_buffer_size + predicted_size + 1 > FTDI2232_SAVE_SIZE)
|
||||||
|
{
|
||||||
|
ftdi2232_send_and_recv(first_unsent, cmd);
|
||||||
|
require_send = 0;
|
||||||
|
first_unsent = cmd;
|
||||||
|
}
|
||||||
|
if (cmd->cmd.statemove->end_state != -1)
|
||||||
|
ftdi2232_end_state(cmd->cmd.statemove->end_state);
|
||||||
|
/* command "Clock Data to TMS/CS Pin (no Read)" */
|
||||||
|
BUFFER_ADD = 0x4b;
|
||||||
|
/* scan 7 bit */
|
||||||
|
BUFFER_ADD = 0x6;
|
||||||
|
/* TMS data bits */
|
||||||
|
BUFFER_ADD = TAP_MOVE(cur_state, end_state);
|
||||||
|
//DEBUG("added TMS scan (no read)");
|
||||||
|
cur_state = end_state;
|
||||||
|
require_send = 1;
|
||||||
|
break;
|
||||||
|
case JTAG_SCAN:
|
||||||
|
scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
|
||||||
|
type = jtag_scan_type(cmd->cmd.scan);
|
||||||
|
predicted_size = ftdi2232_predict_scan_out(scan_size, type);
|
||||||
|
if (ftdi2232_buffer_size + predicted_size + 1 > FTDI2232_SAVE_SIZE)
|
||||||
|
{
|
||||||
|
ftdi2232_send_and_recv(first_unsent, cmd);
|
||||||
|
require_send = 0;
|
||||||
|
first_unsent = cmd;
|
||||||
|
}
|
||||||
|
ftdi2232_expect_read += ftdi2232_predict_scan_in(scan_size, type);
|
||||||
|
//DEBUG("new read size: %i", ftdi2232_expect_read);
|
||||||
|
if (cmd->cmd.scan->end_state != -1)
|
||||||
|
ftdi2232_end_state(cmd->cmd.scan->end_state);
|
||||||
|
ftdi2232_add_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
|
||||||
|
require_send = 1;
|
||||||
|
if (buffer)
|
||||||
|
free(buffer);
|
||||||
|
break;
|
||||||
|
case JTAG_SLEEP:
|
||||||
|
jtag_sleep(cmd->cmd.sleep->us);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("BUG: unknown JTAG command type encountered");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
cmd = cmd->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (require_send > 0)
|
||||||
|
ftdi2232_send_and_recv(first_unsent, cmd);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ftdi2232_init(void)
|
||||||
|
{
|
||||||
|
if (ftdi_init(&ftdic) < 0)
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
|
||||||
|
/* context, vendor id, product id */
|
||||||
|
if (ftdi_usb_open(&ftdic, ftdi2232_vid, ftdi2232_pid) < 0)
|
||||||
|
{
|
||||||
|
ERROR("unable to open ftdi device: %s", ftdic.error_str);
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ftdi_usb_reset(&ftdic) < 0)
|
||||||
|
{
|
||||||
|
ERROR("unable to reset ftdi device");
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ftdi_set_latency_timer(&ftdic, 1) < 0)
|
||||||
|
{
|
||||||
|
ERROR("unable to set latency timer");
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ftdi2232_buffer_size = 0;
|
||||||
|
ftdi2232_buffer = malloc(FTDI2232_BUFFER_SIZE);
|
||||||
|
|
||||||
|
ftdic.bitbang_mode = 0; /* Reset controller */
|
||||||
|
ftdi_enable_bitbang(&ftdic, 0x0b | FTDI2232_SRST | FTDI2232_TRST); /* ctx, i/o mask (out=1, in=0) */
|
||||||
|
|
||||||
|
ftdic.bitbang_mode = 2; /* MPSSE mode */
|
||||||
|
ftdi_enable_bitbang(&ftdic, 0x0b | FTDI2232_SRST | FTDI2232_TRST); /* ctx, i/o mask (out=1, in=0) */
|
||||||
|
|
||||||
|
if (ftdi_usb_purge_buffers(&ftdic) < 0)
|
||||||
|
{
|
||||||
|
ERROR("ftdi_purge_buffers: %s", ftdic.error_str);
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize low byte for jtag */
|
||||||
|
BUFFER_ADD = 0x80; /* command "set data bits low byte" */
|
||||||
|
BUFFER_ADD = 0x08 | FTDI2232_SRST | FTDI2232_TRST; /* value (TMS=1,TCK=0, TDI=0, xRST high) */
|
||||||
|
BUFFER_ADD = 0x0b | FTDI2232_SRST | FTDI2232_TRST; /* dir (output=1), TCK/TDI/TMS=out, TDO=in */
|
||||||
|
BUFFER_ADD = 0x85; /* command "Disconnect TDI/DO to TDO/DI for Loopback" */
|
||||||
|
ftdi2232_debug_dump_buffer();
|
||||||
|
if (ftdi_write_data(&ftdic, ftdi2232_buffer, ftdi2232_buffer_size) != 4)
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
|
||||||
|
ftdi2232_speed(jtag_speed);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ftdi2232_quit(void)
|
||||||
|
{
|
||||||
|
ftdi_disable_bitbang(&ftdic);
|
||||||
|
|
||||||
|
ftdi_usb_close(&ftdic);
|
||||||
|
|
||||||
|
ftdi_deinit(&ftdic);
|
||||||
|
|
||||||
|
free(ftdi2232_buffer);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ftdi2232_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
if (argc >= 2)
|
||||||
|
{
|
||||||
|
ftdi2232_vid = strtol(args[0], NULL, 0);
|
||||||
|
ftdi2232_pid = strtol(args[1], NULL, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WARNING("incomplete ftdi2232_vid_pid configuration directive");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,270 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef JTAG_H
|
||||||
|
#define JTAG_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "binarybuffer.h"
|
||||||
|
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#define _DEBUG_JTAG_IO_
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Tap States
|
||||||
|
* TLR - Test-Logic-Reset, RTI - Run-Test/Idle,
|
||||||
|
* SDS - Select-DR-Scan, CD - Capture-DR, SD - Shift-DR, E1D - Exit1-DR,
|
||||||
|
* PD - Pause-DR, E2D - Exit2-DR, UD - Update-DR,
|
||||||
|
* SIS - Select-IR-Scan, CI - Capture-IR, SI - Shift-IR, E1I - Exit1-IR,
|
||||||
|
* PI - Pause-IR, E2I - Exit2-IR, UI - Update-IR
|
||||||
|
*/
|
||||||
|
enum tap_state
|
||||||
|
{
|
||||||
|
TAP_TLR = 0x0, TAP_RTI = 0x8,
|
||||||
|
TAP_SDS = 0x1, TAP_CD = 0x2, TAP_SD = 0x3, TAP_E1D = 0x4,
|
||||||
|
TAP_PD = 0x5, TAP_E2D = 0x6, TAP_UD = 0x7,
|
||||||
|
TAP_SIS = 0x9, TAP_CI = 0xa, TAP_SI = 0xb, TAP_E1I = 0xc,
|
||||||
|
TAP_PI = 0xd, TAP_E2I = 0xe, TAP_UI = 0xf
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct tap_transition_s
|
||||||
|
{
|
||||||
|
enum tap_state high;
|
||||||
|
enum tap_state low;
|
||||||
|
} tap_transition_t;
|
||||||
|
|
||||||
|
extern char* tap_state_strings[16];
|
||||||
|
extern int tap_move_map[16]; /* map 16 TAP states to 6 stable states */
|
||||||
|
extern u8 tap_move[6][6]; /* value scanned to TMS to move from one of six stable states to another */
|
||||||
|
extern tap_transition_t tap_transitions[16]; /* describe the TAP state diagram */
|
||||||
|
|
||||||
|
extern enum tap_state end_state; /* finish DR scans in dr_end_state */
|
||||||
|
extern enum tap_state cur_state; /* current TAP state */
|
||||||
|
|
||||||
|
#define TAP_MOVE(from, to) tap_move[tap_move_map[from]][tap_move_map[to]]
|
||||||
|
|
||||||
|
typedef struct scan_field_s
|
||||||
|
{
|
||||||
|
int device; /* ordinal device number this instruction refers to */
|
||||||
|
int num_bits; /* number of bits this field specifies (up to 32) */
|
||||||
|
u8 *out_value; /* value to be scanned into the device */
|
||||||
|
u8 *out_mask; /* only masked bits care */
|
||||||
|
u8 *in_value; /* pointer to a 32-bit memory location to take data scanned out */
|
||||||
|
u8 *in_check_value; /* used to validate scan results */
|
||||||
|
u8 *in_check_mask; /* check specified bits against check_value */
|
||||||
|
int (*in_handler)(u8 *in_value, void *priv); /* process received buffer using this handler */
|
||||||
|
void *in_handler_priv; /* additional information for the in_handler */
|
||||||
|
} scan_field_t;
|
||||||
|
|
||||||
|
enum scan_type
|
||||||
|
{
|
||||||
|
/* IN: from device to host, OUT: from host to device */
|
||||||
|
SCAN_IN = 1, SCAN_OUT = 2, SCAN_IO = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct scan_command_s
|
||||||
|
{
|
||||||
|
int ir_scan; /* instruction/not data scan */
|
||||||
|
int num_fields; /* number of fields in *fields array */
|
||||||
|
scan_field_t *fields; /* pointer to an array of data scan fields */
|
||||||
|
enum tap_state end_state; /* TAP state in which JTAG commands should finish */
|
||||||
|
} scan_command_t;
|
||||||
|
|
||||||
|
typedef struct statemove_command_s
|
||||||
|
{
|
||||||
|
enum tap_state end_state; /* TAP state in which JTAG commands should finish */
|
||||||
|
} statemove_command_t;
|
||||||
|
|
||||||
|
typedef struct pathmove_command_s
|
||||||
|
{
|
||||||
|
int num_states; /* number of states in *path */
|
||||||
|
enum tap_state *path; /* states that have to be passed */
|
||||||
|
} pathmove_command_t;
|
||||||
|
|
||||||
|
typedef struct runtest_command_s
|
||||||
|
{
|
||||||
|
int num_cycles; /* number of cycles that should be spent in Run-Test/Idle */
|
||||||
|
enum tap_state end_state; /* TAP state in which JTAG commands should finish */
|
||||||
|
} runtest_command_t;
|
||||||
|
|
||||||
|
typedef struct reset_command_s
|
||||||
|
{
|
||||||
|
int trst; /* trst/srst 0: deassert, 1: assert, -1: don't change */
|
||||||
|
int srst;
|
||||||
|
} reset_command_t;
|
||||||
|
|
||||||
|
typedef struct end_state_command_s
|
||||||
|
{
|
||||||
|
enum tap_state end_state; /* TAP state in which JTAG commands should finish */
|
||||||
|
} end_state_command_t;
|
||||||
|
|
||||||
|
typedef struct sleep_command_s
|
||||||
|
{
|
||||||
|
u32 us; /* number of microseconds to sleep */
|
||||||
|
} sleep_command_t;
|
||||||
|
|
||||||
|
typedef union jtag_command_container_u
|
||||||
|
{
|
||||||
|
scan_command_t *scan;
|
||||||
|
statemove_command_t *statemove;
|
||||||
|
pathmove_command_t *pathmove;
|
||||||
|
runtest_command_t *runtest;
|
||||||
|
reset_command_t *reset;
|
||||||
|
end_state_command_t *end_state;
|
||||||
|
sleep_command_t *sleep;
|
||||||
|
} jtag_command_container_t;
|
||||||
|
|
||||||
|
enum jtag_command_type
|
||||||
|
{
|
||||||
|
JTAG_SCAN = 1,
|
||||||
|
JTAG_STATEMOVE = 2, JTAG_RUNTEST = 3,
|
||||||
|
JTAG_RESET = 4, JTAG_END_STATE = 5,
|
||||||
|
JTAG_PATHMOVE = 6, JTAG_SLEEP = 7
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct jtag_command_s
|
||||||
|
{
|
||||||
|
jtag_command_container_t cmd;
|
||||||
|
enum jtag_command_type type;
|
||||||
|
struct jtag_command_s *next;
|
||||||
|
} jtag_command_t;
|
||||||
|
|
||||||
|
extern jtag_command_t *jtag_command_queue;
|
||||||
|
|
||||||
|
typedef struct jtag_device_s
|
||||||
|
{
|
||||||
|
int ir_length; /* size of instruction register */
|
||||||
|
u8 *expected; /* Capture-IR expected value */
|
||||||
|
u8 *expected_mask; /* Capture-IR expected mask */
|
||||||
|
u32 idcode; /* device identification code */
|
||||||
|
u8 *cur_instr; /* current instruction */
|
||||||
|
int bypass; /* bypass register selected */
|
||||||
|
struct jtag_device_s *next;
|
||||||
|
} jtag_device_t;
|
||||||
|
|
||||||
|
extern jtag_device_t *jtag_devices;
|
||||||
|
extern int jtag_num_devices;
|
||||||
|
extern int jtag_ir_scan_size;
|
||||||
|
|
||||||
|
enum reset_line_mode
|
||||||
|
{
|
||||||
|
LINE_OPEN_DRAIN = 0x0,
|
||||||
|
LINE_PUSH_PULL = 0x1,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct jtag_interface_s
|
||||||
|
{
|
||||||
|
char* name;
|
||||||
|
|
||||||
|
/* queued command execution
|
||||||
|
*/
|
||||||
|
int (*execute_queue)(void);
|
||||||
|
|
||||||
|
/* optional command support
|
||||||
|
*/
|
||||||
|
int support_statemove;
|
||||||
|
|
||||||
|
/* interface initalization
|
||||||
|
*/
|
||||||
|
int (*speed)(int speed);
|
||||||
|
int (*register_commands)(struct command_context_s *cmd_ctx);
|
||||||
|
int (*init)(void);
|
||||||
|
int (*quit)(void);
|
||||||
|
|
||||||
|
} jtag_interface_t;
|
||||||
|
|
||||||
|
enum jtag_event
|
||||||
|
{
|
||||||
|
JTAG_SRST_ASSERTED,
|
||||||
|
JTAG_TRST_ASSERTED,
|
||||||
|
JTAG_SRST_RELEASED,
|
||||||
|
JTAG_TRST_RELEASED,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct jtag_event_callback_s
|
||||||
|
{
|
||||||
|
int (*callback)(enum jtag_event event, void *priv);
|
||||||
|
void *priv;
|
||||||
|
struct jtag_event_callback_s *next;
|
||||||
|
} jtag_event_callback_t;
|
||||||
|
|
||||||
|
extern jtag_event_callback_t *jtag_event_callbacks;
|
||||||
|
|
||||||
|
extern jtag_interface_t *jtag; /* global pointer to configured JTAG interface */
|
||||||
|
extern enum tap_state end_state;
|
||||||
|
extern enum tap_state cur_state;
|
||||||
|
|
||||||
|
extern char* jtag_interface;
|
||||||
|
extern int jtag_speed;
|
||||||
|
|
||||||
|
enum reset_types
|
||||||
|
{
|
||||||
|
RESET_NONE = 0x0,
|
||||||
|
RESET_HAS_TRST = 0x1,
|
||||||
|
RESET_HAS_SRST = 0x2,
|
||||||
|
RESET_TRST_AND_SRST = 0x3,
|
||||||
|
RESET_SRST_PULLS_TRST = 0x4,
|
||||||
|
RESET_TRST_PULLS_SRST = 0x8,
|
||||||
|
RESET_TRST_OPEN_DRAIN = 0x10,
|
||||||
|
RESET_SRST_PUSH_PULL = 0x20,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern enum reset_types jtag_reset_config;
|
||||||
|
|
||||||
|
/* JTAG subsystem */
|
||||||
|
extern int jtag_init(struct command_context_s *cmd_ctx);
|
||||||
|
extern int jtag_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
|
||||||
|
/* JTAG interface */
|
||||||
|
extern int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state endstate);
|
||||||
|
extern int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state endstate);
|
||||||
|
extern int jtag_add_plain_ir_scan(int num_fields, scan_field_t *fields, enum tap_state endstate);
|
||||||
|
extern int jtag_add_plain_dr_scan(int num_fields, scan_field_t *fields, enum tap_state endstate);
|
||||||
|
extern int jtag_add_statemove(enum tap_state endstate);
|
||||||
|
extern int jtag_add_pathmove(int num_states, enum tap_state *path);
|
||||||
|
extern int jtag_add_runtest(int num_cycles, enum tap_state endstate);
|
||||||
|
extern int jtag_add_reset(int trst, int srst);
|
||||||
|
extern int jtag_add_end_state(enum tap_state endstate);
|
||||||
|
extern int jtag_add_sleep(u32 us);
|
||||||
|
extern int jtag_execute_queue(void);
|
||||||
|
extern int jtag_cancel_queue(void);
|
||||||
|
|
||||||
|
/* JTAG support functions */
|
||||||
|
extern enum scan_type jtag_scan_type(scan_command_t *cmd);
|
||||||
|
extern int jtag_scan_size(scan_command_t *cmd);
|
||||||
|
extern int jtag_read_buffer(u8 *buffer, scan_command_t *cmd);
|
||||||
|
extern int jtag_build_buffer(scan_command_t *cmd, u8 **buffer);
|
||||||
|
extern jtag_device_t* jtag_get_device(int num);
|
||||||
|
extern void jtag_sleep(u32 us);
|
||||||
|
extern int jtag_call_event_callbacks(enum jtag_event event);
|
||||||
|
extern int jtag_register_event_callback(int (*callback)(enum jtag_event event, void *priv), void *priv);
|
||||||
|
|
||||||
|
/* error codes
|
||||||
|
* JTAG subsystem uses codes between -100 and -199 */
|
||||||
|
|
||||||
|
#define ERROR_JTAG_INIT_FAILED (-100)
|
||||||
|
#define ERROR_JTAG_INVALID_INTERFACE (-101)
|
||||||
|
#define ERROR_JTAG_NOT_IMPLEMENTED (-102)
|
||||||
|
#define ERROR_JTAG_TRST_ASSERTED (-103)
|
||||||
|
#define ERROR_JTAG_QUEUE_FAILED (-104)
|
||||||
|
#define ERROR_JTAG_RESET_WOULD_ASSERT_TRST (-105)
|
||||||
|
#define ERROR_JTAG_RESET_CANT_SRST (-106)
|
||||||
|
#endif /* JTAG_H */
|
|
@ -0,0 +1,351 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "config.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "jtag.h"
|
||||||
|
#include "bitbang.h"
|
||||||
|
|
||||||
|
/* system includes */
|
||||||
|
// -ino: 060521-1036
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <machine/sysarch.h>
|
||||||
|
#include <machine/cpufunc.h>
|
||||||
|
#define ioperm(startport,length,enable)\
|
||||||
|
i386_set_ioperm((startport), (length), (enable))
|
||||||
|
#else
|
||||||
|
#include <sys/io.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#if PARPORT_USE_PPDEV == 1
|
||||||
|
#include <linux/parport.h>
|
||||||
|
#include <linux/ppdev.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* parallel port cable description
|
||||||
|
*/
|
||||||
|
typedef struct cable_s
|
||||||
|
{
|
||||||
|
char* name;
|
||||||
|
u8 TDO_MASK; /* status port bit containing current TDO value */
|
||||||
|
u8 TRST_MASK; /* data port bit for TRST */
|
||||||
|
u8 TMS_MASK; /* data port bit for TMS */
|
||||||
|
u8 TCK_MASK; /* data port bit for TCK */
|
||||||
|
u8 TDI_MASK; /* data port bit for TDI */
|
||||||
|
u8 SRST_MASK; /* data port bit for SRST */
|
||||||
|
u8 OUTPUT_INVERT; /* data port bits that should be inverted */
|
||||||
|
u8 INPUT_INVERT; /* status port that should be inverted */
|
||||||
|
u8 PORT_INIT; /* initialize data port with this value */
|
||||||
|
} cable_t;
|
||||||
|
|
||||||
|
cable_t cables[] =
|
||||||
|
{
|
||||||
|
/* name tdo trst tms tck tdi srst o_inv i_inv init */
|
||||||
|
{ "wiggler", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80 },
|
||||||
|
{ "old_amt_wiggler", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x11, 0x80, 0x80 },
|
||||||
|
{ "chameleon", 0x80, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00 },
|
||||||
|
{ "dlc5", 0x10, 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x10 },
|
||||||
|
{ "triton", 0x80, 0x08, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00 },
|
||||||
|
{ NULL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* configuration */
|
||||||
|
char* parport_cable;
|
||||||
|
unsigned long parport_port;
|
||||||
|
|
||||||
|
/* interface variables
|
||||||
|
*/
|
||||||
|
static cable_t* cable;
|
||||||
|
static u8 dataport_value = 0x0;
|
||||||
|
|
||||||
|
#if PARPORT_USE_PPDEV == 1
|
||||||
|
static int device_handle;
|
||||||
|
#else
|
||||||
|
static unsigned long dataport;
|
||||||
|
static unsigned long statusport;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* low level command set
|
||||||
|
*/
|
||||||
|
int parport_read(void);
|
||||||
|
void parport_write(int tck, int tms, int tdi);
|
||||||
|
void parport_reset(int trst, int srst);
|
||||||
|
|
||||||
|
int parport_speed(int speed);
|
||||||
|
int parport_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
int parport_init(void);
|
||||||
|
int parport_quit(void);
|
||||||
|
|
||||||
|
/* interface commands */
|
||||||
|
int parport_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int parport_handle_parport_cable_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
|
||||||
|
jtag_interface_t parport_interface =
|
||||||
|
{
|
||||||
|
.name = "parport",
|
||||||
|
|
||||||
|
.execute_queue = bitbang_execute_queue,
|
||||||
|
|
||||||
|
.support_statemove = 0,
|
||||||
|
|
||||||
|
.speed = parport_speed,
|
||||||
|
.register_commands = parport_register_commands,
|
||||||
|
.init = parport_init,
|
||||||
|
.quit = parport_quit,
|
||||||
|
};
|
||||||
|
|
||||||
|
bitbang_interface_t parport_bitbang =
|
||||||
|
{
|
||||||
|
.read = parport_read,
|
||||||
|
.write = parport_write,
|
||||||
|
.reset = parport_reset
|
||||||
|
};
|
||||||
|
|
||||||
|
int parport_read(void)
|
||||||
|
{
|
||||||
|
int data = 0;
|
||||||
|
|
||||||
|
#if PARPORT_USE_PPDEV == 1
|
||||||
|
ioctl(device_handle, PPRSTATUS, & data);
|
||||||
|
#else
|
||||||
|
data = inb(statusport);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((data ^ cable->INPUT_INVERT) & cable->TDO_MASK)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parport_write(int tck, int tms, int tdi)
|
||||||
|
{
|
||||||
|
u8 output;
|
||||||
|
int i = jtag_speed + 1;
|
||||||
|
|
||||||
|
if (tck)
|
||||||
|
dataport_value |= cable->TCK_MASK;
|
||||||
|
else
|
||||||
|
dataport_value &= ~cable->TCK_MASK;
|
||||||
|
|
||||||
|
if (tms)
|
||||||
|
dataport_value |= cable->TMS_MASK;
|
||||||
|
else
|
||||||
|
dataport_value &= ~cable->TMS_MASK;
|
||||||
|
|
||||||
|
if (tdi)
|
||||||
|
dataport_value |= cable->TDI_MASK;
|
||||||
|
else
|
||||||
|
dataport_value &= ~cable->TDI_MASK;
|
||||||
|
|
||||||
|
output = dataport_value ^ cable->OUTPUT_INVERT;
|
||||||
|
|
||||||
|
while (i-- > 0)
|
||||||
|
#if PARPORT_USE_PPDEV == 1
|
||||||
|
ioctl(device_handle, PPWDATA, &output);
|
||||||
|
#else
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
outb(dataport, output);
|
||||||
|
#else
|
||||||
|
outb(output, dataport);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (1) assert or (0) deassert reset lines */
|
||||||
|
void parport_reset(int trst, int srst)
|
||||||
|
{
|
||||||
|
u8 output;
|
||||||
|
DEBUG("trst: %i, srst: %i", trst, srst);
|
||||||
|
|
||||||
|
if (trst == 0)
|
||||||
|
dataport_value |= cable->TRST_MASK;
|
||||||
|
else if (trst == 1)
|
||||||
|
dataport_value &= ~cable->TRST_MASK;
|
||||||
|
|
||||||
|
if (srst == 0)
|
||||||
|
dataport_value |= cable->SRST_MASK;
|
||||||
|
else if (srst == 1)
|
||||||
|
dataport_value &= ~cable->SRST_MASK;
|
||||||
|
|
||||||
|
output = dataport_value ^ cable->OUTPUT_INVERT;
|
||||||
|
|
||||||
|
#if PARPORT_USE_PPDEV == 1
|
||||||
|
ioctl(device_handle, PPWDATA, &output);
|
||||||
|
#else
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
outb(dataport, output);
|
||||||
|
#else
|
||||||
|
outb(output, dataport);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int parport_speed(int speed)
|
||||||
|
{
|
||||||
|
jtag_speed = speed;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parport_register_commands(struct command_context_s *cmd_ctx)
|
||||||
|
{
|
||||||
|
register_command(cmd_ctx, NULL, "parport_port", parport_handle_parport_port_command,
|
||||||
|
COMMAND_CONFIG, NULL);
|
||||||
|
register_command(cmd_ctx, NULL, "parport_cable", parport_handle_parport_cable_command,
|
||||||
|
COMMAND_CONFIG, NULL);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parport_init(void)
|
||||||
|
{
|
||||||
|
cable_t *cur_cable;
|
||||||
|
#if PARPORT_USE_PPDEV == 1
|
||||||
|
char buffer[256];
|
||||||
|
int i = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
cur_cable = cables;
|
||||||
|
|
||||||
|
if ((parport_cable == NULL) || (parport_cable[0] == 0))
|
||||||
|
{
|
||||||
|
parport_cable = "wiggler";
|
||||||
|
WARNING("No parport cable specified, using default 'wiggler'");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (cur_cable->name)
|
||||||
|
{
|
||||||
|
if (strcmp(cur_cable->name, parport_cable) == 0)
|
||||||
|
{
|
||||||
|
cable = cur_cable;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cur_cable++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cable)
|
||||||
|
{
|
||||||
|
ERROR("No matching cable found for %s", parport_cable);
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataport_value = cable->PORT_INIT;
|
||||||
|
|
||||||
|
#if PARPORT_USE_PPDEV == 1
|
||||||
|
if (device_handle>0)
|
||||||
|
{
|
||||||
|
ERROR("device is already opened");
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buffer, 256, "/dev/parport%d", parport_port);
|
||||||
|
device_handle = open(buffer, O_WRONLY);
|
||||||
|
|
||||||
|
if (device_handle<0)
|
||||||
|
{
|
||||||
|
ERROR("cannot open device. check it exists and that user read and write rights are set");
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
i=ioctl(device_handle, PPCLAIM);
|
||||||
|
if (i<0)
|
||||||
|
{
|
||||||
|
ERROR("cannot claim device");
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = PARPORT_MODE_COMPAT;
|
||||||
|
i= ioctl(device_handle, PPSETMODE, & i);
|
||||||
|
if (i<0)
|
||||||
|
{
|
||||||
|
ERROR(" cannot set compatible mode to device");
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = IEEE1284_MODE_COMPAT;
|
||||||
|
i = ioctl(device_handle, PPNEGOT, & i);
|
||||||
|
if (i<0)
|
||||||
|
{
|
||||||
|
ERROR("cannot set compatible 1284 mode to device");
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (parport_port == 0)
|
||||||
|
{
|
||||||
|
parport_port = 0x378;
|
||||||
|
WARNING("No parport port specified, using default '0x378' (LPT1)");
|
||||||
|
}
|
||||||
|
|
||||||
|
dataport = parport_port;
|
||||||
|
statusport = parport_port + 1;
|
||||||
|
|
||||||
|
if (ioperm(dataport, 3, 1) != 0) {
|
||||||
|
ERROR("missing privileges for direct i/o");
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
parport_reset(0, 0);
|
||||||
|
parport_write(0, 0, 0);
|
||||||
|
|
||||||
|
bitbang_interface = &parport_bitbang;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parport_quit(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parport_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
if (argc == 0)
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
/* only if the port wasn't overwritten by cmdline */
|
||||||
|
if (parport_port == 0)
|
||||||
|
parport_port = strtoul(args[0], NULL, 0);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parport_handle_parport_cable_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
if (argc == 0)
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
/* only if the cable name wasn't overwritten by cmdline */
|
||||||
|
if (parport_cable == 0)
|
||||||
|
{
|
||||||
|
parport_cable = malloc(strlen(args[0]) + sizeof(char));
|
||||||
|
strcpy(parport_cable, args[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "jtag.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
#include "interpreter.h"
|
||||||
|
#include "xsvf.h"
|
||||||
|
#include "target.h"
|
||||||
|
#include "flash.h"
|
||||||
|
|
||||||
|
#include "command.h"
|
||||||
|
#include "server.h"
|
||||||
|
#include "telnet_server.h"
|
||||||
|
#include "gdb_server.h"
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
/* initialize commandline interface */
|
||||||
|
command_context_t *cmd_ctx, *cfg_cmd_ctx;
|
||||||
|
cmd_ctx = command_init();
|
||||||
|
|
||||||
|
/* register subsystem commands */
|
||||||
|
server_register_commands(cmd_ctx);
|
||||||
|
telnet_register_commands(cmd_ctx);
|
||||||
|
gdb_register_commands(cmd_ctx);
|
||||||
|
log_register_commands(cmd_ctx);
|
||||||
|
jtag_register_commands(cmd_ctx);
|
||||||
|
interpreter_register_commands(cmd_ctx);
|
||||||
|
xsvf_register_commands(cmd_ctx);
|
||||||
|
target_register_commands(cmd_ctx);
|
||||||
|
flash_register_commands(cmd_ctx);
|
||||||
|
|
||||||
|
if (log_init(cmd_ctx) != ERROR_OK)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
DEBUG("log init complete");
|
||||||
|
|
||||||
|
INFO("Open On-Chip Debugger (Revision 63)");
|
||||||
|
|
||||||
|
cfg_cmd_ctx = copy_command_context(cmd_ctx);
|
||||||
|
cfg_cmd_ctx->mode = COMMAND_CONFIG;
|
||||||
|
command_set_output_handler(cfg_cmd_ctx, configuration_output_handler, NULL);
|
||||||
|
|
||||||
|
if (parse_cmdline_args(cfg_cmd_ctx, argc, argv) != ERROR_OK)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
if (parse_config_file(cfg_cmd_ctx) != ERROR_OK)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
command_done(cfg_cmd_ctx);
|
||||||
|
|
||||||
|
if (jtag_init(cmd_ctx) != ERROR_OK)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
DEBUG("jtag init complete");
|
||||||
|
|
||||||
|
if (target_init(cmd_ctx) != ERROR_OK)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
DEBUG("target init complete");
|
||||||
|
|
||||||
|
if (flash_init(cmd_ctx) != ERROR_OK)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
DEBUG("flash init complete");
|
||||||
|
|
||||||
|
/* initialize tcp server */
|
||||||
|
server_init();
|
||||||
|
|
||||||
|
/* initialize telnet subsystem */
|
||||||
|
telnet_init("Open On-Chip Debugger");
|
||||||
|
gdb_init();
|
||||||
|
|
||||||
|
/* handle network connections */
|
||||||
|
server_loop(cmd_ctx);
|
||||||
|
|
||||||
|
/* free commandline interface */
|
||||||
|
command_done(cmd_ctx);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
INCLUDES = -I$(top_srcdir)/src/helper -I$(top_srcdir)/src/target $(all_includes)
|
||||||
|
METASOURCES = AUTO
|
||||||
|
noinst_LIBRARIES = libserver.a
|
||||||
|
noinst_HEADERS = server.h telnet_server.h gdb_server.h
|
||||||
|
libserver_a_SOURCES = server.c telnet_server.c gdb_server.c
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,47 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef GDB_SERVER_H
|
||||||
|
#define GDB_SERVER_H
|
||||||
|
|
||||||
|
#include "target.h"
|
||||||
|
#include "server.h"
|
||||||
|
|
||||||
|
#define GDB_BUFFER_SIZE 2048
|
||||||
|
|
||||||
|
typedef struct gdb_connection_s
|
||||||
|
{
|
||||||
|
char buffer[GDB_BUFFER_SIZE];
|
||||||
|
char *buf_p;
|
||||||
|
int buf_cnt;
|
||||||
|
int ctrl_c;
|
||||||
|
enum target_state frontend_state;
|
||||||
|
} gdb_connection_t;
|
||||||
|
|
||||||
|
typedef struct gdb_service_s
|
||||||
|
{
|
||||||
|
struct target_s *target;
|
||||||
|
} gdb_service_t;
|
||||||
|
|
||||||
|
extern int gdb_init();
|
||||||
|
extern int gdb_register_commands(command_context_t *command_context);
|
||||||
|
|
||||||
|
#define ERROR_GDB_BUFFER_TOO_SMALL (-800)
|
||||||
|
|
||||||
|
#endif /* GDB_SERVER_H */
|
|
@ -0,0 +1,368 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "server.h"
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "telnet_server.h"
|
||||||
|
#include "target.h"
|
||||||
|
|
||||||
|
#include <command.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
service_t *services = NULL;
|
||||||
|
|
||||||
|
/* shutdown_openocd == 1: exit the main event loop, and quit the debugger */
|
||||||
|
static int shutdown_openocd = 0;
|
||||||
|
int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
|
||||||
|
int add_connection(service_t *service, command_context_t *cmd_ctx)
|
||||||
|
{
|
||||||
|
unsigned int address_size;
|
||||||
|
connection_t *c, *p;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
c = malloc(sizeof(connection_t));
|
||||||
|
c->fd = -1;
|
||||||
|
memset(&c->sin, 0, sizeof(c->sin));
|
||||||
|
c->cmd_ctx = copy_command_context(cmd_ctx);
|
||||||
|
c->service = service;
|
||||||
|
c->input_pending = 0;
|
||||||
|
c->priv = NULL;
|
||||||
|
c->next = NULL;
|
||||||
|
|
||||||
|
address_size = sizeof(c->sin);
|
||||||
|
c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
|
||||||
|
|
||||||
|
if ((retval = service->new_connection(c)) == ERROR_OK)
|
||||||
|
{
|
||||||
|
INFO("accepted '%s' connection from %i", service->name, c->sin.sin_port);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
close(c->fd);
|
||||||
|
INFO("attempted '%s' connection rejected", service->name);
|
||||||
|
free(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (service->connections)
|
||||||
|
{
|
||||||
|
for (p = service->connections; p && p->next; p = p->next);
|
||||||
|
if (p)
|
||||||
|
p->next = c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
service->connections = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
service->max_connections--;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int remove_connection(service_t *service, connection_t *connection)
|
||||||
|
{
|
||||||
|
connection_t *c, *p = NULL;
|
||||||
|
|
||||||
|
/* find connection */
|
||||||
|
for (c = service->connections; c; c = c->next)
|
||||||
|
{
|
||||||
|
if (c->fd == connection->fd)
|
||||||
|
{
|
||||||
|
/* unlink connection */
|
||||||
|
if (p)
|
||||||
|
p->next = c->next;
|
||||||
|
else
|
||||||
|
service->connections = c->next;
|
||||||
|
|
||||||
|
service->connection_closed(c);
|
||||||
|
close(c->fd);
|
||||||
|
|
||||||
|
command_done(c->cmd_ctx);
|
||||||
|
|
||||||
|
/* delete connection */
|
||||||
|
free(c);
|
||||||
|
|
||||||
|
service->max_connections++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remember the last connection for unlinking */
|
||||||
|
p = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int add_service(char *name, enum connection_type type, unsigned short port, int max_connections, new_connection_handler_t new_connection_handler, input_handler_t input_handler, connection_closed_handler_t connection_closed_handler, void *priv)
|
||||||
|
{
|
||||||
|
service_t *c, *p;
|
||||||
|
int so_reuseaddr_option = 1;
|
||||||
|
int oldopts;
|
||||||
|
|
||||||
|
c = malloc(sizeof(service_t));
|
||||||
|
|
||||||
|
c->name = strdup(name);
|
||||||
|
c->type = type;
|
||||||
|
c->port = port;
|
||||||
|
c->max_connections = max_connections;
|
||||||
|
c->fd = -1;
|
||||||
|
c->connections = NULL;
|
||||||
|
c->new_connection = new_connection_handler;
|
||||||
|
c->input = input_handler;
|
||||||
|
c->connection_closed = connection_closed_handler;
|
||||||
|
c->priv = priv;
|
||||||
|
c->next = NULL;
|
||||||
|
|
||||||
|
if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||||
|
{
|
||||||
|
ERROR("error creating socket: %s", strerror(errno));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddr_option, sizeof(int));
|
||||||
|
|
||||||
|
oldopts = fcntl(c->fd, F_GETFL, 0);
|
||||||
|
fcntl(c->fd, F_SETFL, oldopts | O_NONBLOCK);
|
||||||
|
|
||||||
|
memset(&c->sin, 0, sizeof(c->sin));
|
||||||
|
c->sin.sin_family = AF_INET;
|
||||||
|
c->sin.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
c->sin.sin_port = htons(port);
|
||||||
|
|
||||||
|
if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1)
|
||||||
|
{
|
||||||
|
ERROR("couldn't bind to socket: %s", strerror(errno));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(c->fd, 1) == -1)
|
||||||
|
{
|
||||||
|
ERROR("couldn't listen on socket: %s", strerror(errno));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (services)
|
||||||
|
{
|
||||||
|
for (p = services; p && p->next; p = p->next);
|
||||||
|
if (p)
|
||||||
|
p->next = c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
services = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int remove_service(unsigned short port)
|
||||||
|
{
|
||||||
|
service_t *c, *p = NULL;
|
||||||
|
|
||||||
|
/* find service */
|
||||||
|
for (c = services; c; c = c->next)
|
||||||
|
{
|
||||||
|
if (c->port == port)
|
||||||
|
{
|
||||||
|
/* unlink service */
|
||||||
|
if (p)
|
||||||
|
p->next = c->next;
|
||||||
|
else
|
||||||
|
services = c->next;
|
||||||
|
|
||||||
|
if (c->name)
|
||||||
|
free(c->name);
|
||||||
|
|
||||||
|
/* delete service */
|
||||||
|
free(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remember the last service for unlinking */
|
||||||
|
p = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int server_loop(command_context_t *command_context)
|
||||||
|
{
|
||||||
|
service_t *service;
|
||||||
|
|
||||||
|
/* used in select() */
|
||||||
|
fd_set read_fds;
|
||||||
|
struct timeval tv;
|
||||||
|
int fd_max;
|
||||||
|
|
||||||
|
/* used in accept() */
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
|
||||||
|
ERROR("couldn't set SIGPIPE to SIG_IGN");
|
||||||
|
|
||||||
|
/* do regular tasks after at most 10ms */
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 10000;
|
||||||
|
|
||||||
|
while(!shutdown_openocd)
|
||||||
|
{
|
||||||
|
/* monitor sockets for acitvity */
|
||||||
|
fd_max = 0;
|
||||||
|
FD_ZERO(&read_fds);
|
||||||
|
|
||||||
|
/* add service and connection fds to read_fds */
|
||||||
|
for (service = services; service; service = service->next)
|
||||||
|
{
|
||||||
|
if (service->fd != -1)
|
||||||
|
{
|
||||||
|
/* listen for new connections */
|
||||||
|
FD_SET(service->fd, &read_fds);
|
||||||
|
|
||||||
|
if (service->fd > fd_max)
|
||||||
|
fd_max = service->fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (service->connections)
|
||||||
|
{
|
||||||
|
connection_t *c;
|
||||||
|
|
||||||
|
for (c = service->connections; c; c = c->next)
|
||||||
|
{
|
||||||
|
/* check for activity on the connection */
|
||||||
|
FD_SET(c->fd, &read_fds);
|
||||||
|
if (c->fd > fd_max)
|
||||||
|
fd_max = c->fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add STDIN to read_fds */
|
||||||
|
FD_SET(fileno(stdin), &read_fds);
|
||||||
|
|
||||||
|
if ((retval = select(fd_max + 1, &read_fds, NULL, NULL, &tv)) == -1)
|
||||||
|
{
|
||||||
|
if (errno == EINTR)
|
||||||
|
FD_ZERO(&read_fds);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR("error during select: %s", strerror(errno));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
target_call_timer_callbacks();
|
||||||
|
|
||||||
|
if (retval == 0)
|
||||||
|
{
|
||||||
|
/* do regular tasks after at most 100ms */
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 10000;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (shutdown_openocd)
|
||||||
|
return ERROR_COMMAND_CLOSE_CONNECTION;
|
||||||
|
|
||||||
|
handle_target();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
for (service = services; service; service = service->next)
|
||||||
|
{
|
||||||
|
/* handle new connections on listeners */
|
||||||
|
if ((service->fd != -1)
|
||||||
|
&& (FD_ISSET(service->fd, &read_fds)))
|
||||||
|
{
|
||||||
|
if (service->max_connections > 0)
|
||||||
|
add_connection(service, command_context);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
unsigned int address_size = sizeof(sin);
|
||||||
|
int tmp_fd;
|
||||||
|
tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
|
||||||
|
close(tmp_fd);
|
||||||
|
INFO("rejected '%s' connection, no more connections allowed", service->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* handle activity on connections */
|
||||||
|
if (service->connections)
|
||||||
|
{
|
||||||
|
connection_t *c;
|
||||||
|
|
||||||
|
for (c = service->connections; c;)
|
||||||
|
{
|
||||||
|
if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending)
|
||||||
|
{
|
||||||
|
if (service->input(c) != ERROR_OK)
|
||||||
|
{
|
||||||
|
connection_t *next = c->next;
|
||||||
|
remove_connection(service, c);
|
||||||
|
INFO("dropped '%s' connection", service->name);
|
||||||
|
c = next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c = c->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FD_ISSET(fileno(stdin), &read_fds))
|
||||||
|
{
|
||||||
|
if (getc(stdin) == 'x')
|
||||||
|
{
|
||||||
|
shutdown_openocd = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int server_init()
|
||||||
|
{
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int server_register_commands(command_context_t *context)
|
||||||
|
{
|
||||||
|
register_command(context, NULL, "shutdown", handle_shutdown_command,
|
||||||
|
COMMAND_ANY, "shut the server down");
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tell the server we want to shut down */
|
||||||
|
int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
shutdown_openocd = 1;
|
||||||
|
|
||||||
|
return ERROR_COMMAND_CLOSE_CONNECTION;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef SERVER_H
|
||||||
|
#define SERVER_H
|
||||||
|
|
||||||
|
#include "command.h"
|
||||||
|
#include "binarybuffer.h"
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
enum connection_type
|
||||||
|
{
|
||||||
|
CONNECTION_GDB,
|
||||||
|
CONNECTION_TELNET,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct connection_s
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
command_context_t *cmd_ctx;
|
||||||
|
struct service_s *service;
|
||||||
|
int input_pending;
|
||||||
|
void *priv;
|
||||||
|
struct connection_s *next;
|
||||||
|
} connection_t;
|
||||||
|
|
||||||
|
typedef int (*new_connection_handler_t)(connection_t *connection);
|
||||||
|
typedef int (*input_handler_t)(connection_t *connection);
|
||||||
|
typedef int (*connection_closed_handler_t)(connection_t *connection);
|
||||||
|
|
||||||
|
typedef struct service_s
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
enum connection_type type;
|
||||||
|
unsigned short port;
|
||||||
|
int fd;
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
int max_connections;
|
||||||
|
connection_t *connections;
|
||||||
|
new_connection_handler_t new_connection;
|
||||||
|
input_handler_t input;
|
||||||
|
connection_closed_handler_t connection_closed;
|
||||||
|
void *priv;
|
||||||
|
struct service_s *next;
|
||||||
|
} service_t;
|
||||||
|
|
||||||
|
extern int add_service(char *name, enum connection_type type, unsigned short port, int max_connections, new_connection_handler_t new_connection_handler, input_handler_t input_handler, connection_closed_handler_t connection_closed_handler, void *priv);
|
||||||
|
extern int server_init();
|
||||||
|
extern int server_loop(command_context_t *command_context);
|
||||||
|
extern int server_register_commands(command_context_t *context);
|
||||||
|
|
||||||
|
#define ERROR_SERVER_REMOTE_CLOSED (-400)
|
||||||
|
#define ERROR_CONNECTION_REJECTED (-401)
|
||||||
|
|
||||||
|
#endif /* SERVER_H */
|
|
@ -0,0 +1,570 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "telnet_server.h"
|
||||||
|
|
||||||
|
#include "server.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "command.h"
|
||||||
|
#include "target.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
static unsigned short telnet_port = 0;
|
||||||
|
|
||||||
|
int handle_exit_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int handle_telnet_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
|
||||||
|
static char *negotiate =
|
||||||
|
"\xFF\xFB\x03" /* IAC WILL Suppress Go Ahead */
|
||||||
|
"\xFF\xFB\x01" /* IAC WILL Echo */
|
||||||
|
"\xFF\xFD\x03" /* IAC DO Suppress Go Ahead */
|
||||||
|
"\xFF\xFE\x01"; /* IAC DON'T Echo */
|
||||||
|
|
||||||
|
#define CTRL(c) (c - '@')
|
||||||
|
|
||||||
|
void telnet_prompt(connection_t *connection)
|
||||||
|
{
|
||||||
|
telnet_connection_t *t_con = connection->priv;
|
||||||
|
|
||||||
|
write(connection->fd, t_con->prompt, strlen(t_con->prompt));
|
||||||
|
}
|
||||||
|
|
||||||
|
int telnet_output(struct command_context_s *cmd_ctx, char* line)
|
||||||
|
{
|
||||||
|
connection_t *connection = cmd_ctx->output_handler_priv;
|
||||||
|
|
||||||
|
write(connection->fd, line, strlen(line));
|
||||||
|
write(connection->fd, "\r\n\0", 3);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int telnet_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv)
|
||||||
|
{
|
||||||
|
struct command_context_s *cmd_ctx = priv;
|
||||||
|
connection_t *connection = cmd_ctx->output_handler_priv;
|
||||||
|
telnet_connection_t *t_con = connection->priv;
|
||||||
|
char buffer[512];
|
||||||
|
|
||||||
|
switch (event)
|
||||||
|
{
|
||||||
|
case TARGET_EVENT_HALTED:
|
||||||
|
command_print(cmd_ctx, "Target %i halted", get_num_by_target(target));
|
||||||
|
target->type->arch_state(target, buffer, 512);
|
||||||
|
buffer[511] = 0;
|
||||||
|
command_print(cmd_ctx, "%s", buffer);
|
||||||
|
telnet_prompt(connection);
|
||||||
|
t_con->surpress_prompt = 1;
|
||||||
|
break;
|
||||||
|
case TARGET_EVENT_RESUMED:
|
||||||
|
command_print(cmd_ctx, "Target %i resumed", get_num_by_target(target));
|
||||||
|
telnet_prompt(connection);
|
||||||
|
t_con->surpress_prompt = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int telnet_new_connection(connection_t *connection)
|
||||||
|
{
|
||||||
|
telnet_connection_t *telnet_connection = malloc(sizeof(telnet_connection_t));
|
||||||
|
telnet_service_t *telnet_service = connection->service->priv;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
connection->priv = telnet_connection;
|
||||||
|
|
||||||
|
/* initialize telnet connection information */
|
||||||
|
telnet_connection->line_size = 0;
|
||||||
|
telnet_connection->line_cursor = 0;
|
||||||
|
telnet_connection->option_size = 0;
|
||||||
|
telnet_connection->prompt = strdup("> ");
|
||||||
|
telnet_connection->surpress_prompt = 0;
|
||||||
|
telnet_connection->state = TELNET_STATE_DATA;
|
||||||
|
|
||||||
|
/* output goes through telnet connection */
|
||||||
|
command_set_output_handler(connection->cmd_ctx, telnet_output, connection);
|
||||||
|
|
||||||
|
/* negotiate telnet options */
|
||||||
|
write(connection->fd, negotiate, strlen(negotiate));
|
||||||
|
|
||||||
|
/* print connection banner */
|
||||||
|
if (telnet_service->banner)
|
||||||
|
{
|
||||||
|
write(connection->fd, telnet_service->banner, strlen(telnet_service->banner));
|
||||||
|
write(connection->fd, "\r\n\0", 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
telnet_prompt(connection);
|
||||||
|
|
||||||
|
/* initialize history */
|
||||||
|
for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++)
|
||||||
|
{
|
||||||
|
telnet_connection->history[i] = NULL;
|
||||||
|
}
|
||||||
|
telnet_connection->next_history = 0;
|
||||||
|
telnet_connection->current_history = 0;
|
||||||
|
|
||||||
|
target_register_event_callback(telnet_target_callback_event_handler, connection->cmd_ctx);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void telnet_clear_line(connection_t *connection, telnet_connection_t *t_con)
|
||||||
|
{
|
||||||
|
/* move to end of line */
|
||||||
|
if (t_con->line_cursor < t_con->line_size)
|
||||||
|
{
|
||||||
|
write(connection->fd, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* backspace, overwrite with space, backspace */
|
||||||
|
while (t_con->line_size > 0)
|
||||||
|
{
|
||||||
|
write(connection->fd, "\b \b", 3);
|
||||||
|
t_con->line_size--;
|
||||||
|
}
|
||||||
|
t_con->line_cursor = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int telnet_input(connection_t *connection)
|
||||||
|
{
|
||||||
|
int bytes_read;
|
||||||
|
char buffer[TELNET_BUFFER_SIZE];
|
||||||
|
char *buf_p;
|
||||||
|
telnet_connection_t *t_con = connection->priv;
|
||||||
|
command_context_t *command_context = connection->cmd_ctx;
|
||||||
|
|
||||||
|
bytes_read = read(connection->fd, buffer, TELNET_BUFFER_SIZE);
|
||||||
|
|
||||||
|
if (bytes_read == 0)
|
||||||
|
return ERROR_SERVER_REMOTE_CLOSED;
|
||||||
|
else if (bytes_read == -1)
|
||||||
|
{
|
||||||
|
ERROR("error during read: %s", strerror(errno));
|
||||||
|
return ERROR_SERVER_REMOTE_CLOSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf_p = buffer;
|
||||||
|
while (bytes_read)
|
||||||
|
{
|
||||||
|
switch (t_con->state)
|
||||||
|
{
|
||||||
|
case TELNET_STATE_DATA:
|
||||||
|
if (*buf_p == '\xff')
|
||||||
|
{
|
||||||
|
t_con->state = TELNET_STATE_IAC;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (isprint(*buf_p)) /* printable character */
|
||||||
|
{
|
||||||
|
write(connection->fd, buf_p, 1);
|
||||||
|
if (t_con->line_cursor == t_con->line_size)
|
||||||
|
{
|
||||||
|
t_con->line[t_con->line_size++] = *buf_p;
|
||||||
|
t_con->line_cursor++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
memmove(t_con->line + t_con->line_cursor + 1, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor);
|
||||||
|
t_con->line[t_con->line_cursor++] = *buf_p;
|
||||||
|
t_con->line_size++;
|
||||||
|
write(connection->fd, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor);
|
||||||
|
for (i = t_con->line_cursor; i < t_con->line_size; i++)
|
||||||
|
{
|
||||||
|
write(connection->fd, "\b", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else /* non-printable */
|
||||||
|
{
|
||||||
|
if (*buf_p == 0x1b) /* escape */
|
||||||
|
{
|
||||||
|
t_con->state = TELNET_STATE_ESCAPE;
|
||||||
|
t_con->last_escape = '\x00';
|
||||||
|
}
|
||||||
|
else if ((*buf_p == 0xd) || (*buf_p == 0xa)) /* CR/LF */
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
/* skip over combinations with CR/LF + NUL */
|
||||||
|
if (((*(buf_p + 1) == 0xa) || (*(buf_p + 1) == 0xd)) && (bytes_read > 1))
|
||||||
|
{
|
||||||
|
buf_p++;
|
||||||
|
bytes_read--;
|
||||||
|
}
|
||||||
|
if ((*(buf_p + 1) == 0) && (bytes_read > 1))
|
||||||
|
{
|
||||||
|
buf_p++;
|
||||||
|
bytes_read--;
|
||||||
|
}
|
||||||
|
t_con->line[t_con->line_size] = 0;
|
||||||
|
|
||||||
|
write(connection->fd, "\r\n\x00", 3);
|
||||||
|
|
||||||
|
if (strcmp(t_con->line, "history") == 0)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++)
|
||||||
|
{
|
||||||
|
if (t_con->history[i])
|
||||||
|
{
|
||||||
|
write(connection->fd, t_con->history[i], strlen(t_con->history[i]));
|
||||||
|
write(connection->fd, "\r\n\x00", 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
telnet_prompt(connection);
|
||||||
|
t_con->line_size = 0;
|
||||||
|
t_con->line_cursor = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we're running a command, so we need a prompt
|
||||||
|
* if the output handler is called, this gets set again */
|
||||||
|
t_con->surpress_prompt = 0;
|
||||||
|
if ((retval = command_run_line(command_context, t_con->line)) != ERROR_OK)
|
||||||
|
{
|
||||||
|
if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
|
||||||
|
{
|
||||||
|
return ERROR_SERVER_REMOTE_CLOSED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if the history slot is already taken, free it */
|
||||||
|
if (t_con->history[t_con->next_history])
|
||||||
|
{
|
||||||
|
free(t_con->history[t_con->next_history]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add line to history */
|
||||||
|
t_con->history[t_con->next_history++] = strdup(t_con->line);
|
||||||
|
|
||||||
|
/* current history line starts at the new entry */
|
||||||
|
t_con->current_history = t_con->next_history;
|
||||||
|
|
||||||
|
if (t_con->history[t_con->current_history])
|
||||||
|
{
|
||||||
|
free(t_con->history[t_con->current_history]);
|
||||||
|
}
|
||||||
|
t_con->history[t_con->current_history] = strdup("");
|
||||||
|
|
||||||
|
/* wrap history at TELNET_LINE_HISTORY_SIZE */
|
||||||
|
if (t_con->next_history > TELNET_LINE_HISTORY_SIZE - 1)
|
||||||
|
t_con->next_history = 0;
|
||||||
|
|
||||||
|
if (!t_con->surpress_prompt)
|
||||||
|
{
|
||||||
|
telnet_prompt(connection);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
t_con->surpress_prompt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_con->line_size = 0;
|
||||||
|
t_con->line_cursor = 0;
|
||||||
|
}
|
||||||
|
else if ((*buf_p == 0x7f) || (*buf_p == 0x8)) /* delete character */
|
||||||
|
{
|
||||||
|
if (t_con->line_cursor > 0)
|
||||||
|
{
|
||||||
|
if (t_con->line_cursor != t_con->line_size)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
write(connection->fd, "\b", 1);
|
||||||
|
t_con->line_cursor--;
|
||||||
|
t_con->line_size--;
|
||||||
|
memmove(t_con->line + t_con->line_cursor, t_con->line + t_con->line_cursor + 1, t_con->line_size - t_con->line_cursor);
|
||||||
|
|
||||||
|
write(connection->fd, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor);
|
||||||
|
write(connection->fd, " \b", 2);
|
||||||
|
for (i = t_con->line_cursor; i < t_con->line_size; i++)
|
||||||
|
{
|
||||||
|
write(connection->fd, "\b", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
t_con->line_size--;
|
||||||
|
t_con->line_cursor--;
|
||||||
|
/* back space: move the 'printer' head one char back, overwrite with space, move back again */
|
||||||
|
write(connection->fd, "\b \b", 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (*buf_p == 0x15) /* clear line */
|
||||||
|
{
|
||||||
|
telnet_clear_line(connection, t_con);
|
||||||
|
}
|
||||||
|
else if (*buf_p == CTRL('B')) /* cursor left */
|
||||||
|
{
|
||||||
|
if (t_con->line_cursor > 0)
|
||||||
|
{
|
||||||
|
write(connection->fd, "\b", 1);
|
||||||
|
t_con->line_cursor--;
|
||||||
|
}
|
||||||
|
t_con->state = TELNET_STATE_DATA;
|
||||||
|
}
|
||||||
|
else if (*buf_p == CTRL('F')) /* cursor right */
|
||||||
|
{
|
||||||
|
if (t_con->line_cursor < t_con->line_size)
|
||||||
|
{
|
||||||
|
write(connection->fd, t_con->line + t_con->line_cursor++, 1);
|
||||||
|
}
|
||||||
|
t_con->state = TELNET_STATE_DATA;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DEBUG("unhandled nonprintable: %2.2x", *buf_p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TELNET_STATE_IAC:
|
||||||
|
switch (*buf_p)
|
||||||
|
{
|
||||||
|
case '\xfe':
|
||||||
|
t_con->state = TELNET_STATE_DONT;
|
||||||
|
break;
|
||||||
|
case '\xfd':
|
||||||
|
t_con->state = TELNET_STATE_DO;
|
||||||
|
break;
|
||||||
|
case '\xfc':
|
||||||
|
t_con->state = TELNET_STATE_WONT;
|
||||||
|
break;
|
||||||
|
case '\xfb':
|
||||||
|
t_con->state = TELNET_STATE_WILL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TELNET_STATE_SB:
|
||||||
|
break;
|
||||||
|
case TELNET_STATE_SE:
|
||||||
|
break;
|
||||||
|
case TELNET_STATE_WILL:
|
||||||
|
case TELNET_STATE_WONT:
|
||||||
|
case TELNET_STATE_DO:
|
||||||
|
case TELNET_STATE_DONT:
|
||||||
|
t_con->state = TELNET_STATE_DATA;
|
||||||
|
break;
|
||||||
|
case TELNET_STATE_ESCAPE:
|
||||||
|
if (t_con->last_escape == '[')
|
||||||
|
{
|
||||||
|
if (*buf_p == 'D') /* cursor left */
|
||||||
|
{
|
||||||
|
if (t_con->line_cursor > 0)
|
||||||
|
{
|
||||||
|
write(connection->fd, "\b", 1);
|
||||||
|
t_con->line_cursor--;
|
||||||
|
}
|
||||||
|
t_con->state = TELNET_STATE_DATA;
|
||||||
|
}
|
||||||
|
else if (*buf_p == 'C') /* cursor right */
|
||||||
|
{
|
||||||
|
if (t_con->line_cursor < t_con->line_size)
|
||||||
|
{
|
||||||
|
write(connection->fd, t_con->line + t_con->line_cursor++, 1);
|
||||||
|
}
|
||||||
|
t_con->state = TELNET_STATE_DATA;
|
||||||
|
}
|
||||||
|
else if (*buf_p == 'A') /* cursor up */
|
||||||
|
{
|
||||||
|
int last_history = (t_con->current_history - 1 >= 0) ? t_con->current_history - 1 : 127;
|
||||||
|
if (t_con->history[last_history])
|
||||||
|
{
|
||||||
|
telnet_clear_line(connection, t_con);
|
||||||
|
t_con->line_size = strlen(t_con->history[last_history]);
|
||||||
|
t_con->line_cursor = t_con->line_size;
|
||||||
|
memcpy(t_con->line, t_con->history[last_history], t_con->line_size + 1);
|
||||||
|
write(connection->fd, t_con->line, t_con->line_size);
|
||||||
|
t_con->current_history = last_history;
|
||||||
|
}
|
||||||
|
t_con->state = TELNET_STATE_DATA;
|
||||||
|
}
|
||||||
|
else if (*buf_p == 'B') /* cursor down */
|
||||||
|
{
|
||||||
|
int next_history = (t_con->current_history + 1 < 128) ? t_con->current_history + 1 : 0;
|
||||||
|
if (t_con->history[next_history])
|
||||||
|
{
|
||||||
|
telnet_clear_line(connection, t_con);
|
||||||
|
t_con->line_size = strlen(t_con->history[next_history]);
|
||||||
|
t_con->line_cursor = t_con->line_size;
|
||||||
|
memcpy(t_con->line, t_con->history[next_history], t_con->line_size + 1);
|
||||||
|
write(connection->fd, t_con->line, t_con->line_size);
|
||||||
|
t_con->current_history = next_history;
|
||||||
|
}
|
||||||
|
t_con->state = TELNET_STATE_DATA;
|
||||||
|
}
|
||||||
|
else if (*buf_p == '3')
|
||||||
|
{
|
||||||
|
t_con->last_escape = *buf_p;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
t_con->state = TELNET_STATE_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (t_con->last_escape == '3')
|
||||||
|
{
|
||||||
|
/* Remove character */
|
||||||
|
if (*buf_p == '~')
|
||||||
|
{
|
||||||
|
if (t_con->line_cursor < t_con->line_size)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
t_con->line_size--;
|
||||||
|
/* remove char from line buffer */
|
||||||
|
memmove(t_con->line + t_con->line_cursor, t_con->line + t_con->line_cursor + 1, t_con->line_size - t_con->line_cursor);
|
||||||
|
|
||||||
|
/* print remainder of buffer */
|
||||||
|
write(connection->fd, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor);
|
||||||
|
/* overwrite last char with whitespace */
|
||||||
|
write(connection->fd, " \b", 2);
|
||||||
|
|
||||||
|
/* move back to cursor position*/
|
||||||
|
for (i = t_con->line_cursor; i < t_con->line_size; i++)
|
||||||
|
{
|
||||||
|
write(connection->fd, "\b", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t_con->state = TELNET_STATE_DATA;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
t_con->state = TELNET_STATE_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (t_con->last_escape == '\x00')
|
||||||
|
{
|
||||||
|
if (*buf_p == '[')
|
||||||
|
{
|
||||||
|
t_con->last_escape = *buf_p;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
t_con->state = TELNET_STATE_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR("BUG: unexpected value in t_con->last_escape");
|
||||||
|
t_con->state = TELNET_STATE_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("unknown telnet state");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_read--;
|
||||||
|
buf_p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int telnet_connection_closed(connection_t *connection)
|
||||||
|
{
|
||||||
|
telnet_connection_t *t_con = connection->priv;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (t_con->prompt)
|
||||||
|
free(t_con->prompt);
|
||||||
|
|
||||||
|
for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++)
|
||||||
|
{
|
||||||
|
if (t_con->history[i])
|
||||||
|
free(t_con->history[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connection->priv)
|
||||||
|
free(connection->priv);
|
||||||
|
else
|
||||||
|
ERROR("BUG: connection->priv == NULL");
|
||||||
|
|
||||||
|
target_unregister_event_callback(telnet_target_callback_event_handler, connection->cmd_ctx);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int telnet_set_prompt(connection_t *connection, char *prompt)
|
||||||
|
{
|
||||||
|
telnet_connection_t *t_con = connection->priv;
|
||||||
|
|
||||||
|
t_con->prompt = strdup(prompt);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int telnet_init(char *banner)
|
||||||
|
{
|
||||||
|
telnet_service_t *telnet_service = malloc(sizeof(telnet_service_t));
|
||||||
|
|
||||||
|
if (telnet_port == 0)
|
||||||
|
{
|
||||||
|
WARNING("no telnet port specified, using default port 4444");
|
||||||
|
telnet_port = 4444;
|
||||||
|
}
|
||||||
|
|
||||||
|
telnet_service->banner = banner;
|
||||||
|
|
||||||
|
add_service("telnet", CONNECTION_TELNET, telnet_port, 1, telnet_new_connection, telnet_input, telnet_connection_closed, telnet_service);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int telnet_register_commands(command_context_t *command_context)
|
||||||
|
{
|
||||||
|
register_command(command_context, NULL, "exit", handle_exit_command,
|
||||||
|
COMMAND_EXEC, "exit telnet session");
|
||||||
|
|
||||||
|
register_command(command_context, NULL, "telnet_port", handle_telnet_port_command,
|
||||||
|
COMMAND_CONFIG, "");
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* daemon configuration command telnet_port */
|
||||||
|
int handle_telnet_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
if (argc == 0)
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
/* only if the port wasn't overwritten by cmdline */
|
||||||
|
if (telnet_port == 0)
|
||||||
|
telnet_port = strtoul(args[0], NULL, 0);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle_exit_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
return ERROR_COMMAND_CLOSE_CONNECTION;
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef TELNET_SERVER_H
|
||||||
|
#define TELNET_SERVER_H
|
||||||
|
|
||||||
|
#include "server.h"
|
||||||
|
|
||||||
|
#define TELNET_BUFFER_SIZE (1024)
|
||||||
|
|
||||||
|
#define TELNET_OPTION_MAX_SIZE (128)
|
||||||
|
#define TELNET_LINE_HISTORY_SIZE (128)
|
||||||
|
#define TELNET_LINE_MAX_SIZE (256)
|
||||||
|
|
||||||
|
enum telnet_states
|
||||||
|
{
|
||||||
|
TELNET_STATE_DATA,
|
||||||
|
TELNET_STATE_IAC,
|
||||||
|
TELNET_STATE_SB,
|
||||||
|
TELNET_STATE_SE,
|
||||||
|
TELNET_STATE_WILL,
|
||||||
|
TELNET_STATE_WONT,
|
||||||
|
TELNET_STATE_DO,
|
||||||
|
TELNET_STATE_DONT,
|
||||||
|
TELNET_STATE_ESCAPE,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct telnet_connection_s
|
||||||
|
{
|
||||||
|
char *prompt;
|
||||||
|
int surpress_prompt;
|
||||||
|
enum telnet_states state;
|
||||||
|
char line[TELNET_LINE_MAX_SIZE];
|
||||||
|
int line_size;
|
||||||
|
int line_cursor;
|
||||||
|
char option[TELNET_OPTION_MAX_SIZE];
|
||||||
|
int option_size;
|
||||||
|
char last_escape;
|
||||||
|
char *history[TELNET_LINE_HISTORY_SIZE];
|
||||||
|
int next_history;
|
||||||
|
int current_history;
|
||||||
|
} telnet_connection_t;
|
||||||
|
|
||||||
|
typedef struct telnet_service_s
|
||||||
|
{
|
||||||
|
char *banner;
|
||||||
|
} telnet_service_t;
|
||||||
|
|
||||||
|
extern int telnet_init(char *banner);
|
||||||
|
extern int telnet_register_commands(command_context_t *command_context);
|
||||||
|
|
||||||
|
#endif /* TELNET_SERVER_H */
|
|
@ -0,0 +1,7 @@
|
||||||
|
INCLUDES = -I$(top_srcdir)/src/gdb -I$(top_srcdir)/src/helper -I$(top_srcdir)/src/jtag -I$(top_srcdir)/src/xsvf $(all_includes)
|
||||||
|
METASOURCES = AUTO
|
||||||
|
noinst_LIBRARIES = libtarget.a
|
||||||
|
libtarget_a_SOURCES = target.c register.c breakpoints.c armv4_5.c embeddedice.c etm.c arm7tdmi.c arm9tdmi.c \
|
||||||
|
arm_jtag.c arm7_9_common.c algorithm.c arm920t.c arm720t.c armv4_5_mmu.c armv4_5_cache.c
|
||||||
|
noinst_HEADERS = target.h register.h armv4_5.h embeddedice.h etm.h arm7tdmi.h arm9tdmi.h \
|
||||||
|
arm_jtag.h arm7_9_common.h arm920t.h arm720t.h armv4_5_mmu.h armv4_5_cache.h breakpoints.h algorithm.h
|
|
@ -0,0 +1,54 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "config.h"
|
||||||
|
#include "algorithm.h"
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
#include "binarybuffer.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
void init_mem_param(mem_param_t *param, u32 address, u32 size, enum param_direction direction)
|
||||||
|
{
|
||||||
|
param->address = address;
|
||||||
|
param->size = size;
|
||||||
|
param->value = malloc(size);
|
||||||
|
param->direction = direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_mem_param(mem_param_t *param)
|
||||||
|
{
|
||||||
|
free(param->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_reg_param(reg_param_t *param, char *reg_name, u32 size, enum param_direction direction)
|
||||||
|
{
|
||||||
|
param->reg_name = reg_name;
|
||||||
|
param->size = size;
|
||||||
|
param->value = malloc(CEIL(size, 8));
|
||||||
|
param->direction = direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_reg_param(reg_param_t *param)
|
||||||
|
{
|
||||||
|
free(param->value);
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef ALGORITHM_H
|
||||||
|
#define ALGORITHM_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
enum param_direction
|
||||||
|
{
|
||||||
|
PARAM_IN,
|
||||||
|
PARAM_OUT,
|
||||||
|
PARAM_IN_OUT
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct mem_param_s
|
||||||
|
{
|
||||||
|
u32 address;
|
||||||
|
u32 size;
|
||||||
|
u8 *value;
|
||||||
|
enum param_direction direction;
|
||||||
|
} mem_param_t;
|
||||||
|
|
||||||
|
typedef struct reg_param_s
|
||||||
|
{
|
||||||
|
char *reg_name;
|
||||||
|
u32 size;
|
||||||
|
u8 *value;
|
||||||
|
enum param_direction direction;
|
||||||
|
} reg_param_t;
|
||||||
|
|
||||||
|
extern void init_mem_param(mem_param_t *param, u32 address, u32 size, enum param_direction direction);
|
||||||
|
extern void destroy_mem_param(mem_param_t *param);
|
||||||
|
extern void init_reg_param(reg_param_t *param, char *reg_name, u32 size, enum param_direction direction);
|
||||||
|
extern void destroy_reg_param(reg_param_t *param);
|
||||||
|
|
||||||
|
#endif /* ALGORITHM_H */
|
|
@ -0,0 +1,625 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "arm720t.h"
|
||||||
|
#include "jtag.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
#define _DEBUG_INSTRUCTION_EXECUTION_
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* cli handling */
|
||||||
|
int arm720t_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
|
||||||
|
int arm720t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int arm720t_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int arm720t_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int arm720t_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
|
||||||
|
/* forward declarations */
|
||||||
|
int arm720t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
|
||||||
|
int arm720t_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
|
||||||
|
int arm720t_quit();
|
||||||
|
int arm720t_arch_state(struct target_s *target, char *buf, int buf_size);
|
||||||
|
int arm720t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
|
||||||
|
int arm720t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
|
||||||
|
int arm720t_soft_reset_halt(struct target_s *target);
|
||||||
|
|
||||||
|
target_type_t arm720t_target =
|
||||||
|
{
|
||||||
|
.name = "arm720t",
|
||||||
|
|
||||||
|
.poll = arm7_9_poll,
|
||||||
|
.arch_state = arm720t_arch_state,
|
||||||
|
|
||||||
|
.halt = arm7_9_halt,
|
||||||
|
.resume = arm7_9_resume,
|
||||||
|
.step = arm7_9_step,
|
||||||
|
|
||||||
|
.assert_reset = arm7_9_assert_reset,
|
||||||
|
.deassert_reset = arm7_9_deassert_reset,
|
||||||
|
.soft_reset_halt = arm720t_soft_reset_halt,
|
||||||
|
|
||||||
|
.get_gdb_reg_list = armv4_5_get_gdb_reg_list,
|
||||||
|
|
||||||
|
.read_memory = arm720t_read_memory,
|
||||||
|
.write_memory = arm720t_write_memory,
|
||||||
|
.bulk_write_memory = arm7_9_bulk_write_memory,
|
||||||
|
|
||||||
|
.run_algorithm = armv4_5_run_algorithm,
|
||||||
|
|
||||||
|
.add_breakpoint = arm7_9_add_breakpoint,
|
||||||
|
.remove_breakpoint = arm7_9_remove_breakpoint,
|
||||||
|
.add_watchpoint = arm7_9_add_watchpoint,
|
||||||
|
.remove_watchpoint = arm7_9_remove_watchpoint,
|
||||||
|
|
||||||
|
.register_commands = arm720t_register_commands,
|
||||||
|
.target_command = arm720t_target_command,
|
||||||
|
.init_target = arm720t_init_target,
|
||||||
|
.quit = arm720t_quit
|
||||||
|
};
|
||||||
|
|
||||||
|
int arm720t_scan_cp15(target_t *target, u32 out, u32 *in, int instruction, int clock)
|
||||||
|
{
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
scan_field_t fields[2];
|
||||||
|
u8 out_buf[4];
|
||||||
|
u8 instruction_buf = instruction;
|
||||||
|
|
||||||
|
out = flip_u32(out, 32);
|
||||||
|
buf_set_u32(out_buf, 0, 32, out);
|
||||||
|
|
||||||
|
jtag_add_end_state(TAP_PD);
|
||||||
|
arm_jtag_scann(jtag_info, 0xf);
|
||||||
|
arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
|
||||||
|
|
||||||
|
fields[0].device = jtag_info->chain_pos;
|
||||||
|
fields[0].num_bits = 1;
|
||||||
|
fields[0].out_value = &instruction_buf;
|
||||||
|
fields[0].out_mask = NULL;
|
||||||
|
fields[0].in_value = NULL;
|
||||||
|
fields[0].in_check_value = NULL;
|
||||||
|
fields[0].in_check_mask = NULL;
|
||||||
|
fields[0].in_handler = NULL;
|
||||||
|
fields[0].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[1].device = jtag_info->chain_pos;
|
||||||
|
fields[1].num_bits = 32;
|
||||||
|
fields[1].out_value = out_buf;
|
||||||
|
fields[1].out_mask = NULL;
|
||||||
|
if (in)
|
||||||
|
{
|
||||||
|
fields[1].in_value = (u8*)in;
|
||||||
|
fields[1].in_handler = arm_jtag_buf_to_u32_flip;
|
||||||
|
fields[1].in_handler_priv = in;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
fields[1].in_value = NULL;
|
||||||
|
fields[1].in_handler = NULL;
|
||||||
|
fields[1].in_handler_priv = NULL;
|
||||||
|
}
|
||||||
|
fields[1].in_check_value = NULL;
|
||||||
|
fields[1].in_check_mask = NULL;
|
||||||
|
|
||||||
|
jtag_add_dr_scan(2, fields, -1);
|
||||||
|
|
||||||
|
if (clock)
|
||||||
|
jtag_add_runtest(0, -1);
|
||||||
|
|
||||||
|
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
|
||||||
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
if (in)
|
||||||
|
DEBUG("out: %8.8x, in: %8.8x, instruction: %i, clock: %i", out, *in, instruction, clock);
|
||||||
|
else
|
||||||
|
DEBUG("out: %8.8x, instruction: %i, clock: %i", out, instruction, clock);
|
||||||
|
#else
|
||||||
|
DEBUG("out: %8.8x, instruction: %i, clock: %i", in, out, instruction, clock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm720t_read_cp15(target_t *target, u32 opcode, u32 *value)
|
||||||
|
{
|
||||||
|
/* fetch CP15 opcode */
|
||||||
|
arm720t_scan_cp15(target, opcode, NULL, 1, 1);
|
||||||
|
/* "DECODE" stage */
|
||||||
|
arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1);
|
||||||
|
/* "EXECUTE" stage (1) */
|
||||||
|
arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 0);
|
||||||
|
arm720t_scan_cp15(target, 0x0, NULL, 0, 1);
|
||||||
|
/* "EXECUTE" stage (2) */
|
||||||
|
arm720t_scan_cp15(target, 0x0, NULL, 0, 1);
|
||||||
|
/* "EXECUTE" stage (3), CDATA is read */
|
||||||
|
arm720t_scan_cp15(target, ARMV4_5_NOP, value, 1, 1);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm720t_write_cp15(target_t *target, u32 opcode, u32 value)
|
||||||
|
{
|
||||||
|
/* fetch CP15 opcode */
|
||||||
|
arm720t_scan_cp15(target, opcode, NULL, 1, 1);
|
||||||
|
/* "DECODE" stage */
|
||||||
|
arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1);
|
||||||
|
/* "EXECUTE" stage (1) */
|
||||||
|
arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 0);
|
||||||
|
arm720t_scan_cp15(target, 0x0, NULL, 0, 1);
|
||||||
|
/* "EXECUTE" stage (2) */
|
||||||
|
arm720t_scan_cp15(target, value, NULL, 0, 1);
|
||||||
|
arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 arm720t_get_ttb(target_t *target)
|
||||||
|
{
|
||||||
|
u32 ttb = 0x0;
|
||||||
|
|
||||||
|
arm720t_read_cp15(target, 0xee120f10, &ttb);
|
||||||
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
ttb &= 0xffffc000;
|
||||||
|
|
||||||
|
return ttb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm720t_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
|
||||||
|
{
|
||||||
|
u32 cp15_control;
|
||||||
|
|
||||||
|
/* read cp15 control register */
|
||||||
|
arm720t_read_cp15(target, 0xee110f10, &cp15_control);
|
||||||
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
if (mmu)
|
||||||
|
cp15_control &= ~0x1U;
|
||||||
|
|
||||||
|
if (d_u_cache || i_cache)
|
||||||
|
cp15_control &= ~0x4U;
|
||||||
|
|
||||||
|
arm720t_write_cp15(target, 0xee010f10, cp15_control);
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm720t_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
|
||||||
|
{
|
||||||
|
u32 cp15_control;
|
||||||
|
|
||||||
|
/* read cp15 control register */
|
||||||
|
arm720t_read_cp15(target, 0xee110f10, &cp15_control);
|
||||||
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
if (mmu)
|
||||||
|
cp15_control |= 0x1U;
|
||||||
|
|
||||||
|
if (d_u_cache || i_cache)
|
||||||
|
cp15_control |= 0x4U;
|
||||||
|
|
||||||
|
arm720t_write_cp15(target, 0xee010f10, cp15_control);
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm720t_post_debug_entry(target_t *target)
|
||||||
|
{
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info;
|
||||||
|
arm720t_common_t *arm720t = arm7tdmi->arch_info;
|
||||||
|
|
||||||
|
/* examine cp15 control reg */
|
||||||
|
arm720t_read_cp15(target, 0xee110f10, &arm720t->cp15_control_reg);
|
||||||
|
jtag_execute_queue();
|
||||||
|
DEBUG("cp15_control_reg: %8.8x", arm720t->cp15_control_reg);
|
||||||
|
|
||||||
|
arm720t->armv4_5_mmu.mmu_enabled = (arm720t->cp15_control_reg & 0x1U) ? 1 : 0;
|
||||||
|
arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm720t->cp15_control_reg & 0x4U) ? 1 : 0;
|
||||||
|
arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0;
|
||||||
|
|
||||||
|
/* save i/d fault status and address register */
|
||||||
|
arm720t_read_cp15(target, 0xee150f10, &arm720t->fsr);
|
||||||
|
arm720t_read_cp15(target, 0xee160f10, &arm720t->far);
|
||||||
|
jtag_execute_queue();
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm720t_pre_restore_context(target_t *target)
|
||||||
|
{
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info;
|
||||||
|
arm720t_common_t *arm720t = arm7tdmi->arch_info;
|
||||||
|
|
||||||
|
/* restore i/d fault status and address register */
|
||||||
|
arm720t_write_cp15(target, 0xee050f10, arm720t->fsr);
|
||||||
|
arm720t_write_cp15(target, 0xee060f10, arm720t->far);
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm720t_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm7tdmi_common_t **arm7tdmi_p, arm720t_common_t **arm720t_p)
|
||||||
|
{
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9;
|
||||||
|
arm7tdmi_common_t *arm7tdmi;
|
||||||
|
arm720t_common_t *arm720t;
|
||||||
|
|
||||||
|
if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
arm7_9 = armv4_5->arch_info;
|
||||||
|
if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
arm7tdmi = arm7_9->arch_info;
|
||||||
|
if (arm7tdmi->common_magic != ARM7TDMI_COMMON_MAGIC)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
arm720t = arm7tdmi->arch_info;
|
||||||
|
if (arm720t->common_magic != ARM720T_COMMON_MAGIC)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*armv4_5_p = armv4_5;
|
||||||
|
*arm7_9_p = arm7_9;
|
||||||
|
*arm7tdmi_p = arm7tdmi;
|
||||||
|
*arm720t_p = arm720t;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm720t_arch_state(struct target_s *target, char *buf, int buf_size)
|
||||||
|
{
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info;
|
||||||
|
arm720t_common_t *arm720t = arm7tdmi->arch_info;
|
||||||
|
|
||||||
|
char *state[] =
|
||||||
|
{
|
||||||
|
"disabled", "enabled"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
|
||||||
|
{
|
||||||
|
ERROR("BUG: called for a non-ARMv4/5 target");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buf, buf_size,
|
||||||
|
"target halted in %s state due to %s, current mode: %s\n"
|
||||||
|
"cpsr: 0x%8.8x pc: 0x%8.8x\n"
|
||||||
|
"MMU: %s, Cache: %s",
|
||||||
|
armv4_5_state_strings[armv4_5->core_state],
|
||||||
|
target_debug_reason_strings[target->debug_reason],
|
||||||
|
armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)],
|
||||||
|
buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32),
|
||||||
|
buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32),
|
||||||
|
state[arm720t->armv4_5_mmu.mmu_enabled],
|
||||||
|
state[arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled]);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm720t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info;
|
||||||
|
arm720t_common_t *arm720t = arm7tdmi->arch_info;
|
||||||
|
|
||||||
|
/* disable cache, but leave MMU enabled */
|
||||||
|
if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled)
|
||||||
|
arm720t_disable_mmu_caches(target, 0, 1, 0);
|
||||||
|
|
||||||
|
retval = arm7_9_read_memory(target, address, size, count, buffer);
|
||||||
|
|
||||||
|
if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled)
|
||||||
|
arm720t_enable_mmu_caches(target, 0, 1, 0);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm720t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm720t_soft_reset_halt(struct target_s *target)
|
||||||
|
{
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info;
|
||||||
|
arm720t_common_t *arm720t = arm7tdmi->arch_info;
|
||||||
|
reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
|
||||||
|
|
||||||
|
if (target->state == TARGET_RUNNING)
|
||||||
|
{
|
||||||
|
target->type->halt(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (buf_get_u32(dbg_stat->value, EICE_DBG_CONTROL_DBGACK, 1) == 0)
|
||||||
|
{
|
||||||
|
embeddedice_read_reg(dbg_stat);
|
||||||
|
jtag_execute_queue();
|
||||||
|
}
|
||||||
|
|
||||||
|
target->state = TARGET_HALTED;
|
||||||
|
|
||||||
|
/* SVC, ARM state, IRQ and FIQ disabled */
|
||||||
|
buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8, 0xd3);
|
||||||
|
armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1;
|
||||||
|
armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
|
||||||
|
|
||||||
|
/* start fetching from 0x0 */
|
||||||
|
buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0);
|
||||||
|
armv4_5->core_cache->reg_list[15].dirty = 1;
|
||||||
|
armv4_5->core_cache->reg_list[15].valid = 1;
|
||||||
|
|
||||||
|
armv4_5->core_mode = ARMV4_5_MODE_SVC;
|
||||||
|
armv4_5->core_state = ARMV4_5_STATE_ARM;
|
||||||
|
|
||||||
|
arm720t_disable_mmu_caches(target, 1, 1, 1);
|
||||||
|
arm720t->armv4_5_mmu.mmu_enabled = 0;
|
||||||
|
arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0;
|
||||||
|
arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0;
|
||||||
|
|
||||||
|
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm720t_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
|
||||||
|
{
|
||||||
|
arm7tdmi_init_target(cmd_ctx, target);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm720t_quit()
|
||||||
|
{
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm720t_init_arch_info(target_t *target, arm720t_common_t *arm720t, int chain_pos, char *variant)
|
||||||
|
{
|
||||||
|
arm7tdmi_common_t *arm7tdmi = &arm720t->arm7tdmi_common;
|
||||||
|
arm7_9_common_t *arm7_9 = &arm7tdmi->arm7_9_common;
|
||||||
|
|
||||||
|
arm7tdmi_init_arch_info(target, arm7tdmi, chain_pos, variant);
|
||||||
|
|
||||||
|
arm7tdmi->arch_info = arm720t;
|
||||||
|
arm720t->common_magic = ARM720T_COMMON_MAGIC;
|
||||||
|
|
||||||
|
arm7_9->post_debug_entry = arm720t_post_debug_entry;
|
||||||
|
arm7_9->pre_restore_context = arm720t_pre_restore_context;
|
||||||
|
|
||||||
|
arm720t->armv4_5_mmu.armv4_5_cache.ctype = -1;
|
||||||
|
arm720t->armv4_5_mmu.get_ttb = arm720t_get_ttb;
|
||||||
|
arm720t->armv4_5_mmu.read_memory = arm7_9_read_memory;
|
||||||
|
arm720t->armv4_5_mmu.write_memory = arm7_9_write_memory;
|
||||||
|
arm720t->armv4_5_mmu.disable_mmu_caches = arm720t_disable_mmu_caches;
|
||||||
|
arm720t->armv4_5_mmu.enable_mmu_caches = arm720t_enable_mmu_caches;
|
||||||
|
arm720t->armv4_5_mmu.has_tiny_pages = 0;
|
||||||
|
arm720t->armv4_5_mmu.mmu_enabled = 0;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm720t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
|
||||||
|
{
|
||||||
|
int chain_pos;
|
||||||
|
char *variant = NULL;
|
||||||
|
arm720t_common_t *arm720t = malloc(sizeof(arm720t_common_t));
|
||||||
|
|
||||||
|
if (argc < 4)
|
||||||
|
{
|
||||||
|
ERROR("'target arm720t' requires at least one additional argument");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
chain_pos = strtoul(args[3], NULL, 0);
|
||||||
|
|
||||||
|
if (argc >= 5)
|
||||||
|
variant = strdup(args[4]);
|
||||||
|
|
||||||
|
DEBUG("chain_pos: %i, variant: %s", chain_pos, variant);
|
||||||
|
|
||||||
|
arm720t_init_arch_info(target, arm720t, chain_pos, variant);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm720t_register_commands(struct command_context_s *cmd_ctx)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
command_t *arm720t_cmd;
|
||||||
|
|
||||||
|
|
||||||
|
retval = arm7tdmi_register_commands(cmd_ctx);
|
||||||
|
|
||||||
|
arm720t_cmd = register_command(cmd_ctx, NULL, "arm720t", NULL, COMMAND_ANY, NULL);
|
||||||
|
|
||||||
|
register_command(cmd_ctx, arm720t_cmd, "cp15", arm720t_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register <opcode> [value]");
|
||||||
|
register_command(cmd_ctx, arm720t_cmd, "virt2phys", arm720t_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa <va>");
|
||||||
|
|
||||||
|
register_command(cmd_ctx, arm720t_cmd, "mdw_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory words <physical addr> [count]");
|
||||||
|
register_command(cmd_ctx, arm720t_cmd, "mdh_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory half-words <physical addr> [count]");
|
||||||
|
register_command(cmd_ctx, arm720t_cmd, "mdb_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory bytes <physical addr> [count]");
|
||||||
|
|
||||||
|
register_command(cmd_ctx, arm720t_cmd, "mww_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory word <physical addr> <value>");
|
||||||
|
register_command(cmd_ctx, arm720t_cmd, "mwh_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word <physical addr> <value>");
|
||||||
|
register_command(cmd_ctx, arm720t_cmd, "mwb_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory byte <physical addr> <value>");
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm720t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
target_t *target = get_current_target(cmd_ctx);
|
||||||
|
armv4_5_common_t *armv4_5;
|
||||||
|
arm7_9_common_t *arm7_9;
|
||||||
|
arm7tdmi_common_t *arm7tdmi;
|
||||||
|
arm720t_common_t *arm720t;
|
||||||
|
arm_jtag_t *jtag_info;
|
||||||
|
|
||||||
|
if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "current target isn't an ARM720t target");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* one or more argument, access a single register (write if second argument is given */
|
||||||
|
if (argc >= 1)
|
||||||
|
{
|
||||||
|
u32 opcode = strtoul(args[0], NULL, 0);
|
||||||
|
|
||||||
|
if (argc == 1)
|
||||||
|
{
|
||||||
|
u32 value;
|
||||||
|
if ((retval = arm720t_read_cp15(target, opcode, &value)) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "couldn't access cp15 with opcode 0x%8.8x", opcode);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
command_print(cmd_ctx, "0x%8.8x: 0x%8.8x", opcode, value);
|
||||||
|
}
|
||||||
|
else if (argc == 2)
|
||||||
|
{
|
||||||
|
u32 value = strtoul(args[1], NULL, 0);
|
||||||
|
if ((retval = arm720t_write_cp15(target, opcode, value)) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "couldn't access cp15 with opcode 0x%8.8x", opcode);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
command_print(cmd_ctx, "0x%8.8x: 0x%8.8x", opcode, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm720t_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
target_t *target = get_current_target(cmd_ctx);
|
||||||
|
armv4_5_common_t *armv4_5;
|
||||||
|
arm7_9_common_t *arm7_9;
|
||||||
|
arm7tdmi_common_t *arm7tdmi;
|
||||||
|
arm720t_common_t *arm720t;
|
||||||
|
arm_jtag_t *jtag_info;
|
||||||
|
|
||||||
|
if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "current target isn't an ARM720t target");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return armv4_5_mmu_handle_virt2phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu);
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm720t_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
target_t *target = get_current_target(cmd_ctx);
|
||||||
|
armv4_5_common_t *armv4_5;
|
||||||
|
arm7_9_common_t *arm7_9;
|
||||||
|
arm7tdmi_common_t *arm7tdmi;
|
||||||
|
arm720t_common_t *arm720t;
|
||||||
|
arm_jtag_t *jtag_info;
|
||||||
|
|
||||||
|
if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "current target isn't an ARM720t target");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return armv4_5_mmu_handle_md_phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu);
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm720t_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
target_t *target = get_current_target(cmd_ctx);
|
||||||
|
armv4_5_common_t *armv4_5;
|
||||||
|
arm7_9_common_t *arm7_9;
|
||||||
|
arm7tdmi_common_t *arm7tdmi;
|
||||||
|
arm720t_common_t *arm720t;
|
||||||
|
arm_jtag_t *jtag_info;
|
||||||
|
|
||||||
|
if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "current target isn't an ARM720t target");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return armv4_5_mmu_handle_mw_phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef ARM720T_H
|
||||||
|
#define ARM720T_H
|
||||||
|
|
||||||
|
#include "target.h"
|
||||||
|
#include "register.h"
|
||||||
|
#include "embeddedice.h"
|
||||||
|
#include "arm_jtag.h"
|
||||||
|
#include "arm7tdmi.h"
|
||||||
|
#include "armv4_5_mmu.h"
|
||||||
|
#include "armv4_5_cache.h"
|
||||||
|
|
||||||
|
#define ARM720T_COMMON_MAGIC 0xa720a720
|
||||||
|
|
||||||
|
typedef struct arm720t_common_s
|
||||||
|
{
|
||||||
|
int common_magic;
|
||||||
|
armv4_5_mmu_common_t armv4_5_mmu;
|
||||||
|
arm7tdmi_common_t arm7tdmi_common;
|
||||||
|
u32 cp15_control_reg;
|
||||||
|
u32 fsr;
|
||||||
|
u32 far;
|
||||||
|
} arm720t_common_t;
|
||||||
|
|
||||||
|
#endif /* ARM720T_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,129 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef ARM7_9_COMMON_H
|
||||||
|
#define ARM7_9_COMMON_H
|
||||||
|
|
||||||
|
#include "armv4_5.h"
|
||||||
|
#include "arm_jtag.h"
|
||||||
|
#include "breakpoints.h"
|
||||||
|
#include "target.h"
|
||||||
|
|
||||||
|
#define ARM7_9_COMMON_MAGIC 0x0a790a79
|
||||||
|
|
||||||
|
typedef struct arm7_9_common_s
|
||||||
|
{
|
||||||
|
int common_magic;
|
||||||
|
|
||||||
|
arm_jtag_t jtag_info;
|
||||||
|
reg_cache_t *eice_cache;
|
||||||
|
reg_cache_t *etm_cache;
|
||||||
|
|
||||||
|
u32 arm_bkpt;
|
||||||
|
u16 thumb_bkpt;
|
||||||
|
int sw_bkpts_use_wp;
|
||||||
|
int wp_available;
|
||||||
|
int wp0_used;
|
||||||
|
int wp1_used;
|
||||||
|
int sw_bkpts_enabled;
|
||||||
|
int force_hw_bkpts;
|
||||||
|
int dbgreq_adjust_pc;
|
||||||
|
int use_dbgrq;
|
||||||
|
int has_etm;
|
||||||
|
|
||||||
|
int reinit_embeddedice;
|
||||||
|
|
||||||
|
struct working_area_s *dcc_working_area;
|
||||||
|
|
||||||
|
int fast_memory_writes;
|
||||||
|
int dcc_downloads;
|
||||||
|
|
||||||
|
int (*examine_debug_reason)(target_t *target);
|
||||||
|
|
||||||
|
void (*change_to_arm)(target_t *target, u32 *r0, u32 *pc);
|
||||||
|
|
||||||
|
void (*read_core_regs)(target_t *target, u32 mask, u32* core_regs[16]);
|
||||||
|
void (*read_xpsr)(target_t *target, u32 *xpsr, int spsr);
|
||||||
|
|
||||||
|
void (*write_xpsr)(target_t *target, u32 xpsr, int spsr);
|
||||||
|
void (*write_xpsr_im8)(target_t *target, u8 xpsr_im, int rot, int spsr);
|
||||||
|
void (*write_core_regs)(target_t *target, u32 mask, u32 core_regs[16]);
|
||||||
|
|
||||||
|
void (*load_word_regs)(target_t *target, u32 mask);
|
||||||
|
void (*load_hword_reg)(target_t *target, int num);
|
||||||
|
void (*load_byte_reg)(target_t *target, int num);
|
||||||
|
|
||||||
|
void (*store_word_regs)(target_t *target, u32 mask);
|
||||||
|
void (*store_hword_reg)(target_t *target, int num);
|
||||||
|
void (*store_byte_reg)(target_t *target, int num);
|
||||||
|
|
||||||
|
void (*write_pc)(target_t *target, u32 pc);
|
||||||
|
void (*branch_resume)(target_t *target);
|
||||||
|
void (*branch_resume_thumb)(target_t *target);
|
||||||
|
|
||||||
|
void (*enable_single_step)(target_t *target);
|
||||||
|
void (*disable_single_step)(target_t *target);
|
||||||
|
|
||||||
|
void (*pre_debug_entry)(target_t *target);
|
||||||
|
void (*post_debug_entry)(target_t *target);
|
||||||
|
|
||||||
|
void (*pre_restore_context)(target_t *target);
|
||||||
|
void (*post_restore_context)(target_t *target);
|
||||||
|
|
||||||
|
armv4_5_common_t armv4_5_common;
|
||||||
|
void *arch_info;
|
||||||
|
|
||||||
|
} arm7_9_common_t;
|
||||||
|
|
||||||
|
int arm7_9_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
|
||||||
|
enum target_state arm7_9_poll(target_t *target);
|
||||||
|
|
||||||
|
int arm7_9_assert_reset(target_t *target);
|
||||||
|
int arm7_9_deassert_reset(target_t *target);
|
||||||
|
int arm7_9_reset_request_halt(target_t *target);
|
||||||
|
int arm7_9_early_halt(target_t *target);
|
||||||
|
int arm7_9_soft_reset_halt(struct target_s *target);
|
||||||
|
|
||||||
|
int arm7_9_halt(target_t *target);
|
||||||
|
int arm7_9_debug_entry(target_t *target);
|
||||||
|
int arm7_9_full_context(target_t *target);
|
||||||
|
int arm7_9_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution);
|
||||||
|
int arm7_9_step(struct target_s *target, int current, u32 address, int handle_breakpoints);
|
||||||
|
int arm7_9_read_core_reg(struct target_s *target, int num, enum armv4_5_mode mode);
|
||||||
|
int arm7_9_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
|
||||||
|
int arm7_9_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
|
||||||
|
int arm7_9_bulk_write_memory(target_t *target, u32 address, u32 count, u8 *buffer);
|
||||||
|
|
||||||
|
int arm7_9_run_algorithm(struct target_s *target, int num_mem_params, mem_param_t *mem_params, int num_reg_prams, reg_param_t *reg_param, u32 entry_point, void *arch_info);
|
||||||
|
|
||||||
|
int arm7_9_add_breakpoint(struct target_s *target, u32 address, u32 length, enum breakpoint_type type);
|
||||||
|
int arm7_9_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint);
|
||||||
|
int arm7_9_add_watchpoint(struct target_s *target, u32 address, u32 length, enum watchpoint_rw rw);
|
||||||
|
int arm7_9_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint);
|
||||||
|
|
||||||
|
void arm7_9_enable_eice_step(target_t *target);
|
||||||
|
void arm7_9_disable_eice_step(target_t *target);
|
||||||
|
|
||||||
|
int arm7_9_execute_sys_speed(struct target_s *target);
|
||||||
|
|
||||||
|
int arm7_9_init_arch_info(target_t *target, arm7_9_common_t *arm7_9);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ARM7_9_COMMON_H */
|
|
@ -0,0 +1,780 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "arm7tdmi.h"
|
||||||
|
|
||||||
|
#include "arm7_9_common.h"
|
||||||
|
#include "register.h"
|
||||||
|
#include "target.h"
|
||||||
|
#include "armv4_5.h"
|
||||||
|
#include "embeddedice.h"
|
||||||
|
#include "etm.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "jtag.h"
|
||||||
|
#include "arm_jtag.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#define _DEBUG_INSTRUCTION_EXECUTION_
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* cli handling */
|
||||||
|
int arm7tdmi_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
|
||||||
|
/* forward declarations */
|
||||||
|
int arm7tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
|
||||||
|
int arm7tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
|
||||||
|
int arm7tdmi_quit();
|
||||||
|
|
||||||
|
/* target function declarations */
|
||||||
|
enum target_state arm7tdmi_poll(struct target_s *target);
|
||||||
|
int arm7tdmi_halt(target_t *target);
|
||||||
|
int arm7tdmi_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
|
||||||
|
|
||||||
|
target_type_t arm7tdmi_target =
|
||||||
|
{
|
||||||
|
.name = "arm7tdmi",
|
||||||
|
|
||||||
|
.poll = arm7_9_poll,
|
||||||
|
.arch_state = armv4_5_arch_state,
|
||||||
|
|
||||||
|
.halt = arm7_9_halt,
|
||||||
|
.resume = arm7_9_resume,
|
||||||
|
.step = arm7_9_step,
|
||||||
|
|
||||||
|
.assert_reset = arm7_9_assert_reset,
|
||||||
|
.deassert_reset = arm7_9_deassert_reset,
|
||||||
|
.soft_reset_halt = arm7_9_soft_reset_halt,
|
||||||
|
|
||||||
|
.get_gdb_reg_list = armv4_5_get_gdb_reg_list,
|
||||||
|
|
||||||
|
.read_memory = arm7_9_read_memory,
|
||||||
|
.write_memory = arm7_9_write_memory,
|
||||||
|
.bulk_write_memory = arm7_9_bulk_write_memory,
|
||||||
|
|
||||||
|
.run_algorithm = armv4_5_run_algorithm,
|
||||||
|
|
||||||
|
.add_breakpoint = arm7_9_add_breakpoint,
|
||||||
|
.remove_breakpoint = arm7_9_remove_breakpoint,
|
||||||
|
.add_watchpoint = arm7_9_add_watchpoint,
|
||||||
|
.remove_watchpoint = arm7_9_remove_watchpoint,
|
||||||
|
|
||||||
|
.register_commands = arm7tdmi_register_commands,
|
||||||
|
.target_command = arm7tdmi_target_command,
|
||||||
|
.init_target = arm7tdmi_init_target,
|
||||||
|
.quit = arm7tdmi_quit
|
||||||
|
};
|
||||||
|
|
||||||
|
int arm7tdmi_examine_debug_reason(target_t *target)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
|
||||||
|
/* only check the debug reason if we don't know it already */
|
||||||
|
if ((target->debug_reason != DBG_REASON_DBGRQ)
|
||||||
|
&& (target->debug_reason != DBG_REASON_SINGLESTEP))
|
||||||
|
{
|
||||||
|
scan_field_t fields[2];
|
||||||
|
u8 databus[4];
|
||||||
|
u8 breakpoint;
|
||||||
|
|
||||||
|
jtag_add_end_state(TAP_PD);
|
||||||
|
|
||||||
|
fields[0].device = arm7_9->jtag_info.chain_pos;
|
||||||
|
fields[0].num_bits = 1;
|
||||||
|
fields[0].out_value = NULL;
|
||||||
|
fields[0].out_mask = NULL;
|
||||||
|
fields[0].in_value = &breakpoint;
|
||||||
|
fields[0].in_check_value = NULL;
|
||||||
|
fields[0].in_check_mask = NULL;
|
||||||
|
fields[0].in_handler = NULL;
|
||||||
|
fields[0].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[1].device = arm7_9->jtag_info.chain_pos;
|
||||||
|
fields[1].num_bits = 32;
|
||||||
|
fields[1].out_value = NULL;
|
||||||
|
fields[1].out_mask = NULL;
|
||||||
|
fields[1].in_value = databus;
|
||||||
|
fields[1].in_check_value = NULL;
|
||||||
|
fields[1].in_check_mask = NULL;
|
||||||
|
fields[1].in_handler = NULL;
|
||||||
|
fields[1].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
arm_jtag_scann(&arm7_9->jtag_info, 0x1);
|
||||||
|
arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr);
|
||||||
|
|
||||||
|
jtag_add_dr_scan(2, fields, TAP_PD);
|
||||||
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
fields[0].in_value = NULL;
|
||||||
|
fields[0].out_value = &breakpoint;
|
||||||
|
fields[1].in_value = NULL;
|
||||||
|
fields[1].out_value = databus;
|
||||||
|
|
||||||
|
jtag_add_dr_scan(2, fields, TAP_PD);
|
||||||
|
|
||||||
|
if (breakpoint & 1)
|
||||||
|
target->debug_reason = DBG_REASON_WATCHPOINT;
|
||||||
|
else
|
||||||
|
target->debug_reason = DBG_REASON_BREAKPOINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* put an instruction in the ARM7TDMI pipeline or write the data bus, and optionally read data */
|
||||||
|
int arm7tdmi_clock_out(arm_jtag_t *jtag_info, u32 out, u32 *in, int breakpoint)
|
||||||
|
{
|
||||||
|
scan_field_t fields[2];
|
||||||
|
u8 out_buf[4];
|
||||||
|
u8 breakpoint_buf;
|
||||||
|
|
||||||
|
out = flip_u32(out, 32);
|
||||||
|
buf_set_u32(out_buf, 0, 32, out);
|
||||||
|
buf_set_u32(&breakpoint_buf, 0, 1, breakpoint);
|
||||||
|
|
||||||
|
jtag_add_end_state(TAP_PD);
|
||||||
|
arm_jtag_scann(jtag_info, 0x1);
|
||||||
|
arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
|
||||||
|
|
||||||
|
fields[0].device = jtag_info->chain_pos;
|
||||||
|
fields[0].num_bits = 1;
|
||||||
|
fields[0].out_value = &breakpoint_buf;
|
||||||
|
fields[0].out_mask = NULL;
|
||||||
|
fields[0].in_value = NULL;
|
||||||
|
fields[0].in_check_value = NULL;
|
||||||
|
fields[0].in_check_mask = NULL;
|
||||||
|
fields[0].in_handler = NULL;
|
||||||
|
fields[0].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[1].device = jtag_info->chain_pos;
|
||||||
|
fields[1].num_bits = 32;
|
||||||
|
fields[1].out_value = out_buf;
|
||||||
|
fields[1].out_mask = NULL;
|
||||||
|
if (in)
|
||||||
|
{
|
||||||
|
fields[1].in_value = (u8*)in;
|
||||||
|
fields[1].in_handler = arm_jtag_buf_to_u32_flip;
|
||||||
|
fields[1].in_handler_priv = in;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
fields[1].in_value = NULL;
|
||||||
|
fields[1].in_handler = NULL;
|
||||||
|
fields[1].in_handler_priv = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fields[1].in_check_value = NULL;
|
||||||
|
fields[1].in_check_mask = NULL;
|
||||||
|
|
||||||
|
jtag_add_dr_scan(2, fields, -1);
|
||||||
|
|
||||||
|
jtag_add_runtest(0, -1);
|
||||||
|
|
||||||
|
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
|
||||||
|
{
|
||||||
|
char* in_string;
|
||||||
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
if (in)
|
||||||
|
{
|
||||||
|
in_string = buf_to_char((u8*)in, 32);
|
||||||
|
DEBUG("out: 0x%8.8x, in: %s", flip_u32(out, 32), in_string);
|
||||||
|
free(in_string);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
DEBUG("out: 0x%8.8x", flip_u32(out, 32));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* put an instruction in the ARM7TDMI pipeline, and optionally read data */
|
||||||
|
int arm7tdmi_clock_data_in(arm_jtag_t *jtag_info, u32 *in)
|
||||||
|
{
|
||||||
|
scan_field_t fields[2];
|
||||||
|
|
||||||
|
jtag_add_end_state(TAP_PD);
|
||||||
|
arm_jtag_scann(jtag_info, 0x1);
|
||||||
|
arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
|
||||||
|
|
||||||
|
fields[0].device = jtag_info->chain_pos;
|
||||||
|
fields[0].num_bits = 1;
|
||||||
|
fields[0].out_value = NULL;
|
||||||
|
fields[0].out_mask = NULL;
|
||||||
|
fields[0].in_value = NULL;
|
||||||
|
fields[0].in_check_value = NULL;
|
||||||
|
fields[0].in_check_mask = NULL;
|
||||||
|
fields[0].in_handler = NULL;
|
||||||
|
fields[0].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[1].device = jtag_info->chain_pos;
|
||||||
|
fields[1].num_bits = 32;
|
||||||
|
fields[1].out_value = NULL;
|
||||||
|
fields[1].out_mask = NULL;
|
||||||
|
fields[1].in_value = (u8*)in;
|
||||||
|
fields[1].in_handler = arm_jtag_buf_to_u32_flip;
|
||||||
|
fields[1].in_handler_priv = in;
|
||||||
|
fields[1].in_check_value = NULL;
|
||||||
|
fields[1].in_check_mask = NULL;
|
||||||
|
|
||||||
|
jtag_add_dr_scan(2, fields, -1);
|
||||||
|
|
||||||
|
jtag_add_runtest(0, -1);
|
||||||
|
|
||||||
|
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
|
||||||
|
{
|
||||||
|
char* in_string;
|
||||||
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
if (in)
|
||||||
|
{
|
||||||
|
in_string = buf_to_char((u8*)in, 32);
|
||||||
|
DEBUG("in: %s", in_string);
|
||||||
|
free(in_string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm7tdmi_change_to_arm(target_t *target, u32 *r0, u32 *pc)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* save r0 before using it and put system in ARM state
|
||||||
|
* to allow common handling of ARM and THUMB debugging */
|
||||||
|
|
||||||
|
/* fetch STR r0, [r0] */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0);
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
|
||||||
|
/* nothing fetched, STR r0, [r0] in Execute (2) */
|
||||||
|
arm7tdmi_clock_data_in(jtag_info, r0);
|
||||||
|
|
||||||
|
/* MOV r0, r15 fetched, STR in Decode */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), NULL, 0);
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0);
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
|
||||||
|
/* nothing fetched, STR r0, [r0] in Execute (2) */
|
||||||
|
arm7tdmi_clock_data_in(jtag_info, pc);
|
||||||
|
|
||||||
|
/* fetch MOV */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV_IM(0, 0x0), NULL, 0);
|
||||||
|
|
||||||
|
/* fetch BX */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), NULL, 0);
|
||||||
|
/* NOP fetched, BX in Decode, MOV in Execute */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
|
||||||
|
/* NOP fetched, BX in Execute (1) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
|
||||||
|
|
||||||
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
/* fix program counter:
|
||||||
|
* MOV r0, r15 was the 4th instruction (+6)
|
||||||
|
* reading PC in Thumb state gives address of instruction + 4
|
||||||
|
*/
|
||||||
|
*pc -= 0xa;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm7tdmi_read_core_regs(target_t *target, u32 mask, u32* core_regs[16])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* STMIA r0-15, [r0] at debug speed
|
||||||
|
* register values will start to appear on 4th DCLK
|
||||||
|
*/
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0);
|
||||||
|
|
||||||
|
/* fetch NOP, STM in DECODE stage */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
/* fetch NOP, STM in EXECUTE stage (1st cycle) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
|
||||||
|
for (i = 0; i <= 15; i++)
|
||||||
|
{
|
||||||
|
if (mask & (1 << i))
|
||||||
|
/* nothing fetched, STM still in EXECUTE (1+i cycle) */
|
||||||
|
arm7tdmi_clock_data_in(jtag_info, core_regs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm7tdmi_read_xpsr(target_t *target, u32 *xpsr, int spsr)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* MRS r0, cpsr */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), NULL, 0);
|
||||||
|
|
||||||
|
/* STR r0, [r15] */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), NULL, 0);
|
||||||
|
/* fetch NOP, STR in DECODE stage */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
/* fetch NOP, STR in EXECUTE stage (1st cycle) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
/* nothing fetched, STR still in EXECUTE (2nd cycle) */
|
||||||
|
arm7tdmi_clock_data_in(jtag_info, xpsr);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm7tdmi_write_xpsr(target_t *target, u32 xpsr, int spsr)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
DEBUG("xpsr: %8.8x, spsr: %i", xpsr, spsr);
|
||||||
|
|
||||||
|
/* MSR1 fetched */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), NULL, 0);
|
||||||
|
/* MSR2 fetched, MSR1 in DECODE */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), NULL, 0);
|
||||||
|
/* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), NULL, 0);
|
||||||
|
/* nothing fetched, MSR1 in EXECUTE (2) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
/* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), NULL, 0);
|
||||||
|
/* nothing fetched, MSR2 in EXECUTE (2) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
/* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
/* nothing fetched, MSR3 in EXECUTE (2) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
/* NOP fetched, MSR4 in EXECUTE (1) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
/* nothing fetched, MSR4 in EXECUTE (2) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm7tdmi_write_xpsr_im8(target_t *target, u8 xpsr_im, int rot, int spsr)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr);
|
||||||
|
|
||||||
|
/* MSR fetched */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), NULL, 0);
|
||||||
|
/* NOP fetched, MSR in DECODE */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
/* NOP fetched, MSR in EXECUTE (1) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
/* nothing fetched, MSR in EXECUTE (2) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm7tdmi_write_core_regs(target_t *target, u32 mask, u32 core_regs[16])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* LDMIA r0-15, [r0] at debug speed
|
||||||
|
* register values will start to appear on 4th DCLK
|
||||||
|
*/
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), NULL, 0);
|
||||||
|
|
||||||
|
/* fetch NOP, LDM in DECODE stage */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
|
||||||
|
for (i = 0; i <= 15; i++)
|
||||||
|
{
|
||||||
|
if (mask & (1 << i))
|
||||||
|
/* nothing fetched, LDM still in EXECUTE (1+i cycle) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, core_regs[i], NULL, 0);
|
||||||
|
}
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm7tdmi_load_word_regs(target_t *target, u32 mask)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* put system-speed load-multiple into the pipeline */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), NULL, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm7tdmi_load_hword_reg(target_t *target, int num)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* put system-speed load half-word into the pipeline */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), NULL, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm7tdmi_load_byte_reg(target_t *target, int num)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* put system-speed load byte into the pipeline */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), NULL, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm7tdmi_store_word_regs(target_t *target, u32 mask)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* put system-speed store-multiple into the pipeline */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), NULL, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm7tdmi_store_hword_reg(target_t *target, int num)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* put system-speed store half-word into the pipeline */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), NULL, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm7tdmi_store_byte_reg(target_t *target, int num)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* put system-speed store byte into the pipeline */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), NULL, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm7tdmi_write_pc(target_t *target, u32 pc)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* LDMIA r0-15, [r0] at debug speed
|
||||||
|
* register values will start to appear on 4th DCLK
|
||||||
|
*/
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), NULL, 0);
|
||||||
|
/* fetch NOP, LDM in DECODE stage */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
/* nothing fetched, LDM in EXECUTE stage (1st cycle) load register */
|
||||||
|
arm7tdmi_clock_out(jtag_info, pc, NULL, 0);
|
||||||
|
/* nothing fetched, LDM in EXECUTE stage (2nd cycle) load register */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
/* nothing fetched, LDM in EXECUTE stage (3rd cycle) load register */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
/* fetch NOP, LDM in EXECUTE stage (4th cycle) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
/* fetch NOP, LDM in EXECUTE stage (5th cycle) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm7tdmi_branch_resume(target_t *target)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_B(0xfffffa, 0), NULL, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm7tdmi_branch_resume_thumb(target_t *target)
|
||||||
|
{
|
||||||
|
DEBUG("");
|
||||||
|
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
|
||||||
|
|
||||||
|
/* LDMIA r0, [r0] at debug speed
|
||||||
|
* register values will start to appear on 4th DCLK
|
||||||
|
*/
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), NULL, 0);
|
||||||
|
|
||||||
|
/* fetch NOP, LDM in DECODE stage */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
/* nothing fetched, LDM in EXECUTE stage (2nd cycle) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32) | 1, NULL, 0);
|
||||||
|
/* nothing fetched, LDM in EXECUTE stage (3rd cycle) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
|
||||||
|
/* Branch and eXchange */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_BX(0), NULL, 0);
|
||||||
|
|
||||||
|
embeddedice_read_reg(dbg_stat);
|
||||||
|
|
||||||
|
/* fetch NOP, BX in DECODE stage */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
|
||||||
|
/* target is now in Thumb state */
|
||||||
|
embeddedice_read_reg(dbg_stat);
|
||||||
|
|
||||||
|
/* fetch NOP, BX in EXECUTE stage (1st cycle) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
|
||||||
|
|
||||||
|
/* target is now in Thumb state */
|
||||||
|
embeddedice_read_reg(dbg_stat);
|
||||||
|
|
||||||
|
/* clean r0 bits to avoid alignment problems */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV_IM(0, 0x0), NULL, 0);
|
||||||
|
/* load r0 value, MOV_IM in Decode*/
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR(0, 0), NULL, 0);
|
||||||
|
/* fetch NOP, LDR in Decode, MOV_IM in Execute */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
|
||||||
|
/* fetch NOP, LDR in Execute */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
|
||||||
|
/* nothing fetched, LDR in EXECUTE stage (2nd cycle) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, buf_get_u32(armv4_5->core_cache->reg_list[0].value, 0, 32), NULL, 0);
|
||||||
|
/* nothing fetched, LDR in EXECUTE stage (3rd cycle) */
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
|
||||||
|
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
|
||||||
|
|
||||||
|
embeddedice_read_reg(dbg_stat);
|
||||||
|
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 1);
|
||||||
|
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f7), NULL, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm7tdmi_build_reg_cache(target_t *target)
|
||||||
|
{
|
||||||
|
reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache);
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
arm7tdmi_common_t *arch_info = arm7_9->arch_info;
|
||||||
|
|
||||||
|
|
||||||
|
(*cache_p) = armv4_5_build_reg_cache(target, armv4_5);
|
||||||
|
armv4_5->core_cache = (*cache_p);
|
||||||
|
|
||||||
|
(*cache_p)->next = embeddedice_build_reg_cache(target, jtag_info, 0);
|
||||||
|
arm7_9->eice_cache = (*cache_p)->next;
|
||||||
|
|
||||||
|
if (arm7_9->has_etm)
|
||||||
|
{
|
||||||
|
(*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, 0);
|
||||||
|
arm7_9->etm_cache = (*cache_p)->next->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arch_info->has_monitor_mode)
|
||||||
|
(*cache_p)->next->reg_list[0].size = 6;
|
||||||
|
else
|
||||||
|
(*cache_p)->next->reg_list[0].size = 3;
|
||||||
|
|
||||||
|
(*cache_p)->next->reg_list[1].size = 5;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm7tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
|
||||||
|
{
|
||||||
|
|
||||||
|
arm7tdmi_build_reg_cache(target);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm7tdmi_quit()
|
||||||
|
{
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm7tdmi_init_arch_info(target_t *target, arm7tdmi_common_t *arm7tdmi, int chain_pos, char *variant)
|
||||||
|
{
|
||||||
|
armv4_5_common_t *armv4_5;
|
||||||
|
arm7_9_common_t *arm7_9;
|
||||||
|
int has_etm = 0;
|
||||||
|
|
||||||
|
arm7_9 = &arm7tdmi->arm7_9_common;
|
||||||
|
armv4_5 = &arm7_9->armv4_5_common;
|
||||||
|
|
||||||
|
/* prepare JTAG information for the new target */
|
||||||
|
arm7_9->jtag_info.chain_pos = chain_pos;
|
||||||
|
arm7_9->jtag_info.scann_size = 4;
|
||||||
|
|
||||||
|
/* register arch-specific functions */
|
||||||
|
arm7_9->examine_debug_reason = arm7tdmi_examine_debug_reason;
|
||||||
|
arm7_9->change_to_arm = arm7tdmi_change_to_arm;
|
||||||
|
arm7_9->read_core_regs = arm7tdmi_read_core_regs;
|
||||||
|
arm7_9->read_xpsr = arm7tdmi_read_xpsr;
|
||||||
|
|
||||||
|
arm7_9->write_xpsr = arm7tdmi_write_xpsr;
|
||||||
|
arm7_9->write_xpsr_im8 = arm7tdmi_write_xpsr_im8;
|
||||||
|
arm7_9->write_core_regs = arm7tdmi_write_core_regs;
|
||||||
|
|
||||||
|
arm7_9->load_word_regs = arm7tdmi_load_word_regs;
|
||||||
|
arm7_9->load_hword_reg = arm7tdmi_load_hword_reg;
|
||||||
|
arm7_9->load_byte_reg = arm7tdmi_load_byte_reg;
|
||||||
|
|
||||||
|
arm7_9->store_word_regs = arm7tdmi_store_word_regs;
|
||||||
|
arm7_9->store_hword_reg = arm7tdmi_store_hword_reg;
|
||||||
|
arm7_9->store_byte_reg = arm7tdmi_store_byte_reg;
|
||||||
|
|
||||||
|
arm7_9->write_pc = arm7tdmi_write_pc;
|
||||||
|
arm7_9->branch_resume = arm7tdmi_branch_resume;
|
||||||
|
arm7_9->branch_resume_thumb = arm7tdmi_branch_resume_thumb;
|
||||||
|
|
||||||
|
arm7_9->enable_single_step = arm7_9_enable_eice_step;
|
||||||
|
arm7_9->disable_single_step = arm7_9_disable_eice_step;
|
||||||
|
|
||||||
|
arm7_9->pre_debug_entry = NULL;
|
||||||
|
arm7_9->post_debug_entry = NULL;
|
||||||
|
|
||||||
|
arm7_9->pre_restore_context = NULL;
|
||||||
|
arm7_9->post_restore_context = NULL;
|
||||||
|
|
||||||
|
/* initialize arch-specific breakpoint handling */
|
||||||
|
buf_set_u32((u8*)(&arm7_9->arm_bkpt), 0, 32, 0xdeeedeee);
|
||||||
|
buf_set_u32((u8*)(&arm7_9->thumb_bkpt), 0, 16, 0xdeee);
|
||||||
|
|
||||||
|
arm7_9->sw_bkpts_use_wp = 1;
|
||||||
|
arm7_9->sw_bkpts_enabled = 0;
|
||||||
|
arm7_9->dbgreq_adjust_pc = 2;
|
||||||
|
arm7_9->arch_info = arm7tdmi;
|
||||||
|
|
||||||
|
arm7tdmi->has_monitor_mode = 0;
|
||||||
|
arm7tdmi->arch_info = NULL;
|
||||||
|
arm7tdmi->common_magic = ARM7TDMI_COMMON_MAGIC;
|
||||||
|
|
||||||
|
if (variant)
|
||||||
|
{
|
||||||
|
if (strcmp(variant, "arm7tdmi-s_r4") == 0)
|
||||||
|
arm7tdmi->has_monitor_mode = 1;
|
||||||
|
else if (strcmp(variant, "arm7tdmi_r4") == 0)
|
||||||
|
arm7tdmi->has_monitor_mode = 1;
|
||||||
|
else if (strcmp(variant, "lpc2000") == 0)
|
||||||
|
{
|
||||||
|
arm7tdmi->has_monitor_mode = 1;
|
||||||
|
has_etm = 1;
|
||||||
|
}
|
||||||
|
arm7tdmi->variant = strdup(variant);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
arm7tdmi->variant = strdup("");
|
||||||
|
|
||||||
|
arm7_9_init_arch_info(target, arm7_9);
|
||||||
|
|
||||||
|
arm7_9->has_etm = has_etm;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* target arm7tdmi <endianess> <startup_mode> <chain_pos> <variant> */
|
||||||
|
int arm7tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
|
||||||
|
{
|
||||||
|
int chain_pos;
|
||||||
|
char *variant = NULL;
|
||||||
|
arm7tdmi_common_t *arm7tdmi = malloc(sizeof(arm7tdmi_common_t));
|
||||||
|
|
||||||
|
if (argc < 4)
|
||||||
|
{
|
||||||
|
ERROR("'target arm7tdmi' requires at least one additional argument");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
chain_pos = strtoul(args[2], NULL, 0);
|
||||||
|
|
||||||
|
if (argc >= 5)
|
||||||
|
variant = args[4];
|
||||||
|
|
||||||
|
arm7tdmi_init_arch_info(target, arm7tdmi, chain_pos, variant);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm7tdmi_register_commands(struct command_context_s *cmd_ctx)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
retval = arm7_9_register_commands(cmd_ctx);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef ARM7TDMI_H
|
||||||
|
#define ARM7TDMI_H
|
||||||
|
|
||||||
|
#include "target.h"
|
||||||
|
#include "register.h"
|
||||||
|
#include "armv4_5.h"
|
||||||
|
#include "embeddedice.h"
|
||||||
|
#include "arm_jtag.h"
|
||||||
|
#include "arm7_9_common.h"
|
||||||
|
|
||||||
|
#define ARM7TDMI_COMMON_MAGIC 0x00a700a7
|
||||||
|
|
||||||
|
typedef struct arm7tdmi_common_s
|
||||||
|
{
|
||||||
|
int common_magic;
|
||||||
|
char *variant;
|
||||||
|
int has_monitor_mode;
|
||||||
|
void *arch_info;
|
||||||
|
arm7_9_common_t arm7_9_common;
|
||||||
|
} arm7tdmi_common_t;
|
||||||
|
|
||||||
|
int arm7tdmi_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
int arm7tdmi_init_arch_info(target_t *target, arm7tdmi_common_t *arm7tdmi, int chain_pos, char *variant);
|
||||||
|
int arm7tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ARM7TDMI_H */
|
|
@ -0,0 +1,967 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "arm920t.h"
|
||||||
|
#include "jtag.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#define _DEBUG_INSTRUCTION_EXECUTION_
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* cli handling */
|
||||||
|
int arm920t_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
|
||||||
|
int arm920t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int arm920t_handle_cp15i_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int arm920t_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int arm920t_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int arm920t_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
int arm920t_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
|
||||||
|
/* forward declarations */
|
||||||
|
int arm920t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
|
||||||
|
int arm920t_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
|
||||||
|
int arm920t_quit();
|
||||||
|
int arm920t_arch_state(struct target_s *target, char *buf, int buf_size);
|
||||||
|
int arm920t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
|
||||||
|
int arm920t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
|
||||||
|
int arm920t_soft_reset_halt(struct target_s *target);
|
||||||
|
|
||||||
|
target_type_t arm920t_target =
|
||||||
|
{
|
||||||
|
.name = "arm920t",
|
||||||
|
|
||||||
|
.poll = arm7_9_poll,
|
||||||
|
.arch_state = arm920t_arch_state,
|
||||||
|
|
||||||
|
.halt = arm7_9_halt,
|
||||||
|
.resume = arm7_9_resume,
|
||||||
|
.step = arm7_9_step,
|
||||||
|
|
||||||
|
.assert_reset = arm7_9_assert_reset,
|
||||||
|
.deassert_reset = arm7_9_deassert_reset,
|
||||||
|
.soft_reset_halt = arm920t_soft_reset_halt,
|
||||||
|
|
||||||
|
.get_gdb_reg_list = armv4_5_get_gdb_reg_list,
|
||||||
|
|
||||||
|
.read_memory = arm920t_read_memory,
|
||||||
|
.write_memory = arm920t_write_memory,
|
||||||
|
.bulk_write_memory = arm7_9_bulk_write_memory,
|
||||||
|
|
||||||
|
.run_algorithm = armv4_5_run_algorithm,
|
||||||
|
|
||||||
|
.add_breakpoint = arm7_9_add_breakpoint,
|
||||||
|
.remove_breakpoint = arm7_9_remove_breakpoint,
|
||||||
|
.add_watchpoint = arm7_9_add_watchpoint,
|
||||||
|
.remove_watchpoint = arm7_9_remove_watchpoint,
|
||||||
|
|
||||||
|
.register_commands = arm920t_register_commands,
|
||||||
|
.target_command = arm920t_target_command,
|
||||||
|
.init_target = arm920t_init_target,
|
||||||
|
.quit = arm920t_quit
|
||||||
|
};
|
||||||
|
|
||||||
|
int arm920t_read_cp15_physical(target_t *target, int reg_addr, u32 *value)
|
||||||
|
{
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
scan_field_t fields[4];
|
||||||
|
u8 access_type_buf = 1;
|
||||||
|
u8 reg_addr_buf = reg_addr & 0x3f;
|
||||||
|
u8 nr_w_buf = 0;
|
||||||
|
|
||||||
|
jtag_add_end_state(TAP_RTI);
|
||||||
|
arm_jtag_scann(jtag_info, 0xf);
|
||||||
|
arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
|
||||||
|
|
||||||
|
fields[0].device = jtag_info->chain_pos;
|
||||||
|
fields[0].num_bits = 1;
|
||||||
|
fields[0].out_value = &access_type_buf;
|
||||||
|
fields[0].out_mask = NULL;
|
||||||
|
fields[0].in_value = NULL;
|
||||||
|
fields[0].in_check_value = NULL;
|
||||||
|
fields[0].in_check_mask = NULL;
|
||||||
|
fields[0].in_handler = NULL;
|
||||||
|
fields[0].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[1].device = jtag_info->chain_pos;
|
||||||
|
fields[1].num_bits = 32;
|
||||||
|
fields[1].out_value = NULL;
|
||||||
|
fields[1].out_mask = NULL;
|
||||||
|
fields[1].in_value = NULL;
|
||||||
|
fields[1].in_check_value = NULL;
|
||||||
|
fields[1].in_check_mask = NULL;
|
||||||
|
fields[1].in_handler = NULL;
|
||||||
|
fields[1].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[2].device = jtag_info->chain_pos;
|
||||||
|
fields[2].num_bits = 6;
|
||||||
|
fields[2].out_value = ®_addr_buf;
|
||||||
|
fields[2].out_mask = NULL;
|
||||||
|
fields[2].in_value = NULL;
|
||||||
|
fields[2].in_check_value = NULL;
|
||||||
|
fields[2].in_check_mask = NULL;
|
||||||
|
fields[2].in_handler = NULL;
|
||||||
|
fields[2].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[3].device = jtag_info->chain_pos;
|
||||||
|
fields[3].num_bits = 1;
|
||||||
|
fields[3].out_value = &nr_w_buf;
|
||||||
|
fields[3].out_mask = NULL;
|
||||||
|
fields[3].in_value = NULL;
|
||||||
|
fields[3].in_check_value = NULL;
|
||||||
|
fields[3].in_check_mask = NULL;
|
||||||
|
fields[3].in_handler = NULL;
|
||||||
|
fields[3].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
jtag_add_dr_scan(4, fields, -1);
|
||||||
|
|
||||||
|
fields[1].in_value = (u8*)value;
|
||||||
|
|
||||||
|
jtag_add_dr_scan(4, fields, -1);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm920t_write_cp15_physical(target_t *target, int reg_addr, u32 value)
|
||||||
|
{
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
scan_field_t fields[4];
|
||||||
|
u8 access_type_buf = 1;
|
||||||
|
u8 reg_addr_buf = reg_addr & 0x3f;
|
||||||
|
u8 nr_w_buf = 1;
|
||||||
|
|
||||||
|
jtag_add_end_state(TAP_RTI);
|
||||||
|
arm_jtag_scann(jtag_info, 0xf);
|
||||||
|
arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
|
||||||
|
|
||||||
|
fields[0].device = jtag_info->chain_pos;
|
||||||
|
fields[0].num_bits = 1;
|
||||||
|
fields[0].out_value = &access_type_buf;
|
||||||
|
fields[0].out_mask = NULL;
|
||||||
|
fields[0].in_value = NULL;
|
||||||
|
fields[0].in_check_value = NULL;
|
||||||
|
fields[0].in_check_mask = NULL;
|
||||||
|
fields[0].in_handler = NULL;
|
||||||
|
fields[0].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[1].device = jtag_info->chain_pos;
|
||||||
|
fields[1].num_bits = 32;
|
||||||
|
fields[1].out_value = (u8*)&value;
|
||||||
|
fields[1].out_mask = NULL;
|
||||||
|
fields[1].in_value = NULL;
|
||||||
|
fields[1].in_check_value = NULL;
|
||||||
|
fields[1].in_check_mask = NULL;
|
||||||
|
fields[1].in_handler = NULL;
|
||||||
|
fields[1].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[2].device = jtag_info->chain_pos;
|
||||||
|
fields[2].num_bits = 6;
|
||||||
|
fields[2].out_value = ®_addr_buf;
|
||||||
|
fields[2].out_mask = NULL;
|
||||||
|
fields[2].in_value = NULL;
|
||||||
|
fields[2].in_check_value = NULL;
|
||||||
|
fields[2].in_check_mask = NULL;
|
||||||
|
fields[2].in_handler = NULL;
|
||||||
|
fields[2].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[3].device = jtag_info->chain_pos;
|
||||||
|
fields[3].num_bits = 1;
|
||||||
|
fields[3].out_value = &nr_w_buf;
|
||||||
|
fields[3].out_mask = NULL;
|
||||||
|
fields[3].in_value = NULL;
|
||||||
|
fields[3].in_check_value = NULL;
|
||||||
|
fields[3].in_check_mask = NULL;
|
||||||
|
fields[3].in_handler = NULL;
|
||||||
|
fields[3].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
jtag_add_dr_scan(4, fields, -1);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm920t_read_cp15_interpreted(target_t *target, u32 opcode, u32 *value)
|
||||||
|
{
|
||||||
|
u32 cp15c15 = 0x0;
|
||||||
|
scan_field_t fields[4];
|
||||||
|
u8 access_type_buf = 0; /* interpreted access */
|
||||||
|
u8 reg_addr_buf = 0x0;
|
||||||
|
u8 nr_w_buf = 0;
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
u32* context_p[1];
|
||||||
|
|
||||||
|
/* read-modify-write CP15 test state register
|
||||||
|
* to enable interpreted access mode */
|
||||||
|
arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
|
||||||
|
jtag_execute_queue();
|
||||||
|
cp15c15 |= 1; /* set interpret mode */
|
||||||
|
arm920t_write_cp15_physical(target, 0x1e, cp15c15);
|
||||||
|
|
||||||
|
jtag_add_end_state(TAP_RTI);
|
||||||
|
arm_jtag_scann(jtag_info, 0xf);
|
||||||
|
arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
|
||||||
|
|
||||||
|
fields[0].device = jtag_info->chain_pos;
|
||||||
|
fields[0].num_bits = 1;
|
||||||
|
fields[0].out_value = &access_type_buf;
|
||||||
|
fields[0].out_mask = NULL;
|
||||||
|
fields[0].in_value = NULL;
|
||||||
|
fields[0].in_check_value = NULL;
|
||||||
|
fields[0].in_check_mask = NULL;
|
||||||
|
fields[0].in_handler = NULL;
|
||||||
|
fields[0].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[1].device = jtag_info->chain_pos;
|
||||||
|
fields[1].num_bits = 32;
|
||||||
|
fields[1].out_value = (u8*)&opcode;
|
||||||
|
fields[1].out_mask = NULL;
|
||||||
|
fields[1].in_value = NULL;
|
||||||
|
fields[1].in_check_value = NULL;
|
||||||
|
fields[1].in_check_mask = NULL;
|
||||||
|
fields[1].in_handler = NULL;
|
||||||
|
fields[1].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[2].device = jtag_info->chain_pos;
|
||||||
|
fields[2].num_bits = 6;
|
||||||
|
fields[2].out_value = ®_addr_buf;
|
||||||
|
fields[2].out_mask = NULL;
|
||||||
|
fields[2].in_value = NULL;
|
||||||
|
fields[2].in_check_value = NULL;
|
||||||
|
fields[2].in_check_mask = NULL;
|
||||||
|
fields[2].in_handler = NULL;
|
||||||
|
fields[2].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[3].device = jtag_info->chain_pos;
|
||||||
|
fields[3].num_bits = 1;
|
||||||
|
fields[3].out_value = &nr_w_buf;
|
||||||
|
fields[3].out_mask = NULL;
|
||||||
|
fields[3].in_value = NULL;
|
||||||
|
fields[3].in_check_value = NULL;
|
||||||
|
fields[3].in_check_mask = NULL;
|
||||||
|
fields[3].in_handler = NULL;
|
||||||
|
fields[3].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
jtag_add_dr_scan(4, fields, -1);
|
||||||
|
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDR(0, 15), 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
|
||||||
|
arm7_9_execute_sys_speed(target);
|
||||||
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
/* read-modify-write CP15 test state register
|
||||||
|
* to disable interpreted access mode */
|
||||||
|
arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
|
||||||
|
jtag_execute_queue();
|
||||||
|
cp15c15 &= ~1U; /* clear interpret mode */
|
||||||
|
arm920t_write_cp15_physical(target, 0x1e, cp15c15);
|
||||||
|
|
||||||
|
context_p[0] = value;
|
||||||
|
arm9tdmi_read_core_regs(target, 0x1, context_p);
|
||||||
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
DEBUG("opcode: %8.8x, value: %8.8x", opcode, *value);
|
||||||
|
|
||||||
|
ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = 1;
|
||||||
|
ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 15).dirty = 1;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm920t_write_cp15_interpreted(target_t *target, u32 opcode, u32 value, u32 address)
|
||||||
|
{
|
||||||
|
u32 cp15c15 = 0x0;
|
||||||
|
scan_field_t fields[4];
|
||||||
|
u8 access_type_buf = 0; /* interpreted access */
|
||||||
|
u8 reg_addr_buf = 0x0;
|
||||||
|
u8 nr_w_buf = 0;
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
u32 regs[2];
|
||||||
|
|
||||||
|
regs[0] = value;
|
||||||
|
regs[1] = address;
|
||||||
|
|
||||||
|
arm9tdmi_write_core_regs(target, 0x3, regs);
|
||||||
|
|
||||||
|
/* read-modify-write CP15 test state register
|
||||||
|
* to enable interpreted access mode */
|
||||||
|
arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
|
||||||
|
jtag_execute_queue();
|
||||||
|
cp15c15 |= 1; /* set interpret mode */
|
||||||
|
arm920t_write_cp15_physical(target, 0x1e, cp15c15);
|
||||||
|
|
||||||
|
jtag_add_end_state(TAP_RTI);
|
||||||
|
arm_jtag_scann(jtag_info, 0xf);
|
||||||
|
arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
|
||||||
|
|
||||||
|
fields[0].device = jtag_info->chain_pos;
|
||||||
|
fields[0].num_bits = 1;
|
||||||
|
fields[0].out_value = &access_type_buf;
|
||||||
|
fields[0].out_mask = NULL;
|
||||||
|
fields[0].in_value = NULL;
|
||||||
|
fields[0].in_check_value = NULL;
|
||||||
|
fields[0].in_check_mask = NULL;
|
||||||
|
fields[0].in_handler = NULL;
|
||||||
|
fields[0].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[1].device = jtag_info->chain_pos;
|
||||||
|
fields[1].num_bits = 32;
|
||||||
|
fields[1].out_value = (u8*)&opcode;
|
||||||
|
fields[1].out_mask = NULL;
|
||||||
|
fields[1].in_value = NULL;
|
||||||
|
fields[1].in_check_value = NULL;
|
||||||
|
fields[1].in_check_mask = NULL;
|
||||||
|
fields[1].in_handler = NULL;
|
||||||
|
fields[1].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[2].device = jtag_info->chain_pos;
|
||||||
|
fields[2].num_bits = 6;
|
||||||
|
fields[2].out_value = ®_addr_buf;
|
||||||
|
fields[2].out_mask = NULL;
|
||||||
|
fields[2].in_value = NULL;
|
||||||
|
fields[2].in_check_value = NULL;
|
||||||
|
fields[2].in_check_mask = NULL;
|
||||||
|
fields[2].in_handler = NULL;
|
||||||
|
fields[2].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[3].device = jtag_info->chain_pos;
|
||||||
|
fields[3].num_bits = 1;
|
||||||
|
fields[3].out_value = &nr_w_buf;
|
||||||
|
fields[3].out_mask = NULL;
|
||||||
|
fields[3].in_value = NULL;
|
||||||
|
fields[3].in_check_value = NULL;
|
||||||
|
fields[3].in_check_mask = NULL;
|
||||||
|
fields[3].in_handler = NULL;
|
||||||
|
fields[3].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
jtag_add_dr_scan(4, fields, -1);
|
||||||
|
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 1), 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
|
||||||
|
arm7_9_execute_sys_speed(target);
|
||||||
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
/* read-modify-write CP15 test state register
|
||||||
|
* to disable interpreted access mode */
|
||||||
|
arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
|
||||||
|
jtag_execute_queue();
|
||||||
|
cp15c15 &= ~1U; /* set interpret mode */
|
||||||
|
arm920t_write_cp15_physical(target, 0x1e, cp15c15);
|
||||||
|
|
||||||
|
DEBUG("opcode: %8.8x, value: %8.8x, address: %8.8x", opcode, value, address);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 arm920t_get_ttb(target_t *target)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
u32 ttb = 0x0;
|
||||||
|
|
||||||
|
if ((retval = arm920t_read_cp15_interpreted(target, 0xeebf0f51, &ttb)) != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
return ttb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm920t_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
|
||||||
|
{
|
||||||
|
u32 cp15_control;
|
||||||
|
|
||||||
|
/* read cp15 control register */
|
||||||
|
arm920t_read_cp15_physical(target, 0x2, &cp15_control);
|
||||||
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
if (mmu)
|
||||||
|
cp15_control &= ~0x1U;
|
||||||
|
|
||||||
|
if (d_u_cache)
|
||||||
|
cp15_control &= ~0x4U;
|
||||||
|
|
||||||
|
if (i_cache)
|
||||||
|
cp15_control &= ~0x1000U;
|
||||||
|
|
||||||
|
arm920t_write_cp15_physical(target, 0x2, cp15_control);
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm920t_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
|
||||||
|
{
|
||||||
|
u32 cp15_control;
|
||||||
|
|
||||||
|
/* read cp15 control register */
|
||||||
|
arm920t_read_cp15_physical(target, 0x2, &cp15_control);
|
||||||
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
if (mmu)
|
||||||
|
cp15_control |= 0x1U;
|
||||||
|
|
||||||
|
if (d_u_cache)
|
||||||
|
cp15_control |= 0x4U;
|
||||||
|
|
||||||
|
if (i_cache)
|
||||||
|
cp15_control |= 0x1000U;
|
||||||
|
|
||||||
|
arm920t_write_cp15_physical(target, 0x2, cp15_control);
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm920t_post_debug_entry(target_t *target)
|
||||||
|
{
|
||||||
|
u32 cp15c15;
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
|
||||||
|
arm920t_common_t *arm920t = arm9tdmi->arch_info;
|
||||||
|
|
||||||
|
/* examine cp15 control reg */
|
||||||
|
arm920t_read_cp15_physical(target, 0x2, &arm920t->cp15_control_reg);
|
||||||
|
jtag_execute_queue();
|
||||||
|
DEBUG("cp15_control_reg: %8.8x", arm920t->cp15_control_reg);
|
||||||
|
|
||||||
|
if (arm920t->armv4_5_mmu.armv4_5_cache.ctype == -1)
|
||||||
|
{
|
||||||
|
u32 cache_type_reg;
|
||||||
|
/* identify caches */
|
||||||
|
arm920t_read_cp15_physical(target, 0x1, &cache_type_reg);
|
||||||
|
jtag_execute_queue();
|
||||||
|
armv4_5_identify_cache(cache_type_reg, &arm920t->armv4_5_mmu.armv4_5_cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
arm920t->armv4_5_mmu.mmu_enabled = (arm920t->cp15_control_reg & 0x1U) ? 1 : 0;
|
||||||
|
arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm920t->cp15_control_reg & 0x4U) ? 1 : 0;
|
||||||
|
arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (arm920t->cp15_control_reg & 0x1000U) ? 1 : 0;
|
||||||
|
|
||||||
|
/* save i/d fault status and address register */
|
||||||
|
arm920t_read_cp15_interpreted(target, 0xee150f10, &arm920t->d_fsr);
|
||||||
|
arm920t_read_cp15_interpreted(target, 0xee150f30, &arm920t->i_fsr);
|
||||||
|
arm920t_read_cp15_interpreted(target, 0xee160f10, &arm920t->d_far);
|
||||||
|
arm920t_read_cp15_interpreted(target, 0xee160f30, &arm920t->i_far);
|
||||||
|
|
||||||
|
/* read-modify-write CP15 test state register
|
||||||
|
* to disable I/D-cache linefills */
|
||||||
|
arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
|
||||||
|
jtag_execute_queue();
|
||||||
|
cp15c15 |= 0x600;
|
||||||
|
arm920t_write_cp15_physical(target, 0x1e, cp15c15);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm920t_pre_restore_context(target_t *target)
|
||||||
|
{
|
||||||
|
u32 cp15c15;
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
|
||||||
|
arm920t_common_t *arm920t = arm9tdmi->arch_info;
|
||||||
|
|
||||||
|
/* restore i/d fault status and address register */
|
||||||
|
arm920t_write_cp15_interpreted(target, 0xee050f10, arm920t->d_fsr, 0x0);
|
||||||
|
arm920t_write_cp15_interpreted(target, 0xee050f30, arm920t->i_fsr, 0x0);
|
||||||
|
arm920t_write_cp15_interpreted(target, 0xee060f10, arm920t->d_far, 0x0);
|
||||||
|
arm920t_write_cp15_interpreted(target, 0xee060f30, arm920t->i_far, 0x0);
|
||||||
|
|
||||||
|
/* read-modify-write CP15 test state register
|
||||||
|
* to reenable I/D-cache linefills */
|
||||||
|
arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
|
||||||
|
jtag_execute_queue();
|
||||||
|
cp15c15 &= ~0x600U;
|
||||||
|
arm920t_write_cp15_physical(target, 0x1e, cp15c15);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm920t_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm9tdmi_common_t **arm9tdmi_p, arm920t_common_t **arm920t_p)
|
||||||
|
{
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9;
|
||||||
|
arm9tdmi_common_t *arm9tdmi;
|
||||||
|
arm920t_common_t *arm920t;
|
||||||
|
|
||||||
|
if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
arm7_9 = armv4_5->arch_info;
|
||||||
|
if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
arm9tdmi = arm7_9->arch_info;
|
||||||
|
if (arm9tdmi->common_magic != ARM9TDMI_COMMON_MAGIC)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
arm920t = arm9tdmi->arch_info;
|
||||||
|
if (arm920t->common_magic != ARM920T_COMMON_MAGIC)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*armv4_5_p = armv4_5;
|
||||||
|
*arm7_9_p = arm7_9;
|
||||||
|
*arm9tdmi_p = arm9tdmi;
|
||||||
|
*arm920t_p = arm920t;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm920t_arch_state(struct target_s *target, char *buf, int buf_size)
|
||||||
|
{
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
|
||||||
|
arm920t_common_t *arm920t = arm9tdmi->arch_info;
|
||||||
|
|
||||||
|
char *state[] =
|
||||||
|
{
|
||||||
|
"disabled", "enabled"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
|
||||||
|
{
|
||||||
|
ERROR("BUG: called for a non-ARMv4/5 target");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buf, buf_size,
|
||||||
|
"target halted in %s state due to %s, current mode: %s\n"
|
||||||
|
"cpsr: 0x%8.8x pc: 0x%8.8x\n"
|
||||||
|
"MMU: %s, D-Cache: %s, I-Cache: %s",
|
||||||
|
armv4_5_state_strings[armv4_5->core_state],
|
||||||
|
target_debug_reason_strings[target->debug_reason],
|
||||||
|
armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)],
|
||||||
|
buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32),
|
||||||
|
buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32),
|
||||||
|
state[arm920t->armv4_5_mmu.mmu_enabled],
|
||||||
|
state[arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled],
|
||||||
|
state[arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled]);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm920t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
retval = arm7_9_read_memory(target, address, size, count, buffer);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm920t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
|
||||||
|
arm920t_common_t *arm920t = arm9tdmi->arch_info;
|
||||||
|
|
||||||
|
if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
if (((size == 4) || (size == 2)) && (count == 1))
|
||||||
|
{
|
||||||
|
if (arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled)
|
||||||
|
{
|
||||||
|
DEBUG("D-Cache enabled, writing through to main memory");
|
||||||
|
u32 pa, cb, ap;
|
||||||
|
int type, domain;
|
||||||
|
|
||||||
|
pa = armv4_5_mmu_translate_va(target, &arm920t->armv4_5_mmu, address, &type, &cb, &domain, &ap);
|
||||||
|
if (type == -1)
|
||||||
|
return ERROR_OK;
|
||||||
|
/* cacheable & bufferable means write-back region */
|
||||||
|
if (cb == 3)
|
||||||
|
armv4_5_mmu_write_physical(target, &arm920t->armv4_5_mmu, pa, size, count, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled)
|
||||||
|
{
|
||||||
|
DEBUG("I-Cache enabled, invalidating affected I-Cache line");
|
||||||
|
arm920t_write_cp15_interpreted(target, 0xee070f35, 0x0, address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm920t_soft_reset_halt(struct target_s *target)
|
||||||
|
{
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
|
||||||
|
arm920t_common_t *arm920t = arm9tdmi->arch_info;
|
||||||
|
reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
|
||||||
|
|
||||||
|
if (target->state == TARGET_RUNNING)
|
||||||
|
{
|
||||||
|
target->type->halt(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (buf_get_u32(dbg_stat->value, EICE_DBG_CONTROL_DBGACK, 1) == 0)
|
||||||
|
{
|
||||||
|
embeddedice_read_reg(dbg_stat);
|
||||||
|
jtag_execute_queue();
|
||||||
|
}
|
||||||
|
|
||||||
|
target->state = TARGET_HALTED;
|
||||||
|
|
||||||
|
/* SVC, ARM state, IRQ and FIQ disabled */
|
||||||
|
buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8, 0xd3);
|
||||||
|
armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1;
|
||||||
|
armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
|
||||||
|
|
||||||
|
/* start fetching from 0x0 */
|
||||||
|
buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0);
|
||||||
|
armv4_5->core_cache->reg_list[15].dirty = 1;
|
||||||
|
armv4_5->core_cache->reg_list[15].valid = 1;
|
||||||
|
|
||||||
|
armv4_5->core_mode = ARMV4_5_MODE_SVC;
|
||||||
|
armv4_5->core_state = ARMV4_5_STATE_ARM;
|
||||||
|
|
||||||
|
arm920t_disable_mmu_caches(target, 1, 1, 1);
|
||||||
|
arm920t->armv4_5_mmu.mmu_enabled = 0;
|
||||||
|
arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0;
|
||||||
|
arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0;
|
||||||
|
|
||||||
|
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm920t_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
|
||||||
|
{
|
||||||
|
arm9tdmi_init_target(cmd_ctx, target);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm920t_quit()
|
||||||
|
{
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm920t_init_arch_info(target_t *target, arm920t_common_t *arm920t, int chain_pos, char *variant)
|
||||||
|
{
|
||||||
|
arm9tdmi_common_t *arm9tdmi = &arm920t->arm9tdmi_common;
|
||||||
|
arm7_9_common_t *arm7_9 = &arm9tdmi->arm7_9_common;
|
||||||
|
|
||||||
|
arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant);
|
||||||
|
|
||||||
|
arm9tdmi->arch_info = arm920t;
|
||||||
|
arm920t->common_magic = ARM920T_COMMON_MAGIC;
|
||||||
|
|
||||||
|
arm7_9->post_debug_entry = arm920t_post_debug_entry;
|
||||||
|
arm7_9->pre_restore_context = arm920t_pre_restore_context;
|
||||||
|
|
||||||
|
arm920t->armv4_5_mmu.armv4_5_cache.ctype = -1;
|
||||||
|
arm920t->armv4_5_mmu.get_ttb = arm920t_get_ttb;
|
||||||
|
arm920t->armv4_5_mmu.read_memory = arm7_9_read_memory;
|
||||||
|
arm920t->armv4_5_mmu.write_memory = arm7_9_write_memory;
|
||||||
|
arm920t->armv4_5_mmu.disable_mmu_caches = arm920t_disable_mmu_caches;
|
||||||
|
arm920t->armv4_5_mmu.enable_mmu_caches = arm920t_enable_mmu_caches;
|
||||||
|
arm920t->armv4_5_mmu.has_tiny_pages = 1;
|
||||||
|
arm920t->armv4_5_mmu.mmu_enabled = 0;
|
||||||
|
|
||||||
|
arm9tdmi->has_single_step = 1;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm920t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
|
||||||
|
{
|
||||||
|
int chain_pos;
|
||||||
|
char *variant = NULL;
|
||||||
|
arm920t_common_t *arm920t = malloc(sizeof(arm920t_common_t));
|
||||||
|
|
||||||
|
if (argc < 4)
|
||||||
|
{
|
||||||
|
ERROR("'target arm920t' requires at least one additional argument");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
chain_pos = strtoul(args[3], NULL, 0);
|
||||||
|
|
||||||
|
if (argc >= 5)
|
||||||
|
variant = strdup(args[4]);
|
||||||
|
|
||||||
|
DEBUG("chain_pos: %i, variant: %s", chain_pos, variant);
|
||||||
|
|
||||||
|
arm920t_init_arch_info(target, arm920t, chain_pos, variant);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm920t_register_commands(struct command_context_s *cmd_ctx)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
command_t *arm920t_cmd;
|
||||||
|
|
||||||
|
|
||||||
|
retval = arm9tdmi_register_commands(cmd_ctx);
|
||||||
|
|
||||||
|
arm920t_cmd = register_command(cmd_ctx, NULL, "arm920t", NULL, COMMAND_ANY, "arm920t specific commands");
|
||||||
|
|
||||||
|
register_command(cmd_ctx, arm920t_cmd, "cp15", arm920t_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register <num> [value]");
|
||||||
|
register_command(cmd_ctx, arm920t_cmd, "cp15i", arm920t_handle_cp15i_command, COMMAND_EXEC, "display/modify cp15 (interpreted access) <opcode> [value] [address]");
|
||||||
|
register_command(cmd_ctx, arm920t_cmd, "cache_info", arm920t_handle_cache_info_command, COMMAND_EXEC, "display information about target caches");
|
||||||
|
register_command(cmd_ctx, arm920t_cmd, "virt2phys", arm920t_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa <va>");
|
||||||
|
|
||||||
|
register_command(cmd_ctx, arm920t_cmd, "mdw_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory words <physical addr> [count]");
|
||||||
|
register_command(cmd_ctx, arm920t_cmd, "mdh_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory half-words <physical addr> [count]");
|
||||||
|
register_command(cmd_ctx, arm920t_cmd, "mdb_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory bytes <physical addr> [count]");
|
||||||
|
|
||||||
|
register_command(cmd_ctx, arm920t_cmd, "mww_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory word <physical addr> <value>");
|
||||||
|
register_command(cmd_ctx, arm920t_cmd, "mwh_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word <physical addr> <value>");
|
||||||
|
register_command(cmd_ctx, arm920t_cmd, "mwb_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory byte <physical addr> <value>");
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm920t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
target_t *target = get_current_target(cmd_ctx);
|
||||||
|
armv4_5_common_t *armv4_5;
|
||||||
|
arm7_9_common_t *arm7_9;
|
||||||
|
arm9tdmi_common_t *arm9tdmi;
|
||||||
|
arm920t_common_t *arm920t;
|
||||||
|
arm_jtag_t *jtag_info;
|
||||||
|
|
||||||
|
if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "current target isn't an ARM920t target");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* one or more argument, access a single register (write if second argument is given */
|
||||||
|
if (argc >= 1)
|
||||||
|
{
|
||||||
|
int address = strtoul(args[0], NULL, 0);
|
||||||
|
|
||||||
|
if (argc == 1)
|
||||||
|
{
|
||||||
|
u32 value;
|
||||||
|
if ((retval = arm920t_read_cp15_physical(target, address, &value)) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "couldn't access reg %i", address);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
command_print(cmd_ctx, "%i: %8.8x", address, value);
|
||||||
|
}
|
||||||
|
else if (argc == 2)
|
||||||
|
{
|
||||||
|
u32 value = strtoul(args[1], NULL, 0);
|
||||||
|
if ((retval = arm920t_write_cp15_physical(target, address, value)) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "couldn't access reg %i", address);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
command_print(cmd_ctx, "%i: %8.8x", address, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm920t_handle_cp15i_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
target_t *target = get_current_target(cmd_ctx);
|
||||||
|
armv4_5_common_t *armv4_5;
|
||||||
|
arm7_9_common_t *arm7_9;
|
||||||
|
arm9tdmi_common_t *arm9tdmi;
|
||||||
|
arm920t_common_t *arm920t;
|
||||||
|
arm_jtag_t *jtag_info;
|
||||||
|
|
||||||
|
if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "current target isn't an ARM920t target");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* one or more argument, access a single register (write if second argument is given */
|
||||||
|
if (argc >= 1)
|
||||||
|
{
|
||||||
|
u32 opcode = strtoul(args[0], NULL, 0);
|
||||||
|
|
||||||
|
if (argc == 1)
|
||||||
|
{
|
||||||
|
u32 value;
|
||||||
|
if ((retval = arm920t_read_cp15_interpreted(target, opcode, &value)) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "couldn't execute %8.8x", opcode);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
command_print(cmd_ctx, "%8.8x: %8.8x", opcode, value);
|
||||||
|
}
|
||||||
|
else if (argc == 2)
|
||||||
|
{
|
||||||
|
u32 value = strtoul(args[1], NULL, 0);
|
||||||
|
if ((retval = arm920t_write_cp15_interpreted(target, opcode, value, 0)) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "couldn't execute %8.8x", opcode);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
command_print(cmd_ctx, "%8.8x: %8.8x", opcode, value);
|
||||||
|
}
|
||||||
|
else if (argc == 3)
|
||||||
|
{
|
||||||
|
u32 value = strtoul(args[1], NULL, 0);
|
||||||
|
u32 address = strtoul(args[2], NULL, 0);
|
||||||
|
if ((retval = arm920t_write_cp15_interpreted(target, opcode, value, address)) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "couldn't execute %8.8x", opcode);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
command_print(cmd_ctx, "%8.8x: %8.8x %8.8x", opcode, value, address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm920t_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
target_t *target = get_current_target(cmd_ctx);
|
||||||
|
armv4_5_common_t *armv4_5;
|
||||||
|
arm7_9_common_t *arm7_9;
|
||||||
|
arm9tdmi_common_t *arm9tdmi;
|
||||||
|
arm920t_common_t *arm920t;
|
||||||
|
|
||||||
|
if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "current target isn't an ARM920t target");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return armv4_5_handle_cache_info_command(cmd_ctx, &arm920t->armv4_5_mmu.armv4_5_cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm920t_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
target_t *target = get_current_target(cmd_ctx);
|
||||||
|
armv4_5_common_t *armv4_5;
|
||||||
|
arm7_9_common_t *arm7_9;
|
||||||
|
arm9tdmi_common_t *arm9tdmi;
|
||||||
|
arm920t_common_t *arm920t;
|
||||||
|
arm_jtag_t *jtag_info;
|
||||||
|
|
||||||
|
if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "current target isn't an ARM920t target");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return armv4_5_mmu_handle_virt2phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu);
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm920t_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
target_t *target = get_current_target(cmd_ctx);
|
||||||
|
armv4_5_common_t *armv4_5;
|
||||||
|
arm7_9_common_t *arm7_9;
|
||||||
|
arm9tdmi_common_t *arm9tdmi;
|
||||||
|
arm920t_common_t *arm920t;
|
||||||
|
arm_jtag_t *jtag_info;
|
||||||
|
|
||||||
|
if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "current target isn't an ARM920t target");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return armv4_5_mmu_handle_md_phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu);
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm920t_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
target_t *target = get_current_target(cmd_ctx);
|
||||||
|
armv4_5_common_t *armv4_5;
|
||||||
|
arm7_9_common_t *arm7_9;
|
||||||
|
arm9tdmi_common_t *arm9tdmi;
|
||||||
|
arm920t_common_t *arm920t;
|
||||||
|
arm_jtag_t *jtag_info;
|
||||||
|
|
||||||
|
if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "current target isn't an ARM920t target");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return armv4_5_mmu_handle_mw_phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu);
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef ARM920T_H
|
||||||
|
#define ARM920T_H
|
||||||
|
|
||||||
|
#include "target.h"
|
||||||
|
#include "register.h"
|
||||||
|
#include "embeddedice.h"
|
||||||
|
#include "arm_jtag.h"
|
||||||
|
#include "arm9tdmi.h"
|
||||||
|
#include "armv4_5_mmu.h"
|
||||||
|
#include "armv4_5_cache.h"
|
||||||
|
|
||||||
|
#define ARM920T_COMMON_MAGIC 0xa920a920
|
||||||
|
|
||||||
|
typedef struct arm920t_common_s
|
||||||
|
{
|
||||||
|
int common_magic;
|
||||||
|
armv4_5_mmu_common_t armv4_5_mmu;
|
||||||
|
arm9tdmi_common_t arm9tdmi_common;
|
||||||
|
u32 cp15_control_reg;
|
||||||
|
u32 d_fsr;
|
||||||
|
u32 i_fsr;
|
||||||
|
u32 d_far;
|
||||||
|
u32 i_far;
|
||||||
|
} arm920t_common_t;
|
||||||
|
|
||||||
|
#endif /* ARM920T_H */
|
|
@ -0,0 +1,848 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "arm9tdmi.h"
|
||||||
|
|
||||||
|
#include "arm7_9_common.h"
|
||||||
|
#include "register.h"
|
||||||
|
#include "target.h"
|
||||||
|
#include "armv4_5.h"
|
||||||
|
#include "embeddedice.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "jtag.h"
|
||||||
|
#include "arm_jtag.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#define _DEBUG_INSTRUCTION_EXECUTION_
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* cli handling */
|
||||||
|
int arm9tdmi_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
|
||||||
|
/* forward declarations */
|
||||||
|
int arm9tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
|
||||||
|
int arm9tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
|
||||||
|
int arm9tdmi_quit();
|
||||||
|
|
||||||
|
/* target function declarations */
|
||||||
|
enum target_state arm9tdmi_poll(struct target_s *target);
|
||||||
|
int arm9tdmi_halt(target_t *target);
|
||||||
|
int arm9tdmi_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
|
||||||
|
|
||||||
|
target_type_t arm9tdmi_target =
|
||||||
|
{
|
||||||
|
.name = "arm9tdmi",
|
||||||
|
|
||||||
|
.poll = arm7_9_poll,
|
||||||
|
.arch_state = armv4_5_arch_state,
|
||||||
|
|
||||||
|
.halt = arm7_9_halt,
|
||||||
|
.resume = arm7_9_resume,
|
||||||
|
.step = arm7_9_step,
|
||||||
|
|
||||||
|
.assert_reset = arm7_9_assert_reset,
|
||||||
|
.deassert_reset = arm7_9_deassert_reset,
|
||||||
|
.soft_reset_halt = arm7_9_soft_reset_halt,
|
||||||
|
|
||||||
|
.get_gdb_reg_list = armv4_5_get_gdb_reg_list,
|
||||||
|
|
||||||
|
.read_memory = arm7_9_read_memory,
|
||||||
|
.write_memory = arm7_9_write_memory,
|
||||||
|
.bulk_write_memory = arm7_9_bulk_write_memory,
|
||||||
|
|
||||||
|
.add_breakpoint = arm7_9_add_breakpoint,
|
||||||
|
.remove_breakpoint = arm7_9_remove_breakpoint,
|
||||||
|
.add_watchpoint = arm7_9_add_watchpoint,
|
||||||
|
.remove_watchpoint = arm7_9_remove_watchpoint,
|
||||||
|
|
||||||
|
.register_commands = arm9tdmi_register_commands,
|
||||||
|
.target_command = arm9tdmi_target_command,
|
||||||
|
.init_target = arm9tdmi_init_target,
|
||||||
|
.quit = arm9tdmi_quit
|
||||||
|
};
|
||||||
|
|
||||||
|
int arm9tdmi_examine_debug_reason(target_t *target)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
|
||||||
|
/* only check the debug reason if we don't know it already */
|
||||||
|
if ((target->debug_reason != DBG_REASON_DBGRQ)
|
||||||
|
&& (target->debug_reason != DBG_REASON_SINGLESTEP))
|
||||||
|
{
|
||||||
|
scan_field_t fields[3];
|
||||||
|
u8 databus[4];
|
||||||
|
u8 instructionbus[4];
|
||||||
|
u8 debug_reason;
|
||||||
|
|
||||||
|
jtag_add_end_state(TAP_PD);
|
||||||
|
|
||||||
|
fields[0].device = arm7_9->jtag_info.chain_pos;
|
||||||
|
fields[0].num_bits = 32;
|
||||||
|
fields[0].out_value = NULL;
|
||||||
|
fields[0].out_mask = NULL;
|
||||||
|
fields[0].in_value = databus;
|
||||||
|
fields[0].in_check_value = NULL;
|
||||||
|
fields[0].in_check_mask = NULL;
|
||||||
|
fields[0].in_handler = NULL;
|
||||||
|
fields[0].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[1].device = arm7_9->jtag_info.chain_pos;
|
||||||
|
fields[1].num_bits = 3;
|
||||||
|
fields[1].out_value = NULL;
|
||||||
|
fields[1].out_mask = NULL;
|
||||||
|
fields[1].in_value = &debug_reason;
|
||||||
|
fields[1].in_check_value = NULL;
|
||||||
|
fields[1].in_check_mask = NULL;
|
||||||
|
fields[1].in_handler = NULL;
|
||||||
|
fields[1].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[2].device = arm7_9->jtag_info.chain_pos;
|
||||||
|
fields[2].num_bits = 32;
|
||||||
|
fields[2].out_value = NULL;
|
||||||
|
fields[2].out_mask = NULL;
|
||||||
|
fields[2].in_value = instructionbus;
|
||||||
|
fields[2].in_check_value = NULL;
|
||||||
|
fields[2].in_check_mask = NULL;
|
||||||
|
fields[2].in_handler = NULL;
|
||||||
|
fields[2].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
arm_jtag_scann(&arm7_9->jtag_info, 0x1);
|
||||||
|
arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr);
|
||||||
|
|
||||||
|
jtag_add_dr_scan(3, fields, TAP_PD);
|
||||||
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
fields[0].in_value = NULL;
|
||||||
|
fields[0].out_value = databus;
|
||||||
|
fields[1].in_value = NULL;
|
||||||
|
fields[1].out_value = &debug_reason;
|
||||||
|
fields[2].in_value = NULL;
|
||||||
|
fields[2].out_value = instructionbus;
|
||||||
|
|
||||||
|
jtag_add_dr_scan(3, fields, TAP_PD);
|
||||||
|
|
||||||
|
if (debug_reason & 0x4)
|
||||||
|
if (debug_reason & 0x2)
|
||||||
|
target->debug_reason = DBG_REASON_WPTANDBKPT;
|
||||||
|
else
|
||||||
|
target->debug_reason = DBG_REASON_WATCHPOINT;
|
||||||
|
else
|
||||||
|
target->debug_reason = DBG_REASON_BREAKPOINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* put an instruction in the ARM9TDMI pipeline or write the data bus, and optionally read data */
|
||||||
|
int arm9tdmi_clock_out(arm_jtag_t *jtag_info, u32 instr, u32 out, u32 *in, int sysspeed)
|
||||||
|
{
|
||||||
|
scan_field_t fields[3];
|
||||||
|
u8 out_buf[4];
|
||||||
|
u8 instr_buf[4];
|
||||||
|
u8 sysspeed_buf = 0x0;
|
||||||
|
|
||||||
|
/* prepare buffer */
|
||||||
|
buf_set_u32(out_buf, 0, 32, out);
|
||||||
|
|
||||||
|
instr = flip_u32(instr, 32);
|
||||||
|
buf_set_u32(instr_buf, 0, 32, instr);
|
||||||
|
|
||||||
|
if (sysspeed)
|
||||||
|
buf_set_u32(&sysspeed_buf, 2, 1, 1);
|
||||||
|
|
||||||
|
jtag_add_end_state(TAP_PD);
|
||||||
|
arm_jtag_scann(jtag_info, 0x1);
|
||||||
|
arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
|
||||||
|
|
||||||
|
fields[0].device = jtag_info->chain_pos;
|
||||||
|
fields[0].num_bits = 32;
|
||||||
|
fields[0].out_value = out_buf;
|
||||||
|
fields[0].out_mask = NULL;
|
||||||
|
if (in)
|
||||||
|
{
|
||||||
|
fields[0].in_value = (u8*)in;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
fields[0].in_value = NULL;
|
||||||
|
}
|
||||||
|
fields[0].in_check_value = NULL;
|
||||||
|
fields[0].in_check_mask = NULL;
|
||||||
|
fields[0].in_handler = NULL;
|
||||||
|
fields[0].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[1].device = jtag_info->chain_pos;
|
||||||
|
fields[1].num_bits = 3;
|
||||||
|
fields[1].out_value = &sysspeed_buf;
|
||||||
|
fields[1].out_mask = NULL;
|
||||||
|
fields[1].in_value = NULL;
|
||||||
|
fields[1].in_check_value = NULL;
|
||||||
|
fields[1].in_check_mask = NULL;
|
||||||
|
fields[1].in_handler = NULL;
|
||||||
|
fields[1].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[2].device = jtag_info->chain_pos;
|
||||||
|
fields[2].num_bits = 32;
|
||||||
|
fields[2].out_value = instr_buf;
|
||||||
|
fields[2].out_mask = NULL;
|
||||||
|
fields[2].in_value = NULL;
|
||||||
|
fields[2].in_check_value = NULL;
|
||||||
|
fields[2].in_check_mask = NULL;
|
||||||
|
fields[2].in_handler = NULL;
|
||||||
|
fields[2].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
jtag_add_dr_scan(3, fields, -1);
|
||||||
|
|
||||||
|
jtag_add_runtest(0, -1);
|
||||||
|
|
||||||
|
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
|
||||||
|
{
|
||||||
|
char* in_string;
|
||||||
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
if (in)
|
||||||
|
{
|
||||||
|
in_string = buf_to_char((u8*)in, 32);
|
||||||
|
DEBUG("instr: 0x%8.8x, out: 0x%8.8x, in: %s", flip_u32(instr, 32), out, in_string);
|
||||||
|
free(in_string);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
DEBUG("instr: 0x%8.8x, out: 0x%8.8x", flip_u32(instr, 32), out);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* just read data (instruction and data-out = don't care) */
|
||||||
|
int arm9tdmi_clock_data_in(arm_jtag_t *jtag_info, u32 *in)
|
||||||
|
{
|
||||||
|
scan_field_t fields[3];
|
||||||
|
|
||||||
|
jtag_add_end_state(TAP_PD);
|
||||||
|
arm_jtag_scann(jtag_info, 0x1);
|
||||||
|
arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
|
||||||
|
|
||||||
|
fields[0].device = jtag_info->chain_pos;
|
||||||
|
fields[0].num_bits = 32;
|
||||||
|
fields[0].out_value = NULL;
|
||||||
|
fields[0].out_mask = NULL;
|
||||||
|
fields[0].in_value = (u8*)in;
|
||||||
|
fields[0].in_handler = NULL;
|
||||||
|
fields[0].in_handler_priv = NULL;
|
||||||
|
fields[0].in_check_value = NULL;
|
||||||
|
fields[0].in_check_mask = NULL;
|
||||||
|
|
||||||
|
fields[1].device = jtag_info->chain_pos;
|
||||||
|
fields[1].num_bits = 3;
|
||||||
|
fields[1].out_value = NULL;
|
||||||
|
fields[1].out_mask = NULL;
|
||||||
|
fields[1].in_value = NULL;
|
||||||
|
fields[1].in_handler = NULL;
|
||||||
|
fields[1].in_handler_priv = NULL;
|
||||||
|
fields[1].in_check_value = NULL;
|
||||||
|
fields[1].in_check_mask = NULL;
|
||||||
|
|
||||||
|
fields[2].device = jtag_info->chain_pos;
|
||||||
|
fields[2].num_bits = 32;
|
||||||
|
fields[2].out_value = NULL;
|
||||||
|
fields[2].out_mask = NULL;
|
||||||
|
fields[2].in_value = NULL;
|
||||||
|
fields[2].in_check_value = NULL;
|
||||||
|
fields[2].in_check_mask = NULL;
|
||||||
|
fields[2].in_handler = NULL;
|
||||||
|
fields[2].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
jtag_add_dr_scan(3, fields, -1);
|
||||||
|
|
||||||
|
jtag_add_runtest(0, -1);
|
||||||
|
|
||||||
|
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
|
||||||
|
{
|
||||||
|
char* in_string;
|
||||||
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
if (in)
|
||||||
|
{
|
||||||
|
in_string = buf_to_char((u8*)in, 32);
|
||||||
|
DEBUG("in: %s", in_string);
|
||||||
|
free(in_string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm9tdmi_change_to_arm(target_t *target, u32 *r0, u32 *pc)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* save r0 before using it and put system in ARM state
|
||||||
|
* to allow common handling of ARM and THUMB debugging */
|
||||||
|
|
||||||
|
/* fetch STR r0, [r0] */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
|
||||||
|
/* STR r0, [r0] in Memory */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, r0, 0);
|
||||||
|
|
||||||
|
/* MOV r0, r15 fetched, STR in Decode */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
|
||||||
|
/* nothing fetched, STR r0, [r0] in Memory */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, pc, 0);
|
||||||
|
|
||||||
|
/* fetch MOV */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_MOV_IM(0, 0x0), 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
|
||||||
|
|
||||||
|
/* fetch BX */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), 0, NULL, 0);
|
||||||
|
/* NOP fetched, BX in Decode, MOV in Execute */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
|
||||||
|
/* NOP fetched, BX in Execute (1) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
|
||||||
|
|
||||||
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
/* fix program counter:
|
||||||
|
* MOV r0, r15 was the 5th instruction (+8)
|
||||||
|
* reading PC in Thumb state gives address of instruction + 4
|
||||||
|
*/
|
||||||
|
*pc -= 0xc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm9tdmi_read_core_regs(target_t *target, u32 mask, u32* core_regs[16])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* STMIA r0-15, [r0] at debug speed
|
||||||
|
* register values will start to appear on 4th DCLK
|
||||||
|
*/
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0);
|
||||||
|
|
||||||
|
/* fetch NOP, STM in DECODE stage */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
/* fetch NOP, STM in EXECUTE stage (1st cycle) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
|
||||||
|
for (i = 0; i <= 15; i++)
|
||||||
|
{
|
||||||
|
if (mask & (1 << i))
|
||||||
|
/* nothing fetched, STM in MEMORY (i'th cycle) */
|
||||||
|
arm9tdmi_clock_data_in(jtag_info, core_regs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm9tdmi_read_xpsr(target_t *target, u32 *xpsr, int spsr)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* MRS r0, cpsr */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
|
||||||
|
/* STR r0, [r15] */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), 0, NULL, 0);
|
||||||
|
/* fetch NOP, STR in DECODE stage */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
/* fetch NOP, STR in EXECUTE stage (1st cycle) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
/* nothing fetched, STR in MEMORY */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, xpsr, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm9tdmi_write_xpsr(target_t *target, u32 xpsr, int spsr)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
DEBUG("xpsr: %8.8x, spsr: %i", xpsr, spsr);
|
||||||
|
|
||||||
|
/* MSR1 fetched */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), 0, NULL, 0);
|
||||||
|
/* MSR2 fetched, MSR1 in DECODE */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), 0, NULL, 0);
|
||||||
|
/* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), 0, NULL, 0);
|
||||||
|
/* nothing fetched, MSR1 in EXECUTE (2) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
/* nothing fetched, MSR1 in EXECUTE (3) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
/* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), 0, NULL, 0);
|
||||||
|
/* nothing fetched, MSR2 in EXECUTE (2) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
/* nothing fetched, MSR2 in EXECUTE (3) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
/* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
/* nothing fetched, MSR3 in EXECUTE (2) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
/* nothing fetched, MSR3 in EXECUTE (3) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
/* NOP fetched, MSR4 in EXECUTE (1) */
|
||||||
|
/* last MSR writes flags, which takes only one cycle */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm9tdmi_write_xpsr_im8(target_t *target, u8 xpsr_im, int rot, int spsr)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr);
|
||||||
|
|
||||||
|
/* MSR fetched */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), 0, NULL, 0);
|
||||||
|
/* NOP fetched, MSR in DECODE */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
/* NOP fetched, MSR in EXECUTE (1) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
|
||||||
|
/* rot == 4 writes flags, which takes only one cycle */
|
||||||
|
if (rot != 4)
|
||||||
|
{
|
||||||
|
/* nothing fetched, MSR in EXECUTE (2) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
/* nothing fetched, MSR in EXECUTE (3) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm9tdmi_write_core_regs(target_t *target, u32 mask, u32 core_regs[16])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* LDMIA r0-15, [r0] at debug speed
|
||||||
|
* register values will start to appear on 4th DCLK
|
||||||
|
*/
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0);
|
||||||
|
|
||||||
|
/* fetch NOP, LDM in DECODE stage */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
|
||||||
|
for (i = 0; i <= 15; i++)
|
||||||
|
{
|
||||||
|
if (mask & (1 << i))
|
||||||
|
/* nothing fetched, LDM still in EXECUTE (1+i cycle) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, core_regs[i], NULL, 0);
|
||||||
|
}
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm9tdmi_load_word_regs(target_t *target, u32 mask)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* put system-speed load-multiple into the pipeline */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm9tdmi_load_hword_reg(target_t *target, int num)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* put system-speed load half-word into the pipeline */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm9tdmi_load_byte_reg(target_t *target, int num)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* put system-speed load byte into the pipeline */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm9tdmi_store_word_regs(target_t *target, u32 mask)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* put system-speed store-multiple into the pipeline */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm9tdmi_store_hword_reg(target_t *target, int num)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* put system-speed store half-word into the pipeline */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm9tdmi_store_byte_reg(target_t *target, int num)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* put system-speed store byte into the pipeline */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm9tdmi_write_pc(target_t *target, u32 pc)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
/* LDMIA r0-15, [r0] at debug speed
|
||||||
|
* register values will start to appear on 4th DCLK
|
||||||
|
*/
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), 0, NULL, 0);
|
||||||
|
|
||||||
|
/* fetch NOP, LDM in DECODE stage */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
/* nothing fetched, LDM in EXECUTE stage (2nd cycle) (output data) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, pc, NULL, 0);
|
||||||
|
/* nothing fetched, LDM in EXECUTE stage (3rd cycle) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
/* fetch NOP, LDM in EXECUTE stage (4th cycle) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
/* fetch NOP, LDM in EXECUTE stage (5th cycle) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm9tdmi_branch_resume(target_t *target)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_B(0xfffffc, 0), 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm9tdmi_branch_resume_thumb(target_t *target)
|
||||||
|
{
|
||||||
|
DEBUG("");
|
||||||
|
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
|
||||||
|
|
||||||
|
/* LDMIA r0-15, [r0] at debug speed
|
||||||
|
* register values will start to appear on 4th DCLK
|
||||||
|
*/
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), 0, NULL, 0);
|
||||||
|
|
||||||
|
/* fetch NOP, LDM in DECODE stage */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
/* nothing fetched, LDM in EXECUTE stage (2nd cycle) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32) | 1, NULL, 0);
|
||||||
|
/* nothing fetched, LDM in EXECUTE stage (3rd cycle) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
|
||||||
|
/* Branch and eXchange */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_BX(0), 0, NULL, 0);
|
||||||
|
|
||||||
|
embeddedice_read_reg(dbg_stat);
|
||||||
|
|
||||||
|
/* fetch NOP, BX in DECODE stage */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
|
||||||
|
embeddedice_read_reg(dbg_stat);
|
||||||
|
|
||||||
|
/* fetch NOP, BX in EXECUTE stage (1st cycle) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
|
||||||
|
|
||||||
|
/* target is now in Thumb state */
|
||||||
|
embeddedice_read_reg(dbg_stat);
|
||||||
|
|
||||||
|
/* clean r0 bits to avoid alignment problems */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_MOV_IM(0, 0x0), 0, NULL, 0);
|
||||||
|
/* load r0 value, MOV_IM in Decode*/
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR(0, 0), 0, NULL, 0);
|
||||||
|
/* fetch NOP, LDR in Decode, MOV_IM in Execute */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
|
||||||
|
/* fetch NOP, LDR in Execute */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
|
||||||
|
/* nothing fetched, LDR in EXECUTE stage (2nd cycle) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, buf_get_u32(armv4_5->core_cache->reg_list[0].value, 0, 32), NULL, 0);
|
||||||
|
/* nothing fetched, LDR in EXECUTE stage (3rd cycle) */
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
|
||||||
|
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
|
||||||
|
|
||||||
|
embeddedice_read_reg(dbg_stat);
|
||||||
|
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f6), 0, NULL, 1);
|
||||||
|
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm9tdmi_enable_single_step(target_t *target)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm9tdmi_common_t *arm9 = arm7_9->arch_info;
|
||||||
|
|
||||||
|
if (arm9->has_single_step)
|
||||||
|
{
|
||||||
|
buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 3, 1, 1);
|
||||||
|
embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arm7_9_enable_eice_step(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm9tdmi_disable_single_step(target_t *target)
|
||||||
|
{
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm9tdmi_common_t *arm9 = arm7_9->arch_info;
|
||||||
|
|
||||||
|
if (arm9->has_single_step)
|
||||||
|
{
|
||||||
|
buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 3, 1, 0);
|
||||||
|
embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arm7_9_disable_eice_step(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm9tdmi_build_reg_cache(target_t *target)
|
||||||
|
{
|
||||||
|
reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache);
|
||||||
|
/* get pointers to arch-specific information */
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
|
||||||
|
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
|
||||||
|
arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
|
||||||
|
|
||||||
|
|
||||||
|
(*cache_p) = armv4_5_build_reg_cache(target, armv4_5);
|
||||||
|
armv4_5->core_cache = (*cache_p);
|
||||||
|
|
||||||
|
(*cache_p)->next = embeddedice_build_reg_cache(target, jtag_info, 0);
|
||||||
|
arm7_9->eice_cache = (*cache_p)->next;
|
||||||
|
|
||||||
|
if (arm9tdmi->has_monitor_mode)
|
||||||
|
(*cache_p)->next->reg_list[0].size = 6;
|
||||||
|
else
|
||||||
|
(*cache_p)->next->reg_list[0].size = 4;
|
||||||
|
|
||||||
|
(*cache_p)->next->reg_list[1].size = 5;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm9tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
|
||||||
|
{
|
||||||
|
|
||||||
|
arm9tdmi_build_reg_cache(target);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm9tdmi_quit()
|
||||||
|
{
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm9tdmi_init_arch_info(target_t *target, arm9tdmi_common_t *arm9tdmi, int chain_pos, char *variant)
|
||||||
|
{
|
||||||
|
armv4_5_common_t *armv4_5;
|
||||||
|
arm7_9_common_t *arm7_9;
|
||||||
|
|
||||||
|
arm7_9 = &arm9tdmi->arm7_9_common;
|
||||||
|
armv4_5 = &arm7_9->armv4_5_common;
|
||||||
|
|
||||||
|
/* prepare JTAG information for the new target */
|
||||||
|
arm7_9->jtag_info.chain_pos = chain_pos;
|
||||||
|
arm7_9->jtag_info.scann_size = 5;
|
||||||
|
|
||||||
|
/* register arch-specific functions */
|
||||||
|
arm7_9->examine_debug_reason = arm9tdmi_examine_debug_reason;
|
||||||
|
arm7_9->change_to_arm = arm9tdmi_change_to_arm;
|
||||||
|
arm7_9->read_core_regs = arm9tdmi_read_core_regs;
|
||||||
|
arm7_9->read_xpsr = arm9tdmi_read_xpsr;
|
||||||
|
|
||||||
|
arm7_9->write_xpsr = arm9tdmi_write_xpsr;
|
||||||
|
arm7_9->write_xpsr_im8 = arm9tdmi_write_xpsr_im8;
|
||||||
|
arm7_9->write_core_regs = arm9tdmi_write_core_regs;
|
||||||
|
|
||||||
|
arm7_9->load_word_regs = arm9tdmi_load_word_regs;
|
||||||
|
arm7_9->load_hword_reg = arm9tdmi_load_hword_reg;
|
||||||
|
arm7_9->load_byte_reg = arm9tdmi_load_byte_reg;
|
||||||
|
|
||||||
|
arm7_9->store_word_regs = arm9tdmi_store_word_regs;
|
||||||
|
arm7_9->store_hword_reg = arm9tdmi_store_hword_reg;
|
||||||
|
arm7_9->store_byte_reg = arm9tdmi_store_byte_reg;
|
||||||
|
|
||||||
|
arm7_9->write_pc = arm9tdmi_write_pc;
|
||||||
|
arm7_9->branch_resume = arm9tdmi_branch_resume;
|
||||||
|
arm7_9->branch_resume_thumb = arm9tdmi_branch_resume_thumb;
|
||||||
|
|
||||||
|
arm7_9->enable_single_step = arm9tdmi_enable_single_step;
|
||||||
|
arm7_9->disable_single_step = arm9tdmi_disable_single_step;
|
||||||
|
|
||||||
|
arm7_9->pre_debug_entry = NULL;
|
||||||
|
arm7_9->post_debug_entry = NULL;
|
||||||
|
|
||||||
|
arm7_9->pre_restore_context = NULL;
|
||||||
|
arm7_9->post_restore_context = NULL;
|
||||||
|
|
||||||
|
/* initialize arch-specific breakpoint handling */
|
||||||
|
buf_set_u32((u8*)(&arm7_9->arm_bkpt), 0, 32, 0xdeeedeee);
|
||||||
|
buf_set_u32((u8*)(&arm7_9->thumb_bkpt), 0, 16, 0xdeee);
|
||||||
|
|
||||||
|
arm7_9->sw_bkpts_use_wp = 1;
|
||||||
|
arm7_9->sw_bkpts_enabled = 0;
|
||||||
|
arm7_9->dbgreq_adjust_pc = 3;
|
||||||
|
arm7_9->arch_info = arm9tdmi;
|
||||||
|
arm7_9->use_dbgrq = 1;
|
||||||
|
|
||||||
|
arm9tdmi->common_magic = ARM9TDMI_COMMON_MAGIC;
|
||||||
|
arm9tdmi->has_monitor_mode = 0;
|
||||||
|
arm9tdmi->has_single_step = 0;
|
||||||
|
arm9tdmi->arch_info = NULL;
|
||||||
|
|
||||||
|
if (variant)
|
||||||
|
{
|
||||||
|
if (strcmp(variant, "arm920t") == 0)
|
||||||
|
arm9tdmi->has_single_step = 1;
|
||||||
|
else if (strcmp(variant, "arm922t") == 0)
|
||||||
|
arm9tdmi->has_single_step = 1;
|
||||||
|
else if (strcmp(variant, "arm940t") == 0)
|
||||||
|
arm9tdmi->has_single_step = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
arm7_9_init_arch_info(target, arm7_9);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* target arm9tdmi <endianess> <startup_mode> <chain_pos> <variant>*/
|
||||||
|
int arm9tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
|
||||||
|
{
|
||||||
|
int chain_pos;
|
||||||
|
char *variant = NULL;
|
||||||
|
arm9tdmi_common_t *arm9tdmi = malloc(sizeof(arm9tdmi_common_t));
|
||||||
|
|
||||||
|
if (argc < 4)
|
||||||
|
{
|
||||||
|
ERROR("'target arm9tdmi' requires at least one additional argument");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
chain_pos = strtoul(args[3], NULL, 0);
|
||||||
|
|
||||||
|
if (argc >= 5)
|
||||||
|
variant = strdup(args[4]);
|
||||||
|
|
||||||
|
arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm9tdmi_register_commands(struct command_context_s *cmd_ctx)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
retval = arm7_9_register_commands(cmd_ctx);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef ARM9TDMI_H
|
||||||
|
#define ARM9TDMI_H
|
||||||
|
|
||||||
|
#include "target.h"
|
||||||
|
#include "register.h"
|
||||||
|
#include "armv4_5.h"
|
||||||
|
#include "embeddedice.h"
|
||||||
|
#include "arm_jtag.h"
|
||||||
|
#include "arm7_9_common.h"
|
||||||
|
|
||||||
|
#define ARM9TDMI_COMMON_MAGIC 0x00a900a9
|
||||||
|
|
||||||
|
typedef struct arm9tdmi_common_s
|
||||||
|
{
|
||||||
|
int common_magic;
|
||||||
|
char *variant;
|
||||||
|
int has_monitor_mode;
|
||||||
|
int has_single_step;
|
||||||
|
void *arch_info;
|
||||||
|
arm7_9_common_t arm7_9_common;
|
||||||
|
} arm9tdmi_common_t;
|
||||||
|
|
||||||
|
extern int arm9tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
|
||||||
|
extern int arm9tdmi_init_arch_info(target_t *target, arm9tdmi_common_t *arm9tdmi, int chain_pos, char *variant);
|
||||||
|
extern int arm9tdmi_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
|
||||||
|
extern int arm9tdmi_clock_out(arm_jtag_t *jtag_info, u32 instr, u32 out, u32 *in, int sysspeed);
|
||||||
|
extern int arm9tdmi_clock_data_in(arm_jtag_t *jtag_info, u32 *in);
|
||||||
|
extern void arm9tdmi_read_core_regs(target_t *target, u32 mask, u32* core_regs[16]);
|
||||||
|
extern void arm9tdmi_write_core_regs(target_t *target, u32 mask, u32 core_regs[16]);
|
||||||
|
|
||||||
|
#endif /* ARM9TDMI_H */
|
|
@ -0,0 +1,116 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "arm_jtag.h"
|
||||||
|
|
||||||
|
#include "binarybuffer.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "jtag.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int arm_jtag_set_instr(arm_jtag_t *jtag_info, u32 new_instr)
|
||||||
|
{
|
||||||
|
jtag_device_t *device = jtag_get_device(jtag_info->chain_pos);
|
||||||
|
|
||||||
|
if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr)
|
||||||
|
{
|
||||||
|
scan_field_t field;
|
||||||
|
|
||||||
|
field.device = jtag_info->chain_pos;
|
||||||
|
field.num_bits = device->ir_length;
|
||||||
|
field.out_value = calloc(CEIL(field.num_bits, 8), 1);
|
||||||
|
buf_set_u32(field.out_value, 0, field.num_bits, new_instr);
|
||||||
|
field.out_mask = NULL;
|
||||||
|
field.in_value = NULL;
|
||||||
|
field.in_check_value = NULL;
|
||||||
|
field.in_check_mask = NULL;
|
||||||
|
field.in_handler = NULL;
|
||||||
|
field.in_handler_priv = NULL;
|
||||||
|
|
||||||
|
jtag_add_ir_scan(1, &field, -1);
|
||||||
|
|
||||||
|
free(field.out_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm_jtag_scann(arm_jtag_t *jtag_info, u32 new_scan_chain)
|
||||||
|
{
|
||||||
|
if(jtag_info->cur_scan_chain != new_scan_chain)
|
||||||
|
{
|
||||||
|
scan_field_t field;
|
||||||
|
|
||||||
|
field.device = jtag_info->chain_pos;
|
||||||
|
field.num_bits = jtag_info->scann_size;
|
||||||
|
field.out_value = calloc(CEIL(field.num_bits, 8), 1);
|
||||||
|
buf_set_u32(field.out_value, 0, field.num_bits, new_scan_chain);
|
||||||
|
field.out_mask = NULL;
|
||||||
|
//field.in_value = &scan_n_capture;
|
||||||
|
field.in_value = NULL;
|
||||||
|
field.in_check_value = NULL;
|
||||||
|
field.in_check_mask = NULL;
|
||||||
|
field.in_handler = NULL;
|
||||||
|
field.in_handler_priv = NULL;
|
||||||
|
|
||||||
|
arm_jtag_set_instr(jtag_info, jtag_info->scann_instr);
|
||||||
|
jtag_add_dr_scan(1, &field, -1);
|
||||||
|
|
||||||
|
jtag_info->cur_scan_chain = new_scan_chain;
|
||||||
|
|
||||||
|
free(field.out_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm_jtag_reset_callback(enum jtag_event event, void *priv)
|
||||||
|
{
|
||||||
|
arm_jtag_t *jtag_info = priv;
|
||||||
|
|
||||||
|
if (event == JTAG_TRST_ASSERTED)
|
||||||
|
{
|
||||||
|
jtag_info->cur_scan_chain = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm_jtag_setup_connection(arm_jtag_t *jtag_info)
|
||||||
|
{
|
||||||
|
jtag_info->scann_instr = 0x2;
|
||||||
|
jtag_info->cur_scan_chain = 0;
|
||||||
|
jtag_info->intest_instr = 0xc;
|
||||||
|
|
||||||
|
jtag_register_event_callback(arm_jtag_reset_callback, jtag_info);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm_jtag_buf_to_u32_flip(u8 *in_buf, void *priv)
|
||||||
|
{
|
||||||
|
u32 *dest = priv;
|
||||||
|
|
||||||
|
*dest = flip_u32(buf_get_u32(in_buf, 0, 32), 32);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef ARM_JTAG
|
||||||
|
#define ARM_JTAG
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
typedef struct arm_jtag_s
|
||||||
|
{
|
||||||
|
int chain_pos;
|
||||||
|
|
||||||
|
int scann_size;
|
||||||
|
u32 scann_instr;
|
||||||
|
int cur_scan_chain;
|
||||||
|
|
||||||
|
u32 intest_instr;
|
||||||
|
} arm_jtag_t;
|
||||||
|
|
||||||
|
extern int arm_jtag_set_instr(arm_jtag_t *jtag_info, u32 new_instr);
|
||||||
|
extern int arm_jtag_scann(arm_jtag_t *jtag_info, u32 new_scan_chain);
|
||||||
|
extern int arm_jtag_buf_to_u32_flip(u8 *in_buf, void *priv);
|
||||||
|
extern int arm_jtag_setup_connection(arm_jtag_t *jtag_info);
|
||||||
|
|
||||||
|
#endif /* ARM_JTAG */
|
||||||
|
|
|
@ -0,0 +1,583 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "armv4_5.h"
|
||||||
|
|
||||||
|
#include "target.h"
|
||||||
|
#include "register.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "binarybuffer.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
bitfield_desc_t armv4_5_psr_bitfield_desc[] =
|
||||||
|
{
|
||||||
|
{"M[4:0]", 5},
|
||||||
|
{"T", 1},
|
||||||
|
{"F", 1},
|
||||||
|
{"I", 1},
|
||||||
|
{"reserved", 16},
|
||||||
|
{"J", 1},
|
||||||
|
{"reserved", 2},
|
||||||
|
{"Q", 1},
|
||||||
|
{"V", 1},
|
||||||
|
{"C", 1},
|
||||||
|
{"Z", 1},
|
||||||
|
{"N", 1},
|
||||||
|
};
|
||||||
|
|
||||||
|
char* armv4_5_core_reg_list[] =
|
||||||
|
{
|
||||||
|
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13_usr", "lr_usr", "pc",
|
||||||
|
|
||||||
|
"r8_fiq", "r9_fiq", "r10_fiq", "r11_fiq", "r12_fiq", "r13_fiq", "lr_fiq",
|
||||||
|
|
||||||
|
"r13_irq", "lr_irq",
|
||||||
|
|
||||||
|
"r13_svc", "lr_svc",
|
||||||
|
|
||||||
|
"r13_abt", "lr_abt",
|
||||||
|
|
||||||
|
"r13_und", "lr_und",
|
||||||
|
|
||||||
|
"cpsr", "spsr_fiq", "spsr_irq", "spsr_svc", "spsr_abt", "spsr_und"
|
||||||
|
};
|
||||||
|
|
||||||
|
char* armv4_5_mode_strings[] =
|
||||||
|
{
|
||||||
|
"User", "FIQ", "IRQ", "Supervisor", "Abort", "Undefined", "System"
|
||||||
|
};
|
||||||
|
|
||||||
|
char* armv4_5_state_strings[] =
|
||||||
|
{
|
||||||
|
"ARM", "Thumb", "Jazelle"
|
||||||
|
};
|
||||||
|
|
||||||
|
int armv4_5_core_reg_arch_type = -1;
|
||||||
|
|
||||||
|
armv4_5_core_reg_t armv4_5_core_reg_list_arch_info[] =
|
||||||
|
{
|
||||||
|
{0, ARMV4_5_MODE_ANY, NULL, NULL},
|
||||||
|
{1, ARMV4_5_MODE_ANY, NULL, NULL},
|
||||||
|
{2, ARMV4_5_MODE_ANY, NULL, NULL},
|
||||||
|
{3, ARMV4_5_MODE_ANY, NULL, NULL},
|
||||||
|
{4, ARMV4_5_MODE_ANY, NULL, NULL},
|
||||||
|
{5, ARMV4_5_MODE_ANY, NULL, NULL},
|
||||||
|
{6, ARMV4_5_MODE_ANY, NULL, NULL},
|
||||||
|
{7, ARMV4_5_MODE_ANY, NULL, NULL},
|
||||||
|
{8, ARMV4_5_MODE_ANY, NULL, NULL},
|
||||||
|
{9, ARMV4_5_MODE_ANY, NULL, NULL},
|
||||||
|
{10, ARMV4_5_MODE_ANY, NULL, NULL},
|
||||||
|
{11, ARMV4_5_MODE_ANY, NULL, NULL},
|
||||||
|
{12, ARMV4_5_MODE_ANY, NULL, NULL},
|
||||||
|
{13, ARMV4_5_MODE_USR, NULL, NULL},
|
||||||
|
{14, ARMV4_5_MODE_USR, NULL, NULL},
|
||||||
|
{15, ARMV4_5_MODE_ANY, NULL, NULL},
|
||||||
|
|
||||||
|
{8, ARMV4_5_MODE_FIQ, NULL, NULL},
|
||||||
|
{9, ARMV4_5_MODE_FIQ, NULL, NULL},
|
||||||
|
{10, ARMV4_5_MODE_FIQ, NULL, NULL},
|
||||||
|
{11, ARMV4_5_MODE_FIQ, NULL, NULL},
|
||||||
|
{12, ARMV4_5_MODE_FIQ, NULL, NULL},
|
||||||
|
{13, ARMV4_5_MODE_FIQ, NULL, NULL},
|
||||||
|
{14, ARMV4_5_MODE_FIQ, NULL, NULL},
|
||||||
|
|
||||||
|
{13, ARMV4_5_MODE_IRQ, NULL, NULL},
|
||||||
|
{14, ARMV4_5_MODE_IRQ, NULL, NULL},
|
||||||
|
|
||||||
|
{13, ARMV4_5_MODE_SVC, NULL, NULL},
|
||||||
|
{14, ARMV4_5_MODE_SVC, NULL, NULL},
|
||||||
|
|
||||||
|
{13, ARMV4_5_MODE_ABT, NULL, NULL},
|
||||||
|
{14, ARMV4_5_MODE_ABT, NULL, NULL},
|
||||||
|
|
||||||
|
{13, ARMV4_5_MODE_UND, NULL, NULL},
|
||||||
|
{14, ARMV4_5_MODE_UND, NULL, NULL},
|
||||||
|
|
||||||
|
{16, ARMV4_5_MODE_ANY, NULL, NULL},
|
||||||
|
{16, ARMV4_5_MODE_FIQ, NULL, NULL},
|
||||||
|
{16, ARMV4_5_MODE_IRQ, NULL, NULL},
|
||||||
|
{16, ARMV4_5_MODE_SVC, NULL, NULL},
|
||||||
|
{16, ARMV4_5_MODE_ABT, NULL, NULL},
|
||||||
|
{16, ARMV4_5_MODE_UND, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* map core mode (USR, FIQ, ...) and register number to indizes into the register cache */
|
||||||
|
int armv4_5_core_reg_map[7][17] =
|
||||||
|
{
|
||||||
|
{ /* USR */
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31
|
||||||
|
},
|
||||||
|
{ /* FIQ */
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 15, 32
|
||||||
|
},
|
||||||
|
{ /* IRQ */
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 23, 24, 15, 33
|
||||||
|
},
|
||||||
|
{ /* SVC */
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 25, 26, 15, 34
|
||||||
|
},
|
||||||
|
{ /* ABT */
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 27, 28, 15, 35
|
||||||
|
},
|
||||||
|
{ /* UND */
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 29, 30, 15, 36
|
||||||
|
},
|
||||||
|
{ /* SYS */
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
u8 armv4_5_gdb_dummy_fp_value[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
|
|
||||||
|
reg_t armv4_5_gdb_dummy_fp_reg =
|
||||||
|
{
|
||||||
|
"GDB dummy floating-point register", armv4_5_gdb_dummy_fp_value, 0, 1, 96, NULL, 0, NULL, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
u8 armv4_5_gdb_dummy_fps_value[] = {0, 0, 0, 0};
|
||||||
|
|
||||||
|
reg_t armv4_5_gdb_dummy_fps_reg =
|
||||||
|
{
|
||||||
|
"GDB dummy floating-point status register", armv4_5_gdb_dummy_fps_value, 0, 1, 32, NULL, 0, NULL, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
/* map psr mode bits to linear number */
|
||||||
|
int armv4_5_mode_to_number(enum armv4_5_mode mode)
|
||||||
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case 16: return 0; break;
|
||||||
|
case 17: return 1; break;
|
||||||
|
case 18: return 2; break;
|
||||||
|
case 19: return 3; break;
|
||||||
|
case 23: return 4; break;
|
||||||
|
case 27: return 5; break;
|
||||||
|
case 31: return 6; break;
|
||||||
|
case -1: return 0; break; /* map MODE_ANY to user mode */
|
||||||
|
default:
|
||||||
|
ERROR("invalid mode value encountered");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* map linear number to mode bits */
|
||||||
|
enum armv4_5_mode armv4_5_number_to_mode(int number)
|
||||||
|
{
|
||||||
|
switch(number)
|
||||||
|
{
|
||||||
|
case 0: return ARMV4_5_MODE_USR; break;
|
||||||
|
case 1: return ARMV4_5_MODE_FIQ; break;
|
||||||
|
case 2: return ARMV4_5_MODE_IRQ; break;
|
||||||
|
case 3: return ARMV4_5_MODE_SVC; break;
|
||||||
|
case 4: return ARMV4_5_MODE_ABT; break;
|
||||||
|
case 5: return ARMV4_5_MODE_UND; break;
|
||||||
|
case 6: return ARMV4_5_MODE_SYS; break;
|
||||||
|
default:
|
||||||
|
ERROR("mode index out of bounds");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int armv4_5_get_core_reg(reg_t *reg)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
armv4_5_core_reg_t *armv4_5 = reg->arch_info;
|
||||||
|
target_t *target = armv4_5->target;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
//retval = armv4_5->armv4_5_common->full_context(target);
|
||||||
|
retval = armv4_5->armv4_5_common->read_core_reg(target, armv4_5->num, armv4_5->mode);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int armv4_5_set_core_reg(reg_t *reg, u32 value)
|
||||||
|
{
|
||||||
|
armv4_5_core_reg_t *armv4_5 = reg->arch_info;
|
||||||
|
target_t *target = armv4_5->target;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf_set_u32(reg->value, 0, 32, value);
|
||||||
|
reg->dirty = 1;
|
||||||
|
reg->valid = 1;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int armv4_5_invalidate_core_regs(target_t *target)
|
||||||
|
{
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 37; i++)
|
||||||
|
{
|
||||||
|
armv4_5->core_cache->reg_list[i].valid = 0;
|
||||||
|
armv4_5->core_cache->reg_list[i].dirty = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
reg_cache_t* armv4_5_build_reg_cache(target_t *target, armv4_5_common_t *armv4_5_common)
|
||||||
|
{
|
||||||
|
int num_regs = 37;
|
||||||
|
reg_cache_t *cache = malloc(sizeof(reg_cache_t));
|
||||||
|
reg_t *reg_list = malloc(sizeof(reg_t) * num_regs);
|
||||||
|
armv4_5_core_reg_t *arch_info = malloc(sizeof(reg_t) * num_regs);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
cache->name = "arm v4/5 registers";
|
||||||
|
cache->next = NULL;
|
||||||
|
cache->reg_list = reg_list;
|
||||||
|
cache->num_regs = num_regs;
|
||||||
|
|
||||||
|
if (armv4_5_core_reg_arch_type == -1)
|
||||||
|
armv4_5_core_reg_arch_type = register_reg_arch_type(armv4_5_get_core_reg, armv4_5_set_core_reg);
|
||||||
|
|
||||||
|
for (i = 0; i < 37; i++)
|
||||||
|
{
|
||||||
|
arch_info[i] = armv4_5_core_reg_list_arch_info[i];
|
||||||
|
arch_info[i].target = target;
|
||||||
|
arch_info[i].armv4_5_common = armv4_5_common;
|
||||||
|
reg_list[i].name = armv4_5_core_reg_list[i];
|
||||||
|
reg_list[i].size = 32;
|
||||||
|
reg_list[i].value = calloc(1, 4);
|
||||||
|
reg_list[i].dirty = 0;
|
||||||
|
reg_list[i].valid = 0;
|
||||||
|
reg_list[i].bitfield_desc = NULL;
|
||||||
|
reg_list[i].num_bitfields = 0;
|
||||||
|
reg_list[i].arch_type = armv4_5_core_reg_arch_type;
|
||||||
|
reg_list[i].arch_info = &arch_info[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
int armv4_5_arch_state(struct target_s *target, char *buf, int buf_size)
|
||||||
|
{
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
|
||||||
|
if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
|
||||||
|
{
|
||||||
|
ERROR("BUG: called for a non-ARMv4/5 target");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buf, buf_size,
|
||||||
|
"target halted in %s state due to %s, current mode: %s\ncpsr: 0x%8.8x pc: 0x%8.8x",
|
||||||
|
armv4_5_state_strings[armv4_5->core_state],
|
||||||
|
target_debug_reason_strings[target->debug_reason],
|
||||||
|
armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)],
|
||||||
|
buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32),
|
||||||
|
buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32));
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle_armv4_5_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
char output[128];
|
||||||
|
int output_len;
|
||||||
|
int mode, num;
|
||||||
|
target_t *target = get_current_target(cmd_ctx);
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
|
||||||
|
if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "current target isn't an ARMV4/5 target");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "error: target must be halted for register accesses");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (num = 0; num <= 15; num++)
|
||||||
|
{
|
||||||
|
output_len = 0;
|
||||||
|
for (mode = 0; mode < 6; mode++)
|
||||||
|
{
|
||||||
|
if (!ARMV4_5_CORE_REG_MODENUM(armv4_5->core_cache, mode, num).valid)
|
||||||
|
{
|
||||||
|
armv4_5->full_context(target);
|
||||||
|
}
|
||||||
|
output_len += snprintf(output + output_len, 128 - output_len, "%8s: %8.8x ", ARMV4_5_CORE_REG_MODENUM(armv4_5->core_cache, mode, num).name,
|
||||||
|
buf_get_u32(ARMV4_5_CORE_REG_MODENUM(armv4_5->core_cache, mode, num).value, 0, 32));
|
||||||
|
}
|
||||||
|
command_print(cmd_ctx, output);
|
||||||
|
}
|
||||||
|
command_print(cmd_ctx, " cpsr: %8.8x spsr_fiq: %8.8x spsr_irq: %8.8x spsr_svc: %8.8x spsr_abt: %8.8x spsr_und: %8.8x",
|
||||||
|
buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32),
|
||||||
|
buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_SPSR_FIQ].value, 0, 32),
|
||||||
|
buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_SPSR_IRQ].value, 0, 32),
|
||||||
|
buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_SPSR_SVC].value, 0, 32),
|
||||||
|
buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_SPSR_ABT].value, 0, 32),
|
||||||
|
buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_SPSR_UND].value, 0, 32));
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle_armv4_5_core_state_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
target_t *target = get_current_target(cmd_ctx);
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
|
||||||
|
if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "current target isn't an ARMV4/5 target");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc > 0)
|
||||||
|
{
|
||||||
|
if (strcmp(args[0], "arm") == 0)
|
||||||
|
{
|
||||||
|
armv4_5->core_state = ARMV4_5_STATE_ARM;
|
||||||
|
}
|
||||||
|
if (strcmp(args[0], "thumb") == 0)
|
||||||
|
{
|
||||||
|
armv4_5->core_state = ARMV4_5_STATE_THUMB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
command_print(cmd_ctx, "core state: %s", armv4_5_state_strings[armv4_5->core_state]);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int armv4_5_register_commands(struct command_context_s *cmd_ctx)
|
||||||
|
{
|
||||||
|
command_t *armv4_5_cmd;
|
||||||
|
|
||||||
|
armv4_5_cmd = register_command(cmd_ctx, NULL, "armv4_5", NULL, COMMAND_ANY, NULL);
|
||||||
|
|
||||||
|
register_command(cmd_ctx, armv4_5_cmd, "reg", handle_armv4_5_reg_command, COMMAND_EXEC, "display ARM core registers");
|
||||||
|
register_command(cmd_ctx, armv4_5_cmd, "core_state", handle_armv4_5_core_state_command, COMMAND_EXEC, "display/change ARM core state <arm|thumb>");
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int armv4_5_get_gdb_reg_list(target_t *target, reg_t **reg_list[], int *reg_list_size)
|
||||||
|
{
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
*reg_list_size = 26;
|
||||||
|
*reg_list = malloc(sizeof(reg_t*) * (*reg_list_size));
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
(*reg_list)[i] = &ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 16; i < 24; i++)
|
||||||
|
{
|
||||||
|
(*reg_list)[i] = &armv4_5_gdb_dummy_fp_reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*reg_list)[24] = &armv4_5_gdb_dummy_fps_reg;
|
||||||
|
(*reg_list)[25] = &armv4_5->core_cache->reg_list[ARMV4_5_CPSR];
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int armv4_5_run_algorithm(struct target_s *target, int num_mem_params, mem_param_t *mem_params, int num_reg_params, reg_param_t *reg_params, u32 entry_point, u32 exit_point, int timeout_ms, void *arch_info)
|
||||||
|
{
|
||||||
|
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||||
|
armv4_5_algorithm_t *armv4_5_algorithm_info = arch_info;
|
||||||
|
enum armv4_5_state core_state = armv4_5->core_state;
|
||||||
|
enum armv4_5_mode core_mode = armv4_5->core_mode;
|
||||||
|
u32 context[17];
|
||||||
|
u32 cpsr;
|
||||||
|
int exit_breakpoint_size = 0;
|
||||||
|
int i;
|
||||||
|
int retval = ERROR_OK;
|
||||||
|
|
||||||
|
if (armv4_5_algorithm_info->common_magic != ARMV4_5_COMMON_MAGIC)
|
||||||
|
{
|
||||||
|
ERROR("current target isn't an ARMV4/5 target");
|
||||||
|
return ERROR_TARGET_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
WARNING("target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i <= 16; i++)
|
||||||
|
{
|
||||||
|
if (!ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).valid)
|
||||||
|
armv4_5->read_core_reg(target, i, armv4_5_algorithm_info->core_mode);
|
||||||
|
context[i] = buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).value, 0, 32);
|
||||||
|
}
|
||||||
|
cpsr = buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32);
|
||||||
|
|
||||||
|
for (i = 0; i < num_mem_params; i++)
|
||||||
|
{
|
||||||
|
target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < num_reg_params; i++)
|
||||||
|
{
|
||||||
|
reg_t *reg = register_get_by_name(armv4_5->core_cache, reg_params[i].reg_name, 0);
|
||||||
|
if (!reg)
|
||||||
|
{
|
||||||
|
ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reg->size != reg_params[i].size)
|
||||||
|
{
|
||||||
|
ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
armv4_5_set_core_reg(reg, buf_get_u32(reg_params[i].value, 0, 32));
|
||||||
|
}
|
||||||
|
|
||||||
|
armv4_5->core_state = armv4_5_algorithm_info->core_state;
|
||||||
|
if (armv4_5->core_state == ARMV4_5_STATE_ARM)
|
||||||
|
exit_breakpoint_size = 4;
|
||||||
|
else if (armv4_5->core_state == ARMV4_5_STATE_THUMB)
|
||||||
|
exit_breakpoint_size = 2;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR("BUG: can't execute algorithms when not in ARM or Thumb state");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (armv4_5_algorithm_info->core_mode != ARMV4_5_MODE_ANY)
|
||||||
|
{
|
||||||
|
DEBUG("setting core_mode: 0x%2.2x", armv4_5_algorithm_info->core_mode);
|
||||||
|
buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 5, armv4_5_algorithm_info->core_mode);
|
||||||
|
armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1;
|
||||||
|
armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((retval = breakpoint_add(target, exit_point, exit_breakpoint_size, BKPT_HARD)) != ERROR_OK)
|
||||||
|
{
|
||||||
|
ERROR("can't add breakpoint to finish algorithm execution");
|
||||||
|
return ERROR_TARGET_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
target->type->resume(target, 0, entry_point, 1, 1);
|
||||||
|
target->type->poll(target);
|
||||||
|
|
||||||
|
while (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
usleep(10000);
|
||||||
|
target->type->poll(target);
|
||||||
|
if ((timeout_ms -= 10) <= 0)
|
||||||
|
{
|
||||||
|
ERROR("timeout waiting for algorithm to complete, trying to halt target");
|
||||||
|
target->type->halt(target);
|
||||||
|
timeout_ms = 1000;
|
||||||
|
while (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
usleep(10000);
|
||||||
|
target->type->poll(target);
|
||||||
|
if ((timeout_ms -= 10) <= 0)
|
||||||
|
{
|
||||||
|
ERROR("target didn't reenter debug state, exiting");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval = ERROR_TARGET_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
breakpoint_remove(target, exit_point);
|
||||||
|
|
||||||
|
for (i = 0; i < num_mem_params; i++)
|
||||||
|
{
|
||||||
|
if (mem_params[i].direction != PARAM_OUT)
|
||||||
|
target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < num_reg_params; i++)
|
||||||
|
{
|
||||||
|
if (reg_params[i].direction != PARAM_OUT)
|
||||||
|
{
|
||||||
|
|
||||||
|
reg_t *reg = register_get_by_name(armv4_5->core_cache, reg_params[i].reg_name, 0);
|
||||||
|
if (!reg)
|
||||||
|
{
|
||||||
|
ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reg->size != reg_params[i].size)
|
||||||
|
{
|
||||||
|
ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i <= 16; i++)
|
||||||
|
{
|
||||||
|
DEBUG("restoring register %s with value 0x%8.8x", ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).name, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).value, 0, 32));
|
||||||
|
buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).value, 0, 32, context[i]);
|
||||||
|
ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).valid = 1;
|
||||||
|
ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).dirty = 1;
|
||||||
|
}
|
||||||
|
buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32, cpsr);
|
||||||
|
armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
|
||||||
|
armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1;
|
||||||
|
|
||||||
|
armv4_5->core_state = core_state;
|
||||||
|
armv4_5->core_mode = core_mode;
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int armv4_5_init_arch_info(target_t *target, armv4_5_common_t *armv4_5)
|
||||||
|
{
|
||||||
|
target->arch_info = armv4_5;
|
||||||
|
|
||||||
|
armv4_5->common_magic = ARMV4_5_COMMON_MAGIC;
|
||||||
|
armv4_5->core_state = ARMV4_5_STATE_ARM;
|
||||||
|
armv4_5->core_mode = ARMV4_5_MODE_USR;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
|
@ -0,0 +1,237 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef ARMV4_5_H
|
||||||
|
#define ARMV4_5_H
|
||||||
|
|
||||||
|
#include "register.h"
|
||||||
|
#include "target.h"
|
||||||
|
|
||||||
|
enum armv4_5_mode
|
||||||
|
{
|
||||||
|
ARMV4_5_MODE_USR = 16,
|
||||||
|
ARMV4_5_MODE_FIQ = 17,
|
||||||
|
ARMV4_5_MODE_IRQ = 18,
|
||||||
|
ARMV4_5_MODE_SVC = 19,
|
||||||
|
ARMV4_5_MODE_ABT = 23,
|
||||||
|
ARMV4_5_MODE_UND = 27,
|
||||||
|
ARMV4_5_MODE_SYS = 31,
|
||||||
|
ARMV4_5_MODE_ANY = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
extern char* armv4_5_mode_strings[];
|
||||||
|
|
||||||
|
enum armv4_5_state
|
||||||
|
{
|
||||||
|
ARMV4_5_STATE_ARM,
|
||||||
|
ARMV4_5_STATE_THUMB,
|
||||||
|
ARMV4_5_STATE_JAZELLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern char* armv4_5_state_strings[];
|
||||||
|
|
||||||
|
extern int armv4_5_core_reg_map[7][17];
|
||||||
|
|
||||||
|
#define ARMV4_5_CORE_REG_MODE(cache, mode, num) \
|
||||||
|
cache->reg_list[armv4_5_core_reg_map[armv4_5_mode_to_number(mode)][num]]
|
||||||
|
#define ARMV4_5_CORE_REG_MODENUM(cache, mode, num) \
|
||||||
|
cache->reg_list[armv4_5_core_reg_map[mode][num]]
|
||||||
|
|
||||||
|
/* offsets into armv4_5 core register cache */
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ARMV4_5_CPSR = 31,
|
||||||
|
ARMV4_5_SPSR_FIQ = 32,
|
||||||
|
ARMV4_5_SPSR_IRQ = 33,
|
||||||
|
ARMV4_5_SPSR_SVC = 34,
|
||||||
|
ARMV4_5_SPSR_ABT = 35,
|
||||||
|
ARMV4_5_SPSR_UND = 36
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ARMV4_5_COMMON_MAGIC 0x0A450A45
|
||||||
|
|
||||||
|
typedef struct armv4_5_common_s
|
||||||
|
{
|
||||||
|
int common_magic;
|
||||||
|
reg_cache_t *core_cache;
|
||||||
|
enum armv4_5_mode core_mode;
|
||||||
|
enum armv4_5_state core_state;
|
||||||
|
int (*full_context)(struct target_s *target);
|
||||||
|
int (*read_core_reg)(struct target_s *target, int num, enum armv4_5_mode mode);
|
||||||
|
int (*write_core_reg)(struct target_s *target, int num, enum armv4_5_mode mode, u32 value);
|
||||||
|
void *arch_info;
|
||||||
|
} armv4_5_common_t;
|
||||||
|
|
||||||
|
typedef struct armv4_5_algorithm_s
|
||||||
|
{
|
||||||
|
int common_magic;
|
||||||
|
|
||||||
|
enum armv4_5_mode core_mode;
|
||||||
|
enum armv4_5_state core_state;
|
||||||
|
} armv4_5_algorithm_t;
|
||||||
|
|
||||||
|
typedef struct armv4_5_core_reg_s
|
||||||
|
{
|
||||||
|
int num;
|
||||||
|
enum armv4_5_mode mode;
|
||||||
|
target_t *target;
|
||||||
|
armv4_5_common_t *armv4_5_common;
|
||||||
|
} armv4_5_core_reg_t;
|
||||||
|
|
||||||
|
extern reg_cache_t* armv4_5_build_reg_cache(target_t *target, armv4_5_common_t *armv4_5_common);
|
||||||
|
extern enum armv4_5_mode armv4_5_number_to_mode(int number);
|
||||||
|
extern int armv4_5_mode_to_number(enum armv4_5_mode mode);
|
||||||
|
|
||||||
|
extern int armv4_5_arch_state(struct target_s *target, char *buf, int buf_size);
|
||||||
|
extern int armv4_5_get_gdb_reg_list(target_t *target, reg_t **reg_list[], int *reg_list_size);
|
||||||
|
extern int armv4_5_invalidate_core_regs(target_t *target);
|
||||||
|
|
||||||
|
extern int armv4_5_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
extern int armv4_5_init_arch_info(target_t *target, armv4_5_common_t *armv4_5);
|
||||||
|
|
||||||
|
extern int armv4_5_run_algorithm(struct target_s *target, int num_mem_params, mem_param_t *mem_params, int num_reg_params, reg_param_t *reg_params, u32 entry_point, u32 exit_point, int timeout_ms, void *arch_info);
|
||||||
|
|
||||||
|
extern int armv4_5_invalidate_core_regs(target_t *target);
|
||||||
|
|
||||||
|
/* ARM mode instructions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Store multiple increment after
|
||||||
|
* Rn: base register
|
||||||
|
* List: for each bit in list: store register
|
||||||
|
* S: in priviledged mode: store user-mode registers
|
||||||
|
* W=1: update the base register. W=0: leave the base register untouched
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_STMIA(Rn, List, S, W) (0xe8800000 | (S << 22) | (W << 21) | (Rn << 16) | (List))
|
||||||
|
|
||||||
|
/* Load multiple increment after
|
||||||
|
* Rn: base register
|
||||||
|
* List: for each bit in list: store register
|
||||||
|
* S: in priviledged mode: store user-mode registers
|
||||||
|
* W=1: update the base register. W=0: leave the base register untouched
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_LDMIA(Rn, List, S, W) (0xe8900000 | (S << 22) | (W << 21) | (Rn << 16) | (List))
|
||||||
|
|
||||||
|
/* MOV r8, r8 */
|
||||||
|
#define ARMV4_5_NOP (0xe1a08008)
|
||||||
|
|
||||||
|
/* Move PSR to general purpose register
|
||||||
|
* R=1: SPSR R=0: CPSR
|
||||||
|
* Rn: target register
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_MRS(Rn, R) (0xe10f0000 | (R << 22) | (Rn << 12))
|
||||||
|
|
||||||
|
/* Store register
|
||||||
|
* Rd: register to store
|
||||||
|
* Rn: base register
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_STR(Rd, Rn) (0xe5800000 | (Rd << 12) | (Rn << 16))
|
||||||
|
|
||||||
|
/* Load register
|
||||||
|
* Rd: register to load
|
||||||
|
* Rn: base register
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_LDR(Rd, Rn) (0xe5900000 | (Rd << 12) | (Rn << 16))
|
||||||
|
|
||||||
|
/* Move general purpose register to PSR
|
||||||
|
* R=1: SPSR R=0: CPSR
|
||||||
|
* Field: Field mask
|
||||||
|
* 1: control field 2: extension field 4: status field 8: flags field
|
||||||
|
* Rm: source register
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_MSR_GP(Rm, Field, R) (0xe120f000 | Rm | (Field << 16) | (R << 22))
|
||||||
|
#define ARMV4_5_MSR_IM(Im, Rotate, Field, R) (0xe320f000 | (Im) | (Rotate << 8) | (Field << 16) | (R << 22))
|
||||||
|
|
||||||
|
/* Load Register Halfword Immediate Post-Index
|
||||||
|
* Rd: register to load
|
||||||
|
* Rn: base register
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_LDRH_IP(Rd, Rn) (0xe0d000b2 | (Rd << 12) | (Rn << 16))
|
||||||
|
|
||||||
|
/* Load Register Byte Immediate Post-Index
|
||||||
|
* Rd: register to load
|
||||||
|
* Rn: base register
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_LDRB_IP(Rd, Rn) (0xe4d00001 | (Rd << 12) | (Rn << 16))
|
||||||
|
|
||||||
|
/* Store register Halfword Immediate Post-Index
|
||||||
|
* Rd: register to store
|
||||||
|
* Rn: base register
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_STRH_IP(Rd, Rn) (0xe0c000b2 | (Rd << 12) | (Rn << 16))
|
||||||
|
|
||||||
|
/* Store register Byte Immediate Post-Index
|
||||||
|
* Rd: register to store
|
||||||
|
* Rn: base register
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_STRB_IP(Rd, Rn) (0xe4c00001 | (Rd << 12) | (Rn << 16))
|
||||||
|
|
||||||
|
/* Branch (and Link)
|
||||||
|
* Im: Branch target (left-shifted by 2 bits, added to PC)
|
||||||
|
* L: 1: branch and link 0: branch only
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_B(Im, L) (0xea000000 | Im | (L << 24))
|
||||||
|
|
||||||
|
/* Branch and exchange (ARM state)
|
||||||
|
* Rm: register holding branch target address
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_BX(Rm) (0xe12fff10 | Rm)
|
||||||
|
|
||||||
|
/* Thumb mode instructions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Store register (Thumb mode)
|
||||||
|
* Rd: source register
|
||||||
|
* Rn: base register
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_T_STR(Rd, Rn) ((0x6000 | Rd | (Rn << 3)) | ((0x6000 | Rd | (Rn << 3)) << 16))
|
||||||
|
|
||||||
|
/* Load register (Thumb state)
|
||||||
|
* Rd: destination register
|
||||||
|
* Rn: base register
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_T_LDR(Rd, Rn) ((0x6800 | (Rn << 3) | Rd) | ((0x6800 | (Rn << 3) | Rd) << 16))
|
||||||
|
|
||||||
|
/* Move hi register (Thumb mode)
|
||||||
|
* Rd: destination register
|
||||||
|
* Rm: source register
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_T_MOV(Rd, Rm) ((0x4600 | (Rd & 0x7) | ((Rd & 0x8) << 4) | ((Rm & 0x7) << 3) | ((Rm & 0x8) << 3)) | ((0x4600 | (Rd & 0x7) | ((Rd & 0x8) << 4) | ((Rm & 0x7) << 3) | ((Rm & 0x8) << 3)) << 16))
|
||||||
|
|
||||||
|
/* No operation (Thumb mode)
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_T_NOP (0x1c3f | (0x1c3f << 16))
|
||||||
|
|
||||||
|
/* Move immediate to register (Thumb state)
|
||||||
|
* Rd: destination register
|
||||||
|
* Im: 8-bit immediate value
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_T_MOV_IM(Rd, Im) ((0x2000 | (Rd << 8) | Im) | ((0x2000 | (Rd << 8) | Im) << 16))
|
||||||
|
|
||||||
|
/* Branch and Exchange
|
||||||
|
* Rm: register containing branch target
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_T_BX(Rm) ((0x4700 | (Rm << 3)) | ((0x4700 | (Rm << 3)) << 16))
|
||||||
|
|
||||||
|
/* Branch (Thumb state)
|
||||||
|
* Imm: Branch target
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_T_B(Imm) ((0xe000 | Imm) | ((0xe000 | Imm) << 16))
|
||||||
|
|
||||||
|
#endif /* ARMV4_5_H */
|
|
@ -0,0 +1,112 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "armv4_5_cache.h"
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
int armv4_5_identify_cache(u32 cache_type_reg, armv4_5_cache_common_t *cache)
|
||||||
|
{
|
||||||
|
int size, assoc, M, len, multiplier;
|
||||||
|
|
||||||
|
cache->ctype = (cache_type_reg & 0x1e000000U) >> 25;
|
||||||
|
cache->separate = (cache_type_reg & 0x01000000U) >> 24;
|
||||||
|
|
||||||
|
size = (cache_type_reg & 0x1c0000) >> 18;
|
||||||
|
assoc = (cache_type_reg & 0x38000) >> 15;
|
||||||
|
M = (cache_type_reg & 0x4000) >> 14;
|
||||||
|
len = (cache_type_reg & 0x3000) >> 12;
|
||||||
|
multiplier = 2 + M;
|
||||||
|
|
||||||
|
if ((assoc != 0) || (M != 1)) /* assoc 0 and M 1 means cache absent */
|
||||||
|
{
|
||||||
|
/* cache is present */
|
||||||
|
cache->d_u_size.linelen = 1 << (len + 3);
|
||||||
|
cache->d_u_size.associativity = multiplier << (assoc - 1);
|
||||||
|
cache->d_u_size.nsets = 1 << (size + 6 - assoc - len);
|
||||||
|
cache->d_u_size.cachesize = multiplier << (size + 8);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* cache is absent */
|
||||||
|
cache->d_u_size.linelen = -1;
|
||||||
|
cache->d_u_size.associativity = -1;
|
||||||
|
cache->d_u_size.nsets = -1;
|
||||||
|
cache->d_u_size.cachesize = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cache->separate)
|
||||||
|
{
|
||||||
|
size = (cache_type_reg & 0x1c0) >> 6;
|
||||||
|
assoc = (cache_type_reg & 0x38) >> 3;
|
||||||
|
M = (cache_type_reg & 0x4) >> 2;
|
||||||
|
len = (cache_type_reg & 0x3);
|
||||||
|
multiplier = 2 + M;
|
||||||
|
|
||||||
|
if ((assoc != 0) || (M != 1)) /* assoc 0 and M 1 means cache absent */
|
||||||
|
{
|
||||||
|
/* cache is present */
|
||||||
|
cache->i_size.linelen = 1 << (len + 3);
|
||||||
|
cache->i_size.associativity = multiplier << (assoc - 1);
|
||||||
|
cache->i_size.nsets = 1 << (size + 6 - assoc - len);
|
||||||
|
cache->i_size.cachesize = multiplier << (size + 8);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* cache is absent */
|
||||||
|
cache->i_size.linelen = -1;
|
||||||
|
cache->i_size.associativity = -1;
|
||||||
|
cache->i_size.nsets = -1;
|
||||||
|
cache->i_size.cachesize = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cache->i_size = cache->d_u_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int armv4_5_handle_cache_info_command(struct command_context_s *cmd_ctx, armv4_5_cache_common_t *armv4_5_cache)
|
||||||
|
{
|
||||||
|
if (armv4_5_cache->ctype == -1)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "cache not yet identified");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
command_print(cmd_ctx, "cache type: 0x%1.1x, %s", armv4_5_cache->ctype,
|
||||||
|
(armv4_5_cache->separate) ? "separate caches" : "unified cache");
|
||||||
|
|
||||||
|
command_print(cmd_ctx, "D-Cache: linelen %i, associativity %i, nsets %i, cachesize 0x%x",
|
||||||
|
armv4_5_cache->d_u_size.linelen,
|
||||||
|
armv4_5_cache->d_u_size.associativity,
|
||||||
|
armv4_5_cache->d_u_size.nsets,
|
||||||
|
armv4_5_cache->d_u_size.cachesize);
|
||||||
|
|
||||||
|
command_print(cmd_ctx, "I-Cache: linelen %i, associativity %i, nsets %i, cachesize 0x%x",
|
||||||
|
armv4_5_cache->i_size.linelen,
|
||||||
|
armv4_5_cache->i_size.associativity,
|
||||||
|
armv4_5_cache->i_size.nsets,
|
||||||
|
armv4_5_cache->i_size.cachesize);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef ARMV4_5_CACHE_H
|
||||||
|
#define ARMV4_5_CACHE_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
typedef struct armv4_5_cachesize_s
|
||||||
|
{
|
||||||
|
int linelen;
|
||||||
|
int associativity;
|
||||||
|
int nsets;
|
||||||
|
int cachesize;
|
||||||
|
} armv4_5_cachesize_t;
|
||||||
|
|
||||||
|
typedef struct armv4_5_cache_common_s
|
||||||
|
{
|
||||||
|
int ctype; /* specify supported cache operations */
|
||||||
|
int separate; /* separate caches or unified cache */
|
||||||
|
armv4_5_cachesize_t d_u_size; /* data cache */
|
||||||
|
armv4_5_cachesize_t i_size; /* instruction cache */
|
||||||
|
int i_cache_enabled;
|
||||||
|
int d_u_cache_enabled;
|
||||||
|
} armv4_5_cache_common_t;
|
||||||
|
|
||||||
|
extern int armv4_5_identify_cache(u32 cache_type_reg, armv4_5_cache_common_t *cache);
|
||||||
|
extern int armv4_5_cache_state(u32 cp15_control_reg, armv4_5_cache_common_t *cache);
|
||||||
|
|
||||||
|
extern int armv4_5_handle_cache_info_command(struct command_context_s *cmd_ctx, armv4_5_cache_common_t *armv4_5_cache);
|
||||||
|
|
||||||
|
#endif /* ARMV4_5_CACHE_H */
|
|
@ -0,0 +1,358 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "arm7_9_common.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "command.h"
|
||||||
|
#include "armv4_5_mmu.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
u32 armv4mmu_translate_va(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 va, int *type, u32 *cb, int *domain, u32 *ap);
|
||||||
|
int armv4_5_mmu_read_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer);
|
||||||
|
int armv4_5_mmu_write_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer);
|
||||||
|
|
||||||
|
char* armv4_5_mmu_page_type_names[] =
|
||||||
|
{
|
||||||
|
"section", "large page", "small page", "tiny page"
|
||||||
|
};
|
||||||
|
|
||||||
|
u32 armv4_5_mmu_translate_va(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 va, int *type, u32 *cb, int *domain, u32 *ap)
|
||||||
|
{
|
||||||
|
u32 first_lvl_descriptor = 0x0;
|
||||||
|
u32 second_lvl_descriptor = 0x0;
|
||||||
|
u32 ttb = armv4_5_mmu->get_ttb(target);
|
||||||
|
|
||||||
|
armv4_5_mmu_read_physical(target, armv4_5_mmu,
|
||||||
|
(ttb & 0xffffc000) | ((va & 0xfff00000) >> 18),
|
||||||
|
4, 1, (u8*)&first_lvl_descriptor);
|
||||||
|
|
||||||
|
DEBUG("1st lvl desc: %8.8x", first_lvl_descriptor);
|
||||||
|
|
||||||
|
if ((first_lvl_descriptor & 0x3) == 0)
|
||||||
|
{
|
||||||
|
*type = -1;
|
||||||
|
return ERROR_TARGET_TRANSLATION_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!armv4_5_mmu->has_tiny_pages && ((first_lvl_descriptor & 0x3) == 3))
|
||||||
|
{
|
||||||
|
*type = -1;
|
||||||
|
return ERROR_TARGET_TRANSLATION_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* domain is always specified in bits 8-5 */
|
||||||
|
*domain = (first_lvl_descriptor & 0x1e0) >> 5;
|
||||||
|
|
||||||
|
if ((first_lvl_descriptor & 0x3) == 2)
|
||||||
|
{
|
||||||
|
/* section descriptor */
|
||||||
|
*type = ARMV4_5_SECTION;
|
||||||
|
*cb = (first_lvl_descriptor & 0xc) >> 2;
|
||||||
|
*ap = (first_lvl_descriptor & 0xc00) >> 10;
|
||||||
|
return (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((first_lvl_descriptor & 0x3) == 1)
|
||||||
|
{
|
||||||
|
/* coarse page table */
|
||||||
|
armv4_5_mmu_read_physical(target, armv4_5_mmu,
|
||||||
|
(first_lvl_descriptor & 0xfffffc00) | ((va & 0x000ff000) >> 10),
|
||||||
|
4, 1, (u8*)&second_lvl_descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((first_lvl_descriptor & 0x3) == 3)
|
||||||
|
{
|
||||||
|
/* fine page table */
|
||||||
|
armv4_5_mmu_read_physical(target, armv4_5_mmu,
|
||||||
|
(first_lvl_descriptor & 0xfffff000) | ((va & 0x000ffc00) >> 8),
|
||||||
|
4, 1, (u8*)&second_lvl_descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG("2nd lvl desc: %8.8x", first_lvl_descriptor);
|
||||||
|
|
||||||
|
if ((second_lvl_descriptor & 0x3) == 0)
|
||||||
|
{
|
||||||
|
*type = -1;
|
||||||
|
return ERROR_TARGET_TRANSLATION_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cacheable/bufferable is always specified in bits 3-2 */
|
||||||
|
*cb = (second_lvl_descriptor & 0xc) >> 2;
|
||||||
|
|
||||||
|
if ((second_lvl_descriptor & 0x3) == 1)
|
||||||
|
{
|
||||||
|
/* large page descriptor */
|
||||||
|
*type = ARMV4_5_LARGE_PAGE;
|
||||||
|
*ap = (second_lvl_descriptor & 0xff0) >> 4;
|
||||||
|
return (second_lvl_descriptor & 0xffff0000) | (va & 0x0000ffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((second_lvl_descriptor & 0x3) == 2)
|
||||||
|
{
|
||||||
|
/* small page descriptor */
|
||||||
|
*type = ARMV4_5_SMALL_PAGE;
|
||||||
|
*ap = (second_lvl_descriptor & 0xff0) >> 4;
|
||||||
|
return (second_lvl_descriptor & 0xfffff000) | (va & 0x00000fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((second_lvl_descriptor & 0x3) == 3)
|
||||||
|
{
|
||||||
|
/* tiny page descriptor */
|
||||||
|
*type = ARMV4_5_TINY_PAGE;
|
||||||
|
*ap = (second_lvl_descriptor & 0x30) >> 4;
|
||||||
|
return (second_lvl_descriptor & 0xfffffc00) | (va & 0x000003ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* should not happen */
|
||||||
|
*type = -1;
|
||||||
|
return ERROR_TARGET_TRANSLATION_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int armv4_5_mmu_read_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
|
||||||
|
/* disable MMU and data (or unified) cache */
|
||||||
|
armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0);
|
||||||
|
|
||||||
|
retval = armv4_5_mmu->read_memory(target, address, size, count, buffer);
|
||||||
|
|
||||||
|
/* reenable MMU / cache */
|
||||||
|
armv4_5_mmu->enable_mmu_caches(target, armv4_5_mmu->mmu_enabled,
|
||||||
|
armv4_5_mmu->armv4_5_cache.d_u_cache_enabled,
|
||||||
|
armv4_5_mmu->armv4_5_cache.i_cache_enabled);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int armv4_5_mmu_write_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
|
||||||
|
/* disable MMU and data (or unified) cache */
|
||||||
|
armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0);
|
||||||
|
|
||||||
|
retval = armv4_5_mmu->write_memory(target, address, size, count, buffer);
|
||||||
|
|
||||||
|
/* reenable MMU / cache */
|
||||||
|
armv4_5_mmu->enable_mmu_caches(target, armv4_5_mmu->mmu_enabled,
|
||||||
|
armv4_5_mmu->armv4_5_cache.d_u_cache_enabled,
|
||||||
|
armv4_5_mmu->armv4_5_cache.i_cache_enabled);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int armv4_5_mmu_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu)
|
||||||
|
{
|
||||||
|
u32 va;
|
||||||
|
u32 pa;
|
||||||
|
int type;
|
||||||
|
u32 cb;
|
||||||
|
int domain;
|
||||||
|
u32 ap;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "target must be stopped for \"virt2phys\" command");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc == 0)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "usage: virt2phys <virtual address>");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc == 1)
|
||||||
|
{
|
||||||
|
va = strtoul(args[0], NULL, 0);
|
||||||
|
pa = armv4_5_mmu_translate_va(target, armv4_5_mmu, va, &type, &cb, &domain, &ap);
|
||||||
|
if (type == -1)
|
||||||
|
{
|
||||||
|
switch (pa)
|
||||||
|
{
|
||||||
|
case ERROR_TARGET_TRANSLATION_FAULT:
|
||||||
|
command_print(cmd_ctx, "no valid translation for 0x%8.8x", va);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
command_print(cmd_ctx, "unknown translation error");
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
command_print(cmd_ctx, "0x%8.8x -> 0x%8.8x, type: %s, cb: %i, domain: %i, ap: %2.2x",
|
||||||
|
va, pa, armv4_5_mmu_page_type_names[type], cb, domain, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int armv4_5_mmu_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu)
|
||||||
|
{
|
||||||
|
int count = 1;
|
||||||
|
int size = 4;
|
||||||
|
u32 address = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
char output[128];
|
||||||
|
int output_len;
|
||||||
|
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
u8 *buffer;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc < 1)
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
if (argc == 2)
|
||||||
|
count = strtoul(args[1], NULL, 0);
|
||||||
|
|
||||||
|
address = strtoul(args[0], NULL, 0);
|
||||||
|
|
||||||
|
switch (cmd[2])
|
||||||
|
{
|
||||||
|
case 'w':
|
||||||
|
size = 4;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
size = 2;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
size = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = calloc(count, size);
|
||||||
|
if ((retval = armv4_5_mmu_read_physical(target, armv4_5_mmu, address, size, count, buffer)) != ERROR_OK)
|
||||||
|
{
|
||||||
|
switch (retval)
|
||||||
|
{
|
||||||
|
case ERROR_TARGET_UNALIGNED_ACCESS:
|
||||||
|
command_print(cmd_ctx, "error: address not aligned");
|
||||||
|
break;
|
||||||
|
case ERROR_TARGET_NOT_HALTED:
|
||||||
|
command_print(cmd_ctx, "error: target must be halted for memory accesses");
|
||||||
|
break;
|
||||||
|
case ERROR_TARGET_DATA_ABORT:
|
||||||
|
command_print(cmd_ctx, "error: access caused data abort, system possibly corrupted");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
command_print(cmd_ctx, "error: unknown error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output_len = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (i%8 == 0)
|
||||||
|
output_len += snprintf(output + output_len, 128 - output_len, "0x%8.8x: ", address + (i*size));
|
||||||
|
|
||||||
|
switch (size)
|
||||||
|
{
|
||||||
|
case 4:
|
||||||
|
output_len += snprintf(output + output_len, 128 - output_len, "%8.8x ", ((u32*)buffer)[i]);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
output_len += snprintf(output + output_len, 128 - output_len, "%4.4x ", ((u16*)buffer)[i]);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
output_len += snprintf(output + output_len, 128 - output_len, "%2.2x ", ((u8*)buffer)[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((i%8 == 7) || (i == count - 1))
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, output);
|
||||||
|
output_len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int armv4_5_mmu_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu)
|
||||||
|
{
|
||||||
|
u32 address = 0;
|
||||||
|
u32 value = 0;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc < 2)
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
address = strtoul(args[0], NULL, 0);
|
||||||
|
value = strtoul(args[1], NULL, 0);
|
||||||
|
|
||||||
|
switch (cmd[2])
|
||||||
|
{
|
||||||
|
case 'w':
|
||||||
|
retval = armv4_5_mmu_write_physical(target, armv4_5_mmu, address, 4, 1, (u8*)&value);
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
retval = armv4_5_mmu_write_physical(target, armv4_5_mmu, address, 2, 1, (u8*)&value);
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
retval = armv4_5_mmu_write_physical(target, armv4_5_mmu, address, 1, 1, (u8*)&value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (retval)
|
||||||
|
{
|
||||||
|
case ERROR_TARGET_UNALIGNED_ACCESS:
|
||||||
|
command_print(cmd_ctx, "error: address not aligned");
|
||||||
|
break;
|
||||||
|
case ERROR_TARGET_DATA_ABORT:
|
||||||
|
command_print(cmd_ctx, "error: access caused data abort, system possibly corrupted");
|
||||||
|
break;
|
||||||
|
case ERROR_TARGET_NOT_HALTED:
|
||||||
|
command_print(cmd_ctx, "error: target must be halted for memory accesses");
|
||||||
|
break;
|
||||||
|
case ERROR_OK:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
command_print(cmd_ctx, "error: unknown error");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef ARMV4_5_MMU_H
|
||||||
|
#define ARMV4_5_MMU_H
|
||||||
|
|
||||||
|
#include "armv4_5_cache.h"
|
||||||
|
|
||||||
|
typedef struct armv4_5_mmu_common_s
|
||||||
|
{
|
||||||
|
u32 (*get_ttb)(target_t *target);
|
||||||
|
int (*read_memory)(target_t *target, u32 address, u32 size, u32 count, u8 *buffer);
|
||||||
|
int (*write_memory)(target_t *target, u32 address, u32 size, u32 count, u8 *buffer);
|
||||||
|
void (*disable_mmu_caches)(target_t *target, int mmu, int d_u_cache, int i_cache);
|
||||||
|
void (*enable_mmu_caches)(target_t *target, int mmu, int d_u_cache, int i_cache);
|
||||||
|
armv4_5_cache_common_t armv4_5_cache;
|
||||||
|
int has_tiny_pages;
|
||||||
|
int mmu_enabled;
|
||||||
|
} armv4_5_mmu_common_t;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ARMV4_5_SECTION, ARMV4_5_LARGE_PAGE, ARMV4_5_SMALL_PAGE, ARMV4_5_TINY_PAGE
|
||||||
|
};
|
||||||
|
|
||||||
|
extern char* armv4_5_page_type_names[];
|
||||||
|
|
||||||
|
extern u32 armv4_5_mmu_translate_va(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 va, int *type, u32 *cb, int *domain, u32 *ap);
|
||||||
|
extern int armv4_5_mmu_read_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer);
|
||||||
|
extern int armv4_5_mmu_write_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer);
|
||||||
|
|
||||||
|
extern int armv4_5_mmu_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu);
|
||||||
|
extern int armv4_5_mmu_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu);
|
||||||
|
extern int armv4_5_mmu_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu);
|
||||||
|
|
||||||
|
#endif /* ARMV4_5_MMU_H */
|
|
@ -0,0 +1,219 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "binarybuffer.h"
|
||||||
|
#include "target.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#include "breakpoints.h"
|
||||||
|
|
||||||
|
char *breakpoint_type_strings[] =
|
||||||
|
{
|
||||||
|
"hardware",
|
||||||
|
"software"
|
||||||
|
};
|
||||||
|
|
||||||
|
char *watchpoint_rw_strings[] =
|
||||||
|
{
|
||||||
|
"read",
|
||||||
|
"write",
|
||||||
|
"access"
|
||||||
|
};
|
||||||
|
|
||||||
|
int breakpoint_add(target_t *target, u32 address, u32 length, enum breakpoint_type type)
|
||||||
|
{
|
||||||
|
breakpoint_t *breakpoint = target->breakpoints;
|
||||||
|
breakpoint_t **breakpoint_p = &target->breakpoints;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
while (breakpoint)
|
||||||
|
{
|
||||||
|
if (breakpoint->address == address)
|
||||||
|
return ERROR_OK;
|
||||||
|
breakpoint_p = &breakpoint->next;
|
||||||
|
breakpoint = breakpoint->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((retval = target->type->add_breakpoint(target, address, length, type)) != ERROR_OK)
|
||||||
|
{
|
||||||
|
switch (retval)
|
||||||
|
{
|
||||||
|
case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
|
||||||
|
INFO("can't add %s breakpoint, resource not available", breakpoint_type_strings[type]);
|
||||||
|
return retval;
|
||||||
|
break;
|
||||||
|
case ERROR_TARGET_NOT_HALTED:
|
||||||
|
INFO("can't add breakpoint while target is running");
|
||||||
|
return retval;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("unknown error");
|
||||||
|
exit(-1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(*breakpoint_p) = malloc(sizeof(breakpoint_t));
|
||||||
|
(*breakpoint_p)->address = address;
|
||||||
|
(*breakpoint_p)->length = length;
|
||||||
|
(*breakpoint_p)->type = type;
|
||||||
|
(*breakpoint_p)->set = 0;
|
||||||
|
(*breakpoint_p)->orig_instr = malloc(CEIL(length, 8));
|
||||||
|
(*breakpoint_p)->next = NULL;
|
||||||
|
|
||||||
|
DEBUG("added %s breakpoint at 0x%8.8x of length 0x%8.8x", breakpoint_type_strings[type], address, length);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int breakpoint_remove(target_t *target, u32 address)
|
||||||
|
{
|
||||||
|
breakpoint_t *breakpoint = target->breakpoints;
|
||||||
|
breakpoint_t **breakpoint_p = &target->breakpoints;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
while (breakpoint)
|
||||||
|
{
|
||||||
|
if (breakpoint->address == address)
|
||||||
|
break;
|
||||||
|
breakpoint_p = &breakpoint->next;
|
||||||
|
breakpoint = breakpoint->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (breakpoint)
|
||||||
|
{
|
||||||
|
if ((retval = target->type->remove_breakpoint(target, breakpoint)) != ERROR_OK)
|
||||||
|
{
|
||||||
|
switch (retval)
|
||||||
|
{
|
||||||
|
case ERROR_TARGET_NOT_HALTED:
|
||||||
|
INFO("can't remove breakpoint while target is running");
|
||||||
|
return retval;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("unknown error");
|
||||||
|
exit(-1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(*breakpoint_p) = breakpoint->next;
|
||||||
|
free(breakpoint->orig_instr);
|
||||||
|
free(breakpoint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR("no breakpoint at address 0x%8.8x found", address);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
breakpoint_t* breakpoint_find(target_t *target, u32 address)
|
||||||
|
{
|
||||||
|
breakpoint_t *breakpoint = target->breakpoints;
|
||||||
|
|
||||||
|
while (breakpoint)
|
||||||
|
{
|
||||||
|
if (breakpoint->address == address)
|
||||||
|
return breakpoint;
|
||||||
|
breakpoint = breakpoint->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int watchpoint_add(target_t *target, u32 address, u32 length, enum watchpoint_rw rw, u32 value, u32 mask)
|
||||||
|
{
|
||||||
|
watchpoint_t *watchpoint = target->watchpoints;
|
||||||
|
watchpoint_t **watchpoint_p = &target->watchpoints;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
while (watchpoint)
|
||||||
|
{
|
||||||
|
if (watchpoint->address == address)
|
||||||
|
return ERROR_OK;
|
||||||
|
watchpoint_p = &watchpoint->next;
|
||||||
|
watchpoint = watchpoint->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((retval = target->type->add_watchpoint(target, address, length, rw)) != ERROR_OK)
|
||||||
|
{
|
||||||
|
switch (retval)
|
||||||
|
{
|
||||||
|
case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
|
||||||
|
INFO("can't add %s watchpoint, resource not available", watchpoint_rw_strings[rw]);
|
||||||
|
return retval;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("unknown error");
|
||||||
|
exit(-1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(*watchpoint_p) = malloc(sizeof(watchpoint_t));
|
||||||
|
(*watchpoint_p)->address = address;
|
||||||
|
(*watchpoint_p)->length = length;
|
||||||
|
(*watchpoint_p)->value = value;
|
||||||
|
(*watchpoint_p)->mask = mask;
|
||||||
|
(*watchpoint_p)->rw = rw;
|
||||||
|
(*watchpoint_p)->set = 0;
|
||||||
|
(*watchpoint_p)->next = NULL;
|
||||||
|
|
||||||
|
DEBUG("added %s watchpoint at 0x%8.8x of length 0x%8.8x", watchpoint_rw_strings[rw], address, length);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int watchpoint_remove(target_t *target, u32 address)
|
||||||
|
{
|
||||||
|
watchpoint_t *watchpoint = target->watchpoints;
|
||||||
|
watchpoint_t **watchpoint_p = &target->watchpoints;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
while (watchpoint)
|
||||||
|
{
|
||||||
|
if (watchpoint->address == address)
|
||||||
|
break;
|
||||||
|
watchpoint_p = &watchpoint->next;
|
||||||
|
watchpoint = watchpoint->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (watchpoint)
|
||||||
|
{
|
||||||
|
if ((retval = target->type->remove_watchpoint(target, watchpoint)) != ERROR_OK)
|
||||||
|
{
|
||||||
|
ERROR("BUG: can't remove watchpoint");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
(*watchpoint_p) = watchpoint->next;
|
||||||
|
free(watchpoint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR("no watchpoint at address 0x%8.8x found", address);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef BREAKPOINTS_H
|
||||||
|
#define BREAKPOINTS_H
|
||||||
|
|
||||||
|
#include "target.h"
|
||||||
|
|
||||||
|
struct target_s;
|
||||||
|
|
||||||
|
enum breakpoint_type
|
||||||
|
{
|
||||||
|
BKPT_HARD,
|
||||||
|
BKPT_SOFT,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern char *breakpoint_type_strings[];
|
||||||
|
|
||||||
|
enum watchpoint_rw
|
||||||
|
{
|
||||||
|
WPT_READ = 0, WPT_WRITE = 1, WPT_ACCESS = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
extern char *watchpoint_rw_strings[];
|
||||||
|
|
||||||
|
typedef struct breakpoint_s
|
||||||
|
{
|
||||||
|
u32 address;
|
||||||
|
int length;
|
||||||
|
enum breakpoint_type type;
|
||||||
|
int set;
|
||||||
|
u8 *orig_instr;
|
||||||
|
struct breakpoint_s *next;
|
||||||
|
} breakpoint_t;
|
||||||
|
|
||||||
|
typedef struct watchpoint_s
|
||||||
|
{
|
||||||
|
u32 address;
|
||||||
|
int length;
|
||||||
|
u32 mask;
|
||||||
|
u32 value;
|
||||||
|
enum watchpoint_rw rw;
|
||||||
|
int set;
|
||||||
|
struct watchpoint_s *next;
|
||||||
|
} watchpoint_t;
|
||||||
|
|
||||||
|
extern int breakpoint_add(struct target_s *target, u32 address, u32 length, enum breakpoint_type type);
|
||||||
|
extern int breakpoint_remove(struct target_s *target, u32 address);
|
||||||
|
extern breakpoint_t* breakpoint_find(struct target_s *target, u32 address);
|
||||||
|
extern int watchpoint_add(struct target_s *target, u32 address, u32 length, enum watchpoint_rw rw, u32 value, u32 mask);
|
||||||
|
extern int watchpoint_remove(struct target_s *target, u32 address);
|
||||||
|
|
||||||
|
#endif /* BREAKPOINTS_H */
|
||||||
|
|
|
@ -0,0 +1,301 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "embeddedice.h"
|
||||||
|
|
||||||
|
#include "armv4_5.h"
|
||||||
|
#include "arm7_9_common.h"
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "arm_jtag.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "binarybuffer.h"
|
||||||
|
#include "target.h"
|
||||||
|
#include "register.h"
|
||||||
|
#include "jtag.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
bitfield_desc_t embeddedice_comms_ctrl_bitfield_desc[] =
|
||||||
|
{
|
||||||
|
{"R", 1},
|
||||||
|
{"W", 1},
|
||||||
|
{"reserved", 26},
|
||||||
|
{"version", 4}
|
||||||
|
};
|
||||||
|
|
||||||
|
int embeddedice_reg_arch_info[] =
|
||||||
|
{
|
||||||
|
0x0, 0x1, 0x4, 0x5,
|
||||||
|
0x8, 0x9, 0xa, 0xb, 0xc, 0xd,
|
||||||
|
0x10, 0x11, 0x12, 0x13, 0x14, 0x15
|
||||||
|
};
|
||||||
|
|
||||||
|
char* embeddedice_reg_list[] =
|
||||||
|
{
|
||||||
|
"debug_ctrl",
|
||||||
|
"debug_status",
|
||||||
|
|
||||||
|
"comms_ctrl",
|
||||||
|
"comms_data",
|
||||||
|
|
||||||
|
"watch 0 addr value",
|
||||||
|
"watch 0 addr mask",
|
||||||
|
"watch 0 data value",
|
||||||
|
"watch 0 data mask",
|
||||||
|
"watch 0 control value",
|
||||||
|
"watch 0 control mask",
|
||||||
|
|
||||||
|
"watch 1 addr value",
|
||||||
|
"watch 1 addr mask",
|
||||||
|
"watch 1 data value",
|
||||||
|
"watch 1 data mask",
|
||||||
|
"watch 1 control value",
|
||||||
|
"watch 1 control mask"
|
||||||
|
};
|
||||||
|
|
||||||
|
int embeddedice_reg_arch_type = -1;
|
||||||
|
|
||||||
|
int embeddedice_get_reg(reg_t *reg);
|
||||||
|
int embeddedice_set_reg(reg_t *reg, u32 value);
|
||||||
|
|
||||||
|
int embeddedice_write_reg(reg_t *reg, u32 value);
|
||||||
|
int embeddedice_read_reg(reg_t *reg);
|
||||||
|
|
||||||
|
reg_cache_t* embeddedice_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, int extra_reg)
|
||||||
|
{
|
||||||
|
reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t));
|
||||||
|
reg_t *reg_list = NULL;
|
||||||
|
embeddedice_reg_t *arch_info = NULL;
|
||||||
|
int num_regs = 16 + extra_reg;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* register a register arch-type for EmbeddedICE registers only once */
|
||||||
|
if (embeddedice_reg_arch_type == -1)
|
||||||
|
embeddedice_reg_arch_type = register_reg_arch_type(embeddedice_get_reg, embeddedice_set_reg_w_exec);
|
||||||
|
|
||||||
|
/* the actual registers are kept in two arrays */
|
||||||
|
reg_list = calloc(num_regs, sizeof(reg_t));
|
||||||
|
arch_info = calloc(num_regs, sizeof(embeddedice_reg_t));
|
||||||
|
|
||||||
|
/* fill in values for the reg cache */
|
||||||
|
reg_cache->name = "EmbeddedICE registers";
|
||||||
|
reg_cache->next = NULL;
|
||||||
|
reg_cache->reg_list = reg_list;
|
||||||
|
reg_cache->num_regs = num_regs;
|
||||||
|
|
||||||
|
/* set up registers */
|
||||||
|
for (i = 0; i < num_regs - extra_reg; i++)
|
||||||
|
{
|
||||||
|
reg_list[i].name = embeddedice_reg_list[i];
|
||||||
|
reg_list[i].size = 32;
|
||||||
|
reg_list[i].dirty = 0;
|
||||||
|
reg_list[i].valid = 0;
|
||||||
|
reg_list[i].bitfield_desc = NULL;
|
||||||
|
reg_list[i].num_bitfields = 0;
|
||||||
|
reg_list[i].value = calloc(1, 4);
|
||||||
|
reg_list[i].arch_info = &arch_info[i];
|
||||||
|
reg_list[i].arch_type = embeddedice_reg_arch_type;
|
||||||
|
arch_info[i].addr = embeddedice_reg_arch_info[i];
|
||||||
|
arch_info[i].jtag_info = jtag_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* there may be one extra reg (Abort status (ARM7 rev4) or Vector catch (ARM9)) */
|
||||||
|
if (extra_reg)
|
||||||
|
{
|
||||||
|
reg_list[num_regs - 1].arch_info = &arch_info[num_regs - 1];
|
||||||
|
arch_info[num_regs - 1].jtag_info = jtag_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reg_cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
int embeddedice_get_reg(reg_t *reg)
|
||||||
|
{
|
||||||
|
if (embeddedice_read_reg(reg) != ERROR_OK)
|
||||||
|
{
|
||||||
|
ERROR("BUG: error scheduling EmbeddedICE register read");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jtag_execute_queue() != ERROR_OK)
|
||||||
|
{
|
||||||
|
ERROR("register read failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int embeddedice_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask)
|
||||||
|
{
|
||||||
|
embeddedice_reg_t *ice_reg = reg->arch_info;
|
||||||
|
u8 reg_addr = ice_reg->addr & 0x1f;
|
||||||
|
scan_field_t fields[3];
|
||||||
|
|
||||||
|
DEBUG("%i", ice_reg->addr);
|
||||||
|
|
||||||
|
jtag_add_end_state(TAP_RTI);
|
||||||
|
arm_jtag_scann(ice_reg->jtag_info, 0x2);
|
||||||
|
arm_jtag_set_instr(ice_reg->jtag_info, ice_reg->jtag_info->intest_instr);
|
||||||
|
|
||||||
|
fields[0].device = ice_reg->jtag_info->chain_pos;
|
||||||
|
fields[0].num_bits = 32;
|
||||||
|
fields[0].out_value = reg->value;
|
||||||
|
fields[0].out_mask = NULL;
|
||||||
|
fields[0].in_value = NULL;
|
||||||
|
fields[0].in_check_value = NULL;
|
||||||
|
fields[0].in_check_mask = NULL;
|
||||||
|
fields[0].in_handler = NULL;
|
||||||
|
fields[0].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[1].device = ice_reg->jtag_info->chain_pos;
|
||||||
|
fields[1].num_bits = 5;
|
||||||
|
fields[1].out_value = malloc(1);
|
||||||
|
buf_set_u32(fields[1].out_value, 0, 5, reg_addr);
|
||||||
|
fields[1].out_mask = NULL;
|
||||||
|
fields[1].in_value = NULL;
|
||||||
|
fields[1].in_check_value = NULL;
|
||||||
|
fields[1].in_check_mask = NULL;
|
||||||
|
fields[1].in_handler = NULL;
|
||||||
|
fields[1].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[2].device = ice_reg->jtag_info->chain_pos;
|
||||||
|
fields[2].num_bits = 1;
|
||||||
|
fields[2].out_value = malloc(1);
|
||||||
|
buf_set_u32(fields[2].out_value, 0, 1, 0);
|
||||||
|
fields[2].out_mask = NULL;
|
||||||
|
fields[2].in_value = NULL;
|
||||||
|
fields[2].in_check_value = NULL;
|
||||||
|
fields[2].in_check_mask = NULL;
|
||||||
|
fields[2].in_handler = NULL;
|
||||||
|
fields[2].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
jtag_add_dr_scan(3, fields, -1);
|
||||||
|
|
||||||
|
fields[0].in_value = reg->value;
|
||||||
|
fields[0].in_check_value = check_value;
|
||||||
|
fields[0].in_check_mask = check_mask;
|
||||||
|
|
||||||
|
/* when reading the DCC data register, leaving the address field set to
|
||||||
|
* EICE_COMMS_DATA would read the register twice
|
||||||
|
* reading the control register is safe
|
||||||
|
*/
|
||||||
|
buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_CTRL]);
|
||||||
|
|
||||||
|
jtag_add_dr_scan(3, fields, -1);
|
||||||
|
|
||||||
|
free(fields[1].out_value);
|
||||||
|
free(fields[2].out_value);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int embeddedice_read_reg(reg_t *reg)
|
||||||
|
{
|
||||||
|
return embeddedice_read_reg_w_check(reg, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int embeddedice_set_reg(reg_t *reg, u32 value)
|
||||||
|
{
|
||||||
|
if (embeddedice_write_reg(reg, value) != ERROR_OK)
|
||||||
|
{
|
||||||
|
ERROR("BUG: error scheduling EmbeddedICE register write");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf_set_u32(reg->value, 0, reg->size, value);
|
||||||
|
reg->valid = 1;
|
||||||
|
reg->dirty = 0;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int embeddedice_set_reg_w_exec(reg_t *reg, u32 value)
|
||||||
|
{
|
||||||
|
embeddedice_set_reg(reg, value);
|
||||||
|
|
||||||
|
if (jtag_execute_queue() != ERROR_OK)
|
||||||
|
{
|
||||||
|
ERROR("register write failed");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int embeddedice_write_reg(reg_t *reg, u32 value)
|
||||||
|
{
|
||||||
|
embeddedice_reg_t *ice_reg = reg->arch_info;
|
||||||
|
u8 reg_addr = ice_reg->addr & 0x1f;
|
||||||
|
scan_field_t fields[3];
|
||||||
|
|
||||||
|
DEBUG("%i: 0x%8.8x", ice_reg->addr, value);
|
||||||
|
|
||||||
|
jtag_add_end_state(TAP_RTI);
|
||||||
|
arm_jtag_scann(ice_reg->jtag_info, 0x2);
|
||||||
|
arm_jtag_set_instr(ice_reg->jtag_info, ice_reg->jtag_info->intest_instr);
|
||||||
|
|
||||||
|
fields[0].device = ice_reg->jtag_info->chain_pos;
|
||||||
|
fields[0].num_bits = 32;
|
||||||
|
fields[0].out_value = malloc(4);
|
||||||
|
buf_set_u32(fields[0].out_value, 0, 32, value);
|
||||||
|
fields[0].out_mask = NULL;
|
||||||
|
fields[0].in_value = NULL;
|
||||||
|
fields[0].in_check_value = NULL;
|
||||||
|
fields[0].in_check_mask = NULL;
|
||||||
|
fields[0].in_handler = NULL;
|
||||||
|
fields[0].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[1].device = ice_reg->jtag_info->chain_pos;
|
||||||
|
fields[1].num_bits = 5;
|
||||||
|
fields[1].out_value = malloc(1);
|
||||||
|
buf_set_u32(fields[1].out_value, 0, 5, reg_addr);
|
||||||
|
fields[1].out_mask = NULL;
|
||||||
|
fields[1].in_value = NULL;
|
||||||
|
fields[1].in_check_value = NULL;
|
||||||
|
fields[1].in_check_mask = NULL;
|
||||||
|
fields[1].in_handler = NULL;
|
||||||
|
fields[1].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[2].device = ice_reg->jtag_info->chain_pos;
|
||||||
|
fields[2].num_bits = 1;
|
||||||
|
fields[2].out_value = malloc(1);
|
||||||
|
buf_set_u32(fields[2].out_value, 0, 1, 1);
|
||||||
|
fields[2].out_mask = NULL;
|
||||||
|
fields[2].in_value = NULL;
|
||||||
|
fields[2].in_check_value = NULL;
|
||||||
|
fields[2].in_check_mask = NULL;
|
||||||
|
fields[2].in_handler = NULL;
|
||||||
|
fields[2].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
jtag_add_dr_scan(3, fields, -1);
|
||||||
|
|
||||||
|
free(fields[0].out_value);
|
||||||
|
free(fields[1].out_value);
|
||||||
|
free(fields[2].out_value);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int embeddedice_store_reg(reg_t *reg)
|
||||||
|
{
|
||||||
|
return embeddedice_write_reg(reg, buf_get_u32(reg->value, 0, reg->size));
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef EMBEDDED_ICE_H
|
||||||
|
#define EMBEDDED_ICE_H
|
||||||
|
|
||||||
|
#include "target.h"
|
||||||
|
#include "register.h"
|
||||||
|
#include "arm_jtag.h"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
EICE_DBG_CTRL = 0,
|
||||||
|
EICE_DBG_STAT = 1,
|
||||||
|
EICE_COMMS_CTRL = 2,
|
||||||
|
EICE_COMMS_DATA = 3,
|
||||||
|
EICE_W0_ADDR_VALUE = 4,
|
||||||
|
EICE_W0_ADDR_MASK = 5,
|
||||||
|
EICE_W0_DATA_VALUE = 6,
|
||||||
|
EICE_W0_DATA_MASK = 7,
|
||||||
|
EICE_W0_CONTROL_VALUE = 8,
|
||||||
|
EICE_W0_CONTROL_MASK = 9,
|
||||||
|
EICE_W1_ADDR_VALUE = 10,
|
||||||
|
EICE_W1_ADDR_MASK = 11,
|
||||||
|
EICE_W1_DATA_VALUE = 12,
|
||||||
|
EICE_W1_DATA_MASK = 13,
|
||||||
|
EICE_W1_CONTROL_VALUE = 14,
|
||||||
|
EICE_W1_CONTROL_MASK = 15
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
EICE_DBG_CONTROL_INTDIS = 2,
|
||||||
|
EICE_DBG_CONTROL_DBGRQ = 1,
|
||||||
|
EICE_DBG_CONTROL_DBGACK = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
EICE_DBG_STATUS_ITBIT = 4,
|
||||||
|
EICE_DBG_STATUS_SYSCOMP = 3,
|
||||||
|
EICE_DBG_STATUS_IFEN = 2,
|
||||||
|
EICE_DBG_STATUS_DBGRQ = 1,
|
||||||
|
EICE_DBG_STATUS_DBGACK = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
EICE_W_CTRL_ENABLE = 0x100,
|
||||||
|
EICE_W_CTRL_RANGE = 0x80,
|
||||||
|
EICE_W_CTRL_CHAIN = 0x40,
|
||||||
|
EICE_W_CTRL_EXTERN = 0x20,
|
||||||
|
EICE_W_CTRL_nTRANS = 0x10,
|
||||||
|
EICE_W_CTRL_nOPC = 0x8,
|
||||||
|
EICE_W_CTRL_MAS = 0x6,
|
||||||
|
EICE_W_CTRL_ITBIT = 0x2,
|
||||||
|
EICE_W_CTRL_nRW = 0x1
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct embeddedice_reg_s
|
||||||
|
{
|
||||||
|
int addr;
|
||||||
|
arm_jtag_t *jtag_info;
|
||||||
|
} embeddedice_reg_t;
|
||||||
|
|
||||||
|
extern reg_cache_t* embeddedice_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, int extra_reg);
|
||||||
|
extern int embeddedice_read_reg(reg_t *reg);
|
||||||
|
extern int embeddedice_write_reg(reg_t *reg, u32 value);
|
||||||
|
extern int embeddedice_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask);
|
||||||
|
extern int embeddedice_store_reg(reg_t *reg);
|
||||||
|
extern int embeddedice_set_reg(reg_t *reg, u32 value);
|
||||||
|
extern int embeddedice_set_reg_w_exec(reg_t *reg, u32 value);
|
||||||
|
|
||||||
|
#endif /* EMBEDDED_ICE_H */
|
|
@ -0,0 +1,409 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "etm.h"
|
||||||
|
|
||||||
|
#include "armv4_5.h"
|
||||||
|
#include "arm7_9_common.h"
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "arm_jtag.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "binarybuffer.h"
|
||||||
|
#include "target.h"
|
||||||
|
#include "register.h"
|
||||||
|
#include "jtag.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
bitfield_desc_t etm_comms_ctrl_bitfield_desc[] =
|
||||||
|
{
|
||||||
|
{"R", 1},
|
||||||
|
{"W", 1},
|
||||||
|
{"reserved", 26},
|
||||||
|
{"version", 4}
|
||||||
|
};
|
||||||
|
|
||||||
|
int etm_reg_arch_info[] =
|
||||||
|
{
|
||||||
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||||
|
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||||
|
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||||
|
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||||
|
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||||
|
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||||
|
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||||
|
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||||
|
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
||||||
|
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||||
|
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
|
||||||
|
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||||
|
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x67,
|
||||||
|
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||||
|
};
|
||||||
|
|
||||||
|
int etm_reg_arch_size_info[] =
|
||||||
|
{
|
||||||
|
32, 32, 17, 8, 3, 9, 32, 17,
|
||||||
|
26, 16, 25, 8, 17, 32, 32, 17,
|
||||||
|
32, 32, 32, 32, 32, 32, 32, 32,
|
||||||
|
32, 32, 32, 32, 32, 32, 32, 32,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
32, 32, 32, 32, 32, 32, 32, 32,
|
||||||
|
32, 32, 32, 32, 32, 32, 32, 32,
|
||||||
|
32, 32, 32, 32, 32, 32, 32, 32,
|
||||||
|
32, 32, 32, 32, 32, 32, 32, 32,
|
||||||
|
16, 16, 16, 16, 18, 18, 18, 18,
|
||||||
|
17, 17, 17, 17, 16, 16, 16, 16,
|
||||||
|
17, 17, 17, 17, 17, 17, 2,
|
||||||
|
17, 17, 17, 17, 32, 32, 32, 32
|
||||||
|
};
|
||||||
|
|
||||||
|
char* etm_reg_list[] =
|
||||||
|
{
|
||||||
|
"ETM_CTRL",
|
||||||
|
"ETM_CONFIG",
|
||||||
|
"ETM_TRIG_EVENT",
|
||||||
|
"ETM_MMD_CTRL",
|
||||||
|
"ETM_STATUS",
|
||||||
|
"ETM_SYS_CONFIG",
|
||||||
|
"ETM_TRACE_RESOURCE_CTRL",
|
||||||
|
"ETM_TRACE_EN_CTRL2",
|
||||||
|
"ETM_TRACE_EN_EVENT",
|
||||||
|
"ETM_TRACE_EN_CTRL1",
|
||||||
|
"ETM_FIFOFULL_REGION",
|
||||||
|
"ETM_FIFOFULL_LEVEL",
|
||||||
|
"ETM_VIEWDATA_EVENT",
|
||||||
|
"ETM_VIEWDATA_CTRL1",
|
||||||
|
"ETM_VIEWDATA_CTRL2",
|
||||||
|
"ETM_VIEWDATA_CTRL3",
|
||||||
|
"ETM_ADDR_COMPARATOR_VALUE1",
|
||||||
|
"ETM_ADDR_COMPARATOR_VALUE2",
|
||||||
|
"ETM_ADDR_COMPARATOR_VALUE3",
|
||||||
|
"ETM_ADDR_COMPARATOR_VALUE4",
|
||||||
|
"ETM_ADDR_COMPARATOR_VALUE5",
|
||||||
|
"ETM_ADDR_COMPARATOR_VALUE6",
|
||||||
|
"ETM_ADDR_COMPARATOR_VALUE7",
|
||||||
|
"ETM_ADDR_COMPARATOR_VALUE8",
|
||||||
|
"ETM_ADDR_COMPARATOR_VALUE9",
|
||||||
|
"ETM_ADDR_COMPARATOR_VALUE10",
|
||||||
|
"ETM_ADDR_COMPARATOR_VALUE11",
|
||||||
|
"ETM_ADDR_COMPARATOR_VALUE12",
|
||||||
|
"ETM_ADDR_COMPARATOR_VALUE13",
|
||||||
|
"ETM_ADDR_COMPARATOR_VALUE14",
|
||||||
|
"ETM_ADDR_COMPARATOR_VALUE15",
|
||||||
|
"ETM_ADDR_COMPARATOR_VALUE16",
|
||||||
|
"ETM_ADDR_ACCESS_TYPE1",
|
||||||
|
"ETM_ADDR_ACCESS_TYPE2",
|
||||||
|
"ETM_ADDR_ACCESS_TYPE3",
|
||||||
|
"ETM_ADDR_ACCESS_TYPE4",
|
||||||
|
"ETM_ADDR_ACCESS_TYPE5",
|
||||||
|
"ETM_ADDR_ACCESS_TYPE6",
|
||||||
|
"ETM_ADDR_ACCESS_TYPE7",
|
||||||
|
"ETM_ADDR_ACCESS_TYPE8",
|
||||||
|
"ETM_ADDR_ACCESS_TYPE9",
|
||||||
|
"ETM_ADDR_ACCESS_TYPE10",
|
||||||
|
"ETM_ADDR_ACCESS_TYPE11",
|
||||||
|
"ETM_ADDR_ACCESS_TYPE12",
|
||||||
|
"ETM_ADDR_ACCESS_TYPE13",
|
||||||
|
"ETM_ADDR_ACCESS_TYPE14",
|
||||||
|
"ETM_ADDR_ACCESS_TYPE15",
|
||||||
|
"ETM_ADDR_ACCESS_TYPE16",
|
||||||
|
"ETM_DATA_COMPARATOR_VALUE1",
|
||||||
|
"ETM_DATA_COMPARATOR_VALUE2",
|
||||||
|
"ETM_DATA_COMPARATOR_VALUE3",
|
||||||
|
"ETM_DATA_COMPARATOR_VALUE4",
|
||||||
|
"ETM_DATA_COMPARATOR_VALUE5",
|
||||||
|
"ETM_DATA_COMPARATOR_VALUE6",
|
||||||
|
"ETM_DATA_COMPARATOR_VALUE7",
|
||||||
|
"ETM_DATA_COMPARATOR_VALUE8",
|
||||||
|
"ETM_DATA_COMPARATOR_VALUE9",
|
||||||
|
"ETM_DATA_COMPARATOR_VALUE10",
|
||||||
|
"ETM_DATA_COMPARATOR_VALUE11",
|
||||||
|
"ETM_DATA_COMPARATOR_VALUE12",
|
||||||
|
"ETM_DATA_COMPARATOR_VALUE13",
|
||||||
|
"ETM_DATA_COMPARATOR_VALUE14",
|
||||||
|
"ETM_DATA_COMPARATOR_VALUE15",
|
||||||
|
"ETM_DATA_COMPARATOR_VALUE16",
|
||||||
|
"ETM_DATA_COMPARATOR_MASK1",
|
||||||
|
"ETM_DATA_COMPARATOR_MASK2",
|
||||||
|
"ETM_DATA_COMPARATOR_MASK3",
|
||||||
|
"ETM_DATA_COMPARATOR_MASK4",
|
||||||
|
"ETM_DATA_COMPARATOR_MASK5",
|
||||||
|
"ETM_DATA_COMPARATOR_MASK6",
|
||||||
|
"ETM_DATA_COMPARATOR_MASK7",
|
||||||
|
"ETM_DATA_COMPARATOR_MASK8",
|
||||||
|
"ETM_DATA_COMPARATOR_MASK9",
|
||||||
|
"ETM_DATA_COMPARATOR_MASK10",
|
||||||
|
"ETM_DATA_COMPARATOR_MASK11",
|
||||||
|
"ETM_DATA_COMPARATOR_MASK12",
|
||||||
|
"ETM_DATA_COMPARATOR_MASK13",
|
||||||
|
"ETM_DATA_COMPARATOR_MASK14",
|
||||||
|
"ETM_DATA_COMPARATOR_MASK15",
|
||||||
|
"ETM_DATA_COMPARATOR_MASK16",
|
||||||
|
"ETM_COUNTER_INITAL_VALUE1",
|
||||||
|
"ETM_COUNTER_INITAL_VALUE2",
|
||||||
|
"ETM_COUNTER_INITAL_VALUE3",
|
||||||
|
"ETM_COUNTER_INITAL_VALUE4",
|
||||||
|
"ETM_COUNTER_ENABLE1",
|
||||||
|
"ETM_COUNTER_ENABLE2",
|
||||||
|
"ETM_COUNTER_ENABLE3",
|
||||||
|
"ETM_COUNTER_ENABLE4",
|
||||||
|
"ETM_COUNTER_RELOAD_VALUE1",
|
||||||
|
"ETM_COUNTER_RELOAD_VALUE2",
|
||||||
|
"ETM_COUNTER_RELOAD_VALUE3",
|
||||||
|
"ETM_COUNTER_RELOAD_VALUE4",
|
||||||
|
"ETM_COUNTER_VALUE1",
|
||||||
|
"ETM_COUNTER_VALUE2",
|
||||||
|
"ETM_COUNTER_VALUE3",
|
||||||
|
"ETM_COUNTER_VALUE4",
|
||||||
|
"ETM_SEQUENCER_CTRL1",
|
||||||
|
"ETM_SEQUENCER_CTRL2",
|
||||||
|
"ETM_SEQUENCER_CTRL3",
|
||||||
|
"ETM_SEQUENCER_CTRL4",
|
||||||
|
"ETM_SEQUENCER_CTRL5",
|
||||||
|
"ETM_SEQUENCER_CTRL6",
|
||||||
|
"ETM_SEQUENCER_STATE",
|
||||||
|
"ETM_EXTERNAL_OUTPUT1",
|
||||||
|
"ETM_EXTERNAL_OUTPUT2",
|
||||||
|
"ETM_EXTERNAL_OUTPUT3",
|
||||||
|
"ETM_EXTERNAL_OUTPUT4",
|
||||||
|
"ETM_CONTEXTID_COMPARATOR_VALUE1",
|
||||||
|
"ETM_CONTEXTID_COMPARATOR_VALUE2",
|
||||||
|
"ETM_CONTEXTID_COMPARATOR_VALUE3",
|
||||||
|
"ETM_CONTEXTID_COMPARATOR_MASK"
|
||||||
|
};
|
||||||
|
|
||||||
|
int etm_reg_arch_type = -1;
|
||||||
|
|
||||||
|
int etm_get_reg(reg_t *reg);
|
||||||
|
int etm_set_reg(reg_t *reg, u32 value);
|
||||||
|
|
||||||
|
int etm_write_reg(reg_t *reg, u32 value);
|
||||||
|
int etm_read_reg(reg_t *reg);
|
||||||
|
|
||||||
|
reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, int extra_reg)
|
||||||
|
{
|
||||||
|
reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t));
|
||||||
|
reg_t *reg_list = NULL;
|
||||||
|
etm_reg_t *arch_info = NULL;
|
||||||
|
int num_regs = sizeof(etm_reg_arch_info)/sizeof(int);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* register a register arch-type for etm registers only once */
|
||||||
|
if (etm_reg_arch_type == -1)
|
||||||
|
etm_reg_arch_type = register_reg_arch_type(etm_get_reg, etm_set_reg_w_exec);
|
||||||
|
|
||||||
|
/* the actual registers are kept in two arrays */
|
||||||
|
reg_list = calloc(num_regs, sizeof(reg_t));
|
||||||
|
arch_info = calloc(num_regs, sizeof(etm_reg_t));
|
||||||
|
|
||||||
|
/* fill in values for the reg cache */
|
||||||
|
reg_cache->name = "etm registers";
|
||||||
|
reg_cache->next = NULL;
|
||||||
|
reg_cache->reg_list = reg_list;
|
||||||
|
reg_cache->num_regs = num_regs;
|
||||||
|
|
||||||
|
/* set up registers */
|
||||||
|
for (i = 0; i < num_regs; i++)
|
||||||
|
{
|
||||||
|
reg_list[i].name = etm_reg_list[i];
|
||||||
|
reg_list[i].size = 32;
|
||||||
|
reg_list[i].dirty = 0;
|
||||||
|
reg_list[i].valid = 0;
|
||||||
|
reg_list[i].bitfield_desc = NULL;
|
||||||
|
reg_list[i].num_bitfields = 0;
|
||||||
|
reg_list[i].value = calloc(1, 4);
|
||||||
|
reg_list[i].arch_info = &arch_info[i];
|
||||||
|
reg_list[i].arch_type = etm_reg_arch_type;
|
||||||
|
reg_list[i].size = etm_reg_arch_size_info[i];
|
||||||
|
arch_info[i].addr = etm_reg_arch_info[i];
|
||||||
|
arch_info[i].jtag_info = jtag_info;
|
||||||
|
}
|
||||||
|
return reg_cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
int etm_get_reg(reg_t *reg)
|
||||||
|
{
|
||||||
|
if (etm_read_reg(reg) != ERROR_OK)
|
||||||
|
{
|
||||||
|
ERROR("BUG: error scheduling etm register read");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jtag_execute_queue() != ERROR_OK)
|
||||||
|
{
|
||||||
|
ERROR("register read failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int etm_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask)
|
||||||
|
{
|
||||||
|
etm_reg_t *etm_reg = reg->arch_info;
|
||||||
|
u8 reg_addr = etm_reg->addr & 0x7f;
|
||||||
|
scan_field_t fields[3];
|
||||||
|
|
||||||
|
DEBUG("%i", etm_reg->addr);
|
||||||
|
|
||||||
|
jtag_add_end_state(TAP_RTI);
|
||||||
|
arm_jtag_scann(etm_reg->jtag_info, 0x6);
|
||||||
|
arm_jtag_set_instr(etm_reg->jtag_info, etm_reg->jtag_info->intest_instr);
|
||||||
|
|
||||||
|
fields[0].device = etm_reg->jtag_info->chain_pos;
|
||||||
|
fields[0].num_bits = 32;
|
||||||
|
fields[0].out_value = reg->value;
|
||||||
|
fields[0].out_mask = NULL;
|
||||||
|
fields[0].in_value = NULL;
|
||||||
|
fields[0].in_check_value = NULL;
|
||||||
|
fields[0].in_check_mask = NULL;
|
||||||
|
fields[0].in_handler = NULL;
|
||||||
|
fields[0].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[1].device = etm_reg->jtag_info->chain_pos;
|
||||||
|
fields[1].num_bits = 7;
|
||||||
|
fields[1].out_value = malloc(1);
|
||||||
|
buf_set_u32(fields[1].out_value, 0, 7, reg_addr);
|
||||||
|
fields[1].out_mask = NULL;
|
||||||
|
fields[1].in_value = NULL;
|
||||||
|
fields[1].in_check_value = NULL;
|
||||||
|
fields[1].in_check_mask = NULL;
|
||||||
|
fields[1].in_handler = NULL;
|
||||||
|
fields[1].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[2].device = etm_reg->jtag_info->chain_pos;
|
||||||
|
fields[2].num_bits = 1;
|
||||||
|
fields[2].out_value = malloc(1);
|
||||||
|
buf_set_u32(fields[2].out_value, 0, 1, 0);
|
||||||
|
fields[2].out_mask = NULL;
|
||||||
|
fields[2].in_value = NULL;
|
||||||
|
fields[2].in_check_value = NULL;
|
||||||
|
fields[2].in_check_mask = NULL;
|
||||||
|
fields[2].in_handler = NULL;
|
||||||
|
fields[2].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
jtag_add_dr_scan(3, fields, -1);
|
||||||
|
|
||||||
|
fields[0].in_value = reg->value;
|
||||||
|
fields[0].in_check_value = check_value;
|
||||||
|
fields[0].in_check_mask = check_mask;
|
||||||
|
|
||||||
|
jtag_add_dr_scan(3, fields, -1);
|
||||||
|
|
||||||
|
free(fields[1].out_value);
|
||||||
|
free(fields[2].out_value);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int etm_read_reg(reg_t *reg)
|
||||||
|
{
|
||||||
|
return etm_read_reg_w_check(reg, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int etm_set_reg(reg_t *reg, u32 value)
|
||||||
|
{
|
||||||
|
if (etm_write_reg(reg, value) != ERROR_OK)
|
||||||
|
{
|
||||||
|
ERROR("BUG: error scheduling etm register write");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf_set_u32(reg->value, 0, reg->size, value);
|
||||||
|
reg->valid = 1;
|
||||||
|
reg->dirty = 0;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int etm_set_reg_w_exec(reg_t *reg, u32 value)
|
||||||
|
{
|
||||||
|
etm_set_reg(reg, value);
|
||||||
|
|
||||||
|
if (jtag_execute_queue() != ERROR_OK)
|
||||||
|
{
|
||||||
|
ERROR("register write failed");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int etm_write_reg(reg_t *reg, u32 value)
|
||||||
|
{
|
||||||
|
etm_reg_t *etm_reg = reg->arch_info;
|
||||||
|
u8 reg_addr = etm_reg->addr & 0x7f;
|
||||||
|
scan_field_t fields[3];
|
||||||
|
|
||||||
|
DEBUG("%i: 0x%8.8x", etm_reg->addr, value);
|
||||||
|
|
||||||
|
jtag_add_end_state(TAP_RTI);
|
||||||
|
arm_jtag_scann(etm_reg->jtag_info, 0x6);
|
||||||
|
arm_jtag_set_instr(etm_reg->jtag_info, etm_reg->jtag_info->intest_instr);
|
||||||
|
|
||||||
|
fields[0].device = etm_reg->jtag_info->chain_pos;
|
||||||
|
fields[0].num_bits = 32;
|
||||||
|
fields[0].out_value = malloc(4);
|
||||||
|
buf_set_u32(fields[0].out_value, 0, 32, value);
|
||||||
|
fields[0].out_mask = NULL;
|
||||||
|
fields[0].in_value = NULL;
|
||||||
|
fields[0].in_check_value = NULL;
|
||||||
|
fields[0].in_check_mask = NULL;
|
||||||
|
fields[0].in_handler = NULL;
|
||||||
|
fields[0].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[1].device = etm_reg->jtag_info->chain_pos;
|
||||||
|
fields[1].num_bits = 7;
|
||||||
|
fields[1].out_value = malloc(1);
|
||||||
|
buf_set_u32(fields[1].out_value, 0, 7, reg_addr);
|
||||||
|
fields[1].out_mask = NULL;
|
||||||
|
fields[1].in_value = NULL;
|
||||||
|
fields[1].in_check_value = NULL;
|
||||||
|
fields[1].in_check_mask = NULL;
|
||||||
|
fields[1].in_handler = NULL;
|
||||||
|
fields[1].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
fields[2].device = etm_reg->jtag_info->chain_pos;
|
||||||
|
fields[2].num_bits = 1;
|
||||||
|
fields[2].out_value = malloc(1);
|
||||||
|
buf_set_u32(fields[2].out_value, 0, 1, 1);
|
||||||
|
fields[2].out_mask = NULL;
|
||||||
|
fields[2].in_value = NULL;
|
||||||
|
fields[2].in_check_value = NULL;
|
||||||
|
fields[2].in_check_mask = NULL;
|
||||||
|
fields[2].in_handler = NULL;
|
||||||
|
fields[2].in_handler_priv = NULL;
|
||||||
|
|
||||||
|
jtag_add_dr_scan(3, fields, -1);
|
||||||
|
|
||||||
|
free(fields[0].out_value);
|
||||||
|
free(fields[1].out_value);
|
||||||
|
free(fields[2].out_value);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int etm_store_reg(reg_t *reg)
|
||||||
|
{
|
||||||
|
return etm_write_reg(reg, buf_get_u32(reg->value, 0, reg->size));
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef ETM_H
|
||||||
|
#define ETM_H
|
||||||
|
|
||||||
|
#include "target.h"
|
||||||
|
#include "register.h"
|
||||||
|
#include "arm_jtag.h"
|
||||||
|
|
||||||
|
// ETM registers (V1.2 protocol)
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ETM_CTRL = 0x00,
|
||||||
|
ETM_CONFIG = 0x01,
|
||||||
|
ETM_TRIG_EVENT = 0x02,
|
||||||
|
ETM_MMD_CTRL = 0x03,
|
||||||
|
ETM_STATUS = 0x04,
|
||||||
|
ETM_SYS_CONFIG = 0x05,
|
||||||
|
ETM_TRACE_RESOURCE_CTRL = 0x06,
|
||||||
|
ETM_TRACE_EN_CTRL2 = 0x07,
|
||||||
|
ETM_TRACE_EN_EVENT = 0x08,
|
||||||
|
ETM_TRACE_EN_CTRL1 = 0x09,
|
||||||
|
ETM_FIFOFULL_REGION = 0x0a,
|
||||||
|
ETM_FIFOFULL_LEVEL = 0x0b,
|
||||||
|
ETM_VIEWDATA_EVENT = 0x0c,
|
||||||
|
ETM_VIEWDATA_CTRL1 = 0x0d,
|
||||||
|
ETM_VIEWDATA_CTRL2 = 0x0e,
|
||||||
|
ETM_VIEWDATA_CTRL3 = 0x0f,
|
||||||
|
ETM_ADDR_COMPARATOR_VALUE = 0x10,
|
||||||
|
ETM_ADDR_ACCESS_TYPE = 0x20,
|
||||||
|
ETM_DATA_COMPARATOR_VALUE = 0x30,
|
||||||
|
ETM_DATA_COMPARATOR_MASK = 0x40,
|
||||||
|
ETM_COUNTER_INITAL_VALUE = 0x50,
|
||||||
|
ETM_COUNTER_ENABLE = 0x54,
|
||||||
|
ETM_COUNTER_RELOAD_VALUE = 0x58,
|
||||||
|
ETM_COUNTER_VALUE = 0x5c,
|
||||||
|
ETM_SEQUENCER_CTRL = 0x60,
|
||||||
|
ETM_SEQUENCER_STATE = 0x67,
|
||||||
|
ETM_EXTERNAL_OUTPUT = 0x68,
|
||||||
|
ETM_CONTEXTID_COMPARATOR_VALUE = 0x6c,
|
||||||
|
ETM_CONTEXTID_COMPARATOR_MASK = 0x6f,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct etm_reg_s
|
||||||
|
{
|
||||||
|
int addr;
|
||||||
|
arm_jtag_t *jtag_info;
|
||||||
|
} etm_reg_t;
|
||||||
|
|
||||||
|
extern reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, int extra_reg);
|
||||||
|
extern int etm_read_reg(reg_t *reg);
|
||||||
|
extern int etm_write_reg(reg_t *reg, u32 value);
|
||||||
|
extern int etm_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask);
|
||||||
|
extern int etm_store_reg(reg_t *reg);
|
||||||
|
extern int etm_set_reg(reg_t *reg, u32 value);
|
||||||
|
extern int etm_set_reg_w_exec(reg_t *reg, u32 value);
|
||||||
|
|
||||||
|
#endif /* ETM_H */
|
|
@ -0,0 +1,100 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "register.h"
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
reg_arch_type_t *reg_arch_types = NULL;
|
||||||
|
|
||||||
|
reg_t* register_get_by_name(reg_cache_t *first, char *name, int search_all)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
reg_cache_t *cache = first;
|
||||||
|
|
||||||
|
while (cache)
|
||||||
|
{
|
||||||
|
for (i = 0; i < cache->num_regs; i++)
|
||||||
|
{
|
||||||
|
if (strcmp(cache->reg_list[i].name, name) == 0)
|
||||||
|
return &(cache->reg_list[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (search_all)
|
||||||
|
cache = cache->next;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
reg_cache_t** register_get_last_cache_p(reg_cache_t **first)
|
||||||
|
{
|
||||||
|
reg_cache_t **cache_p = first;
|
||||||
|
|
||||||
|
if (*cache_p)
|
||||||
|
while (*cache_p)
|
||||||
|
cache_p = &((*cache_p)->next);
|
||||||
|
else
|
||||||
|
return first;
|
||||||
|
|
||||||
|
return cache_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int register_reg_arch_type(int (*get)(reg_t *reg), int (*set)(reg_t *reg, u32 value))
|
||||||
|
{
|
||||||
|
reg_arch_type_t** arch_type_p = ®_arch_types;
|
||||||
|
int id = 0;
|
||||||
|
|
||||||
|
if (*arch_type_p)
|
||||||
|
{
|
||||||
|
while (*arch_type_p)
|
||||||
|
{
|
||||||
|
id = (*arch_type_p)->id;
|
||||||
|
arch_type_p = &((*arch_type_p)->next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(*arch_type_p) = malloc(sizeof(reg_arch_type_t));
|
||||||
|
(*arch_type_p)->id = id + 1;
|
||||||
|
(*arch_type_p)->set = set;
|
||||||
|
(*arch_type_p)->get = get;
|
||||||
|
(*arch_type_p)->next = NULL;
|
||||||
|
|
||||||
|
return id + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
reg_arch_type_t* register_get_arch_type(int id)
|
||||||
|
{
|
||||||
|
reg_arch_type_t *arch_type = reg_arch_types;
|
||||||
|
|
||||||
|
while (arch_type)
|
||||||
|
{
|
||||||
|
if (arch_type->id == id)
|
||||||
|
return arch_type;
|
||||||
|
arch_type = arch_type->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef REGISTER_H
|
||||||
|
#define REGISTER_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "target.h"
|
||||||
|
|
||||||
|
struct target_s;
|
||||||
|
|
||||||
|
typedef struct bitfield_desc_s
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
int num_bits;
|
||||||
|
} bitfield_desc_t;
|
||||||
|
|
||||||
|
typedef struct reg_s
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
u8 *value;
|
||||||
|
int dirty;
|
||||||
|
int valid;
|
||||||
|
int size;
|
||||||
|
bitfield_desc_t *bitfield_desc;
|
||||||
|
int num_bitfields;
|
||||||
|
void *arch_info;
|
||||||
|
int arch_type;
|
||||||
|
} reg_t;
|
||||||
|
|
||||||
|
typedef struct reg_cache_s
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
struct reg_cache_s *next;
|
||||||
|
reg_t *reg_list;
|
||||||
|
int num_regs;
|
||||||
|
} reg_cache_t;
|
||||||
|
|
||||||
|
typedef struct reg_arch_type_s
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
int (*get)(reg_t *reg);
|
||||||
|
int (*set)(reg_t *reg, u32 value);
|
||||||
|
struct reg_arch_type_s *next;
|
||||||
|
} reg_arch_type_t;
|
||||||
|
|
||||||
|
extern reg_t* register_get_by_name(reg_cache_t *first, char *name, int search_all);
|
||||||
|
extern reg_cache_t** register_get_last_cache_p(reg_cache_t **first);
|
||||||
|
extern int register_reg_arch_type(int (*get)(reg_t *reg), int (*set)(reg_t *reg, u32 value));
|
||||||
|
extern reg_arch_type_t* register_get_arch_type(int id);
|
||||||
|
|
||||||
|
#endif /* REGISTER_H */
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,231 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef TARGET_H
|
||||||
|
#define TARGET_H
|
||||||
|
|
||||||
|
#include "register.h"
|
||||||
|
#include "breakpoints.h"
|
||||||
|
#include "algorithm.h"
|
||||||
|
|
||||||
|
#include "command.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
struct reg_s;
|
||||||
|
struct command_context_s;
|
||||||
|
|
||||||
|
enum target_state
|
||||||
|
{
|
||||||
|
TARGET_UNKNOWN = 0,
|
||||||
|
TARGET_RUNNING = 1,
|
||||||
|
TARGET_HALTED = 2,
|
||||||
|
TARGET_RESET = 3,
|
||||||
|
TARGET_DEBUG_RUNNING = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern char *target_state_strings[];
|
||||||
|
|
||||||
|
enum daemon_startup_mode
|
||||||
|
{
|
||||||
|
DAEMON_ATTACH, /* simply attach to the target */
|
||||||
|
DAEMON_RESET, /* reset target (behaviour defined by reset_mode */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum target_reset_mode
|
||||||
|
{
|
||||||
|
RESET_RUN = 0, /* reset and let target run */
|
||||||
|
RESET_HALT = 1, /* reset and halt target out of reset */
|
||||||
|
RESET_INIT = 2, /* reset and halt target out of reset, then run init script */
|
||||||
|
RESET_RUN_AND_HALT = 3, /* reset and let target run, halt after n milliseconds */
|
||||||
|
RESET_RUN_AND_INIT = 4, /* reset and let target run, halt after n milliseconds, then run init script */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum target_debug_reason
|
||||||
|
{
|
||||||
|
DBG_REASON_DBGRQ = 0,
|
||||||
|
DBG_REASON_BREAKPOINT = 1,
|
||||||
|
DBG_REASON_WATCHPOINT = 2,
|
||||||
|
DBG_REASON_WPTANDBKPT = 3,
|
||||||
|
DBG_REASON_SINGLESTEP = 4,
|
||||||
|
DBG_REASON_NOTHALTED = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
extern char *target_debug_reason_strings[];
|
||||||
|
|
||||||
|
enum target_endianess
|
||||||
|
{
|
||||||
|
TARGET_BIG_ENDIAN = 0, TARGET_LITTLE_ENDIAN = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
extern char *target_endianess_strings[];
|
||||||
|
|
||||||
|
struct target_s;
|
||||||
|
|
||||||
|
typedef struct working_area_s
|
||||||
|
{
|
||||||
|
u32 address;
|
||||||
|
u32 size;
|
||||||
|
int free;
|
||||||
|
u8 *backup;
|
||||||
|
struct working_area_s **user;
|
||||||
|
struct working_area_s *next;
|
||||||
|
} working_area_t;
|
||||||
|
|
||||||
|
typedef struct target_type_s
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
/* poll current target status */
|
||||||
|
enum target_state (*poll)(struct target_s *target);
|
||||||
|
/* architecture specific status reply */
|
||||||
|
int (*arch_state)(struct target_s *target, char *buf, int buf_size);
|
||||||
|
|
||||||
|
/* target execution control */
|
||||||
|
int (*halt)(struct target_s *target);
|
||||||
|
int (*resume)(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution);
|
||||||
|
int (*step)(struct target_s *target, int current, u32 address, int handle_breakpoints);
|
||||||
|
|
||||||
|
/* target reset control */
|
||||||
|
int (*assert_reset)(struct target_s *target);
|
||||||
|
int (*deassert_reset)(struct target_s *target);
|
||||||
|
int (*soft_reset_halt)(struct target_s *target);
|
||||||
|
|
||||||
|
/* target register access for gdb */
|
||||||
|
int (*get_gdb_reg_list)(struct target_s *target, struct reg_s **reg_list[], int *reg_list_size);
|
||||||
|
|
||||||
|
/* target memory access
|
||||||
|
* size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit)
|
||||||
|
* count: number of items of <size>
|
||||||
|
*/
|
||||||
|
int (*read_memory)(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
|
||||||
|
int (*write_memory)(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
|
||||||
|
|
||||||
|
/* write target memory in multiples of 4 byte, optimized for writing large quantities of data */
|
||||||
|
int (*bulk_write_memory)(struct target_s *target, u32 address, u32 count, u8 *buffer);
|
||||||
|
|
||||||
|
/* target break-/watchpoint control
|
||||||
|
* rw: 0 = write, 1 = read, 2 = access
|
||||||
|
*/
|
||||||
|
int (*add_breakpoint)(struct target_s *target, u32 address, u32 length, enum breakpoint_type type);
|
||||||
|
int (*remove_breakpoint)(struct target_s *target, breakpoint_t *breakpoint);
|
||||||
|
int (*add_watchpoint)(struct target_s *target, u32 address, u32 length, enum watchpoint_rw rw);
|
||||||
|
int (*remove_watchpoint)(struct target_s *target, watchpoint_t *watchpoint);
|
||||||
|
|
||||||
|
/* target algorithm support */
|
||||||
|
int (*run_algorithm)(struct target_s *target, int num_mem_params, mem_param_t *mem_params, int num_reg_params, reg_param_t *reg_param, u32 entry_point, u32 exit_point, int timeout_ms, void *arch_info);
|
||||||
|
|
||||||
|
int (*register_commands)(struct command_context_s *cmd_ctx);
|
||||||
|
int (*target_command)(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
|
||||||
|
int (*init_target)(struct command_context_s *cmd_ctx, struct target_s *target);
|
||||||
|
int (*quit)(void);
|
||||||
|
|
||||||
|
} target_type_t;
|
||||||
|
|
||||||
|
typedef struct target_s
|
||||||
|
{
|
||||||
|
target_type_t *type; /* target type definition (name, access functions) */
|
||||||
|
enum target_reset_mode reset_mode; /* what to do after a reset */
|
||||||
|
int run_and_halt_time; /* how long the target should run after a run_and_halt reset */
|
||||||
|
char *reset_script; /* script file to initialize the target after a reset */
|
||||||
|
char *post_halt_script; /* script file to execute after the target halted */
|
||||||
|
char *pre_resume_script; /* script file to execute before the target resumed */
|
||||||
|
u32 working_area; /* working area (initialized RAM) */
|
||||||
|
u32 working_area_size; /* size in bytes */
|
||||||
|
u32 backup_working_area; /* whether the content of the working area has to be preserved */
|
||||||
|
struct working_area_s *working_areas;/* list of allocated working areas */
|
||||||
|
enum target_debug_reason debug_reason; /* reason why the target entered debug state */
|
||||||
|
enum target_endianess endianness; /* target endianess */
|
||||||
|
enum target_state state; /* the current backend-state (running, halted, ...) */
|
||||||
|
struct reg_cache_s *reg_cache; /* the first register cache of the target (core regs) */
|
||||||
|
struct breakpoint_s *breakpoints; /* list of breakpoints */
|
||||||
|
struct watchpoint_s *watchpoints; /* list of watchpoints */
|
||||||
|
void *arch_info; /* architecture specific information */
|
||||||
|
struct target_s *next; /* next target in list */
|
||||||
|
} target_t;
|
||||||
|
|
||||||
|
enum target_event
|
||||||
|
{
|
||||||
|
TARGET_EVENT_HALTED, /* target entered debug state from normal execution or reset */
|
||||||
|
TARGET_EVENT_RESUMED, /* target resumed to normal execution */
|
||||||
|
TARGET_EVENT_RESET, /* target entered reset */
|
||||||
|
TARGET_EVENT_DEBUG_HALTED, /* target entered debug state, but was executing on behalf of the debugger */
|
||||||
|
TARGET_EVENT_DEBUG_RESUMED, /* target resumed to execute on behalf of the debugger */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct target_event_callback_s
|
||||||
|
{
|
||||||
|
int (*callback)(struct target_s *target, enum target_event event, void *priv);
|
||||||
|
void *priv;
|
||||||
|
struct target_event_callback_s *next;
|
||||||
|
} target_event_callback_t;
|
||||||
|
|
||||||
|
typedef struct target_timer_callback_s
|
||||||
|
{
|
||||||
|
int (*callback)(void *priv);
|
||||||
|
int time_ms;
|
||||||
|
int periodic;
|
||||||
|
struct timeval when;
|
||||||
|
void *priv;
|
||||||
|
struct target_timer_callback_s *next;
|
||||||
|
} target_timer_callback_t;
|
||||||
|
|
||||||
|
extern int target_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
extern int target_register_user_commands(struct command_context_s *cmd_ctx);
|
||||||
|
extern int target_init(struct command_context_s *cmd_ctx);
|
||||||
|
extern int handle_target(void *priv);
|
||||||
|
|
||||||
|
extern int target_register_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv);
|
||||||
|
extern int target_unregister_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv);
|
||||||
|
extern int target_call_event_callbacks(target_t *target, enum target_event event);
|
||||||
|
|
||||||
|
extern int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv);
|
||||||
|
extern int target_unregister_timer_callback(int (*callback)(void *priv), void *priv);
|
||||||
|
extern int target_call_timer_callbacks();
|
||||||
|
|
||||||
|
extern target_t* get_current_target(struct command_context_s *cmd_ctx);
|
||||||
|
extern int get_num_by_target(target_t *query_target);
|
||||||
|
extern target_t* get_target_by_num(int num);
|
||||||
|
|
||||||
|
extern int target_write_buffer(struct target_s *target, u32 address, u32 size, u8 *buffer);
|
||||||
|
extern int target_read_buffer(struct target_s *target, u32 address, u32 size, u8 *buffer);
|
||||||
|
|
||||||
|
extern int target_alloc_working_area(struct target_s *target, u32 size, working_area_t **area);
|
||||||
|
extern int target_free_working_area(struct target_s *target, working_area_t *area);
|
||||||
|
extern int target_free_all_working_areas(struct target_s *target);
|
||||||
|
|
||||||
|
extern target_t *targets;
|
||||||
|
|
||||||
|
extern target_event_callback_t *target_event_callbacks;
|
||||||
|
extern target_timer_callback_t *target_timer_callbacks;
|
||||||
|
|
||||||
|
#define ERROR_TARGET_INVALID (-300)
|
||||||
|
#define ERROR_TARGET_INIT_FAILED (-301)
|
||||||
|
#define ERROR_TARGET_TIMEOUT (-302)
|
||||||
|
#define ERROR_TARGET_ALREADY_HALTED (-303)
|
||||||
|
#define ERROR_TARGET_NOT_HALTED (-304)
|
||||||
|
#define ERROR_TARGET_FAILURE (-305)
|
||||||
|
#define ERROR_TARGET_UNALIGNED_ACCESS (-306)
|
||||||
|
#define ERROR_TARGET_DATA_ABORT (-307)
|
||||||
|
#define ERROR_TARGET_RESOURCE_NOT_AVAILABLE (-308)
|
||||||
|
#define ERROR_TARGET_TRANSLATION_FAULT (-309)
|
||||||
|
|
||||||
|
#endif /* TARGET_H */
|
|
@ -0,0 +1,5 @@
|
||||||
|
INCLUDES = -I$(top_srcdir)/src/gdb -I$(top_srcdir)/src/helper -I$(top_srcdir)/src/jtag $(all_includes)
|
||||||
|
METASOURCES = AUTO
|
||||||
|
noinst_LIBRARIES = libxsvf.a
|
||||||
|
noinst_HEADERS = xsvf.h
|
||||||
|
libxsvf_a_SOURCES = xsvf.c
|
|
@ -0,0 +1,506 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "xsvf.h"
|
||||||
|
|
||||||
|
#include "jtag.h"
|
||||||
|
#include "command.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#define XSTATE_MAX_PATH (12)
|
||||||
|
|
||||||
|
int handle_xsvf_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||||
|
|
||||||
|
int xsvf_fd = 0;
|
||||||
|
|
||||||
|
u8 *dr_out_buf; /* from host to device (TDI) */
|
||||||
|
u8 *dr_in_buf; /* from device to host (TDO) */
|
||||||
|
u8 *dr_in_mask;
|
||||||
|
|
||||||
|
int xsdrsize = 0;
|
||||||
|
int xruntest = 0; /* number of TCK cycles / microseconds */
|
||||||
|
int xrepeat = 0x20; /* number of XC9500 retries */
|
||||||
|
|
||||||
|
int xendir = 0;
|
||||||
|
int xenddr = 0;
|
||||||
|
|
||||||
|
enum tap_state xsvf_to_tap[] =
|
||||||
|
{
|
||||||
|
TAP_TLR, TAP_RTI,
|
||||||
|
TAP_SDS, TAP_CD, TAP_SD, TAP_E1D, TAP_PD, TAP_E2D, TAP_UD,
|
||||||
|
TAP_SIS, TAP_CI, TAP_SI, TAP_E1I, TAP_PI, TAP_E2I, TAP_UI,
|
||||||
|
};
|
||||||
|
|
||||||
|
int tap_to_xsvf[] =
|
||||||
|
{
|
||||||
|
0x0, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x1, 0x9, 0xa, 0xb, 0xc, 0xe, 0xf
|
||||||
|
};
|
||||||
|
|
||||||
|
int xsvf_register_commands(struct command_context_s *cmd_ctx)
|
||||||
|
{
|
||||||
|
register_command(cmd_ctx, NULL, "xsvf", handle_xsvf_command,
|
||||||
|
COMMAND_EXEC, "run xsvf <file>");
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xsvf_read_buffer(int num_bits, int fd, u8* buf)
|
||||||
|
{
|
||||||
|
int num_bytes;
|
||||||
|
|
||||||
|
for (num_bytes = (num_bits + 7) / 8; num_bytes > 0; num_bytes--)
|
||||||
|
{
|
||||||
|
if (read(fd, buf + num_bytes - 1, 1) < 0)
|
||||||
|
return ERROR_XSVF_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xsvf_read_xstates(int fd, enum tap_state *path, int max_path, int *path_len)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
unsigned char uc;
|
||||||
|
|
||||||
|
while ((read(fd, &c, 1) > 0) && (c == 0x12))
|
||||||
|
{
|
||||||
|
if (*path_len > max_path)
|
||||||
|
{
|
||||||
|
WARNING("XSTATE path longer than max_path");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (read(fd, &uc, 1) < 0)
|
||||||
|
{
|
||||||
|
return ERROR_XSVF_EOF;
|
||||||
|
}
|
||||||
|
path[(*path_len)++] = xsvf_to_tap[uc];
|
||||||
|
}
|
||||||
|
|
||||||
|
lseek(fd, -1, SEEK_CUR);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle_xsvf_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
unsigned char uc, uc2;
|
||||||
|
unsigned int ui;
|
||||||
|
unsigned short us;
|
||||||
|
|
||||||
|
int do_abort = 0;
|
||||||
|
int unsupported = 0;
|
||||||
|
int tdo_mismatch = 0;
|
||||||
|
|
||||||
|
int runtest_requires_tck = 0;
|
||||||
|
|
||||||
|
int device = -1; /* use -1 to indicate a "plain" xsvf file which accounts for additional devices in the scan chain, otherwise the device that should be affected */
|
||||||
|
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "usage: xsvf <device#|plain> <file> <variant>");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(args[0], "plain") != 0)
|
||||||
|
{
|
||||||
|
device = strtoul(args[0], NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((xsvf_fd = open(args[1], O_RDONLY)) < 0)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "file %s not found", args[0]);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((argc > 2) && (strcmp(args[2], "virt2") == 0))
|
||||||
|
{
|
||||||
|
runtest_requires_tck = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (read(xsvf_fd, &c, 1) > 0)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 0x00: /* XCOMPLETE */
|
||||||
|
DEBUG("XCOMPLETE");
|
||||||
|
if (jtag_execute_queue() != ERROR_OK)
|
||||||
|
{
|
||||||
|
tdo_mismatch = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x01: /* XTDOMASK */
|
||||||
|
DEBUG("XTDOMASK");
|
||||||
|
if (dr_in_mask && (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_in_mask) != ERROR_OK))
|
||||||
|
do_abort = 1;
|
||||||
|
break;
|
||||||
|
case 0x02: /* XSIR */
|
||||||
|
DEBUG("XSIR");
|
||||||
|
if (read(xsvf_fd, &c, 1) < 0)
|
||||||
|
do_abort = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u8 *ir_buf = malloc((c + 7) / 8);
|
||||||
|
if (xsvf_read_buffer(c, xsvf_fd, ir_buf) != ERROR_OK)
|
||||||
|
do_abort = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scan_field_t field;
|
||||||
|
field.device = device;
|
||||||
|
field.num_bits = c;
|
||||||
|
field.out_value = ir_buf;
|
||||||
|
field.out_mask = NULL;
|
||||||
|
field.in_value = NULL;
|
||||||
|
field.in_check_value = NULL;
|
||||||
|
field.in_check_mask = NULL;
|
||||||
|
field.in_handler = NULL;
|
||||||
|
field.in_handler_priv = NULL;
|
||||||
|
if (device == -1)
|
||||||
|
jtag_add_plain_ir_scan(1, &field, TAP_PI);
|
||||||
|
else
|
||||||
|
jtag_add_ir_scan(1, &field, TAP_PI);
|
||||||
|
if (jtag_execute_queue() != ERROR_OK)
|
||||||
|
{
|
||||||
|
tdo_mismatch = 1;
|
||||||
|
free(ir_buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (xruntest)
|
||||||
|
{
|
||||||
|
if (runtest_requires_tck)
|
||||||
|
jtag_add_runtest(xruntest, xsvf_to_tap[xendir]);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jtag_add_statemove(TAP_RTI);
|
||||||
|
jtag_add_sleep(xruntest);
|
||||||
|
jtag_add_statemove(xsvf_to_tap[xendir]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (xendir != 0xd) /* Pause-IR */
|
||||||
|
jtag_add_statemove(xsvf_to_tap[xendir]);
|
||||||
|
}
|
||||||
|
free(ir_buf);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x03: /* XSDR */
|
||||||
|
DEBUG("XSDR");
|
||||||
|
if (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_out_buf) != ERROR_OK)
|
||||||
|
do_abort = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scan_field_t field;
|
||||||
|
field.device = device;
|
||||||
|
field.num_bits = xsdrsize;
|
||||||
|
field.out_value = dr_out_buf;
|
||||||
|
field.out_mask = NULL;
|
||||||
|
field.in_value = NULL;
|
||||||
|
field.in_check_value = dr_in_buf;
|
||||||
|
field.in_check_mask = dr_in_mask;
|
||||||
|
field.in_handler = NULL;
|
||||||
|
field.in_handler_priv = NULL;
|
||||||
|
if (device == -1)
|
||||||
|
jtag_add_plain_dr_scan(1, &field, TAP_PD);
|
||||||
|
else
|
||||||
|
jtag_add_dr_scan(1, &field, TAP_PD);
|
||||||
|
if (jtag_execute_queue() != ERROR_OK)
|
||||||
|
{
|
||||||
|
tdo_mismatch = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (xruntest)
|
||||||
|
{
|
||||||
|
if (runtest_requires_tck)
|
||||||
|
jtag_add_runtest(xruntest, xsvf_to_tap[xenddr]);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jtag_add_statemove(TAP_RTI);
|
||||||
|
jtag_add_sleep(xruntest);
|
||||||
|
jtag_add_statemove(xsvf_to_tap[xenddr]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (xendir != 0x6) /* Pause-DR */
|
||||||
|
jtag_add_statemove(xsvf_to_tap[xenddr]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x04: /* XRUNTEST */
|
||||||
|
DEBUG("XRUNTEST");
|
||||||
|
if (read(xsvf_fd, &ui, 4) < 0)
|
||||||
|
do_abort = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xruntest = ntohl(ui);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x07: /* XREPEAT */
|
||||||
|
DEBUG("XREPEAT");
|
||||||
|
if (read(xsvf_fd, &c, 1) < 0)
|
||||||
|
do_abort = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xrepeat = c;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x08: /* XSDRSIZE */
|
||||||
|
DEBUG("XSDRSIZE");
|
||||||
|
if (read(xsvf_fd, &ui, 4) < 0)
|
||||||
|
do_abort = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xsdrsize = ntohl(ui);
|
||||||
|
free(dr_out_buf);
|
||||||
|
free(dr_in_buf);
|
||||||
|
free(dr_in_mask);
|
||||||
|
dr_out_buf = malloc((xsdrsize + 7) / 8);
|
||||||
|
dr_in_buf = malloc((xsdrsize + 7) / 8);
|
||||||
|
dr_in_mask = malloc((xsdrsize + 7) / 8);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x09: /* XSDRTDO */
|
||||||
|
DEBUG("XSDRTDO");
|
||||||
|
if (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_out_buf) != ERROR_OK)
|
||||||
|
do_abort = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_in_buf) != ERROR_OK)
|
||||||
|
do_abort = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scan_field_t field;
|
||||||
|
field.device = device;
|
||||||
|
field.num_bits = xsdrsize;
|
||||||
|
field.out_value = dr_out_buf;
|
||||||
|
field.out_mask = NULL;
|
||||||
|
field.in_value = NULL;
|
||||||
|
field.in_check_value = dr_in_buf;
|
||||||
|
field.in_check_mask = dr_in_mask;
|
||||||
|
field.in_handler = NULL;
|
||||||
|
field.in_handler_priv = NULL;
|
||||||
|
if (device == -1)
|
||||||
|
jtag_add_plain_dr_scan(1, &field, TAP_PD);
|
||||||
|
else
|
||||||
|
jtag_add_dr_scan(1, &field, TAP_PD);
|
||||||
|
if (jtag_execute_queue() != ERROR_OK)
|
||||||
|
{
|
||||||
|
tdo_mismatch = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (xruntest)
|
||||||
|
{
|
||||||
|
if (runtest_requires_tck)
|
||||||
|
jtag_add_runtest(xruntest, xsvf_to_tap[xenddr]);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jtag_add_statemove(TAP_RTI);
|
||||||
|
jtag_add_sleep(xruntest);
|
||||||
|
jtag_add_statemove(xsvf_to_tap[xenddr]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (xendir != 0x6) /* Pause-DR */
|
||||||
|
jtag_add_statemove(xsvf_to_tap[xenddr]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x0a: /* XSETDRMASKS */
|
||||||
|
printf("unsupported XSETSDRMASKS\n");
|
||||||
|
unsupported = 1;
|
||||||
|
break;
|
||||||
|
case 0x0b: /* XSDRINC */
|
||||||
|
printf("unsupported XSDRINC\n");
|
||||||
|
unsupported = 1;
|
||||||
|
break;
|
||||||
|
case 0x0c: /* XSDRB */
|
||||||
|
unsupported = 1;
|
||||||
|
break;
|
||||||
|
case 0x0d: /* XSDRC */
|
||||||
|
unsupported = 1;
|
||||||
|
break;
|
||||||
|
case 0x0e: /* XSDRE */
|
||||||
|
unsupported = 1;
|
||||||
|
break;
|
||||||
|
case 0x0f: /* XSDRTDOB */
|
||||||
|
unsupported = 1;
|
||||||
|
break;
|
||||||
|
case 0x10: /* XSDRTDOB */
|
||||||
|
unsupported = 1;
|
||||||
|
break;
|
||||||
|
case 0x11: /* XSDRTDOB */
|
||||||
|
unsupported = 1;
|
||||||
|
break;
|
||||||
|
case 0x12: /* XSTATE */
|
||||||
|
DEBUG("XSTATE");
|
||||||
|
if (read(xsvf_fd, &uc, 1) < 0)
|
||||||
|
do_abort = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum tap_state *path = calloc(XSTATE_MAX_PATH, 4);
|
||||||
|
int path_len = 1;
|
||||||
|
path[0] = xsvf_to_tap[uc];
|
||||||
|
if (xsvf_read_xstates(xsvf_fd, path, XSTATE_MAX_PATH, &path_len) != ERROR_OK)
|
||||||
|
do_abort = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jtag_add_pathmove(path_len, path);
|
||||||
|
}
|
||||||
|
free(path);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x13: /* XENDIR */
|
||||||
|
DEBUG("XENDIR");
|
||||||
|
if (read(xsvf_fd, &c, 1) < 0)
|
||||||
|
do_abort = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (c == 0)
|
||||||
|
xendir = 1;
|
||||||
|
else if (c == 1)
|
||||||
|
xendir = 0xd;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR("unknown XENDIR endstate");
|
||||||
|
unsupported = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x14: /* XENDDR */
|
||||||
|
DEBUG("XENDDR");
|
||||||
|
if (read(xsvf_fd, &c, 1) < 0)
|
||||||
|
do_abort = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (c == 0)
|
||||||
|
xenddr = 1;
|
||||||
|
else if (c == 1)
|
||||||
|
xenddr = 0x6;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR("unknown XENDDR endstate");
|
||||||
|
unsupported = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x15: /* XSIR2 */
|
||||||
|
DEBUG("XSIR2");
|
||||||
|
if (read(xsvf_fd, &us, 2) < 0)
|
||||||
|
do_abort = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u8 *ir_buf;
|
||||||
|
us = ntohs(us);
|
||||||
|
ir_buf = malloc((us + 7) / 8);
|
||||||
|
if (xsvf_read_buffer(us, xsvf_fd, ir_buf) != ERROR_OK)
|
||||||
|
do_abort = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scan_field_t field;
|
||||||
|
field.device = device;
|
||||||
|
field.num_bits = us;
|
||||||
|
field.out_value = ir_buf;
|
||||||
|
field.out_mask = NULL;
|
||||||
|
field.in_value = NULL;
|
||||||
|
field.in_check_value = NULL;
|
||||||
|
field.in_check_mask = NULL;
|
||||||
|
field.in_handler = NULL;
|
||||||
|
field.in_handler_priv = NULL;
|
||||||
|
if (device == -1)
|
||||||
|
jtag_add_plain_ir_scan(1, &field, xsvf_to_tap[xendir]);
|
||||||
|
else
|
||||||
|
jtag_add_ir_scan(1, &field, xsvf_to_tap[xendir]);
|
||||||
|
}
|
||||||
|
free(ir_buf);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x16: /* XCOMMENT */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (read(xsvf_fd, &c, 1) < 0)
|
||||||
|
{
|
||||||
|
do_abort = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (c != 0);
|
||||||
|
break;
|
||||||
|
case 0x17: /* XWAIT */
|
||||||
|
DEBUG("XWAIT");
|
||||||
|
if ((read(xsvf_fd, &uc, 1) < 0) || (read(xsvf_fd, &uc2, 1) < 0) || (read(xsvf_fd, &ui, 4) < 0))
|
||||||
|
do_abort = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jtag_add_statemove(xsvf_to_tap[uc]);
|
||||||
|
ui = ntohl(ui);
|
||||||
|
jtag_add_sleep(ui);
|
||||||
|
jtag_add_statemove(xsvf_to_tap[uc2]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("unknown xsvf command (0x%2.2x)\n", c);
|
||||||
|
unsupported = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do_abort || unsupported || tdo_mismatch)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tdo_mismatch)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "TDO mismatch, aborting");
|
||||||
|
jtag_cancel_queue();
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unsupported)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "unsupported xsvf command encountered, aborting");
|
||||||
|
jtag_cancel_queue();
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do_abort)
|
||||||
|
{
|
||||||
|
command_print(cmd_ctx, "premature end detected, aborting");
|
||||||
|
jtag_cancel_queue();
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dr_out_buf)
|
||||||
|
free(dr_out_buf);
|
||||||
|
|
||||||
|
if (dr_in_buf)
|
||||||
|
free(dr_in_buf);
|
||||||
|
|
||||||
|
if (dr_in_mask)
|
||||||
|
free(dr_in_mask);
|
||||||
|
|
||||||
|
close(xsvf_fd);
|
||||||
|
|
||||||
|
command_print(cmd_ctx, "XSVF file programmed successfully");
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef XSVF_H
|
||||||
|
#define XSVF_H
|
||||||
|
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
extern int xsvf_register_commands(struct command_context_s *cmd_ctx);
|
||||||
|
|
||||||
|
#define ERROR_XSVF_EOF (-200)
|
||||||
|
#define ERROR_XSVF_FAILED (-201)
|
||||||
|
|
||||||
|
#endif /* XSVF_H */
|
Loading…
Reference in New Issue