#ifndef AVREMU_CPU_H_ #define AVREMU_CPU_H_ #include "util.h" #include "memory.h" #include #include #include #include #define AVR_VECTOR_RESET 0x000 /* Status register bits. */ #define SREG_C_BIT 0 #define SREG_C (1 << SREG_C_BIT) /* Carry */ #define SREG_Z_BIT 1 #define SREG_Z (1 << SREG_Z_BIT) /* Zero */ #define SREG_N_BIT 2 #define SREG_N (1 << SREG_N_BIT) /* Negative */ #define SREG_V_BIT 3 #define SREG_V (1 << SREG_V_BIT) /* Two's complement overflow */ #define SREG_S_BIT 4 #define SREG_S (1 << SREG_S_BIT) /* Sign */ #define SREG_H_BIT 5 #define SREG_H (1 << SREG_H_BIT) /* Half carry */ #define SREG_T_BIT 6 #define SREG_T (1 << SREG_T_BIT) /* Bit copy storage */ #define SREG_I_BIT 7 #define SREG_I (1 << SREG_I_BIT) /* Global IRQ enable */ /* Instruction identifiers for lazy SREG flags evaluation. */ enum lazy_flag_insn { /* Instructions with 8-bit operands. */ INSN_SBCI, INSN_SUBI, INSN_ORI, INSN_ANDI, INSN_CPI, INSN_COM, INSN_NEG, INSN_DEC, INSN_INC, INSN_LSR, INSN_ROR, INSN_ASR, INSN_CPC, INSN_SBC, INSN_ADD, INSN_CP, INSN_SUB, INSN_ADC, INSN_AND, INSN_EOR, INSN_OR, /* Instructions with 16-bit operands */ INSN_ADIW, INSN_SBIW, /* The total number of lazy flag instructions. */ NR_LAZYFLAG_INSNS, /* The first instruction with 16-bit operands. */ FIRST_16BIT_INSN = INSN_ADIW, }; /* Context data for fetching a lazy sreg flag. */ struct lazy_flag { union { /* 8-bit operations */ struct { /* The operands to the instruction. */ uint8_t op[2]; /* The operation result. */ uint8_t res; }; /* 16-bit operations */ struct { /* The operands to the instruction. */ uint16_t op16[2]; /* The operation result. */ uint16_t res16; }; }; }; struct avr_irq_descriptor { struct list_head list; /* The vector to jump to. */ uint8_t vector; }; #define MAX_IRQS_PENDING 0xFF #define AVR_NR_REGS 32 /* The AVR CPU */ struct avr_cpu { /* Program counter. * The PC addresses 16-bit words (not bytes). */ uint32_t pc; /* The PC where to break execution. */ uint32_t breakpoint; /* Array of general purpose registers */ uint8_t *r; /* SREG flags bitmap. * Look at sreg_valid bitmap to check whether a bit in "sreg" is valid. */ uint8_t sreg; /* Bitmap of the valid flags in the "sreg" bitmap. If a flag * is invalid but needed it must be fetched lazyly. */ uint8_t sreg_valid; /* Per-SREG-flag array of pointers to lazy_flag data structures. */ struct lazy_flag *sreg_lazy[8]; /* Per-instruction lazy_flag operand cache. */ struct lazy_flag lazy_flag_cache[NR_LAZYFLAG_INSNS]; /* Used to trap the CPU at a safe point from another thread. */ uint8_t trap; pthread_mutex_t trap_mutex; pthread_cond_t trapped_cond; /* Interrupts */ uint8_t irqs_pending; struct list_head irqdesc_pending; struct list_head irqdesc_cache; pthread_spinlock_t irq_lock; void *irq_cache_p; /* Only used for freeing the data. */ bool initialized; bool running; /* Statistics */ /* CPU cycle counter. */ uint64_t cycles_count; /* Interrupt counter. */ uint64_t irq_count; }; /* Pointer registers */ #define X_LO 26 #define X_HI 27 #define Y_LO 28 #define Y_HI 29 #define Z_LO 30 #define Z_HI 31 /* Initialize and reset the CPU data structures. */ int cpu_initialize(const char *bin, size_t bin_size); void cpu_exit(void); int cpu_reset(void); void dump_cpu(FILE *fd); /* API for trapping and liberating the CPU from another thread. * The CPU will be trapped before it fetches the next instruction. */ enum cpu_trap_id { CPU_TRAP_CONTINUE = 0, CPU_TRAP_WAIT, CPU_TRAP_SINGLESTEP, CPU_TRAP_EXIT, /* Shutdown the CPU. */ }; int trap_cpu(uint8_t id, bool synchronize); /* Trigger an interrupt on the CPU. * This will return -EBUSY if there are already * MAX_IRQS_PENDING irqs pending. */ int cpu_trigger_interrupt(uint8_t vector); extern struct avr_cpu cpu; #endif /* AVREMU_CPU_H_ */