RPA Toolkit
0d1f17581507209660b3586b9927b811c305122b
[rpatk.git] / rpa2 / rpavm.c
1 #include "rpavm.h"
2 #include "rpastat.h"
3 #include "rutf.h"
4 #include "rmem.h"
5
6
7 static void rpavm_swi_shift(rvmcpu_t *cpu, rvm_asmins_t *ins)
8 {
9         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
10         rlong top = RVM_CPUREG_GETL(cpu, R_TOP);
11
12         if ((top = rpa_stat_shift(stat, top)) >= 0)
13                 RVM_CPUREG_SETL(cpu, R_TOP, top);
14 }
15
16
17 static void rpavm_swi_matchchr_nan(rvmcpu_t *cpu, rvm_asmins_t *ins)
18 {
19         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
20         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
21         rword matched = 0;
22
23         if (rpa_stat_matchchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
24                 rpavm_swi_shift(cpu, ins);
25                 matched = 1;
26         }
27         cpu->status = matched ? 0 : RVM_STATUS_N;
28         RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
29 }
30
31
32 static void rpavm_swi_matchchr_opt(rvmcpu_t *cpu, rvm_asmins_t *ins)
33 {
34         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
35         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
36         rword matched = 0;
37
38         if (rpa_stat_matchspchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
39                 rpavm_swi_shift(cpu, ins);
40                 matched = 1;
41         }
42         cpu->status = matched ? 0 : RVM_STATUS_Z;
43         RVM_CPUREG_SETU(cpu, R0, matched);
44 }
45
46
47 static void rpavm_swi_matchchr_mul(rvmcpu_t *cpu, rvm_asmins_t *ins)
48 {
49         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
50         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
51         rword matched = 0;
52
53         while (rpa_stat_matchspchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
54                 rpavm_swi_shift(cpu, ins);
55                 matched += 1;
56         }
57         cpu->status = matched ? 0 : RVM_STATUS_N;
58         RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
59 }
60
61
62 static void rpavm_swi_matchchr_mop(rvmcpu_t *cpu, rvm_asmins_t *ins)
63 {
64         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
65         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
66         rword matched = 0;
67
68         while (rpa_stat_matchchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
69                 rpavm_swi_shift(cpu, ins);
70                 matched += 1;
71         }
72         cpu->status = matched ? 0 : RVM_STATUS_Z;
73         RVM_CPUREG_SETU(cpu, R0, matched );
74 }
75
76
77 static void rpavm_swi_matchspchr_nan(rvmcpu_t *cpu, rvm_asmins_t *ins)
78 {
79         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
80         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
81         rword matched = 0;
82
83         if (rpa_stat_matchspchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
84                 rpavm_swi_shift(cpu, ins);
85                 matched = 1;
86         }
87         cpu->status = matched ? 0 : RVM_STATUS_N;
88         RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
89 }
90
91
92 static void rpavm_swi_matchspchr_opt(rvmcpu_t *cpu, rvm_asmins_t *ins)
93 {
94         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
95         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
96         rword matched = 0;
97
98         if (rpa_stat_matchspchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
99                 rpavm_swi_shift(cpu, ins);
100                 matched = 1;
101         }
102         cpu->status = matched ? 0 : RVM_STATUS_Z;
103         RVM_CPUREG_SETU(cpu, R0, matched);
104
105 }
106
107
108 static void rpavm_swi_matchspchr_mul(rvmcpu_t *cpu, rvm_asmins_t *ins)
109 {
110         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
111         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
112         rword matched = 0;
113
114         while (rpa_stat_matchspchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
115                 rpavm_swi_shift(cpu, ins);
116                 matched += 1;
117         }
118         cpu->status = matched ? 0 : RVM_STATUS_N;
119         RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
120
121 }
122
123
124 static void rpavm_swi_matchspchr_mop(rvmcpu_t *cpu, rvm_asmins_t *ins)
125 {
126         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
127         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
128         rword matched = 0;
129
130         while (rpa_stat_matchspchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
131                 rpavm_swi_shift(cpu, ins);
132                 matched += 1;
133         }
134         cpu->status = matched ? 0 : RVM_STATUS_Z;
135         RVM_CPUREG_SETU(cpu, R0, matched );
136 }
137
138
139 static void rpavm_swi_matchrng_peek(rvmcpu_t *cpu, rvm_asmins_t *ins)
140 {
141         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
142         rpair_t pr = RVM_CPUREG_GETPAIR(cpu, ins->op1);
143         rword matched = 0;
144
145         if (rpa_stat_matchrng(stat, RVM_CPUREG_GETL(cpu, R_TOP), pr.p1, pr.p2) <= 0) {
146                 cpu->status = matched ? 0 : RVM_STATUS_N;
147                 RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
148         }
149 }
150
151
152 static void rpavm_swi_matchrng_nan(rvmcpu_t *cpu, rvm_asmins_t *ins)
153 {
154         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
155         rpair_t pr = RVM_CPUREG_GETPAIR(cpu, ins->op1);
156         rword matched = 0;
157
158         if (rpa_stat_matchrng(stat, RVM_CPUREG_GETL(cpu, R_TOP), pr.p1, pr.p2) > 0) {
159                 rpavm_swi_shift(cpu, ins);
160                 matched = 1;
161         }
162         cpu->status = matched ? 0 : RVM_STATUS_N;
163         RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
164 }
165
166
167 static void rpavm_swi_matchrng_opt(rvmcpu_t *cpu, rvm_asmins_t *ins)
168 {
169         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
170         rpair_t pr = RVM_CPUREG_GETPAIR(cpu, ins->op1);
171         rword matched = 0;
172
173         if (rpa_stat_matchrng(stat, RVM_CPUREG_GETL(cpu, R_TOP), pr.p1, pr.p2) > 0) {
174                 rpavm_swi_shift(cpu, ins);
175                 matched = 1;
176         }
177         cpu->status = matched ? 0 : RVM_STATUS_Z;
178         RVM_CPUREG_SETU(cpu, R0, matched);
179 }
180
181
182 static void rpavm_swi_matchrng_mul(rvmcpu_t *cpu, rvm_asmins_t *ins)
183 {
184         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
185         rpair_t pr = RVM_CPUREG_GETPAIR(cpu, ins->op1);
186         rword matched = 0;
187
188         while (rpa_stat_matchrng(stat, RVM_CPUREG_GETL(cpu, R_TOP), pr.p1, pr.p2) > 0) {
189                 rpavm_swi_shift(cpu, ins);
190                 matched += 1;
191         }
192         cpu->status = matched ? 0 : RVM_STATUS_N;
193         RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
194 }
195
196
197 static void rpavm_swi_matchrng_mop(rvmcpu_t *cpu, rvm_asmins_t *ins)
198 {
199         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
200         rpair_t pr = RVM_CPUREG_GETPAIR(cpu, ins->op1);
201         rword matched = 0;
202
203         while (rpa_stat_matchrng(stat, RVM_CPUREG_GETL(cpu, R_TOP), pr.p1, pr.p2) > 0) {
204                 rpavm_swi_shift(cpu, ins);
205                 matched += 1;
206         }
207         cpu->status = matched ? 0 : RVM_STATUS_Z;
208         RVM_CPUREG_SETU(cpu, R0, matched );
209 }
210
211
212
213 static void rpavm_swi_emithead(rvmcpu_t *cpu, rvm_asmins_t *ins)
214 {
215         rparecord_t *rec;
216         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
217         rlong index = RVM_CPUREG_GETL(cpu, R_REC);
218
219         index = r_array_add(stat->records, NULL);
220         RVM_CPUREG_SETL(cpu, R_REC, index);
221         rec = (rparecord_t *)r_array_slot(stat->records, index);
222         rec->type = RPA_RECORD_HEAD;
223 }
224
225
226 static void rpavm_swi_emittail(rvmcpu_t *cpu, rvm_asmins_t *ins)
227 {
228         rparecord_t *rec, *crec;
229         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
230         rlong index = RVM_CPUREG_GETL(cpu, R_REC);
231
232         index = r_array_add(stat->records, NULL);
233         crec = (rparecord_t *)r_array_slot(stat->records, RVM_CPUREG_GETL(cpu, R_REC));
234         RVM_CPUREG_SETL(cpu, R_REC, index);
235         rec = (rparecord_t *)r_array_slot(stat->records, index);
236         rec->type = RPA_RECORD_TAIL;
237         crec->next = index;
238 }
239
240
241 static void rpavm_swi_emitstart(rvmcpu_t *cpu, rvm_asmins_t *ins)
242 {
243         rpa_ruledata_t *ruledata = RVM_CPUREG_GETP(cpu, ins->op1);
244         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
245         rparecord_t *rec, *crec;
246         rlong index = RVM_CPUREG_GETL(cpu, R_REC);
247         rword tp = RVM_CPUREG_GETU(cpu, ins->op2);
248         rstr_t name = {(rchar*)ruledata + ruledata->name, ruledata->namesize};
249
250         if (stat->debug)
251                 r_printf("%ld: %s, %s, tp = %ld\n", RVM_CPUREG_GETU(cpu, FP), "START", name.str, tp);
252         if (!(ruledata->flags & RPA_RFLAG_EMITRECORD))
253                 return;
254         R_ASSERT(RVM_CPUREG_GETL(cpu, R_REC) >= 0);
255 //      index = r_array_replace(stat->records, index + 1, NULL);
256         index = r_array_add(stat->records, NULL);
257
258         /*
259          * Important: get the pointer to crec after modifying the array, because if
260          * it gets reallocated the pointer will be invalid.
261          */
262         crec = (rparecord_t *)r_array_slot(stat->records, RVM_CPUREG_GETL(cpu, R_REC));
263         RVM_CPUREG_SETL(cpu, R_REC, index);
264         rec = (rparecord_t *)r_array_slot(stat->records, index);
265         rec->rule = name.str;
266         rec->top = tp;
267         rec->ruleuid = ruledata->ruleuid;
268         rec->type = RPA_RECORD_START;
269         rec->input = stat->instack[tp].input;
270         rec->inputsiz = 0;
271         crec->next = index;
272 }
273
274
275
276 static void rpavm_swi_emitend(rvmcpu_t *cpu, rvm_asmins_t *ins)
277 {
278         rpa_ruledata_t *ruledata = RVM_CPUREG_GETP(cpu, ins->op1);
279         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
280         rparecord_t *rec, *crec;
281         rlong index = RVM_CPUREG_GETL(cpu, R_REC);
282         rword tp = RVM_CPUREG_GETU(cpu, ins->op2);
283         rword tplen = RVM_CPUREG_GETU(cpu, ins->op3);
284         rstr_t name = {(rchar*)ruledata + ruledata->name, ruledata->namesize};
285
286         if (stat->debug)
287                 r_printf("%ld: %s, %s, tp = %ld, tplen = %ld\n", RVM_CPUREG_GETU(cpu, FP), "END ", name.str, tp, tplen);
288         if (!(ruledata->flags & RPA_RFLAG_EMITRECORD))
289                 return;
290
291         R_ASSERT(RVM_CPUREG_GETL(cpu, R_REC) >= 0);
292 //      index = r_array_replace(stat->records, index + 1, NULL);
293         index = r_array_add(stat->records, NULL);
294
295         /*
296          * Important: get the pointer to crec after modifying the array, because if
297          * it gets reallocated the pointer will be invalid.
298          */
299         crec = (rparecord_t *)r_array_slot(stat->records, RVM_CPUREG_GETL(cpu, R_REC));
300         RVM_CPUREG_SETL(cpu, R_REC, index);
301         rec = (rparecord_t *)r_array_slot(stat->records, index);
302         rec->rule = name.str;
303         rec->top = tp;
304         rec->size = tplen;
305         rec->type = RPA_RECORD_END;
306         rec->ruleuid = ruledata->ruleuid;
307         rec->input = stat->instack[tp].input;
308         rec->inputsiz = stat->instack[tp + tplen].input - stat->instack[tp].input;
309         crec->next = index;
310
311         if (tplen) {
312                 rec->type |= RPA_RECORD_MATCH;
313         }
314 }
315
316
317 static void rpavm_swi_prninfo(rvmcpu_t *cpu, rvm_asmins_t *ins)
318 {
319         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
320         rpa_ruledata_t *ruledata = RVM_CPUREG_GETP(cpu, ins->op1);
321         rstr_t name = {"unknown", 7};
322         if (!stat->debug)
323                 return;
324         if (ruledata) {
325                 name.str = (rchar*)ruledata + ruledata->name;
326                 name.size = ruledata->namesize;
327         }
328
329         r_printf("%s: ", name.str);
330         rvm_cpu_dumpregs(cpu, ins);
331 }
332
333
334 static void rpavm_swi_getnextrec(rvmcpu_t *cpu, rvm_asmins_t *ins)
335 {
336         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
337         rlong rec = RVM_CPUREG_GETL(cpu, ins->op2);
338
339         rparecord_t *prec = (rparecord_t *)r_array_slot(stat->records, rec);
340
341 //      r_printf("%s, rec = %ld, next = %ld\n", __FUNCTION__, rec, prec->next);
342         RVM_CPUREG_SETL(cpu, ins->op1, prec->next);
343 }
344
345
346 static void rpavm_swi_getreclen(rvmcpu_t *cpu, rvm_asmins_t *ins)
347 {
348         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
349         RVM_CPUREG_SETU(cpu, ins->op1, r_array_length(stat->records));
350 }
351
352
353 static void rpavm_swi_setreclen(rvmcpu_t *cpu, rvm_asmins_t *ins)
354 {
355         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
356
357         r_array_setlength(stat->records, (ruint)RVM_CPUREG_GETU(cpu, ins->op1));
358         RVM_CPUREG_SETL(cpu, R_REC, RVM_CPUREG_GETU(cpu, ins->op1) - 1);
359 }
360
361
362 static void rpavm_swi_getcurrec(rvmcpu_t *cpu, rvm_asmins_t *ins)
363 {
364         RVM_CPUREG_SETL(cpu, ins->op1, RVM_CPUREG_GETL(cpu, R_REC));
365 }
366
367
368 static void rpavm_swi_setcurrec(rvmcpu_t *cpu, rvm_asmins_t *ins)
369 {
370         RVM_CPUREG_SETL(cpu, R_REC, RVM_CPUREG_GETU(cpu, ins->op1));
371 }
372
373
374 static void rpavm_swi_setcache(rvmcpu_t *cpu, rvm_asmins_t *ins)
375 {
376         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
377         rlong r0 = RVM_CPUREG_GETL(cpu, R0);
378         rlong ruleid = RVM_CPUREG_GETL(cpu, ins->op1);
379         rlong prevrec = RVM_CPUREG_GETL(cpu, ins->op2);
380         rlong endrec = RVM_CPUREG_GETL(cpu, ins->op3);
381         rlong top = RVM_CPUREG_GETL(cpu, R_OTP);
382         rlong startrec = 0;
383         rparecord_t *prec = NULL;
384
385         if (stat->cache->disalbled)
386                 return;
387
388         if (r0 > 0 && prevrec != endrec) {
389                 prec = (rparecord_t *)r_array_slot(stat->records, prevrec);
390                 startrec = prec->next;
391                 prec = (rparecord_t *)r_array_slot(stat->records, startrec);
392 //              r_printf("Set the cache for: %s (%ld, %ld), top = %ld, ret = %ld, ruleid=%ld\n", prec->rule, startrec, endrec, prec->top, r0, ruleid);
393                 rpa_cache_set(stat->cache, top, ruleid, r0, startrec, endrec);
394
395                 /*
396                  * The next optimization is supposed to reduce the size of
397                  * garbage records.
398                  */
399                 if (stat->cursize < endrec + 1)
400                         stat->cursize = endrec + 1;
401         } else {
402                 rpa_cache_set(stat->cache, top, ruleid, r0, 0, 0);
403                 /*
404                  * The next optimization is supposed to reduce the size of
405                  * garbage records.
406                  */
407                 if (stat->cursize < endrec + 1) {
408                         r_array_setlength(stat->records, endrec + 1);
409                         stat->cursize = endrec + 1;
410                 }
411         }
412 }
413
414
415 static void rpavm_swi_checkcache(rvmcpu_t *cpu, rvm_asmins_t *ins)
416 {
417         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
418         rpacachedentry_t *entry;
419         rlong ruleid = RVM_CPUREG_GETL(cpu, ins->op1);
420         rlong top = RVM_CPUREG_GETL(cpu, ins->op2);
421         rlong r0 = 0;
422         entry = rpa_cache_lookup(stat->cache, top, ruleid);
423         if (entry) {
424 //              rparecord_t *prec = (rparecord_t *)r_array_slot(stat->records, entry->startrec);
425 //              r_printf("Hit the cache for: %s (%ld, %ld), r0 = %ld\n", prec->rule, entry->startrec, entry->endrec, entry->ret);
426
427                 r0 = entry->ret;
428                 if (entry->startrec != entry->endrec) {
429                         rparecord_t *crec = (rparecord_t *)r_array_slot(stat->records, RVM_CPUREG_GETL(cpu, R_REC));
430                         crec->next = entry->startrec;
431                         RVM_CPUREG_SETL(cpu, R_REC, entry->endrec);
432                 }
433                 if (r0 > 0) {
434                         top += r0;
435                         RVM_CPUREG_SETU(cpu, R_TOP, top);
436                 }
437         }
438
439         RVM_STATUS_CLRALL(cpu);
440         RVM_CPUREG_SETU(cpu, R0, r0);
441         RVM_STATUS_UPDATE(cpu, RVM_STATUS_Z, !r0);
442         if (r0 < 0 && entry) {
443                 RVM_STATUS_UPDATE(cpu, RVM_STATUS_N, (r0 < 0));
444 //              r_printf("Hit the cache for: %ld, r0 = %ld\n", entry->ruleid, entry->ret);
445         }
446 }
447
448
449 static void rpavm_swi_matchchrinstr_nan(rvmcpu_t *cpu, rvm_asmins_t *ins)
450 {
451         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
452         rchar *str = RVM_CPUREG_GETSTR(cpu, ins->op1);
453         rword matched = 0;
454         rword wc;
455
456         while (*str) {
457                 wc = *str++;
458                 if (rpa_stat_matchchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
459                         rpavm_swi_shift(cpu, ins);
460                         matched = 1;
461                         break;
462                 }
463         }
464         cpu->status = matched ? 0 : RVM_STATUS_N;
465         RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
466 }
467
468
469
470
471 static rvm_switable_t rpavm_swi_table[] = {
472                 {"RPA_MATCHCHR_NAN", rpavm_swi_matchchr_nan},
473                 {"RPA_MATCHCHR_OPT", rpavm_swi_matchchr_opt},
474                 {"RPA_MATCHCHR_MUL", rpavm_swi_matchchr_mul},
475                 {"RPA_MATCHCHR_MOP", rpavm_swi_matchchr_mop},
476                 {"RPA_MATCHRNG_NAN", rpavm_swi_matchrng_nan},
477                 {"RPA_MATCHRNG_OPT", rpavm_swi_matchrng_opt},
478                 {"RPA_MATCHRNG_MUL", rpavm_swi_matchrng_mul},
479                 {"RPA_MATCHRNG_MOP", rpavm_swi_matchrng_mop},
480                 {"RPA_MATCHRNG_PEEK", rpavm_swi_matchrng_peek},
481                 {"RPA_MATCHSPCHR_NAN", rpavm_swi_matchspchr_nan},
482                 {"RPA_MATCHSPCHR_OPT", rpavm_swi_matchspchr_opt},
483                 {"RPA_MATCHSPCHR_MUL", rpavm_swi_matchspchr_mul},
484                 {"RPA_MATCHSPCHR_MOP", rpavm_swi_matchspchr_mop},
485                 {"RPA_SHIFT", rpavm_swi_shift},
486                 {"RPA_SETCACHE", rpavm_swi_setcache},
487                 {"RPA_CHECKCACHE", rpavm_swi_checkcache},
488                 {"RPA_EMITSTART", rpavm_swi_emitstart},
489                 {"RPA_EMITEND", rpavm_swi_emitend},
490                 {"RPA_EMITHEAD", rpavm_swi_emithead},
491                 {"RPA_EMITTAIL", rpavm_swi_emittail},
492                 {"RPA_GETNEXTREC", rpavm_swi_getnextrec},
493                 {"RPA_PRNINFO", rpavm_swi_prninfo},
494                 {"RPA_MATCHCHRINSTR_NAN", rpavm_swi_matchchrinstr_nan},
495
496                 {"RPA_GETRECLEN", rpavm_swi_getreclen},
497                 {"RPA_SETRECLEN", rpavm_swi_setreclen},
498                 {"RPA_GETCURREC", rpavm_swi_getcurrec},
499                 {"RPA_SETCURREC", rpavm_swi_setcurrec},
500                 {NULL, NULL},
501 };
502
503
504 rvmcpu_t *rpavm_cpu_create(rulong stacksize)
505 {
506         rvmcpu_t *cpu = rvm_cpu_create(stacksize);
507         rint tableid = rvm_cpu_addswitable(cpu, "rpavm_swi_table", rpavm_swi_table);
508
509         if (tableid != RPAVM_SWI_TABLEID) {
510                 rpavm_cpu_destroy(cpu);
511                 return NULL;
512         }
513         return cpu;
514 }
515
516
517 void rpavm_cpu_destroy(rvmcpu_t * cpu)
518 {
519         rvm_cpu_destroy(cpu);
520 }
521
522