''[JM] 14 Nov 2012'' - After "[Playing Assembler]" a little bit, and looking at the [RS] comments that says: "''Of course this is no real assembler. The memory model is constant-size instructions...''", that just sounded like how the PIC microcontroller is arranged [http://en.wikipedia.org/wiki/PIC_micro#Code_space]<
>
So I took a section of a PIC's working code (a loop that fills a RAM buffer for a later transfer to a LCD) and tweak [Playing Assembler] with a few of the PIC's instruction set.<
>
the example shows a RAM buffer (from 30H to 3FH) filled with values descending from 30H to 21H. The real thing in hardware shows all the possible charactes a LCD can display.[http://www.add.ece.ufl.edu/4744/docs/lcdmanual/characterset.html]
======
console show
namespace eval asm {
proc asm body {
variable mem
catch {unset mem} ;# good for repeated sourcing
foreach line [split $body \n] {
foreach i {label op args} {set $i ""}
regexp {([^;]*);} $line -> line ;# strip off comments
regexp {^ *(([A-Z0-9]+):)? *([A-Z]*) +(.*)} [string toupper $line]\
-> - label op args
# puts label=$label,op=$op,args=$args
if {$label!=""} {set sym($label) $PC}
if {$op==""} continue
if {$op=="DB"} {set mem($PC) [convertHex $args]; incr PC; continue}
if {$op=="EQU"} {set sym($label) [convertHex $args]; continue}
if {$op=="ORG"} {
set PC [convertHex $args]
continue
}
regsub -all ", *" $args " " args ;# normalize commas
set mem($PC) "$op $args"
incr PC
}
substituteSymbols sym
dump sym
}
proc convertHex s {
set s [string trim $s]
#tk_messageBox -message $s
if [regexp {^H'([0-9A-F]+)'$} $s -> s] {set s [expr 0x$s]}
if [regexp {^D'([0-9A-F]+)'$} $s -> s] {set s $s}
set s
}
proc substituteSymbols {_sym} {
variable mem
upvar $_sym sym
foreach i [array names mem] {
set tmp [lindex $mem($i) 0]
foreach j [lrange $mem($i) 1 end] {
if {[array names sym $j]==$j} {set j $sym($j)}
lappend tmp $j
}
set mem($i) $tmp
}
}
proc dump {_sym} {
variable mem
variable ram
upvar $_sym sym
puts "\n dump...prog memory"
foreach i [lsort -integer [array names mem]] {
puts [format " %04d %s" $i $mem($i)]
}
puts "\n dump...sym names"
foreach i [lsort [array names sym]] {
puts [format " %-10s: %04x" $i $sym($i)]
}
}
proc run {{pc 0}} {
puts "\n running ASM program..."
#incr pc -1
variable mem
foreach i {A B C D E Z W} {set ::$i 0}
#tk_messageBox -message "pc: $pc: $mem($pc)"
while {$pc>=0} {
incr pc
#tk_messageBox -message "pc: $pc: $mem($pc)"
if {[info exists mem($pc)]} {
#puts "$mem($pc)\tA:$::A B:$::B C:$::C D:$::D E:$::E Z:$::Z"
#tk_messageBox -message "$mem($pc)\tA:$::A B:$::B C:$::C D:$::D E:$::E Z:$::Z"
eval $mem($pc)
} else {
break
}
}
puts " ASM program ended..."
}
#----------------- "machine opcodes" implemented as procs
proc SHOWRAM dummyNr {
variable ram
puts "---RAM dump"
foreach i [lsort [array names ram]] {
puts "$i: $ram($i)"
}
}
proc ADDWF {adr dest} {
variable ram
if {$dest == "W"} {
set ::W [expr $ram($adr) + $::W]
} else {
set ram($adr) [expr $ram($adr) + $::W]
}
}
proc CALL {name} {[string tolower $name] $::W}
proc GOTO adr {
#tk_messageBox -message "GOTO $adr"
uplevel 1 set pc [expr $adr - 1]
}
proc INCF adr {
variable ram
set ram($adr) [expr $ram($adr) + 1]
}
proc DECFSZ adr {
variable ram
set ram($adr) [expr $ram($adr) - 1]
if {$ram($adr) == 0} {uplevel 1 set pc [expr [uplevel 1 set pc] +1]}
}
proc MOV {reg adr} {variable mem; set ::$reg $mem($adr)}
proc MOVWF adr {
variable ram
if {$adr == "INDF"} {
set fsrC $ram(FSR)
set ram($fsrC) $::W
} else {
set ram($adr) $::W
}
}
proc MOVFW adr {
variable ram
set ::W $ram($adr)
}
proc MVI {reg value} {set ::$reg $value}
proc MOVLW value {set ::W [convertHex $value]}
}
#-- Now testing:
asm::asm {
org 0 ; the canonical start address in PICs
movlw 0
movwf offset
movlw H'20'
movwf chrix
movlw H'30'
movwf FSR
movlw D'16'
movwf counter
WEER: movfw counter
addwf chrix,w
movwf INDF
;call puts
incf FSR
decfsz counter
goto weer
incf offset
incf chrix
end
}
asm::run
puts "\n RAM after run:"
puts " addr contents"
puts " ---- --"
foreach i [lsort [array names asm::ram]] {
#puts "$i [string is integer $i]"
if [string is integer $i] {
puts [format " %04x: %02x (%c)" $i $asm::ram($i) $asm::ram($i)]
} else {
puts [format " %-10s: %02x" $i $asm::ram($i)]
}
}
======
When running the example, the outputs is:
dump...prog memory
0000 MOVLW 0
0001 MOVWF OFFSET
0002 MOVLW H'20'
0003 MOVWF CHRIX
0004 MOVLW H'30'
0005 MOVWF FSR
0006 MOVLW D'16'
0007 MOVWF COUNTER
0008 MOVFW COUNTER
0009 ADDWF CHRIX W
0010 MOVWF INDF
0011 INCF FSR
0012 DECFSZ COUNTER
0013 GOTO 8
0014 INCF OFFSET
0015 INCF CHRIX
dump...sym names
WEER : 0008
running ASM program...
ASM program ended...
RAM after run:
addr contents
---- --
0030: 30 (0)
0031: 2f (/)
0032: 2e (.)
0033: 2d (-)
0034: 2c (,)
0035: 2b (+)
0036: 2a (*)
0037: 29 ())
0038: 28 (()
0039: 27 (')
003a: 26 (&)
003b: 25 (%)
003c: 24 ($)
003d: 23 (#)
003e: 22 (")
003f: 21 (!)
CHRIX : 21
COUNTER : 00
FSR : 40
OFFSET : 01
(code) 1 %
----
'''[Jorge] - 2012-11-15 16:57:13'''
* changed the ORG address to the canonical start address for PICs
* prepared the hex pattern for conversion to be H'nn'
* cleaned up the output to show RAM addresses in hex format also
----
'''[Jorge] - 2012-11-15 22:18:41'''
* the command addwf was fixed to properly use "d" as a switch to define if the result is to be stored in the file register itselt or the W register.
addwf chrix,w
* hex preffix was changed to H'nn' to follow MPLAB syntax (the well known 0x is also valid though not implemented here yet)
* default ORG address in run proc was set to 0
* the corresponding char is shown to illustrate which set of symbols are going to be displayed on LCD
<> Language | Tcl and other languages