1. Brief introduction So, we are chip. We have not any IO devices, we have only a few pins. We have three address spaces: FLASH for instruction codes, 2-byte bigendian EEPROM for long time data, like hard drive RAM for other data, addressing by instructions. The first 32 bytes of RAM space named "registers" and can be effectivly accessed by two-operand instructios. The next 64 bytes of RAM space named "io", can be accessed by special instructions and correspond to our different pins and internal modules, like timers. The rest of RAM named SRAM, it's just common space, stack and so on. What does imavr do? When starts, it open files proc/FLASH, proc/RAM and proc/EEPROM. The FLASH should exist, the rest two imavr can create automatically. If size of FLASH is less then we should have, the rest is filled with 0xff, like in real chip, unprogrammed memory reads as -1. RAM is inithialised according to ATMEL specification, but registries and SRAM in real chip are unchanged while reset signal, so, we can keep them. Before start imavr, you should prepare proc/FLASH. It can be done, for example, by following scenario (see my makefiles in examples): avr-as -o main.o main.s avr-ld -o main.elf main.o avr-objcopy main.elf -O binary -R .text proc/FLASH Also before start imavr you should prepare .imavr config file. It's simple enough: the first line should be chip name and optional start address. The rest line starts with '+' or '-', followed by module name and optional module parameters. Available chip names and modules one can see with "imavr -v". As we are chip, we can not stop, execution starts immediatly from the first word of proc/FLASH. As we are chip, we understand only binary data. Our internal loop do the following: 1. Update proc/RAM and proc/FLASH via mmap technology. 2. If we are in "step" mode, print out disassembled current instruction and ask for user command. 3. Execute one instruction. The execution module checks for interrupt conditions and, if so, not execute current instruction - just pushed PC, clear condition and set PC to interrupt vector. 4. Execute all internal modules, enabled in .imavr. You can enable only modules you work with, it's increase the speed of emulation. Anothre apporach - enable all modules, it's real chip, each module can influense for result of execution. 5. If enabled +external, execute all external modules. Each external module, wants to be executed, should write his unix pid in proc/*.pid file. In this case, we send SIGUSR1 for him. Module can share our IO space, change it, perform any interraction with user in independent window. In our examples - external module is COM-port, connected to UART pins of chip. 6. Continue. In "step mode" we support only a few commands now: g[,break_addr] automatic execution, leave step mode t step "into" procedure, in case of call command d[addr] disassembler FLASH space execute one step q quit While automatic execution, you can press Ctrl/c (break) to enter step mode. It's recommended use different windows for debugging, starts imavr in one of them, and study proc/registers and so on in others. You can watch memory by any binary dump program. for example, hd proc/RAM. imavr can understand name in any place your shoul put addr. Names are obtained from elf binary, default from a.out. We suggest comiple program with -gstab, in this case imavr has access to source lines. You can enable or disable source mode with s+ or s-. 2. External module sinchronization The problem is: we have only one Unix CPU, it's not very much, We want emulate several devices. In fact, we could not do it in real time. After chip changes IO, we should be sure, that other devices can see it, catches processor quantum from main CPU. The solution is: imavr execute nice(20) near the start of his main. All external modules sholud have higher priority and wait signal by pause() call. After each instruction imavr sends SIGUSR1 to externals, it stops the execution of imavr until all modules executes new pause(). Maybe, it's not the best solution, maybe, it should be better to send some kind of marker between modules. But it works good in my applications, it's effective, it's enough. 3. Special case for UART/USART internal module In many cases embeded systems are connected to "human" interface via UART/USART. imavr help to debug it. There can be two parameters in .imavr after modulo name, for example, +USART .pcget .pcput In this case imavr creates two pipe-files (man mkfifo), which can be used for characters interchange by flash program requests. imavr package has special utility - imtty. You can run it in independent window and perform full dialog with your flash program.