+ d->control->close(d->handle);
+ d->handle = NULL;
+ return true;
+}
+
+static bool workram_execute(HSQUIRRELVM v, struct dump_config *d)
+{
+ bool ret = true;
+ if(SQ_FAILED(sqstd_dofile(v, wgT("dumpcore.nut"), SQFalse, SQTrue))){
+ d->log.append(d->log.object, wgT("dump core script error\n"));
+ ret = false;
+ }else{
+ SQRESULT r = qr_call(
+ v, wgT("workram_rw"), (SQUserPointer) d, d->script,
+ 1, d->cpu.increase
+ );
+ if(SQ_FAILED(r)){
+ ret = false;
+ Free(d->cpu.memory.data);
+ d->cpu.memory.data = NULL;
+// Free(d->ppu.memory.data);
+// d->ppu.memory.data = NULL;
+ }
+ }
+ return ret;
+}
+
+static SQInteger cpu_ramrw_check(HSQUIRRELVM v)
+{
+ static const struct range range_address = {0x4800, 0xdfff};
+ static const struct range range_length = {1, 0x2000};
+ USERPOINTER_GET(d, r)
+
+ return read_count(v, &d->log, &d->cpu, &range_address, &range_length);
+}
+
+static SQInteger ramimage_open(HSQUIRRELVM v)
+{
+ USERPOINTER_GET(d, r)
+ memory_new(v);
+ if(buf_load(d->cpu.memory.data, d->target, d->cpu.memory.size) == NG){
+ return r = sq_throwerror(v, wgT("RAM image open error"));
+ }
+ return 0;
+}
+
+static SQInteger memory_finalize(HSQUIRRELVM v)
+{
+ USERPOINTER_GET(d, r)
+
+ if(d->mode == MODE_RAM_READ){
+ buf_save(d->cpu.memory.data, d->target, d->cpu.memory.size);
+ }
+ Free(d->cpu.memory.data);
+ d->cpu.memory.data = NULL;
+// Free(d->ppu.memory.data);
+// d->ppu.memory.data = NULL;
+
+ return 0;
+}
+
+static SQInteger cpu_write_ramimage(HSQUIRRELVM v)
+{
+ USERPOINTER_GET(d, r)
+
+ long address, length;
+ uint8_t *cmp;
+ const uint8_t *writedata = d->cpu.memory.data;
+ writedata += d->cpu.memory.offset;
+
+ r = qr_argument_get(v, 2, &address, &length);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ cmp = Malloc(length);
+ assert(d->cpu.memory.attribute == MEMORY_ATTR_READ);
+
+ d->cpu.access->memory_write(
+ d->handle, address, length, writedata
+ );
+ d->cpu.access->memory_read(
+ d->handle, &d->cpu.gauge, address, length, cmp
+ );
+ d->cpu.memory.offset += length;
+
+ r = memcmp(cmp, writedata, length);
+ Free(cmp);
+ if(r != 0){
+ r = sq_throwerror(v, wgT("memory write failed"));
+ }
+ return 0;
+}
+
+static SQInteger mode_is_read(HSQUIRRELVM v)
+{
+ USERPOINTER_GET(d, r)
+ sq_pushbool(v, d->mode == MODE_RAM_READ ? SQTrue : SQFalse);
+ return 1;
+}
+
+static SQInteger cpu_read_bit_check(HSQUIRRELVM v)
+{
+ static const struct range range_address = {0x4800, 0xdfff};
+ static const struct range range_bit = {0, 7};
+ USERPOINTER_GET(d, r)
+
+ long address, bit;
+ r = qr_argument_get(v, 2, &address, &bit);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ r = range_check(v, wgT("address"), address, &range_address);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ r = range_check(v, wgT("bit"), bit, &range_bit);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+ d->cpu.read_count_bit += 1;
+ return 0;
+}
+
+static inline void gauge_increment(const struct gauge *g)
+{
+ g->value_add(g->bar, g->label, 1);
+}
+
+static SQInteger cpu_read_bit_msb(HSQUIRRELVM v)
+{
+ USERPOINTER_GET(d, r)
+ long address, bit;
+ r = qr_argument_get(v, 2, &address, &bit);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+
+ assert(d->cpu.memory.attribute == MEMORY_ATTR_WRITE);
+ uint8_t readdata;
+
+ d->cpu.access->memory_read(d->handle, &GAUGE_DUMMY, address, 1, &readdata);
+ readdata >>= bit;
+ readdata &= 1;
+
+ if(d->cpu.read_count_bit == 0){
+ d->cpu.bitbuffer = 0;
+ }
+ d->cpu.bitbuffer |= readdata;
+
+ d->cpu.read_count_bit += 1;
+
+ if(d->cpu.read_count_bit == 8){
+ d->cpu.read_count_bit = 0;
+ d->cpu.memory.data[d->cpu.memory.offset] = d->cpu.bitbuffer;
+ d->cpu.memory.offset += 1;
+ gauge_increment(&d->cpu.gauge);
+ }else{
+ d->cpu.bitbuffer <<= 1;
+ }
+ return 0;
+}
+
+static SQInteger cpu_fetch_bit_check(HSQUIRRELVM v)
+{
+ USERPOINTER_GET(d, r)
+ d->cpu.read_count_bit += 1;
+ return 0;
+}
+
+static SQInteger cpu_fetch_bit_msb(HSQUIRRELVM v)
+{
+ USERPOINTER_GET(d, r)
+
+ if(d->cpu.read_count_bit == 0){
+ d->cpu.bitbuffer = d->cpu.memory.data[d->cpu.memory.offset];
+ }
+ sq_pushinteger(v, d->cpu.bitbuffer & 0x80);
+
+ d->cpu.read_count_bit += 1;
+ if(d->cpu.read_count_bit == 8){
+ d->cpu.read_count_bit = 0;
+ d->cpu.memory.offset += 1;
+ gauge_increment(&d->cpu.gauge);
+ }else{
+ d->cpu.bitbuffer <<= 1;
+ }
+ return 1;
+}
+
+bool script_workram_execute(struct dump_config *d)
+{
+ dump_memory_driver_init(&d->cpu, d->mode == MODE_RAM_READ ? MEMORY_ATTR_WRITE : MEMORY_ATTR_READ);
+ dump_memory_driver_init(&d->ppu, MEMORY_ATTR_NOTUSE);
+ d->cpu.memory.name = wgT("Workram");
+ d->ppu.memory.name = wgT("N/A");
+
+ {
+ HSQUIRRELVM v = qr_open(&d->log);
+ qr_function_register_global(v, wgT("memory_new"), memory_size_set);
+ qr_function_register_global(v, wgT("cpu_write"), cpu_write_check);
+ qr_function_register_global(v, wgT("cpu_ramrw"), cpu_ramrw_check);
+ qr_function_register_global(v, wgT("memory_finalize"), length_check);
+ qr_function_register_global(v, wgT("mode_is_read"), mode_is_read);
+ qr_function_register_global(v, wgT("cpu_read_register"), cpu_read_register_check);
+ switch(d->mode){
+ case MODE_RAM_READ:
+ qr_function_register_global(v, wgT("cpu_read_bit_msb"), cpu_read_bit_check);
+ break;
+ case MODE_RAM_WRITE:
+ qr_function_register_global(v, wgT("cpu_fetch_bit_msb"), cpu_fetch_bit_check);
+ break;
+ default:
+ break;
+ }
+ if(workram_execute(v, d) == false){
+ qr_close(v);
+ return false;
+ }
+ qr_close(v);
+ }
+
+ d->handle = d->control->open(d->except, &d->log);
+ if(d->handle == NULL){
+ d->log.append(d->log.object, wgT("reader open error\n"));
+ return false;
+ }
+ assert((d->cpu.read_count_bit & 7) == 0);
+ d->cpu.read_count_bit = 0;
+ d->control->init(d->handle);
+ if(connection_check(d->handle, &d->log, d->cpu.access, d->ppu.access) == false){
+ d->control->close(d->handle);
+ return false;
+ }
+ {
+ HSQUIRRELVM v = qr_open(&d->log);
+ qr_function_register_global(v, wgT("cpu_write"), cpu_write);
+ qr_function_register_global(v, wgT("cpu_read_register"), cpu_read_register);
+ qr_function_register_global(v, wgT("mode_is_read"), mode_is_read);
+ switch(d->mode){
+ case MODE_RAM_READ:
+ qr_function_register_global(v, wgT("memory_new"), memory_new);
+ qr_function_register_global(v, wgT("cpu_ramrw"), cpu_read);
+ qr_function_register_global(v, wgT("cpu_read_bit_msb"), cpu_read_bit_msb);
+ break;
+ case MODE_RAM_WRITE:
+ qr_function_register_global(v, wgT("memory_new"), ramimage_open);
+ qr_function_register_global(v, wgT("cpu_ramrw"), cpu_write_ramimage);
+ qr_function_register_global(v, wgT("cpu_fetch_bit_msb"), cpu_fetch_bit_msb);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ qr_function_register_global(v, wgT("memory_finalize"), memory_finalize);
+ workram_execute(v, d);
+ qr_close(v);
+ }
+ d->control->close(d->handle);
+ d->handle = NULL;
+ return true;