Intel HEX format is the simple ASCII format usually used to program different devices (it's flash and EEPROM memories). To create such data records, I use this code:
package provide ihex 1.0
namespace eval ihex {
namespace export data EOF eraser
set EOF ":00000001FF"
proc verint {type value} {
# Verify that value is in the type range. Known types are b (byte),
# w (word), d (doubleword), q (quadword). If is out-of-range, then
# raise will be callen
set absvalue [::tcl::mathfunc::abs $value]
proc raise {t v} {
# Raise error message. t is type name, such as "word" or "quadword"
error [format "Value 0x%X is not a %s" $v $t]
}
switch -- $type {
b { if {$absvalue > 255} {raise byte $absvalue} }
w { if {$absvalue > 65536} {raise word $absvalue} }
d { if {$absvalue > 4294967296} {raise doubleword $absvalue} }
q { if {$absvalue > 18446744073709551616} {raise quadword $absvalue} }
}
return 1
}
proc args2bytes {args} {
# Converts args to list of bytes (binary form of args). See
# >>> args2bytes b1 w4A
# 01 00 4A
#
# Each arg is integer prefixed by b|w|d|q and is in hex-form.
set bytes [list]
foreach arg $args {
set r [scan $arg %1s%x argtype argvalue]
if {$r != 2} {
#puts "some string..."
continue
} else {
# verify value of argvalue (in type bounds)
verint $argtype $argvalue
# format argvalue into string
switch -- $argtype {
b {set fmt %02X}
w {set fmt %04X}
d {set fmt %08X}
q {set fmt %016X}
}
set sarg [format $fmt $argvalue]
set argbytes [regexp -all -inline .. $sarg]
set bytes [concat $bytes $argbytes]
}
}
return $bytes
}
proc crc {bytes} {
# Calculate Intel-hex CRC for list of bytes (usual numbers in hex format
# but without prefixes like b|w|d|q)
set sum 0
foreach b $bytes {
incr sum 0x$b
}
set sum [expr {(1 + ~$sum) & 0xFF}] ;# bcb
return $sum
}
proc data {address args} {
# Returns data record for Intel hex format. args are list of integers such
# b23 wAE... - byte 0x23, word 0x00AE
set bytes [args2bytes {*}$args]
set len [args2bytes [format b%X [llength $bytes]]]
set address [args2bytes $address]
set type 00
set cc [crc [concat {} $len $address $type $bytes]]
# Prepare output line
set head :$len[join $address ""]$type
set tail [join $bytes ""][format %02X $cc]
return $head$tail
}
proc join_eep {args} {
# Join eep data records (":LLAAAA00..." strings) into one data record with size <= 256.
# Does not check CRC of input records!
set MAXSZ 256 ; # DONT USE > 256!!!
# In the mem will be 256 "00 00 00..."
for {set i 0} {$i < $MAXSZ} {incr i} { lappend mem 00 }
set last_index 0
foreach rec $args {
set len [string range $rec 1 2]
set address [string range $rec 3 6]
set type [string range $rec 7 8]
if {"0x$type" != 0} { continue } ;# skip not data records
set bytes [string range $rec 9 end-2]
set bytes [regexp -all -inline .. $bytes]
#set ev [eval "expr {0x$address + 0x$len - 1}"]
set from "0x$address"; set to [expr {"0x$address" + "0x$len" - 1}]
set last_index [::tcl::mathfunc::max $last_index $to]
set replacing "lreplace \$mem $from $to $bytes"
set mem [eval $replacing]
}
set len [format b%X [expr {$last_index + 1}]]
set len [args2bytes $len]
set address "00 00"
set type 00
set mem [lrange $mem 0 $last_index]
set cc [crc [concat {} $len $address $type $mem]]
# Prepare output line
set head :$len[join $address ""]$type
set tail [join $mem ""][format %02X $cc]
return $head$tail
}
}
Procedure ihex::data is for create one record (ASCII line) from it's arguments as:
ihex::data b23 w0A
where each argument is value prefixed by b (for byte), w (for word), d (for doubleword), q (for quadword).
Procedure ihex::join_eep is used to "join" into one memory 256-bytes chunk several records. It's arguments are in form of ":LLAAAATTDD...DCC".
Procedure args2bytes is not exported but may be usable for creation bytes dump of it's arguments (also used b, w, d, q prefixes).
Комментариев нет:
Отправить комментарий
Thanks for your posting!