summaryrefslogtreecommitdiff
path: root/src/tcl
diff options
context:
space:
mode:
Diffstat (limited to 'src/tcl')
-rw-r--r--src/tcl/README_ABOUT_TCL.txt430
-rw-r--r--src/tcl/bitsbytes.tcl63
-rw-r--r--src/tcl/chip/atmel/at91/aic.tcl101
-rw-r--r--src/tcl/chip/atmel/at91/at91sam7x128.tcl128
-rw-r--r--src/tcl/chip/atmel/at91/at91sam7x256.tcl126
-rw-r--r--src/tcl/chip/atmel/at91/pmc.tcl17
-rw-r--r--src/tcl/chip/atmel/at91/rtt.tcl54
-rw-r--r--src/tcl/chip/atmel/at91/usarts.tcl135
-rw-r--r--src/tcl/cpu/arm/arm7tdmi.tcl6
-rw-r--r--src/tcl/cpu/arm/arm920.tcl6
-rw-r--r--src/tcl/cpu/arm/arm946.tcl6
-rw-r--r--src/tcl/cpu/arm/arm966.tcl6
-rw-r--r--src/tcl/memory.tcl108
-rw-r--r--src/tcl/mmr_helpers.tcl59
-rw-r--r--src/tcl/readable.tcl25
15 files changed, 1270 insertions, 0 deletions
diff --git a/src/tcl/README_ABOUT_TCL.txt b/src/tcl/README_ABOUT_TCL.txt
new file mode 100644
index 00000000..47131fef
--- /dev/null
+++ b/src/tcl/README_ABOUT_TCL.txt
@@ -0,0 +1,430 @@
+****************************************
+****************************************
+
+This is a short introduction to 'un-scare' you about the language
+known as TCL. It is structured as a guided tour through the files
+written by me [Duane Ellis] - in early July 2008 for OpenOCD.
+
+Which uses the "JIM" embedded Tcl clone-ish language.
+
+Thing described here are *totally* TCL generic... not Jim specific.
+
+The goal of this document is to encourage you to add your own set of
+chips to the TCL package - and most importantly you should know where
+you should put them - so they end up in an orginized way.
+
+--Duane Ellis.
+ duane@duaneellis.com
+
+****************************************
+****************************************
+
+Adding "chip" support - Duane Ellis July 5 - 2008.
+
+The concept is this:
+ In your "openocd.cfg" file add something like this:
+
+ source [find tcl/chip/VENDOR/FAMILY/NAME.tcl]
+
+ For example...
+ source [find tcl/chip/atmel/at91/at91sam7x256.tcl]
+
+ You'll notice that it makes use of:
+
+ tcl/cpu/arm/<NAME>.tcl.
+
+ Yes, that is where you should put "core" specific things.
+ Be carefull and learn the difference:
+
+ THE "CORE" - is not the entire chip!
+
+Definition:
+ That "file" listed above is called a "CHIP FILE".
+
+ It may be standalone, or may need to "source" other "helper" files.
+
+ The reference [7/5/2008] is the at91sam7x256.tcl file.
+
+****************************************
+****************************************
+=== TCL TOUR ===
+Open: at91sam7x256.tcl
+=== TCL TOUR ===
+
+A walk through --- For those who are new to TCL.
+
+Examine the file: at91sam7x256.tcl
+
+It starts with:
+ source [find path/filename.tcl]
+
+In TCL - this is very important.
+
+ Rule #1 Everything is a string.
+ Rule #2 If you think other wise See #1.
+Reminds you of:
+ Rule #1: The wife is correct.
+ Rule #2: If you think otherwise, See #1
+
+Any text contained inside of [square-brackets]
+is just like `back-ticks` in BASH.
+
+Hence, the [find FILENAME] executes the command find with a single
+parameter the filename.
+
+========================================
+
+Next you see a series of:
+
+set NAME VALUE
+
+It is mostly "obious" what is going on.
+
+Execption: The arrays.
+
+ You would *THINK* Tcl supports arrays.
+ In fact, multi-dim arrays. That is false.
+
+ For the index for"FLASH(0,CHIPSELECT)" is actually the string
+ "0,CHIPSELECT". This is problematic. In the normal world, you think
+ of array indexes as integers.
+
+ For example these are different:
+
+ set foo(0x0c) 123
+ set foo(12) 444
+
+ Why? Because 0x0c {lowercase} is a string.
+ Don't forget UPPER CASE.
+
+ You must be careful - always... always... use simple decimal
+ numbers. When in doubt use 'expr' the evaluator. These are all the
+ same.
+
+ set x 0x0c
+ set foo([expr $x]) "twelve"
+
+ set x 12
+ set foo([expr $x]) "twelve"
+
+ set x "2 * 6"
+ set foo([expr $x]) "twelve"
+
+**************************************************
+***************************************************
+=== TCL TOUR ===
+Open the file: "bitsbytes.tcl"
+
+There is some tricky things going on.
+===============
+
+First, there is a "for" loop - at level 0
+{level 0 means: out side of a proc/function}
+
+This means it is evaluated when the file is parsed.
+
+== SIDEBAR: About The FOR command ==
+In TCL, "FOR" is a funny thing, it is not what you think it is.
+
+Syntatically - FOR is a just a command, it is not language
+construct like for(;;) in C...
+
+The "for" command takes 4 parameters.
+ (1) The "initial command" to execute.
+ (2) the test "expression"
+ (3) the "next command"
+ (4) the "body command" of the FOR loop.
+
+Notice I used the words "command" and "expresion" above.
+
+The FOR command:
+1) executes the "initial command"
+2) evaluates the expression if 0 it stops.
+3) executes the "body command"
+4) executes the "next command"
+5) Goto Step 2.
+
+As show, each of these items are in {curly-braces}. This means they
+are passed as they are - KEY-POINT: un evaluated to the FOR
+command. Think of it like escaping the backticks in Bash so that the
+"under-lying" command can evaluate the contents. In this case, the FOR
+COMMAND.
+
+== END: SIDEBAR: About The FOR command ==
+
+You'll see two lines:
+
+LINE1:
+ set vn [format "BIT%d" $x]
+
+Format is like "sprintf". Because of the [brackets], it becomes what
+you think. But here's how:
+
+First - the line is parsed - for {braces}. In this case, there are
+none. The, the parser looks for [brackets] and finds them. The,
+parser then evaluates the contents of the [brackets], and replaces
+them. It is alot this bash statement.
+
+ EXPORT vn=`date`
+
+LINE 2 & 3
+ set $vn [expr (1024 * $x)]
+ global $vn
+
+In line 1, we dynamically created a variable name. Here, we are
+assigning it a value. Lastly Line 3 we force the variable to be
+global, not "local" the the "for command body"
+
+===============
+The PROCS
+
+proc create_mask { MSB LSB } {
+ ... body ....
+}
+
+Like "for" - PROC is really just a command that takes 3 parameters.
+The (1) NAME of the function, a (2) LIST of parameters, and a (3) BODY
+
+Again, this is at "level 0" so it is a global function. (Yes, TCL
+supports local functions, you put them inside of a function}
+
+You'll see in some cases, I nest [brackets] alot and in others I'm
+lazy or wanted it to be more clear... it is a matter of choice.
+===============
+
+
+**************************************************
+***************************************************
+=== TCL TOUR ===
+Open the file: "memory.tcl"
+===============
+
+Here is where I setup some 'memory definitions' that various targets can use.
+
+For example - there is an "unknown" memory region.
+
+All memory regions must have 2 things:
+
+ (1) N_<name>
+ (2) NAME( array )
+ And the array must have some specific names:
+ ( <idx>, THING )
+ Where: THING is one of:
+ CHIPSELECT
+ BASE
+ LEN
+ HUMAN
+ TYPE
+ RWX - the access ablity.
+ WIDTH - the accessable width.
+
+ ie: Some regions of memory are not 'word'
+ accessable.
+
+The function "address_info" - given an address should
+tell you about the address.
+
+ [as of this writing: 7/5/2008 I have done
+ only a little bit with this -Duane]
+
+===
+MAJOR FUNCTION:
+==
+
+proc memread32 { ADDR }
+proc memread16 { ADDR }
+proc memread8 { ADDR }
+
+All read memory - and return the contents.
+
+[ fixme: 7/5/2008 - I need to create "memwrite" functions]
+
+**************************************************
+***************************************************
+=== TCL TOUR ===
+Open the file: "mmr_helpers.tcl"
+===============
+
+This file is used to display and work with "memory mapped registers"
+
+For example - 'show_mmr32_reg' is given the NAME of the register to
+display. The assumption is - the NAME is a global variable holding the
+address of that MMR.
+
+The code does some tricks. The [set [set NAME]] is the TCL way
+of doing double variable interpolation - like makefiles...
+
+In a makefile or shell script you may have seen this:
+
+ FOO_linux = "Penguins rule"
+ FOO_winXP = "Broken Glass"
+ FOO_mac = "I like cat names"
+
+ # Pick one
+ BUILD = linux
+ #BUILD = winXP
+ #BUILD = mac
+ FOO = ${FOO_${BUILD}}
+
+The "double [set] square bracket" thing is the TCL way, nothing more.
+
+----
+
+The IF statement - and "CATCH" .
+
+Notice this IF COMMAND - (not statement) is like this:
+[7/5/2008 it is this way]
+
+ if ![catch { command } msg ] {
+ ...something...
+ } else {
+ error [format string...]
+ }
+
+The "IF" command expects either 2 params, or 4 params.
+
+ === Sidebar: About "commands" ===
+
+ Take a look at the internals of "jim.c"
+ Look for the function: Jim_IfCoreCommand()
+ And all those other "CoreCommands"
+
+ You'll notice - they all have "argc" and "argv"
+
+ Yea, the entire thing is done that way.
+
+ IF is a command. SO is "FOR" and "WHILE" and "DO" and the
+ others. That is why I keep using the prhase it is a "command"
+
+ === END: Sidebar: About "commands" ===
+
+Paramter 1 to the IF command is expected to be an expression.
+
+As such, I do not need to wrap it in {braces}.
+
+In this case, the "expression" is the resul of the "CATCH" command.
+
+CATCH - is an error catcher.
+
+You give CATCH 1 or 2 parameters.
+ The first 1st parameter is the "code to execute"
+ The 2nd (optional) is where to put the error message.
+
+ CATCH returns 0 on success, 1 for failure.
+ The "![catch command]" is self explaintory.
+
+
+The 3rd parameter to IF must be exacty "else" or "elseif" [I lied
+above, the IF command can take many parameters they just have to
+be joined by exactly the words "else" or "elseif".
+
+The 4th parameter contains:
+
+ "error [format STRING....]"
+
+This lets me modify the previous lower level error by tacking more
+text onto the end of it. In this case, i want to add the MMR register
+name to make my error message look better.
+
+---------
+Back to something inside show_mmr32_reg{}.
+
+You'll see something 'set fn show_${NAME}_helper' Here I am
+constructing a 'function name' Then - I look it up to see if it
+exists. {the function: "proc_exists" does this}
+
+And - if it does - I call the function.
+
+In "C" it is alot like using: 'sprintf()' to construct a function name
+string, then using "dlopen()" and "dlsym()" to look it up - and get a
+function pointer - and calling the function pointer.
+
+In this case - I execute a dynamic command. You can do some cool
+tricks with interpretors.
+
+----------
+
+Function: show_mmr32_bits()
+
+In this case, we use the special TCL command "upvar" which tcl's way
+of passing things by reference. In this case, we want to reach up into
+the callers lexical scope and find the array named "NAMES"
+
+The rest of the function is pretty straight forward.
+
+First - we figure out the longest name.
+Then print 4 rows of 8bits - with names.
+
+
+**************************************************
+***************************************************
+=== TCL TOUR ===
+Open the file: "chips/atmel/at91/usarts.tcl"
+===============
+
+First - about the AT91SAM series - all of the usarts
+are basically identical...
+
+Second - there can be many of them.
+
+In this case - I do some more TCL tricks to dynamically
+create functions out of thin air.
+
+Some assumptions:
+
+The "CHIP" file has defined some variables in a proper form.
+
+ie: AT91C_BASE_US0 - for usart0,
+ AT91C_BASE_US1 - for usart1
+ ... And so on ...
+
+Near the end of the file - look for a large "foreach" loop that
+looks like this:
+
+ foreach WHO { US0 US1 US2 US3 US4 .... } {
+
+ }
+
+In this case, I'm trying to figure out what USARTs exist.
+
+Step 1 - is to determine if the NAME has been defined.
+ie: Does AT91C_BASE_USx - where X is some number exist?
+
+The "info exists VARNAME" tells you if the variable exists. Then -
+inside the IF statement... There is another loop. This loop is the
+name of various "sub-registers" within the USART.
+
+Some more trick are played with the [set VAR] backtick evaluation stuff.
+And we create two variables
+
+We calculate and create the global variable name for every subregister in the USART.
+And - declare that variable as GLOBAL so the world can find it.
+
+Then - we dynamically create a function - based on the register name.
+
+Look carefully at how that is done. You'll notice the FUNCTION BODY is
+a string - not something in {braces}. Why? This is because we need TCL
+to evaluate the contents of that string "*NOW*" - when $vn exists not
+later, when the function "show_FOO" is invoked.
+
+Lastly - we build a "str" of commands - and create a single function -
+with the generated list of commands for the entire USART.
+
+With that little bit of code - I now have a bunch of functions like:
+
+ show_US0, show_US1, show_US2, .... etc ...
+
+ And show_US0_MR, show_US0_IMR ... etc...
+
+And - I have this for every USART... without having to create tons of
+boiler plate yucky code.
+
+****************************************
+****************************************
+END of the Tcl Intro and Walk Through
+****************************************
+****************************************
+
+FUTURE PLANS
+
+ Some "GPIO" functions...
diff --git a/src/tcl/bitsbytes.tcl b/src/tcl/bitsbytes.tcl
new file mode 100644
index 00000000..b1771b4b
--- /dev/null
+++ b/src/tcl/bitsbytes.tcl
@@ -0,0 +1,63 @@
+#----------------------------------------
+# Purpose - Create some $BIT variables
+# Create $K and $M variables
+# and some bit field extraction variables.
+# Creat helper variables ...
+# BIT0.. BIT31
+
+for { set x 0 } { $x < 32 } { set x [expr $x + 1]} {
+ set vn [format "BIT%d" $x]
+ set $vn [expr (1 << $x)]
+ global $vn
+
+}
+
+# Create K bytes values
+# __1K ... to __2048K
+for { set x 1 } { $x < 2048 } { set x [expr $x * 2]} {
+ set vn [format "__%dK" $x]
+ set $vn [expr (1024 * $x)]
+ global $vn
+}
+
+# Create M bytes values
+# __1M ... to __2048K
+for { set x 1 } { $x < 2048 } { set x [expr $x * 2]} {
+ set vn [format "__%dM" $x]
+ set $vn [expr (1024 * 1024 * $x)]
+ global $vn
+}
+
+proc create_mask { MSB LSB } {
+ return [expr (((1 << ($MSB - $LSB + 1))-1) << $LSB)]
+
+}
+
+# Cut Bits $MSB to $LSB out of this value.
+# Example: % format "0x%08x" [extract_bitfield 0x12345678 27 16]
+# Result: 0x02340000
+
+proc extract_bitfield { VALUE MSB LSB } {
+ return [expr [create_mask $MSB $LSB] & $VALUE]
+}
+
+
+# Cut bits $MSB to $LSB out of this value
+# and shift (normalize) them down to bit 0.
+#
+# Example: % format "0x%08x" [normalize_bitfield 0x12345678 27 16]
+# Result: 0x00000234
+#
+proc normalize_bitfield { VALUE MSB LSB } {
+ return [expr [extract_bitfield $VALUE $MSB $LSB ] >> $LSB]
+}
+
+proc show_normalize_bitfield { VALUE MSB LSB } {
+ set m [create_mask $MSB $LSB]
+ set mr [expr $VALUE & $m]
+ set sr [expr $mr >> $LSB]
+ puts [format "((0x%08x & 0x%08x) -> 0x%08x) >> %2d => (0x%x) %5d " $VALUE $m $mr $LSB $sr $sr]
+ return $sr
+}
+
+
diff --git a/src/tcl/chip/atmel/at91/aic.tcl b/src/tcl/chip/atmel/at91/aic.tcl
new file mode 100644
index 00000000..245224a5
--- /dev/null
+++ b/src/tcl/chip/atmel/at91/aic.tcl
@@ -0,0 +1,101 @@
+set AIC_SMR [expr $AT91C_BASE_AIC + 0x00000000 ]
+global AIC_SMR
+set AIC_SVR [expr $AT91C_BASE_AIC + 0x00000080 ]
+global AIC_SVR
+set AIC_IVR [expr $AT91C_BASE_AIC + 0x00000100 ]
+global AIC_IVR
+set AIC_FVR [expr $AT91C_BASE_AIC + 0x00000104 ]
+global AIC_FVR
+set AIC_ISR [expr $AT91C_BASE_AIC + 0x00000108 ]
+global AIC_ISR
+set AIC_IPR [expr $AT91C_BASE_AIC + 0x0000010C ]
+global AIC_IPR
+set AIC_IMR [expr $AT91C_BASE_AIC + 0x00000110 ]
+global AIC_IMR
+set AIC_CISR [expr $AT91C_BASE_AIC + 0x00000114 ]
+global AIC_CISR
+set AIC_IECR [expr $AT91C_BASE_AIC + 0x00000120 ]
+global AIC_IECR
+set AIC_IDCR [expr $AT91C_BASE_AIC + 0x00000124 ]
+global AIC_IDCR
+set AIC_ICCR [expr $AT91C_BASE_AIC + 0x00000128 ]
+global AIC_ICCR
+set AIC_ISCR [expr $AT91C_BASE_AIC + 0x0000012C ]
+global AIC_ISCR
+set AIC_EOICR [expr $AT91C_BASE_AIC + 0x00000130 ]
+global AIC_EOICR
+set AIC_SPU [expr $AT91C_BASE_AIC + 0x00000134 ]
+global AIC_SPU
+set AIC_DCR [expr $AT91C_BASE_AIC + 0x00000138 ]
+global AIC_DCR
+set AIC_FFER [expr $AT91C_BASE_AIC + 0x00000140 ]
+global AIC_FFER
+set AIC_FFDR [expr $AT91C_BASE_AIC + 0x00000144 ]
+global AIC_FFDR
+set AIC_FFSR [expr $AT91C_BASE_AIC + 0x00000148 ]
+global AIC_FFSR
+
+
+proc aic_enable_disable_list { VAL ENAME DNAME } {
+ global AT91C_ID
+
+ show_mmr32_bits AT91C_ID $VAL
+
+}
+
+proc show_AIC_IPR_helper { NAME ADDR VAL } {
+ aic_enable_disable_list $VAL "IRQ PENDING" "irq not-pending"
+}
+
+proc show_AIC_IMR_helper { NAME ADDR VAL } {
+ aic_enable_disable_list $VAL "IRQ ENABLED" "irq disabled"
+}
+
+
+proc show_AIC { } {
+ global AIC_SMR
+ if [catch { mem2array aaa 32 $AIC_SMR [expr 32 * 4] } msg ] {
+ error [format "%s (%s)" $msg AIC_SMR]
+ }
+ puts "AIC_SMR: Mode & Type"
+ global AT91C_ID
+ for { set x 0 } { $x < 32 } { } {
+ puts -nonewline " "
+ puts -nonewline [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)]
+ incr x
+ puts -nonewline [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)]
+ incr x
+ puts -nonewline [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)]
+ incr x
+ puts [format "%2d: %5s 0x%08x" $x $AT91C_ID($x) $aaa($x)]
+ incr x
+ }
+ global AIC_SVR
+ if [catch { mem2array aaa 32 $AIC_SVR [expr 32 * 4] } msg ] {
+ error [format "%s (%s)" $msg AIC_SVR]
+ }
+ puts "AIC_SVR: Vectors"
+ for { set x 0 } { $x < 32 } { } {
+ puts -nonewline " "
+ puts -nonewline [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)]
+ incr x
+ puts -nonewline [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)]
+ incr x
+ puts -nonewline [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)]
+ incr x
+ puts [format "%2d: %5s 0x%08x" $x $AT91C_ID($x) $aaa($x)]
+ incr x
+ }
+
+ foreach REG {
+ AIC_IVR AIC_FVR AIC_ISR
+ AIC_IPR AIC_IMR AIC_CISR AIC_IECR AIC_IDCR
+ AIC_ICCR AIC_ISCR AIC_EOICR AIC_SPU AIC_DCR
+ AIC_FFER AIC_FFDR AIC_FFSR } {
+ if [catch { show_mmr32_reg $REG } msg ] {
+ error $msg
+ break
+ }
+ }
+}
+
diff --git a/src/tcl/chip/atmel/at91/at91sam7x128.tcl b/src/tcl/chip/atmel/at91/at91sam7x128.tcl
new file mode 100644
index 00000000..1cf7c1cf
--- /dev/null
+++ b/src/tcl/chip/atmel/at91/at91sam7x128.tcl
@@ -0,0 +1,128 @@
+source [find tcl/bitsbytes.tcl]
+source [find tcl/cpu/arm/arm7tdmi.tcl]
+source [find tcl/memory.tcl]
+source [find tcl/mmr_helpers.tcl]
+
+set CHIP_MAKER atmel
+set CHIP_FAMILY at91sam7
+set CHIP_NAME at91sam7x128
+# how many flash regions.
+set N_FLASH 1
+set FLASH(0,CHIPSELECT) -1
+set FLASH(0,BASE) 0x00100000
+set FLASH(0,LEN) $__128K
+set FLASH(0,HUMAN) "internal flash"
+set FLASH(0,TYPE) "flash"
+set FLASH(0,RWX) $RWX_R_X
+set FLASH(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY
+# how many ram regions.
+set N_RAM 1
+set RAM(0,CHIPSELECT) -1
+set RAM(0,BASE) 0x00200000
+set RAM(0,LEN) $__32K
+set RAM(0,HUMAN) "internal ram"
+set RAM(0,TYPE) "ram"
+set RAM(0,RWX) $RWX_RWX
+set RAM(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY
+
+# I AM LAZY... I create 1 region for all MMRs.
+set N_MMREGS 1
+set MMREGS(0,CHIPSELECT) -1
+set MMREGS(0,BASE) 0xfff00000
+set MMREGS(0,LEN) 0x000fffff
+set MMREGS(0,HUMAN) "mm-regs"
+set MMREGS(0,TYPE) "mmr"
+set MMREGS(0,RWX) $RWX_RW
+set MMREGS(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY
+
+# no external memory
+set N_XMEM 0
+
+
+
+
+set AT91C_BASE_SYS 0xFFFFF000
+set AT91C_BASE_AIC 0xFFFFF000
+set AT91C_BASE_PDC_DBGU 0xFFFFF300
+set AT91C_BASE_DBGU 0xFFFFF200
+set AT91C_BASE_PIOA 0xFFFFF400
+set AT91C_BASE_PIOB 0xFFFFF600
+set AT91C_BASE_CKGR 0xFFFFFC20
+set AT91C_BASE_PMC 0xFFFFFC00
+set AT91C_BASE_RSTC 0xFFFFFD00
+set AT91C_BASE_RTTC 0xFFFFFD20
+set AT91C_BASE_PITC 0xFFFFFD30
+set AT91C_BASE_WDTC 0xFFFFFD40
+set AT91C_BASE_VREG 0xFFFFFD60
+set AT91C_BASE_MC 0xFFFFFF00
+set AT91C_BASE_PDC_SPI1 0xFFFE4100
+set AT91C_BASE_SPI1 0xFFFE4000
+set AT91C_BASE_PDC_SPI0 0xFFFE0100
+set AT91C_BASE_SPI0 0xFFFE0000
+set AT91C_BASE_PDC_US1 0xFFFC4100
+set AT91C_BASE_US1 0xFFFC4000
+set AT91C_BASE_PDC_US0 0xFFFC0100
+set AT91C_BASE_US0 0xFFFC0000
+set AT91C_BASE_PDC_SSC 0xFFFD4100
+set AT91C_BASE_SSC 0xFFFD4000
+set AT91C_BASE_TWI 0xFFFB8000
+set AT91C_BASE_PWMC_CH3 0xFFFCC260
+set AT91C_BASE_PWMC_CH2 0xFFFCC240
+set AT91C_BASE_PWMC_CH1 0xFFFCC220
+set AT91C_BASE_PWMC_CH0 0xFFFCC200
+set AT91C_BASE_PWMC 0xFFFCC000
+set AT91C_BASE_UDP 0xFFFB0000
+set AT91C_BASE_TC0 0xFFFA0000
+set AT91C_BASE_TC1 0xFFFA0040
+set AT91C_BASE_TC2 0xFFFA0080
+set AT91C_BASE_TCB 0xFFFA0000
+set AT91C_BASE_CAN_MB0 0xFFFD0200
+set AT91C_BASE_CAN_MB1 0xFFFD0220
+set AT91C_BASE_CAN_MB2 0xFFFD0240
+set AT91C_BASE_CAN_MB3 0xFFFD0260
+set AT91C_BASE_CAN_MB4 0xFFFD0280
+set AT91C_BASE_CAN_MB5 0xFFFD02A0
+set AT91C_BASE_CAN_MB6 0xFFFD02C0
+set AT91C_BASE_CAN_MB7 0xFFFD02E0
+set AT91C_BASE_CAN 0xFFFD0000
+set AT91C_BASE_EMAC 0xFFFDC000
+set AT91C_BASE_PDC_ADC 0xFFFD8100
+set AT91C_BASE_ADC 0xFFFD8000
+
+set AT91C_ID(0) FIQ
+set AT91C_ID(1) SYS
+set AT91C_ID(2) PIOA
+set AT91C_ID(3) PIOB
+set AT91C_ID(4) SPI0
+set AT91C_ID(5) SPI1
+set AT91C_ID(6) US0
+set AT91C_ID(7) US1
+set AT91C_ID(8) SSC
+set AT91C_ID(9) TWI
+set AT91C_ID(10) PWMC
+set AT91C_ID(11) UDP
+set AT91C_ID(12) TC0
+set AT91C_ID(13) TC1
+set AT91C_ID(14) TC2
+set AT91C_ID(15) CAN
+set AT91C_ID(16) EMAC
+set AT91C_ID(17) ADC
+set AT91C_ID(18) ""
+set AT91C_ID(19) ""
+set AT91C_ID(20) ""
+set AT91C_ID(21) ""
+set AT91C_ID(22) ""
+set AT91C_ID(23) ""
+set AT91C_ID(24) ""
+set AT91C_ID(25) ""
+set AT91C_ID(26) ""
+set AT91C_ID(27) ""
+set AT91C_ID(28) ""
+set AT91C_ID(29) ""
+set AT91C_ID(30) IRQ0
+set AT91C_ID(31) IRQ1
+
+source [find tcl/chip/atmel/at91/aic.tcl]
+source [find tcl/chip/atmel/at91/usarts.tcl]
+source [find tcl/chip/atmel/at91/pmc.tcl]
+source [find tcl/chip/atmel/at91/rtt.tcl]
diff --git a/src/tcl/chip/atmel/at91/at91sam7x256.tcl b/src/tcl/chip/atmel/at91/at91sam7x256.tcl
new file mode 100644
index 00000000..1cba4859
--- /dev/null
+++ b/src/tcl/chip/atmel/at91/at91sam7x256.tcl
@@ -0,0 +1,126 @@
+source [find tcl/bitsbytes.tcl]
+source [find tcl/cpu/arm/arm7tdmi.tcl]
+source [find tcl/memory.tcl]
+source [find tcl/mmr_helpers.tcl]
+
+set CHIP_MAKER atmel
+set CHIP_FAMILY at91sam7
+set CHIP_NAME at91sam7x256
+# how many flash regions.
+set N_FLASH 1
+set FLASH(0,CHIPSELECT) -1
+set FLASH(0,BASE) 0x00100000
+set FLASH(0,LEN) $__256K
+set FLASH(0,HUMAN) "internal flash"
+set FLASH(0,TYPE) "flash"
+set FLASH(0,RWX) $RWX_R_X
+set FLASH(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY
+# how many ram regions.
+set N_RAM 1
+set RAM(0,CHIPSELECT) -1
+set RAM(0,BASE) 0x00200000
+set RAM(0,LEN) $__64K
+set RAM(0,HUMAN) "internal ram"
+set RAM(0,TYPE) "ram"
+set RAM(0,RWX) $RWX_RWX
+set RAM(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY
+
+# I AM LAZY... I create 1 region for all MMRs.
+set N_MMREGS 1
+set MMREGS(0,CHIPSELECT) -1
+set MMREGS(0,BASE) 0xfff00000
+set MMREGS(0,LEN) 0x000fffff
+set MMREGS(0,HUMAN) "mm-regs"
+set MMREGS(0,TYPE) "mmr"
+set MMREGS(0,RWX) $RWX_RW
+set MMREGS(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY
+
+# no external memory
+set N_XMEM 0
+
+set AT91C_BASE_SYS 0xFFFFF000
+set AT91C_BASE_AIC 0xFFFFF000
+set AT91C_BASE_PDC_DBGU 0xFFFFF300
+set AT91C_BASE_DBGU 0xFFFFF200
+set AT91C_BASE_PIOA 0xFFFFF400
+set AT91C_BASE_PIOB 0xFFFFF600
+set AT91C_BASE_CKGR 0xFFFFFC20
+set AT91C_BASE_PMC 0xFFFFFC00
+set AT91C_BASE_RSTC 0xFFFFFD00
+set AT91C_BASE_RTTC 0xFFFFFD20
+set AT91C_BASE_PITC 0xFFFFFD30
+set AT91C_BASE_WDTC 0xFFFFFD40
+set AT91C_BASE_VREG 0xFFFFFD60
+set AT91C_BASE_MC 0xFFFFFF00
+set AT91C_BASE_PDC_SPI1 0xFFFE4100
+set AT91C_BASE_SPI1 0xFFFE4000
+set AT91C_BASE_PDC_SPI0 0xFFFE0100
+set AT91C_BASE_SPI0 0xFFFE0000
+set AT91C_BASE_PDC_US1 0xFFFC4100
+set AT91C_BASE_US1 0xFFFC4000
+set AT91C_BASE_PDC_US0 0xFFFC0100
+set AT91C_BASE_US0 0xFFFC0000
+set AT91C_BASE_PDC_SSC 0xFFFD4100
+set AT91C_BASE_SSC 0xFFFD4000
+set AT91C_BASE_TWI 0xFFFB8000
+set AT91C_BASE_PWMC_CH3 0xFFFCC260
+set AT91C_BASE_PWMC_CH2 0xFFFCC240
+set AT91C_BASE_PWMC_CH1 0xFFFCC220
+set AT91C_BASE_PWMC_CH0 0xFFFCC200
+set AT91C_BASE_PWMC 0xFFFCC000
+set AT91C_BASE_UDP 0xFFFB0000
+set AT91C_BASE_TC0 0xFFFA0000
+set AT91C_BASE_TC1 0xFFFA0040
+set AT91C_BASE_TC2 0xFFFA0080
+set AT91C_BASE_TCB 0xFFFA0000
+set AT91C_BASE_CAN_MB0 0xFFFD0200
+set AT91C_BASE_CAN_MB1 0xFFFD0220
+set AT91C_BASE_CAN_MB2 0xFFFD0240
+set AT91C_BASE_CAN_MB3 0xFFFD0260
+set AT91C_BASE_CAN_MB4 0xFFFD0280
+set AT91C_BASE_CAN_MB5 0xFFFD02A0
+set AT91C_BASE_CAN_MB6 0xFFFD02C0
+set AT91C_BASE_CAN_MB7 0xFFFD02E0
+set AT91C_BASE_CAN 0xFFFD0000
+set AT91C_BASE_EMAC 0xFFFDC000
+set AT91C_BASE_PDC_ADC 0xFFFD8100
+set AT91C_BASE_ADC 0xFFFD8000
+
+set AT91C_ID(0) "FIQ"
+set AT91C_ID(1) "SYS"
+set AT91C_ID(2) "PIOA"
+set AT91C_ID(3) "PIOB"
+set AT91C_ID(4) "SPI0"
+set AT91C_ID(5) "SPI1"
+set AT91C_ID(6) "US0"
+set AT91C_ID(7) "US1"
+set AT91C_ID(8) "SSC"
+set AT91C_ID(9) "TWI"
+set AT91C_ID(10) "PWMC"
+set AT91C_ID(11) "UDP"
+set AT91C_ID(12) "TC0"
+set AT91C_ID(13) "TC1"
+set AT91C_ID(14) "TC2"
+set AT91C_ID(15) "CAN"
+set AT91C_ID(16) "EMAC"
+set AT91C_ID(17) "ADC"
+set AT91C_ID(18) ""
+set AT91C_ID(19) ""
+set AT91C_ID(20) ""
+set AT91C_ID(21) ""
+set AT91C_ID(22) ""
+set AT91C_ID(23) ""
+set AT91C_ID(24) ""
+set AT91C_ID(25) ""
+set AT91C_ID(26) ""
+set AT91C_ID(27) ""
+set AT91C_ID(28) ""
+set AT91C_ID(29) ""
+set AT91C_ID(30) "IRQ0"
+set AT91C_ID(31) "IRQ1"
+
+
+source [find tcl/chip/atmel/at91/aic.tcl]
+source [find tcl/chip/atmel/at91/usarts.tcl]
+source [find tcl/chip/atmel/at91/pmc.tcl]
+source [find tcl/chip/atmel/at91/rtt.tcl]
diff --git a/src/tcl/chip/atmel/at91/pmc.tcl b/src/tcl/chip/atmel/at91/pmc.tcl
new file mode 100644
index 00000000..584acb80
--- /dev/null
+++ b/src/tcl/chip/atmel/at91/pmc.tcl
@@ -0,0 +1,17 @@
+
+if [info exists AT91C_MAINOSC_FREQ] {
+ # user set this... let it be.
+} {
+ # 18.432mhz is a common thing...
+ set AT91C_MAINOSC_FREQ 18432000
+}
+global AT91C_MAINOSC_FREQ
+
+if [info exists AT91C_SLOWOSC_FREQ] {
+ # user set this... let it be.
+} {
+ # 32khz is the norm
+ set AT91C_SLOWOSC_FREQ 32768
+}
+global AT91C_SLOWOSC_FREQ
+
diff --git a/src/tcl/chip/atmel/at91/rtt.tcl b/src/tcl/chip/atmel/at91/rtt.tcl
new file mode 100644
index 00000000..56abb29e
--- /dev/null
+++ b/src/tcl/chip/atmel/at91/rtt.tcl
@@ -0,0 +1,54 @@
+
+set RTTC_RTMR [expr $AT91C_BASE_RTTC + 0x00]
+set RTTC_RTAR [expr $AT91C_BASE_RTTC + 0x04]
+set RTTC_RTVR [expr $AT91C_BASE_RTTC + 0x08]
+set RTTC_RTSR [expr $AT91C_BASE_RTTC + 0x0c]
+global RTTC_RTMR
+global RTTC_RTAR
+global RTTC_RTVR
+global RTTC_RTSR
+
+proc show_RTTC_RTMR_helper { NAME ADDR VAL } {
+ set rtpres [expr $VAL & 0x0ffff]
+ global BIT16 BIT17
+ if { $rtpres == 0 } {
+ set rtpres 65536;
+ }
+ global AT91C_SLOWOSC_FREQ
+ set f [expr double($AT91C_SLOWOSC_FREQ) / double($rtpres)]
+ puts [format "\tPrescale value: 0x%04x (%5d) => %f Hz" $rtpres $rtpres $f]
+ if { $VAL & $BIT16 } {
+ puts "\tBit16 -> Alarm IRQ Enabled"
+ } else {
+ puts "\tBit16 -> Alarm IRQ Disabled"
+ }
+ if { $VAL & $BIT17 } {
+ puts "\tBit17 -> RTC Inc IRQ Enabled"
+ } else {
+ puts "\tBit17 -> RTC Inc IRQ Disabled"
+ }
+ # Bit 18 is write only.
+}
+
+proc show_RTTC_RTSR_helper { NAME ADDR VAL } {
+ global BIT0 BIT1
+ if { $VAL & $BIT0 } {
+ puts "\tBit0 -> ALARM PENDING"
+ } else {
+ puts "\tBit0 -> alarm not pending"
+ }
+ if { $VAL & $BIT1 } {
+ puts "\tBit0 -> RTINC PENDING"
+ } else {
+ puts "\tBit0 -> rtinc not pending"
+ }
+}
+
+proc show_RTTC { } {
+
+ show_mmr32_reg RTTC_RTMR
+ show_mmr32_reg RTTC_RTAR
+ show_mmr32_reg RTTC_RTVR
+ show_mmr32_reg RTTC_RTSR
+}
+
diff --git a/src/tcl/chip/atmel/at91/usarts.tcl b/src/tcl/chip/atmel/at91/usarts.tcl
new file mode 100644
index 00000000..19f4ed4c
--- /dev/null
+++ b/src/tcl/chip/atmel/at91/usarts.tcl
@@ -0,0 +1,135 @@
+# the DBGU and USARTs are 'almost' indentical'
+set DBGU_CR [expr $AT91C_BASE_DBGU + 0x00000000]
+set DBGU_MR [expr $AT91C_BASE_DBGU + 0x00000004]
+set DBGU_IER [expr $AT91C_BASE_DBGU + 0x00000008]
+set DBGU_IDR [expr $AT91C_BASE_DBGU + 0x0000000C]
+set DBGU_IMR [expr $AT91C_BASE_DBGU + 0x00000010]
+set DBGU_CSR [expr $AT91C_BASE_DBGU + 0x00000014]
+set DBGU_RHR [expr $AT91C_BASE_DBGU + 0x00000018]
+set DBGU_THR [expr $AT91C_BASE_DBGU + 0x0000001C]
+set DBGU_BRGR [expr $AT91C_BASE_DBGU + 0x00000020]
+# no RTOR
+# no TTGR
+# no FIDI
+# no NER
+set DBGU_CIDR [expr $AT91C_BASE_DBGU + 0x00000040]
+set DBGU_EXID [expr $AT91C_BASE_DBGU + 0x00000044]
+set DBGU_FNTR [expr $AT91C_BASE_DBGU + 0x00000048]
+
+
+set USx_CR 0x00000000
+set USx_MR 0x00000004
+set USx_IER 0x00000008
+set USx_IDR 0x0000000C
+set USx_IMR 0x00000010
+set USx_CSR 0x00000014
+set USx_RHR 0x00000018
+set USx_THR 0x0000001C
+set USx_BRGR 0x00000020
+set USx_RTOR 0x00000024
+set USx_TTGR 0x00000028
+set USx_FIDI 0x00000040
+set USx_NER 0x00000044
+set USx_IF 0x0000004C
+
+# Create all the uarts that exist..
+# we blow up if there are >9
+
+
+proc show_mmr_USx_MR_helper { NAME ADDR VAL } {
+ # First - just print it
+
+ set x [show_normalize_bitfield $VAL 3 0]
+ if { $x == 0 } {
+ puts "\tNormal operation"
+ } else {
+ puts [format "\tNon Normal operation mode: 0x%02x" $x]
+ }
+
+ set x [show_normalize_bitfield $VAL 11 9]
+ set s "unknown"
+ switch -exact $x {
+ 0 { set s "Even" }
+ 1 { set s "Odd" }
+ 2 { set s "Force=0" }
+ 3 { set s "Force=1" }
+ * {
+ set $x [expr $x & 6]
+ switch -exact $x {
+ 4 { set s "None" }
+ 6 { set s "Multidrop Mode" }
+ }
+ }
+ }
+ puts [format "\tParity: %s " $s]
+
+ set x [expr 5 + [show_normalize_bitfield $VAL 7 6]]
+ puts [format "\tDatabits: %d" $x]
+
+ set x [show_normalize_bitfield $VAL 13 12]
+ switch -exact $x {
+ 0 { puts "\tStop bits: 1" }
+ 1 { puts "\tStop bits: 1.5" }
+ 2 { puts "\tStop bits: 2" }
+ 3 { puts "\tStop bits: Illegal/Reserved" }
+ }
+}
+
+# For every possbile usart...
+foreach WHO { US0 US1 US2 US3 US4 US5 US6 US7 US8 US9 } {
+ set n AT91C_BASE_[set WHO]
+ set str ""
+
+ # Only if it exists on the chip
+ if [ info exists $n ] {
+ # Hence: $n - is like AT91C_BASE_USx
+ # For every sub-register
+ foreach REG {CR MR IER IDR IMR CSR RHR THR BRGR RTOR TTGR FIDI NER IF} {
+ # vn = variable name
+ set vn [set WHO]_[set REG]
+ # vn = USx_IER
+ # vv = variable value
+ set vv [expr $$n + [set USx_[set REG]]]
+ # And VV is the address in memory of that register
+
+
+ # make that VN a GLOBAL so others can find it
+ global $vn
+ set $vn $vv
+
+ # Create a command for this specific register.
+ proc show_$vn { } "show_mmr32_reg $vn"
+
+ # Add this command to the Device(as a whole) command
+ set str "$str\nshow_$vn"
+ }
+ # Now - create the DEVICE(as a whole) command
+ set fn show_$WHO
+ proc $fn { } $str
+ }
+}
+
+# The Debug Uart is special..
+set str ""
+
+
+# For every sub-register
+foreach REG {DBGU_CR DBGU_MR DBGU_IER DBGU_IDR DBGU_IMR
+ DBGU_CSR DBGU_RHR DBGU_THR DBGU_BRGR DBGU_CIDR DBGU_EXID DBGU_FNTR} {
+
+ # Create a command for this specific register.
+ proc show_$REG { } "show_mmr32_reg $REG"
+
+ # Add this command to the Device(as a whole) command
+ set str "$str\nshow_$REG"
+}
+
+# Now - create the DEVICE(as a whole) command
+proc show_DBGU { } $str
+
+unset str
+
+proc show_DBGU_MR_helper { NAME ADDR VAL } { show_mmr_USx_MR_helper $NAME $ADDR $VAL }
+
+
+
diff --git a/src/tcl/cpu/arm/arm7tdmi.tcl b/src/tcl/cpu/arm/arm7tdmi.tcl
new file mode 100644
index 00000000..37db2661
--- /dev/null
+++ b/src/tcl/cpu/arm/arm7tdmi.tcl
@@ -0,0 +1,6 @@
+set CPU_TYPE arm
+set CPU_NAME arm7tdmi
+set CPU_ARCH armv4t
+set CPU_MAX_ADDRESS 0xFFFFFFFF
+set CPU_NBITS 32
+
diff --git a/src/tcl/cpu/arm/arm920.tcl b/src/tcl/cpu/arm/arm920.tcl
new file mode 100644
index 00000000..f19b20b3
--- /dev/null
+++ b/src/tcl/cpu/arm/arm920.tcl
@@ -0,0 +1,6 @@
+set CPU_TYPE arm
+set CPU_NAME arm920
+set CPU_ARCH armv4t
+set CPU_MAX_ADDRESS 0xFFFFFFFF
+set CPU_NBITS 32
+
diff --git a/src/tcl/cpu/arm/arm946.tcl b/src/tcl/cpu/arm/arm946.tcl
new file mode 100644
index 00000000..52041017
--- /dev/null
+++ b/src/tcl/cpu/arm/arm946.tcl
@@ -0,0 +1,6 @@
+set CPU_TYPE arm
+set CPU_NAME arm946
+set CPU_ARCH armv5te
+set CPU_MAX_ADDRESS 0xFFFFFFFF
+set CPU_NBITS 32
+
diff --git a/src/tcl/cpu/arm/arm966.tcl b/src/tcl/cpu/arm/arm966.tcl
new file mode 100644
index 00000000..83ce0f67
--- /dev/null
+++ b/src/tcl/cpu/arm/arm966.tcl
@@ -0,0 +1,6 @@
+set CPU_TYPE arm
+set CPU_NAME arm966
+set CPU_ARCH armv5te
+set CPU_MAX_ADDRESS 0xFFFFFFFF
+set CPU_NBITS 32
+
diff --git a/src/tcl/memory.tcl b/src/tcl/memory.tcl
new file mode 100644
index 00000000..1f90ef2c
--- /dev/null
+++ b/src/tcl/memory.tcl
@@ -0,0 +1,108 @@
+# MEMORY
+#
+# All Memory regions have two components.
+# (1) A count of regions, in the form N_NAME
+# (2) An array within info about each region.
+#
+# The ARRAY
+#
+# <NAME>( RegionNumber , ATTRIBUTE )
+#
+# Where <NAME> is one of:
+#
+# N_FLASH & FLASH (internal memory)
+# N_RAM & RAM (internal memory)
+# N_MMREGS & MMREGS (for memory mapped registers)
+# N_XMEM & XMEM (off chip memory, ie: flash on cs0, sdram on cs2)
+# or N_UNKNOWN & UNKNOWN for things that do not exist.
+#
+# We have 1 unknown region.
+set N_UNKNOWN 1
+# All MEMORY regions must have these attributes
+# CS - chip select (if internal, use -1)
+set UNKNOWN(0,CHIPSELECT) -1
+# BASE - base address in memory
+set UNKNOWN(0,BASE) 0
+# LEN - length in bytes
+set UNKNOWN(0,LEN) $CPU_MAX_ADDRESS
+# HUMAN - human name of the region
+set UNKNOWN(0,HUMAN) "unknown"
+# TYPE - one of:
+# flash, ram, mmr, unknown
+# For harvard arch:
+# iflash, dflash, iram, dram
+set UNKNOWN(0,TYPE) "unknown"
+# RWX - access ablity
+# unix style chmod bits
+# 0 - no access
+# 1 - execute
+# 2 - write
+# 4 - read
+# hence: 7 - readwrite execute
+set RWX_NO_ACCESS 0
+set RWX_X_ONLY $BIT0
+set RWX_W_ONLY $BIT1
+set RWX_R_ONLY $BIT2
+set RWX_RW [expr $RWX_R_ONLY + $RWX_W_ONLY]
+set RWX_R_X [expr $RWX_R_ONLY + $RWX_X_ONLY]
+set RWX_RWX [expr $RWX_R_ONLY + $RWX_W_ONLY + $RWX_X_ONLY]
+set UNKNOWN(0,RWX) $RWX_NO_ACCESS
+
+# WIDTH - access width
+# 8,16,32 [0 means ANY]
+set ACCESS_WIDTH_NONE 0
+set ACCESS_WIDTH_8 $BIT0
+set ACCESS_WIDTH_16 $BIT1
+set ACCESS_WIDTH_32 $BIT2
+set ACCESS_WIDTH_ANY [expr $ACCESS_WIDTH_8 + $ACCESS_WIDTH_16 + $ACCESS_WIDTH_32]
+set UNKNOWN(0,ACCESS_WIDTH) $ACCESS_WIDTH_NONE
+
+proc iswithin { ADDRESS BASE LEN } {
+ return [expr ((($ADDRESS - $BASE) > 0) && (($ADDRESS - $BASE + $LEN) > 0))]
+}
+
+proc address_info { ADDRESS } {
+
+ foreach WHERE { FLASH RAM MMREGS XMEM UNKNOWN } {
+ if { info exists $WHERE } {
+ set lmt [set N_[set WHERE]]
+ for { set region 0 } { $region < $lmt } { incr region } {
+ if { iswithin $ADDRESS $WHERE($region,BASE) $WHERE($region,LEN) } {
+ return "$WHERE $region";
+ }
+ }
+ }
+ }
+
+ # Return the 'unknown'
+ return "UNKNOWN 0"
+}
+
+proc memread32 {ADDR } {
+ set foo(0) 0
+ if ![ catch { mem2array foo 32 $ADDR 1 } msg ] {
+ return $foo(0)
+ } else {
+ error "memead32: $msg"
+ }
+}
+
+proc memread16 {ADDR } {
+ set foo(0) 0
+ if ![ catch { mem2array foo 16 $ADDR 1 } msg ] {
+ return $foo(0)
+ } else {
+ error "memead16: $msg"
+ }
+}
+
+proc memread82 {ADDR } {
+ set foo(0) 0
+ if ![ catch { mem2array foo 8 $ADDR 1 } msg ] {
+ return $foo(0)
+ } else {
+ error "memead8: $msg"
+ }
+}
+
+
diff --git a/src/tcl/mmr_helpers.tcl b/src/tcl/mmr_helpers.tcl
new file mode 100644
index 00000000..5dac48a8
--- /dev/null
+++ b/src/tcl/mmr_helpers.tcl
@@ -0,0 +1,59 @@
+
+proc proc_exists { NAME } {
+ set n [info commands $NAME]
+ set l [string length $n]
+ return [expr $l != 0]
+}
+
+# Give: REGISTER name - must be a global variable.
+proc show_mmr32_reg { NAME } {
+
+ global $NAME
+ # we want $($NAME)
+ set a [set [set NAME]]
+
+ if ![catch { set v [memread32 $a] } msg ] {
+ puts [format "%10s: (0x%08x): 0x%08x" $NAME $a $v]
+
+ # Was a helper defined?
+ set fn show_${NAME}_helper
+ if [ proc_exists $fn ] {
+ # Then call it
+ $fn $NAME $a $v
+ }
+ return $v;
+ } else {
+ error [format "%s (%s)" $msg $NAME ]
+ }
+}
+
+
+# Give: NAMES - an array of names accessable
+# in the callers symbol-scope.
+# VAL - the bits to display.
+
+proc show_mmr32_bits { NAMES VAL } {
+
+ upvar $NAMES MYNAMES
+
+ set w 0
+ foreach {IDX N} $MYNAMES {
+ set l [string length $N]
+ if { $l > $w } { set w $l }
+ }
+
+ for { set x 24 } { $x >= 0 } { incr x -8 } {
+ puts -nonewline " "
+ for { set y 7 } { $y >= 0 } { incr y -1 } {
+ set s $MYNAMES([expr $x + $y])
+ puts -nonewline [format "%2d: %-*s | " [expr $x + $y] $w $s ]
+ }
+ puts ""
+
+ puts -nonewline " "
+ for { set y 7 } { $y >= 0 } { incr y -1 } {
+ puts -nonewline [format " %d%*s | " [expr !!($VAL & (1 << ($x + $y)))] [expr $w -1] ""]
+ }
+ puts ""
+ }
+}
diff --git a/src/tcl/readable.tcl b/src/tcl/readable.tcl
new file mode 100644
index 00000000..39f43caa
--- /dev/null
+++ b/src/tcl/readable.tcl
@@ -0,0 +1,25 @@
+proc iswithin { ADDRESS BASE LEN } {
+ return [expr ((($ADDRESS - $BASE) > 0) && (($ADDRESS - $BASE + $LEN) > 0))]
+}
+
+proc memorytype { ADDRESS } {
+ for { set chip 0 } { $chip < $N_CHIP } { incr chip } {
+ if { iswithin $ADDRESS $FLASH($chip,BASE) $FLASH($chip,LEN) } {
+ return "flash"
+ }
+ }
+
+ for { set chip 0 } { $chip < $N_RAM } { incr chip } {
+ if { iswithin $ADDRESS $RAM($chip,BASE) $RAM($chip,LEN) } {
+ return "ram"
+ }
+ }
+}
+
+# default to 32bit reads.
+proc isreadable { ADDRESS } {
+ return isreadable32 $ADDRESS
+}
+
+proc isreadable32 { ADDRESS } {
+ \ No newline at end of file