WIP, not all instructions are supported yet, but enough to run simple programs
Given this simple factorial C program:
int factorial(int n){
if (n == 0) {
return 1;
} else {
return n * factorial(n-1);
}
}
int main(void){
return factorial(5);
}
Lets compile it with avr-gcc into a Intel Hex file:
avr-g++ -c -g -O0 -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -MMD -flto -mmcu=atmega328p -DF_CPU=16000000L factorial.c -o factorial.o
avr-gcc -w -Os -g -flto -fuse-linker-plugin -Wl,--gc-sections -mmcu=atmega328p -o factorial.elf factorial.o
avr-objcopy -O ihex -R .eeprom factorial.elf factorial.hex
avr-objdump -m avr -D factorial.hex
Now we can load the hex file and disassemble it using clj-avr disassembler:
(require '[clj-avr.hex-loader :as hex-loader])
(require '[clj-avr.disassembler :as da])
(def fact-disassm (-> "./resources/factorial.hex"
slurp
hex-loader/parse-hex
da/disassemble-hex))
;; =>
;; ({:op/args [:addr],
;; :addr 52,
;; :op/bytes-cnt 4,
;; :op/pattern "1001010kkkkk110kkkkkkkkkkkkkkkkk",
;; :op/pattern-vars {\k "0000000000000000110100"},
;; :op :jmp,
;; :op/bytes 2483814452,
;; :memory/address 0}
;; {:memory/address 104,
;; :src-reg 1,
;; :op/pattern-vars {\r "00001", \d "00001"},
;; :op/bytes 9233,
;; :op :eor,
;; :dst-reg 1,
;; :op/args [:dst-reg :src-reg],
;; :op/bytes-cnt 2,
;; :op/pattern "001001rdddddrrrr"}
;; {:memory/address 106,
;; :src-reg 1,
;; :op/pattern-vars {\a "111111", \r "00001"},
;; :op/bytes 48671,
;; :op :out,
;; :op/args [:io-reg :src-reg],
;; :op/bytes-cnt 2,
;; :io-reg 63,
;; :op/pattern "10111aarrrrraaaa"}
;; {:memory/address 108,
;; :op/pattern-vars {\k "11111111", \d "1100"},
;; :op/bytes 61391,
;; :op :ldi,
;; :dst-reg 28,
;; :op/args [:dst-reg :const],
;; :const 255,
;; :op/bytes-cnt 2,
;; :op/pattern "1110kkkkddddkkkk"}
;; {:memory/address 110,
;; :op/pattern-vars {\k "00001000", \d "1101"},
;; :op/bytes 57560,
;; :op :ldi,
;; :dst-reg 29,
;; :op/args [:dst-reg :const],
;; :const 8,
;; :op/bytes-cnt 2,
;; :op/pattern "1110kkkkddddkkkk"}
;; ...)
;; And you ca also print it :
(da/print-disassemble fact-disassm)
;; 0x00000000 jmp 0x68
;; 0x00000068 eor r1, r1
;; 0x0000006a out 0x3f, r1
;; 0x0000006c ldi r28, 0xff
;; 0x0000006e ldi r29, 0x08
;; ...
We can also emulate the entire program:
(require '[clj-avr.hex-loader :as hex-loader])
(require '[clj-avr.emulator :as emu])
(-> (emu/empty-emu)
(emu/load-prog (hex-loader/parse-hex (slurp "./resources/factorial.hex")))
(emu/run)
(emu/get-reg-by-addr 24))
;;=> 120
You can load Intel HEX files using clj-avr.hex-loader:
(require '[clj-avr.hex-loader :as hex-loader])
(-> "./resources/Blink.ino.hex"
slurp
hex-loader/parse-hex)
;; =>
;; ({:type :data,
;; :address 0,
;; :data (12 148 92 0 12 148 110 0 12 148 110 0 12 148 110 0)}
;; {:type :data,
;; :address 16,
;; :data (12 148 110 0 12 148 110 0 12 148 110 0 12 148 110 0)}
;; {:type :data,
;; :address 32,
;; :data (12 148 110 0 12 148 110 0 12 148 110 0 12 148 110 0)}
;; ...
;; ...)