Skip to content

jpmonettas/clj-avr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Clojure[Script] AVR emulator and disassembler

WIP, not all instructions are supported yet, but enough to run simple programs

Emulator and disassembler

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

Other useful tools:

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)}
;; ...
;; ...)

Projects currently using clj-avr

About

AVR micros related stuff

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published