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