6 #include <kazzo_task.h>
10 #include "memory_manage.h"
11 #include "reader_master.h"
12 #include "squirrel_wrap.h"
13 #include "flash_device.h"
14 #include "script_common.h"
15 #include "script_program.h"
17 static SQInteger vram_mirrorfind(HSQUIRRELVM v)
19 struct program_config *d;
20 SQRESULT r = SQ_FAILED(qr_userpointer_get(v, (SQUserPointer) &d));
24 const uint8_t c = d->control->vram_connection(d->handle);
26 d->log.append(d->log.object, wgT("vram connection %x\n"), c);
28 if((c == 0x0a || c == 0x05) && d->vram_mirroring == MIRROR_VERTICAL){
30 }else if((c == 0x0c || c == 0x09) && d->vram_mirroring == MIRROR_HORIZONAL){
33 wgChar cartridge, image;
45 if(d->vram_mirroring == MIRROR_HORIZONAL){
50 d->log.append(d->log.object, wgT("warning: vram connection is unmmacted\n"));
51 d->log.append(d->log.object, wgT("cartridge:%c romimage:%c\n"), cartridge, image);
55 static SQInteger command_set(HSQUIRRELVM v, struct flash_memory_driver *t)
57 long command, address ,mask;
58 SQRESULT r = qr_argument_get(v, 3, &command, &address, &mask);
62 long d = command & (mask - 1);
68 case 0x02aa: case 0x2aaa:
71 case 0x0555: case 0x5555:
75 return sq_throwerror(v, wgT("unknown command address"));
77 t->command_change = true;
80 static SQInteger cpu_command(HSQUIRRELVM v)
82 struct program_config *d;
83 SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
87 return command_set(v, &d->cpu);
89 static SQInteger ppu_command(HSQUIRRELVM v)
91 struct program_config *d;
92 SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
96 return command_set(v, &d->ppu);
99 static SQInteger cpu_write(HSQUIRRELVM v)
101 struct program_config *d;
102 SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
106 cpu_write_execute(v, d->handle, d->cpu.access);
110 static SQInteger erase_set(HSQUIRRELVM v, const struct reader_handle *h, struct flash_memory_driver *t, struct textcontrol *log)
112 t->access->flash_config(h, t->c000x, t->c2aaa, t->c5555, t->flash.pagesize, t->flash.retry);
113 t->command_change = false;
114 if(t->flash.erase_require == true){
115 t->access->flash_erase(h, t->c2aaa, false);
116 t->gauge.label_set(t->gauge.label, wgT("erasing "));
120 static SQInteger cpu_erase(HSQUIRRELVM v)
122 struct program_config *d;
123 SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
127 return erase_set(v, d->handle, &d->cpu, &d->log);
129 static SQInteger ppu_erase(HSQUIRRELVM v)
131 struct program_config *d;
132 SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
136 return erase_set(v, d->handle, &d->ppu, &d->log);
138 static SQInteger program_regist(HSQUIRRELVM v, const struct reader_handle *h, struct flash_memory_driver *t)
140 SQRESULT r = qr_argument_get(v, 2, &t->programming.address, &t->programming.length);
144 t->compare = t->programming;
145 t->compare.offset = t->memory.offset & (t->memory.size - 1);
146 if(t->command_change == true){
147 t->access->flash_config(
148 h, t->c000x, t->c2aaa, t->c5555,
149 t->flash.pagesize, t->flash.retry
151 t->command_change = false;
154 return sq_suspendvm(v);
157 static void program_execute(const struct reader_handle *h, struct flash_memory_driver *t)
159 const long w = t->access->flash_program(
161 t->programming.address, t->programming.length,
162 t->memory.data + t->memory.offset, false,
163 t->flash.erase_require
165 t->programming.address += w;
166 t->programming.length -= w;
167 t->memory.offset += w;
168 t->memory.offset &= t->memory.size - 1;
169 t->programming.offset += w;
172 static bool program_compare(const struct reader_handle *h, struct flash_memory_driver *t)
174 uint8_t *comparea = Malloc(t->compare.length);
176 if(t->flash.erase_require == true){
177 memset(comparea, 0xff, t->compare.length);
178 int doread = memcmp(comparea, t->memory.data + t->compare.offset, t->compare.length);
180 memset(comparea, 0, t->compare.length);
181 doread &= memcmp(comparea, t->memory.data + t->compare.offset, t->compare.length);
189 t->access->memory_read(h, &GAUGE_DUMMY, t->compare.address, t->compare.length, comparea);
190 if(memcmp(comparea, t->memory.data + t->compare.offset, t->compare.length) == 0){
196 static SQInteger cpu_program_memory(HSQUIRRELVM v)
198 struct program_config *d;
199 SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
203 return program_regist(v, d->handle, &d->cpu);
205 static SQInteger ppu_program_memory(HSQUIRRELVM v)
207 struct program_config *d;
208 SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
212 return program_regist(v, d->handle, &d->ppu);
215 static long erase_timer_get(const struct reader_handle *h, struct flash_memory_driver *t)
218 (t->memory.transtype != TRANSTYPE_EMPTY) &&
219 (t->flash.erase_require == true)
221 return t->flash.erase_wait;
226 static SQInteger erase_wait(HSQUIRRELVM v)
228 struct program_config *d;
229 SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
234 long timer_wait = erase_timer_get(d->handle, &d->cpu);
235 long timer_ppu = erase_timer_get(d->handle, &d->ppu);
236 if(timer_wait < timer_ppu){
237 timer_wait = timer_ppu;
244 d->control->flash_status(d->handle, s);
245 //本来の意図からではここの条件式は && ではなく || だが、先に erase が終わったデバイスが動かせるので残しておく
246 }while((s[0] != KAZZO_TASK_FLASH_IDLE) && (s[1] != KAZZO_TASK_FLASH_IDLE));
251 static void gauge_init(struct flash_memory_driver *t)
253 t->gauge.range_set(t->gauge.bar, t->programming.count);
255 t->gauge.value_set(t->gauge.bar, t->gauge.label, 0);
258 static bool program_memoryarea(HSQUIRRELVM co, const struct reader_handle *h, struct flash_memory_driver *t, bool compare, SQInteger *state, struct textcontrol *log)
260 if(t->programming.length == 0){
261 if(t->programming.offset != 0 && compare == true){
262 if(program_compare(h, t) == false){
263 log->append(log->object, wgT("%s memory compare failed, offset 0x%06x\n"), t->memory.name, t->programming.offset);
268 sq_wakeupvm(co, SQFalse, SQFalse, SQTrue, SQFalse);
269 *state = sq_getvmstate(co);
271 program_execute(h, t);
276 static SQInteger program_main(HSQUIRRELVM v)
278 if(sq_gettop(v) != (1 + 3)){ //roottable, userpointer, co_cpu, co_ppu
279 return sq_throwerror(v, wgT("argument number error"));
281 struct program_config *d;
282 SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
286 HSQUIRRELVM co_cpu, co_ppu;
287 if(SQ_FAILED(sq_getthread(v, 3, &co_cpu))){
288 return sq_throwerror(v, wgT("thread error"));
290 if(SQ_FAILED(sq_getthread(v, 4, &co_ppu))){
291 return sq_throwerror(v, wgT("thread error"));
293 SQInteger state_cpu = sq_getvmstate(co_cpu);
294 SQInteger state_ppu = sq_getvmstate(co_ppu);
295 const long sleepms = d->compare == true ? 6 : 2; //W29C040 で compare をすると、error が出るので出ない値に調整 (やっつけ対応)
297 while((state_cpu != SQ_VMSTATE_IDLE) || (state_ppu != SQ_VMSTATE_IDLE)){
300 d->control->flash_status(d->handle, s);
301 if(state_cpu != SQ_VMSTATE_IDLE && s[0] == KAZZO_TASK_FLASH_IDLE){
302 if(program_memoryarea(co_cpu, d->handle, &d->cpu, d->compare, &state_cpu, &d->log) == false){
303 //sq_pushbool(v, SQFalse);
307 if(state_ppu != SQ_VMSTATE_IDLE && s[1] == KAZZO_TASK_FLASH_IDLE){
308 if(program_memoryarea(co_ppu, d->handle, &d->ppu, d->compare, &state_ppu, &d->log) == false){
309 //sq_pushbool(v, SQFalse);
314 //sq_pushbool(v, SQTrue);
318 static SQInteger program_count(HSQUIRRELVM v, struct flash_memory_driver *t, const struct range *range_address, const struct range *range_length, struct textcontrol *log)
320 SQRESULT r = qr_argument_get(v, 2, &t->programming.address, &t->programming.length);
324 r = range_check(v, wgT("length"), t->programming.length, range_length);
328 if((t->programming.address < range_address->start) || ((t->programming.address + t->programming.length) > range_address->end)){
329 log->append(log->object, wgT("address range must be 0x%06x to 0x%06x"), (int) range_address->start, (int) range_address->end - 1);
330 return sq_throwerror(v, wgT("script logical error"));
332 t->programming.count += t->programming.length;
335 static SQInteger cpu_program_count(HSQUIRRELVM v)
337 static const struct range range_address = {0x8000, 0x10000};
338 static const struct range range_length = {0x0100, 0x4000};
339 struct program_config *d;
340 SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
344 return program_count(v, &d->cpu, &range_address, &range_length, &d->log);
347 static SQInteger ppu_program_count(HSQUIRRELVM v)
349 static const struct range range_address = {0x0000, 0x2000};
350 static const struct range range_length = {0x0100, 0x2000};
351 struct program_config *d;
352 SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
356 return program_count(v, &d->ppu, &range_address, &range_length, &d->log);
359 static bool script_execute(HSQUIRRELVM v, const wgChar *function, struct program_config *c)
362 if(SQ_FAILED(sqstd_dofile(v, _SC("programcore.nut"), SQFalse, SQTrue))){
363 c->log.append(c->log.object, wgT("flash core script error\n"));
366 SQRESULT r = qr_call(
367 v, function, (SQUserPointer) c, c->script,
368 1 + 3 * 2, c->mappernum,
369 c->cpu.memory.transtype, c->cpu.memory.size, c->cpu.flash.capacity,
370 c->ppu.memory.transtype, c->ppu.memory.size, c->cpu.flash.capacity
379 static bool zendan(struct program_config *c)
383 static const wgChar *functionname[] = {
384 wgT("cpu_erase"), wgT("ppu_erase"),
385 wgT("erase_wait"), wgT("program_main")
387 HSQUIRRELVM v = qr_open(&c->log);
389 for(i = 0; i < sizeof(functionname)/sizeof(wgChar *); i++){
390 qr_function_register_global(v, functionname[i], script_nop);
392 qr_function_register_global(v, _SC("cpu_write"), cpu_write_check);
393 qr_function_register_global(v, _SC("cpu_command"), cpu_command);
394 qr_function_register_global(v, _SC("cpu_program"), cpu_program_count);
396 qr_function_register_global(v, _SC("ppu_program"), ppu_program_count);
397 qr_function_register_global(v, _SC("ppu_command"), ppu_command);
398 qr_function_register_global(v, _SC("vram_mirrorfind"), vram_mirrorfind);
400 if(script_execute(v, wgT("testrun"), c) == false){
405 assert(c->cpu.memory.size != 0);
407 if(c->cpu.programming.count % c->cpu.memory.size != 0){
408 c->log.append(c->log.object, wgT("logical error: cpu_programsize is not connected 0x%06x/0x%06x\n"), (int) c->cpu.programming.count, (int) c->cpu.memory.size);
411 if(c->ppu.memory.size != 0){
412 if(c->ppu.programming.count % c->ppu.memory.size != 0){
413 c->log.append(c->log.object, wgT("logical error: ppu_programsize is not connected 0x%06x/0x%06x\n"), (int) c->ppu.programming.count, (int) c->ppu.memory.size);
420 c->cpu.command_change = true;
422 c->ppu.command_change = true;
425 HSQUIRRELVM v = qr_open(&c->log);
426 qr_function_register_global(v, _SC("cpu_write"), cpu_write);
427 qr_function_register_global(v, _SC("cpu_erase"), cpu_erase);
428 qr_function_register_global(v, _SC("cpu_program"), cpu_program_memory);
429 qr_function_register_global(v, _SC("cpu_command"), cpu_command);
430 qr_function_register_global(v, _SC("ppu_erase"), ppu_erase);
431 qr_function_register_global(v, _SC("ppu_program"), ppu_program_memory);
432 qr_function_register_global(v, _SC("ppu_command"), ppu_command);
433 qr_function_register_global(v, _SC("program_main"), program_main);
434 qr_function_register_global(v, _SC("erase_wait"), erase_wait);
435 qr_function_register_global(v, _SC("vram_mirrorfind"), script_nop);
436 script_execute(v, wgT("program"), c);
437 //assert(sq_gettype(v, -2) == OT_BOOL);
438 //sq_getbool(v, -1, &ret);
441 return true; //ret == SQTrue ? true : false;
444 static bool memory_image_init(const struct memory *from, struct flash_memory_driver *t, struct textcontrol *log)
446 t->memory.data = from->data;
447 t->memory.size = from->size;
448 t->memory.attribute = MEMORY_ATTR_READ;
449 t->command_change = true;
450 t->programming.count = 0;
451 t->programming.offset = 0;
452 if(t->memory.size == 0){
453 t->memory.transtype = TRANSTYPE_EMPTY;
455 if(t->flash.capacity < from->size){
456 log->append(log->object, t->memory.name);
458 log->append(log->object, wgT(" image size is larger than target device"));
464 bool script_program_execute(struct program_config *c)
468 if(nesfile_load(&c->log, c->target, &rom) == false){
469 c->log.append(c->log.object, wgT("ROM image open error"));
473 c->mappernum = rom.mappernum;
474 c->vram_mirroring = rom.mirror;
475 c->cpu.memory.name = wgT("Program Flash");
476 if(memory_image_init(&rom.cpu_rom, &c->cpu, &c->log) == false){
477 nesbuffer_free(&rom, 0);
480 c->ppu.memory.name = wgT("Charcter Flash");
481 if(memory_image_init(&rom.ppu_rom, &c->ppu, &c->log) == false){
482 nesbuffer_free(&rom, 0);
486 c->handle = c->control->open(c->except, &c->log);
487 if(c->handle == NULL){
488 c->log.append(c->log.object, wgT("reader open error\n"));
489 nesbuffer_free(&rom, 0);
492 //program start, reader finalize
493 if(connection_check(c->handle, &c->log, c->cpu.access, c->ppu.access) == false){
494 nesbuffer_free(&rom, 0);
495 c->control->close(c->handle);
498 bool ret = zendan(c);
499 c->control->close(c->handle);
501 nesbuffer_free(&rom, 0);