summaryrefslogtreecommitdiffstats
path: root/emulator/cpu.h
blob: 6674ad6f10b44c7e7d840f2f353d85f83af0799b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#ifndef AVREMU_CPU_H_
#define AVREMU_CPU_H_

#include "util.h"
#include "memory.h"

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <pthread.h>


#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_ */
bues.ch cgit interface