comparison debug.c @ 2365:8c060849a503

Basic function call support in debug language
author Michael Pavone <pavone@retrodev.com>
date Wed, 08 Nov 2023 23:47:26 -0800
parents c822bb628fc3
children 1e36d8a2633c
comparison
equal deleted inserted replaced
2364:c822bb628fc3 2365:8c060849a503
22 #define Z80_OPTS opts 22 #define Z80_OPTS opts
23 #else 23 #else
24 #define Z80_OPTS options 24 #define Z80_OPTS options
25 #endif 25 #endif
26 26
27 static debug_root *roots; 27 static debug_func *funcs;
28 static uint32_t num_roots, root_storage; 28 static uint32_t num_funcs, func_storage;
29 29
30 debug_root *find_root(void *cpu) 30 static debug_func* alloc_func(void)
31 { 31 {
32 for (uint32_t i = 0; i < num_roots; i++) 32 if (num_funcs == func_storage) {
33 { 33 func_storage = func_storage ? func_storage * 2 : 4;
34 if (roots[i].cpu_context == cpu) { 34 funcs = realloc(funcs, sizeof(debug_func) * func_storage);
35 return roots + i; 35 }
36 } 36 return funcs + num_funcs++;
37 } 37 }
38 if (num_roots == root_storage) { 38
39 root_storage = root_storage ? root_storage * 2 : 5; 39 static debug_val new_native_func(debug_native_func impl, int max_args, int min_args)
40 roots = realloc(roots, root_storage * sizeof(debug_root)); 40 {
41 } 41 debug_func *f = alloc_func();
42 num_roots++; 42 f->impl.native = impl;
43 memset(roots + num_roots - 1, 0, sizeof(debug_root)); 43 f->max_args = max_args;
44 roots[num_roots-1].cpu_context = cpu; 44 f->min_args = min_args;
45 return roots + num_roots - 1; 45 f->is_native = 1;
46 } 46 return (debug_val) {
47 47 .v = {
48 bp_def ** find_breakpoint(bp_def ** cur, uint32_t address, uint8_t type) 48 .u32 = f - funcs
49 { 49 },
50 while (*cur) { 50 .type = DBG_VAL_FUNC
51 if ((*cur)->type == type && (*cur)->address == (((*cur)->mask) & address)) { 51 };
52 break; 52 }
53 } 53
54 cur = &((*cur)->next); 54 debug_val user_var_get(debug_var *var)
55 } 55 {
56 return cur; 56 return var->val;
57 } 57 }
58 58
59 bp_def ** find_breakpoint_idx(bp_def ** cur, uint32_t index) 59 void user_var_set(debug_var *var, debug_val val)
60 { 60 {
61 while (*cur) { 61 var->val = val;
62 if ((*cur)->index == index) { 62 }
63 break; 63
64 } 64 static void new_user_variable(debug_root *root, const char *name, debug_val val)
65 cur = &((*cur)->next); 65 {
66 } 66 debug_var *var = calloc(1, sizeof(debug_var));
67 return cur; 67 var->get = user_var_get;
68 var->set = user_var_set;
69 var->val = val;
70 root->variables = tern_insert_ptr(root->variables, name, var);
71 }
72
73 static void new_readonly_variable(debug_root *root, const char *name, debug_val val)
74 {
75 debug_var *var = calloc(1, sizeof(debug_var));
76 var->get = user_var_get;
77 var->set = NULL;
78 var->val = val;
79 root->variables = tern_insert_ptr(root->variables, name, var);
68 } 80 }
69 81
70 static debug_array *arrays; 82 static debug_array *arrays;
71 static uint32_t num_arrays, array_storage; 83 static uint32_t num_arrays, array_storage;
72 static debug_array *alloc_array(void) 84 static debug_array *alloc_array(void)
134 return NULL; 146 return NULL;
135 } 147 }
136 return arrays + val.v.u32; 148 return arrays + val.v.u32;
137 } 149 }
138 150
139 debug_val user_var_get(debug_var *var) 151 static uint8_t debug_cast_int(debug_val val, uint32_t *out)
140 { 152 {
141 return var->val; 153 if (val.type == DBG_VAL_U32) {
142 } 154 *out = val.v.u32;
143 155 return 1;
144 void user_var_set(debug_var *var, debug_val val) 156 }
145 { 157 if (val.type == DBG_VAL_F32) {
146 var->val = val; 158 *out = val.v.f32;
147 } 159 return 1;
148 160 }
149 static void new_user_variable(debug_root *root, const char *name, debug_val val) 161 return 0;
150 { 162 }
151 debug_var *var = calloc(1, sizeof(debug_var)); 163
152 var->get = user_var_get; 164 static uint8_t debug_cast_float(debug_val val, float *out)
153 var->set = user_var_set; 165 {
154 var->val = val; 166 if (val.type == DBG_VAL_U32) {
155 root->variables = tern_insert_ptr(root->variables, name, var); 167 *out = val.v.u32;
156 } 168 return 1;
157 169 }
158 static void new_readonly_variable(debug_root *root, const char *name, debug_val val) 170 if (val.type == DBG_VAL_F32) {
159 { 171 *out = val.v.f32;
160 debug_var *var = calloc(1, sizeof(debug_var)); 172 return 1;
161 var->get = user_var_get; 173 }
162 var->set = NULL; 174 return 0;
163 var->val = val; 175 }
164 root->variables = tern_insert_ptr(root->variables, name, var); 176
177 static uint8_t debug_cast_bool(debug_val val)
178 {
179 switch(val.type)
180 {
181 case DBG_VAL_U32: return val.v.u32 != 0;
182 case DBG_VAL_F32: return val.v.f32 != 0.0f;
183 case DBG_VAL_ARRAY: return get_array(val)->size != 0;
184 default: return 1;
185 }
165 } 186 }
166 187
167 static debug_val debug_int(uint32_t i) 188 static debug_val debug_int(uint32_t i)
168 { 189 {
169 debug_val ret; 190 debug_val ret;
178 .type = DBG_VAL_F32, 199 .type = DBG_VAL_F32,
179 .v = { 200 .v = {
180 .f32 = f 201 .f32 = f
181 } 202 }
182 }; 203 };
204 }
205
206 debug_val debug_sin(debug_val *args, int num_args)
207 {
208 float f;
209 if (!debug_cast_float(args[0], &f)) {
210 return debug_float(0.0f);
211 }
212 return debug_float(sinf(f));
213 }
214
215 static debug_root *roots;
216 static uint32_t num_roots, root_storage;
217
218 debug_root *find_root(void *cpu)
219 {
220 for (uint32_t i = 0; i < num_roots; i++)
221 {
222 if (roots[i].cpu_context == cpu) {
223 return roots + i;
224 }
225 }
226 if (num_roots == root_storage) {
227 root_storage = root_storage ? root_storage * 2 : 5;
228 roots = realloc(roots, root_storage * sizeof(debug_root));
229 }
230 debug_root *root = roots + num_roots++;
231 memset(root, 0, sizeof(debug_root));
232 root->cpu_context = cpu;
233 new_readonly_variable(root, "sin", new_native_func(debug_sin, 1, 1));
234 return root;
235 }
236
237 bp_def ** find_breakpoint(bp_def ** cur, uint32_t address, uint8_t type)
238 {
239 while (*cur) {
240 if ((*cur)->type == type && (*cur)->address == (((*cur)->mask) & address)) {
241 break;
242 }
243 cur = &((*cur)->next);
244 }
245 return cur;
246 }
247
248 bp_def ** find_breakpoint_idx(bp_def ** cur, uint32_t index)
249 {
250 while (*cur) {
251 if ((*cur)->index == index) {
252 break;
253 }
254 cur = &((*cur)->next);
255 }
256 return cur;
183 } 257 }
184 258
185 static const char *token_type_names[] = { 259 static const char *token_type_names[] = {
186 "TOKEN_NONE", 260 "TOKEN_NONE",
187 "TOKEN_INT", 261 "TOKEN_INT",
953 } 1027 }
954 1028
955 uint8_t eval_expr(debug_root *root, expr *e, debug_val *out) 1029 uint8_t eval_expr(debug_root *root, expr *e, debug_val *out)
956 { 1030 {
957 debug_val right; 1031 debug_val right;
1032 debug_val *args;
1033 debug_func *func;
1034 int num_args;
958 switch(e->type) 1035 switch(e->type)
959 { 1036 {
960 case EXPR_SCALAR: 1037 case EXPR_SCALAR:
961 if (e->op.type == TOKEN_NAME || e->op.type == TOKEN_ARRAY) { 1038 if (e->op.type == TOKEN_NAME || e->op.type == TOKEN_ARRAY) {
962 debug_var *var = tern_find_ptr(root->variables, e->op.v.str); 1039 debug_var *var = tern_find_ptr(root->variables, e->op.v.str);
1141 if (!root) { 1218 if (!root) {
1142 fprintf(stderr, "%s is not a valid namespace\n", e->op.v.str); 1219 fprintf(stderr, "%s is not a valid namespace\n", e->op.v.str);
1143 return 0; 1220 return 0;
1144 } 1221 }
1145 return eval_expr(root, e->left, out); 1222 return eval_expr(root, e->left, out);
1223 case EXPR_FUNCALL:
1224 if (!eval_expr(root, e->left, out)) {
1225 return 0;
1226 }
1227 if (out->type != DBG_VAL_FUNC) {
1228 fprintf(stderr, "Funcall expression requires function");
1229 return 0;
1230 }
1231 func = funcs + out->v.u32;
1232 num_args = e->op.v.num;
1233 if (func->min_args > 0 && num_args < func->min_args) {
1234 fprintf(stderr, "Function requires at least %d args, but %d given\n", func->min_args, num_args);
1235 return 0;
1236 }
1237 if (func->max_args >= 0 && num_args > func->max_args) {
1238 fprintf(stderr, "Function requires no more than %d args, but %d given\n", func->max_args, num_args);
1239 return 0;
1240 }
1241 args = calloc(num_args, sizeof(debug_val));
1242 for (int i = 0; i < num_args; i++)
1243 {
1244 if (!eval_expr(root, e->right + i, args + i)) {
1245 return 0;
1246 }
1247 }
1248 if (func->is_native) {
1249 *out = func->impl.native(args, num_args);
1250 } else {
1251 //TODO: Implement me
1252 }
1253 return 1;
1146 default: 1254 default:
1147 return 0; 1255 return 0;
1148 } 1256 }
1149 } 1257 }
1150 1258
1225 return 0; 1333 return 0;
1226 } 1334 }
1227 write_word(address, value, (void **)context->mem_pointers, &context->options->gen, context); 1335 write_word(address, value, (void **)context->mem_pointers, &context->options->gen, context);
1228 } 1336 }
1229 return 1; 1337 return 1;
1230 }
1231
1232 static uint8_t debug_cast_int(debug_val val, uint32_t *out)
1233 {
1234 if (val.type == DBG_VAL_U32) {
1235 *out = val.v.u32;
1236 return 1;
1237 }
1238 if (val.type == DBG_VAL_F32) {
1239 *out = val.v.f32;
1240 return 1;
1241 }
1242 return 0;
1243 }
1244
1245 static uint8_t debug_cast_float(debug_val val, float *out)
1246 {
1247 if (val.type == DBG_VAL_U32) {
1248 *out = val.v.u32;
1249 return 1;
1250 }
1251 if (val.type == DBG_VAL_F32) {
1252 *out = val.v.f32;
1253 return 1;
1254 }
1255 return 0;
1256 }
1257
1258 static uint8_t debug_cast_bool(debug_val val)
1259 {
1260 switch(val.type)
1261 {
1262 case DBG_VAL_U32: return val.v.u32 != 0;
1263 case DBG_VAL_F32: return val.v.f32 != 0.0f;
1264 case DBG_VAL_ARRAY: return get_array(val)->size != 0;
1265 default: return 1;
1266 }
1267 } 1338 }
1268 1339
1269 static debug_val m68k_dreg_get(debug_var *var) 1340 static debug_val m68k_dreg_get(debug_var *var)
1270 { 1341 {
1271 m68k_context *context = var->ptr; 1342 m68k_context *context = var->ptr;