Mercurial > repos > simple16
annotate src/cpu.c @ 0:7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 22 Mar 2016 22:44:02 -0700 |
parents | |
children | 6204c81e2933 |
rev | line source |
---|---|
0
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
1 #include <stdint.h> |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
2 #include <stdlib.h> |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
3 #include <string.h> |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
4 #include <stdio.h> |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
5 #include "cpu.h" |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
6 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
7 enum { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
8 EXCEPTION_INTERRUPT_0, |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
9 EXCEPTION_INTERRUPT_1, |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
10 EXCEPTION_UNALIGNED_READ, |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
11 EXCEPTION_INVALID_INSTRUCTION |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
12 }; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
13 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
14 enum { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
15 STATE_NEED_FETCH, |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
16 STATE_NORMAL, |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
17 STATE_EXCEPTION_START |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
18 }; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
19 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
20 #define STATUS_INT0_ENABLE 1 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
21 #define STATUS_INT1_ENABLE 2 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
22 #define FLAG_Z 4 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
23 #define FLAG_C 8 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
24 #define FLAG_N 16 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
25 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
26 #define REG_PC 14 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
27 #define REG_SR 15 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
28 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
29 cpu* alloc_cpu(uint32_t clock_divider, uint32_t num_regions, memory_region *regions) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
30 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
31 size_t alloc_size = sizeof(cpu) + sizeof(memory_region) * num_regions; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
32 cpu *context = malloc(alloc_size); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
33 memset(context, 0, alloc_size); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
34 context->clock_inc = clock_divider; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
35 context->num_mem_regions = num_regions; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
36 memcpy(context->mem_regions, regions, num_regions*sizeof(memory_region)); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
37 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
38 return context; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
39 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
40 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
41 uint16_t cpu_read_16(cpu *context, uint16_t address) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
42 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
43 context->cycles += context->clock_inc; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
44 if (address & 1) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
45 context->exception = EXCEPTION_UNALIGNED_READ; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
46 context->state = STATE_EXCEPTION_START; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
47 return 0xFFFF; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
48 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
49 memory_region *cur = context->mem_regions; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
50 for (memory_region *end = cur + context->num_mem_regions; cur < end; cur++) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
51 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
52 if (address >= cur->start && address <= cur->end && (cur->flags & MEM_READ)) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
53 return cur->base[address - cur->start] << 8 | cur->base[address - cur->start + 1]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
54 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
55 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
56 return 0xFFFF; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
57 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
58 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
59 uint8_t cpu_read_8(cpu *context, uint16_t address) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
60 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
61 context->cycles += context->clock_inc; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
62 memory_region *cur = context->mem_regions; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
63 for (memory_region *end = cur + context->num_mem_regions; cur < end; cur++) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
64 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
65 if (address >= cur->start && address <= cur->end && (cur->flags & MEM_READ)) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
66 return cur->base[address - cur->start]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
67 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
68 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
69 return 0xFF; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
70 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
71 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
72 void cpu_write_16(cpu *context, uint16_t address, uint16_t value) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
73 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
74 context->cycles += context->clock_inc; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
75 if (address & 1) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
76 context->exception = EXCEPTION_UNALIGNED_READ; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
77 context->state = STATE_EXCEPTION_START; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
78 return; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
79 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
80 memory_region *cur = context->mem_regions; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
81 for (memory_region *end = cur + context->num_mem_regions; cur < end; cur++) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
82 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
83 if (address >= cur->start && address <= cur->end && (cur->flags & MEM_WRITE)) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
84 cur->base[address - cur->start] = value >> 8; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
85 cur->base[address - cur->start + 1] = value; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
86 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
87 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
88 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
89 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
90 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
91 void cpu_write_8(cpu *context, uint16_t address, uint8_t value) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
92 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
93 context->cycles += context->clock_inc; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
94 memory_region *cur = context->mem_regions; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
95 for (memory_region *end = cur + context->num_mem_regions; cur < end; cur++) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
96 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
97 if (address >= cur->start && address <= cur->end && (cur->flags & MEM_WRITE)) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
98 cur->base[address - cur->start] = value; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
99 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
100 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
101 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
102 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
103 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
104 uint16_t cpu_read_port(cpu *context, uint8_t port) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
105 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
106 port &= 0xF; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
107 if (context->port_handlers[port].read) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
108 return context->port_handlers[port].read(context, port); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
109 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
110 return 0xFFFF; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
111 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
112 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
113 void cpu_write_port(cpu *context, uint8_t port, uint16_t value) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
114 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
115 port &= 0xF; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
116 if (context->port_handlers[port].write) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
117 context->port_handlers[port].write(context, port, value); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
118 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
119 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
120 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
121 void fetch_instruction(cpu *context) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
122 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
123 context->prefetch = cpu_read_16(context, context->regs[REG_PC]); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
124 context->regs[REG_PC] += 2; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
125 context->state = STATE_NORMAL; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
126 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
127 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
128 void vector_fetch(cpu *context) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
129 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
130 context->exception_pc = context->regs[REG_PC] - 2; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
131 context->exception_sr = context->regs[REG_SR]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
132 context->regs[REG_SR] &= ~(STATUS_INT0_ENABLE | STATUS_INT1_ENABLE); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
133 context->regs[REG_PC] = cpu_read_16(context, context->vector_base + context->exception); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
134 context->state = STATE_NEED_FETCH; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
135 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
136 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
137 uint16_t sign_extend(uint16_t val) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
138 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
139 if (val & 0x80) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
140 return val | 0xFF00; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
141 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
142 return val; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
143 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
144 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
145 void update_flags_arith(cpu *context, uint32_t result) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
146 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
147 context->regs[REG_SR] &= ~(FLAG_N|FLAG_C|FLAG_Z); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
148 if (!(result & 0xFFFF)) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
149 context->regs[REG_SR] |= FLAG_Z; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
150 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
151 if (result &= 0x8000) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
152 context->regs[REG_SR] |= FLAG_N; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
153 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
154 if (result &= 0x10000) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
155 context->regs[REG_SR] |= FLAG_C; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
156 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
157 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
158 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
159 void update_flags_bitwise(cpu *context, uint32_t result) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
160 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
161 context->regs[REG_SR] &= ~(FLAG_N|FLAG_Z); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
162 if (!(result & 0xFFFF)) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
163 context->regs[REG_SR] |= FLAG_Z; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
164 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
165 if (result &= 0x8000) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
166 context->regs[REG_SR] |= FLAG_N; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
167 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
168 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
169 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
170 void run_bcc(cpu *context, uint8_t condition, uint8_t a, uint8_t b) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
171 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
172 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
173 uint8_t doit = 0; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
174 switch (condition) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
175 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
176 case COND_ALWAYS: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
177 doit = 1; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
178 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
179 case COND_NEVER: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
180 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
181 case COND_ZERO: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
182 doit = context->regs[REG_SR] & FLAG_Z; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
183 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
184 case COND_NZERO: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
185 doit = !(context->regs[REG_SR] & FLAG_Z); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
186 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
187 case COND_NEG: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
188 doit = context->regs[REG_SR] & FLAG_N; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
189 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
190 case COND_POS: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
191 doit = !(context->regs[REG_SR] & FLAG_N); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
192 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
193 case COND_CARRY: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
194 doit = context->regs[REG_SR] & FLAG_C; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
195 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
196 case COND_NCARRY: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
197 doit = context->regs[REG_SR] & FLAG_C; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
198 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
199 case COND_GREATER: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
200 //not zero and not carry |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
201 doit = !(context->regs[REG_SR] & FLAG_Z) || !(context->regs[REG_SR] & FLAG_C); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
202 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
203 case COND_LEQ: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
204 //zero or carry |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
205 doit = (context->regs[REG_SR] & FLAG_Z) || (context->regs[REG_SR] & FLAG_C); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
206 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
207 default: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
208 context->exception = EXCEPTION_INVALID_INSTRUCTION; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
209 context->state = STATE_EXCEPTION_START; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
210 return; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
211 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
212 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
213 if (doit) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
214 context->regs[REG_PC] += sign_extend(a << 4 | b) * 2; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
215 context->state = STATE_NEED_FETCH; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
216 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
217 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
218 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
219 uint16_t format_immediate_bitwise(uint16_t val) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
220 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
221 if (val & 8) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
222 val |= 0xFFF0; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
223 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
224 return val; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
225 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
226 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
227 uint16_t format_immediate(uint16_t val) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
228 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
229 val = format_immediate_bitwise(val); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
230 if (!val) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
231 val = 8; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
232 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
233 return val; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
234 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
235 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
236 void run_single_reg(cpu *context, uint8_t dst, uint8_t op) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
237 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
238 switch(op) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
239 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
240 case RETI: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
241 context->regs[dst] = context->exception_ur; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
242 context->regs[REG_PC] = context->exception_pc; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
243 context->regs[REG_SR] = context->exception_sr; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
244 context->state = STATE_NEED_FETCH; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
245 return; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
246 case TRAP: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
247 context->state = STATE_EXCEPTION_START; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
248 context->exception = context->regs[dst]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
249 return; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
250 case TRAPI: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
251 context->state = STATE_EXCEPTION_START; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
252 context->exception = dst; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
253 return; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
254 case GETEPC: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
255 context->regs[dst] = context->exception_pc; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
256 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
257 case SETEPC: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
258 context->exception_pc = context->regs[dst]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
259 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
260 case GETESR: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
261 context->regs[dst] = context->exception_sr; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
262 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
263 case SETESR: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
264 context->exception_sr = context->regs[dst]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
265 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
266 case GETEUR: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
267 context->regs[dst] = context->exception_ur; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
268 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
269 case SETEUR: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
270 context->exception_ur = context->regs[dst]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
271 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
272 case GETENUM: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
273 context->regs[dst] = context->exception; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
274 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
275 case SETENUM: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
276 context->exception = context->regs[dst]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
277 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
278 default: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
279 context->state = STATE_EXCEPTION_START; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
280 context->exception = EXCEPTION_INVALID_INSTRUCTION; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
281 return; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
282 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
283 if (dst == REG_PC) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
284 context->state = STATE_NEED_FETCH; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
285 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
286 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
287 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
288 void run_single_source(cpu *context, uint8_t dst, uint8_t a, uint8_t op) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
289 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
290 uint32_t tmp; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
291 uint8_t shift; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
292 switch(op) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
293 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
294 case MOVE: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
295 context->regs[dst] = context->regs[a]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
296 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
297 case NEG: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
298 tmp = -context->regs[a]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
299 context->regs[dst] = tmp; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
300 update_flags_arith(context, tmp); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
301 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
302 case NOT: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
303 context->regs[dst] = ~context->regs[a]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
304 update_flags_bitwise(context, context->regs[dst]); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
305 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
306 case CMP: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
307 tmp = context->regs[dst] - context->regs[a]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
308 update_flags_arith(context, tmp); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
309 return; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
310 case CALL: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
311 context->regs[dst] = context->regs[REG_PC] - 2; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
312 context->regs[REG_PC] = context->regs[a]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
313 context->state = STATE_NEED_FETCH; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
314 return; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
315 case SWAP: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
316 tmp = context->regs[dst]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
317 context->regs[dst] = context->regs[a]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
318 context->regs[a] = tmp; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
319 if (a == REG_PC) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
320 context->state = STATE_NEED_FETCH; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
321 return; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
322 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
323 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
324 case IN: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
325 context->regs[dst] = cpu_read_port(context, context->regs[a]); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
326 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
327 case OUT: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
328 cpu_write_port(context, context->regs[a], context->regs[dst]); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
329 return; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
330 case INI: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
331 context->regs[dst] = cpu_read_port(context, a); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
332 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
333 case OUTI: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
334 cpu_write_port(context, a, context->regs[dst]); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
335 return; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
336 case ADDI: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
337 tmp = context->regs[dst] + format_immediate(a); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
338 context->regs[dst] = tmp; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
339 update_flags_arith(context, tmp); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
340 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
341 case ANDI: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
342 context->regs[dst] = context->regs[dst] & format_immediate_bitwise(a); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
343 update_flags_bitwise(context, context->regs[dst]); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
344 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
345 case ORI: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
346 context->regs[dst] = context->regs[dst] | format_immediate_bitwise(a); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
347 update_flags_bitwise(context, context->regs[dst]); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
348 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
349 case LSI: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
350 shift = a & 7; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
351 if (!shift) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
352 shift = 8; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
353 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
354 if (a & 8) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
355 tmp = context->regs[dst] >> shift; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
356 tmp |= (context->regs[dst] >> (shift - 1)) << 16 & 0x10000; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
357 } else { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
358 tmp = context->regs[dst] << (a & 7); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
359 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
360 context->regs[dst] = tmp; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
361 update_flags_arith(context, tmp); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
362 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
363 case ASRI: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
364 shift = a; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
365 if (!shift) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
366 shift = 16; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
367 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
368 tmp = context->regs[dst]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
369 if (tmp & 0x8000) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
370 tmp |= 0xFFFF0000; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
371 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
372 tmp = tmp >> shift & 0xFFFF; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
373 tmp |= (context->regs[dst] >> (context->regs[shift] - 1)) << 16 & 0x10000; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
374 context->regs[dst] = tmp; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
375 update_flags_arith(context, tmp); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
376 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
377 case SINGLE_REG: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
378 run_single_reg(context, dst, a); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
379 return; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
380 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
381 if (dst == REG_PC) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
382 context->state = STATE_NEED_FETCH; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
383 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
384 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
385 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
386 char * mnemonics[] = { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
387 "ldim", "ldimh", "ld8", "ld16", "str8", "str16", "add", "adc", "and", "or", "xor", "lsl", "lsr", "asr", "bcc", "single" |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
388 }; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
389 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
390 void run_instruction(cpu *context) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
391 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
392 uint16_t instruction = context->prefetch; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
393 fetch_instruction(context); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
394 uint8_t dst = instruction >> 12; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
395 uint8_t a = instruction >> 8 & 0xF; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
396 uint8_t b = instruction >> 4 & 0xF; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
397 uint8_t op = instruction & 0xF; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
398 uint32_t tmp; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
399 switch (op) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
400 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
401 case LDIM: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
402 context->regs[dst] = sign_extend(a << 4 | b); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
403 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
404 case LDIMH: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
405 context->regs[dst] &= 0xFF; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
406 context->regs[dst] |= a << 12 | b << 8; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
407 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
408 case LD8: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
409 context->regs[dst] = cpu_read_8(context, context->regs[a] + context->regs[b]); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
410 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
411 case LD16: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
412 context->regs[dst] = cpu_read_16(context, context->regs[a] + context->regs[b]); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
413 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
414 case STR8: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
415 cpu_write_8(context, context->regs[a] + context->regs[b], context->regs[dst]); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
416 return; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
417 case STR16: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
418 cpu_write_16(context, context->regs[a] + context->regs[b], context->regs[dst]); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
419 return; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
420 case ADD: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
421 tmp = context->regs[a] + context->regs[b]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
422 context->regs[dst] = tmp; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
423 update_flags_arith(context, tmp); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
424 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
425 case ADC: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
426 tmp = context->regs[a] + context->regs[b] + (context->regs[REG_SR] & FLAG_C ? 1 : 0); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
427 context->regs[dst] = tmp; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
428 update_flags_arith(context, tmp); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
429 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
430 case AND: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
431 context->regs[dst] = context->regs[a] & context->regs[b]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
432 update_flags_bitwise(context, context->regs[dst]); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
433 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
434 case OR: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
435 context->regs[dst] = context->regs[a] | context->regs[b]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
436 update_flags_bitwise(context, context->regs[dst]); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
437 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
438 case XOR: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
439 context->regs[dst] = context->regs[a] ^ context->regs[b]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
440 update_flags_bitwise(context, context->regs[dst]); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
441 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
442 case LSL: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
443 tmp = context->regs[a] << context->regs[b]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
444 context->regs[dst] = tmp; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
445 update_flags_arith(context, tmp); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
446 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
447 case LSR: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
448 tmp = context->regs[a] >> context->regs[b]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
449 tmp |= (context->regs[a] >> (context->regs[b] - 1)) << 16 & 0x10000; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
450 context->regs[dst] = tmp; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
451 update_flags_arith(context, tmp); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
452 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
453 case ASR: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
454 tmp = context->regs[a]; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
455 if (tmp & 0x8000) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
456 tmp |= 0xFFFF0000; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
457 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
458 tmp = tmp >> context->regs[b] & 0xFFFF; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
459 tmp |= (context->regs[a] >> (context->regs[b] - 1)) << 16 & 0x10000; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
460 context->regs[dst] = tmp; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
461 update_flags_arith(context, tmp); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
462 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
463 case BCC: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
464 run_bcc(context, dst, a, b); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
465 return; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
466 case SINGLE_SOURCE: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
467 run_single_source(context, dst, a, b); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
468 return; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
469 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
470 if (dst == REG_PC) { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
471 context->state = STATE_NEED_FETCH; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
472 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
473 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
474 |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
475 void run_cpu(cpu *context, uint32_t target_cycle) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
476 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
477 while (context->cycles < target_cycle) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
478 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
479 switch (context->state) |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
480 { |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
481 case STATE_NEED_FETCH: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
482 fetch_instruction(context); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
483 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
484 case STATE_NORMAL: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
485 run_instruction(context); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
486 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
487 case STATE_EXCEPTION_START: |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
488 vector_fetch(context); |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
489 break; |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
490 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
491 } |
7e44f7d5810b
Initial commit. CPU working well enough for simple hello world program.
Michael Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
492 } |