Mercurial > repos > blastem
comparison jagcpu_x86.c @ 1115:c1e78a101912
WIP Jaguar GPU/DSP emulation
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Mon, 19 Dec 2016 14:16:59 -0800 |
parents | |
children | 137dbd05ceab |
comparison
equal
deleted
inserted
replaced
1114:b45d1f64060e | 1115:c1e78a101912 |
---|---|
1 #include <stdint.h> | |
2 #include "backend.h" | |
3 #include "jagcpu.h" | |
4 #include "gen_x86.h" | |
5 | |
6 void jag_check_resultwrite(jag_cpu_options *opts, uint8_t src, uint8_t dst) | |
7 { | |
8 code_info *code = &opts->gen.code; | |
9 cmp_ir(code, JAGCPU_NOREG, opts->resultreg, SZ_B); | |
10 code_ptr no_result = code->cur + 1; | |
11 jcc(code, CC_Z, no_result + 1); | |
12 //save result to current bank | |
13 movzx_rr(code, opts->resultreg, opts->scratch1, SZ_B, SZ_D); | |
14 mov_rrindex(code, opts->result, opts->bankptr, opts->scratch1, 4, SZ_D); | |
15 | |
16 code_ptr writeback_penatly; | |
17 if (dst == src) { | |
18 //unclear if src and dst read can share a port if it's the same register | |
19 //assume that is the case for now | |
20 writeback_penalty = NULL; | |
21 } else { | |
22 cmp_ir(code, JAGCPU_NOREG, opts->writeback, SZ_B); | |
23 code_ptr no_writeback_penalty = code->cur + 1; | |
24 jcc(code, CC_Z, no_writeback_penalty + 1); | |
25 cmp_ir(code, src, opts->writeback, SZ_B); | |
26 code_ptr no_writeback_penalty2 = code->cur + 1; | |
27 jcc(code, CC_Z, no_writeback_penalty2 + 1); | |
28 cmp_ir(code, dst, opts->writeback, SZ_B); | |
29 writeback_penalty = code->cur + 1; | |
30 jcc(code, CC_NZ, writeback_penalty + 1); | |
31 *no_writeback_penalty = code->cur - (no_writeback_penalty + 1); | |
32 *no_writeback_penalty2 = code->cur - (no_writeback_penalty2 + 1); | |
33 } | |
34 cmp_ir(code, src, opts->resultreg, SZ_B); | |
35 code_ptr no_result_penalty; | |
36 if (dst == src) { | |
37 no_result_penalty = code->cur+1; | |
38 jcc(code, CC_NZ, no_result_penalty+1); | |
39 } else { | |
40 code_ptr result_penalty = code->cur + 1; | |
41 jcc(code, CC_Z, result_penalty+1); | |
42 cmp_ir(code, dst, opts->resultreg, SZ_B); | |
43 no_result_penalty = code->cur+1; | |
44 jcc(code, CC_NZ, no_result_penalty+1); | |
45 *result_penalty = code->cur - (result_penalty + 1); | |
46 } | |
47 code_ptr penalty = code->cur; | |
48 cycles(code, 1); | |
49 *no_result_penalty = code->cur - (no_result_penalty + 1); | |
50 code_ptr end = code->cur + 1; | |
51 jmp(end + 1); | |
52 //No result to save, but there could still be a writeback, source read conflict | |
53 code_ptr end2 = NULL; | |
54 | |
55 cmp_ir(code, JAGCPU_NOREG, opts->writeback, SZ_B); | |
56 code_ptr no_resultreg_move = code->cur + 1; | |
57 jcc(code, CC_Z, no_resultreg_move+1); | |
58 | |
59 if (src != dst) { | |
60 //unclear if src and dst read can share a port if it's the same register | |
61 //assume that is the case for now | |
62 cmp_ir(code, src, opts->writeback, SZ_B); | |
63 end2 = code->cur + 1; | |
64 jcc(code, CC_Z, end2+1); | |
65 cmp_ir(code, src, opts->writeback, SZ_B); | |
66 jcc(code, CC_NZ, penalty) | |
67 } | |
68 *end = code->cur - (end + 1); | |
69 if (end2) { | |
70 *end2 = code->cur - (end2 + 1); | |
71 } | |
72 *no_result = code->cur - (no_result + 1); | |
73 mov_rr(code, opts->resultreg, opts->writeback, SZ_B); | |
74 *no_resultreg_move = code->cur - (no_resultreg_move + 1); | |
75 } | |
76 | |
77 void jag_check_resultwrite_noread(jag_cpu_options *opts) | |
78 { | |
79 code_info *code = &opts->gen.code; | |
80 cmp_ir(code, JAGCPU_NOREG, opts->resultreg, SZ_B); | |
81 code_ptr no_result = code->cur + 1; | |
82 jcc(code, CC_Z, no_result + 1); | |
83 //save result to current bank | |
84 movzx_rr(code, opts->resultreg, opts->scratch1, SZ_B, SZ_D); | |
85 mov_rrindex(code, opts->result, opts->bankptr, opts->scratch1, 4, SZ_D); | |
86 *no_result = code->cur - (no_result + 1); | |
87 mov_rr(code, opts->resultreg, opts->writeback, SZ_B); | |
88 } | |
89 | |
90 void jag_check_resultwrite_singleread(jag_cpu options *opts, uint8_t reg) | |
91 { | |
92 code_info *code = &opts->gen.code; | |
93 cmp_ir(code, JAGCPU_NOREG, opts->resultreg, SZ_B); | |
94 code_ptr no_result = code->cur + 1; | |
95 jcc(code, CC_Z, no_result + 1); | |
96 //save result to current bank | |
97 movzx_rr(code, opts->resultreg, opts->scratch1, SZ_B, SZ_D); | |
98 mov_rrindex(code, opts->result, opts->bankptr, opts->scratch1, 4, SZ_D); | |
99 | |
100 //check for a scoreboard delay | |
101 cmp_ir(code, reg, opts->resultreg, SZ_B); | |
102 code_ptr no_delay = code-.cur + 1; | |
103 jcc(code, CC_NZ, no_delay + 1); | |
104 ccylces(code, 1); | |
105 *no_delay = code->cur - (no_delay = 1); | |
106 *no_result = code->cur - (no_result + 1); | |
107 mov_rr(code, opts->resultreg, opts->writeback, SZ_B); | |
108 } | |
109 | |
110 void translate_jag_quickimmed(jag_cpu_options *opts, uint32_t address, uint16_t opcode, uint32_t value, uint16_t dest) | |
111 { | |
112 jag_check_resultwrite_singleread(opts, dest); | |
113 switch (opcode) | |
114 { | |
115 case ADDQ: | |
116 break; | |
117 case ADDQT: | |
118 break; | |
119 } | |
120 } | |
121 | |
122 | |
123 uint16_t *translate_jag_inst(uint16_t *stream, jag_cpu_options *opts, uint32_t address) | |
124 { | |
125 uint16_t inst = *stream | |
126 ++stream; | |
127 uint16_t opcode = jag_opcode(inst, opts->is_gpu); | |
128 check_cycles_int(&opts->gen, address); | |
129 code_info *code = &opts->gen.code; | |
130 switch (opcode) | |
131 { | |
132 case JAG_MOVEI: { | |
133 uint32_t value = *stream; | |
134 ++stream; | |
135 value |= *stream << 16; | |
136 ++stream; | |
137 | |
138 jag_check_resultwrite_noread(opts); | |
139 mov_ir(code, value, opts->result, SZ_D); | |
140 mov_ir(code, jag_reg2(inst), opts->resultreg, SZ_B); | |
141 break; | |
142 } | |
143 case JAG_MOVE: { | |
144 uint8_t src = jag_reg1(inst), dst = jag_reg2(inst); | |
145 jag_check_resultwrite_singleread(opts, src); | |
146 //move has a shorter pipeline than normal instructions | |
147 if (src != dst) { | |
148 mov_rdispr(code, opts->bankptr, src * 4, opts->gen.scratch1, SZ_D); | |
149 mov_rrdisp(code, opts->gen.scratch1, opts->bankptr, dst * 4, SZ_D); | |
150 } | |
151 mov_ir(code, dst, opts->writeback, SZ_B); | |
152 mov_ir(code, JAGCPU_NOREG, opts->resultreg, SZ_B); | |
153 break; | |
154 } | |
155 case JAG_MOVEQ: { | |
156 uint8_t dst = jag_reg2(inst); | |
157 jag_check_resultwrite_noread(opts); | |
158 //moveq has a shorter pipeline than normal instructions | |
159 mov_irdisp(code, jag_quick(inst), opts->bankptr, dst * 4, SZ_D); | |
160 mov_ir(code, dst, opts->writeback, SZ_B); | |
161 mov_ir(code, JAGCPU_NOREG, opts->resultreg, SZ_B); | |
162 } | |
163 break; | |
164 case JAG_JR: { | |
165 jag_check_resultwrite_noread(opts); | |
166 //TODO: Pipeline stalls on flag readiness | |
167 uint16_t cond = jag_reg2(inst); | |
168 if (jag_is_always_false(cond)) { | |
169 } else { | |
170 int32_t offset = jag_quick(inst); | |
171 if (offset & 0x10) { | |
172 offset = -16 + (offset & 0xF); | |
173 } | |
174 } | |
175 | |
176 } | |
177 break; | |
178 default: | |
179 if (is_quick_1_32_opcode(opcode, opts->is_gpu)) { | |
180 translate_jag_quickimmed(opts, address, jag_quick(inst), jag_reg2(inst)); | |
181 } else if (is_quick_0_31_opcode(opcode)) { | |
182 translate_jag_quickimmed(opts, address, jag_reg1(inst), jag_reg2(inst)); | |
183 } else if (is_single_source(opcode, opts->is_gpu)) { | |
184 translate_jag_single_source(opts, address, jag_reg2(isnt)); | |
185 } else { | |
186 translate_jag_normal(opts, address, jag_reg1(inst), jag_reg2(inst)); | |
187 } | |
188 } | |
189 return stream; | |
190 } |