#include <sqstdio.h>
#include <sqstdaux.h>
#include "type.h"
+#include "file.h"
#include "widget.h"
-#include "header.h"
-#include "progress.h"
+#include "romimage.h"
#include "memory_manage.h"
#include "reader_master.h"
#include "squirrel_wrap.h"
#include "script_common.h"
#include "script_dump.h"
-struct dump_driver{
- const char *target;
- struct memory_driver{
- struct memory memory;
- long read_count;
- void (*const write)(long address, long length, const uint8_t *data);
- void (*const read)(long address, long length, u8 *data);
- struct gauge *const gauge;
- }cpu, ppu;
- uint8_t (*const vram_connection)(void);
- bool progress;
- struct textcontrol *const log;
-};
-static SQInteger write_memory(HSQUIRRELVM v, struct memory_driver *t)
-{
- long address, data;
- SQRESULT r = qr_argument_get(v, 2, &address, &data);
- if(SQ_FAILED(r)){
- return r;
- }
- uint8_t d8 = (uint8_t) data;
- t->write(address, 1, &d8);
- return 0;
-}
+#define USERPOINTER_GET(Pointer, Result) \
+ struct dump_config *Pointer; \
+ SQRESULT Result = qr_userpointer_get(v, (SQUserPointer) &Pointer); \
+ if(SQ_FAILED(Result)){ \
+ return Result; \
+ }
+
+
static SQInteger cpu_write(HSQUIRRELVM v)
{
- struct dump_driver *d;
- SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
- if(SQ_FAILED(r)){
- return r;
- }
- return write_memory(v, &d->cpu);
+ USERPOINTER_GET(d, r)
+ cpu_write_execute(v, d->handle, d->cpu.access);
+ return 0;
}
-//¤³¤³¤Î printf ¤Ï debug ÍѤ˻Ĥ·¤Æ¤ª¤¯
+//ここの printf は debug 用に残しておく
static void buffer_show(struct memory *t, long length)
{
int i;
const uint8_t *buf = t->data + t->offset;
+#ifdef _UNICODE
+ wprintf(L"%s 0x%06x:", t->name, t->offset);
+#else
printf("%s 0x%06x:", t->name, t->offset);
+#endif
for(i = 0; i < 0x10; i++){
- char dump[3+1];
+ wgChar dump[3+1];
+#ifdef _UNICODE
+ //wsprintf(dump, L"%02x", buf[i]);
+#else
sprintf(dump, "%02x", buf[i]);
+#endif
switch(i){
case 7:
- dump[2] = '-';
+ dump[2] = wgT('-');
break;
case 0x0f:
- dump[2] = '\0';
+ dump[2] = wgT('\0');
break;
default:
- dump[2] = ' ';
+ dump[2] = wgT(' ');
break;
}
- dump[3] = '\0';
+ dump[3] = wgT('\0');
+#ifdef _UNICODE
+ wprintf(L"%s", dump);
+#else
printf("%s", dump);
+#endif
}
int sum = 0;
while(length != 0){
buf++;
length--;
}
+#ifdef _UNICODE
+ wprintf(L":0x%06x\n", sum);
+#else
printf(":0x%06x\n", sum);
+#endif
fflush(stdout);
}
-static void progress_show(struct memory_driver *d, const char *area)
-{
- char str[80];
- d->gauge->value_set(d->gauge->bar, d->memory.offset);
- snprintf(str, 80, "%s 0x%06x/0x%06x", area, d->memory.offset, d->memory.size);
- d->gauge->label_set(d->gauge->label, str);
-}
-static SQInteger read_memory(HSQUIRRELVM v, struct memory_driver *t, bool progress)
+static SQInteger read_memory(HSQUIRRELVM v, const struct reader_handle *h, struct dump_memory_driver *t, bool progress)
{
long address, length;
SQRESULT r = qr_argument_get(v, 2, &address, &length);
if(SQ_FAILED(r)){
return r;
}
- t->read(address, length == 0 ? 1: length, t->memory.data + t->memory.offset);
+ assert(t->memory.attribute == MEMORY_ATTR_WRITE);
+ t->access->memory_read(h, &t->gauge, address, length == 0 ? 1: length, t->memory.data + t->memory.offset);
if((length != 0) && (progress == false)){
buffer_show(&t->memory, length);
}
t->memory.offset += length;
return 0;
}
+
static SQInteger cpu_read(HSQUIRRELVM v)
{
- struct dump_driver *d;
- SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
- if(SQ_FAILED(r)){
- return r;
- }
- r = read_memory(v, &d->cpu, d->progress);
- progress_show(&d->cpu, "CPU");
+ USERPOINTER_GET(d, r)
+ r = read_memory(v, d->handle, &d->cpu, d->progress);
return r;
}
static SQInteger ppu_read(HSQUIRRELVM v)
{
- struct dump_driver *d;
- SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
- if(SQ_FAILED(r)){
- return r;
- }
- r = read_memory(v, &d->ppu, d->progress);
- progress_show(&d->ppu, "PPU");
+ USERPOINTER_GET(d, r)
+ r = read_memory(v, d->handle, &d->ppu, d->progress);
return r;
}
static SQInteger ppu_ramfind(HSQUIRRELVM v)
{
- struct dump_driver *d;
+ struct dump_config *d;
enum{
testsize = 8,
testaddress = 1234
static const uint8_t test_val[testsize] = {0xaa, 0x55, 0, 0xff, 0x46, 0x49, 0x07, 0x21};
static const uint8_t test_str[testsize] = "pputest";
uint8_t test_result[testsize];
-
SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ struct dump_memory_driver *p = &d->ppu;
+
if(SQ_FAILED(r)){
return r;
}
- d->ppu.write(testaddress, testsize, test_val);
- d->ppu.read(testaddress, testsize, test_result);
+ p->access->memory_write(d->handle, testaddress, testsize, test_val);
+ p->access->memory_read(d->handle, &GAUGE_DUMMY, testaddress, testsize, test_result);
if(memcmp(test_val, test_result, testsize) != 0){
sq_pushbool(v, SQFalse);
return 1;
}
- d->ppu.write(testaddress, testsize, test_str);
- d->ppu.read(testaddress, testsize, test_result);
+ p->access->memory_write(d->handle, testaddress, testsize, test_str);
+ p->access->memory_read(d->handle, &GAUGE_DUMMY, testaddress, testsize, test_result);
if(memcmp(test_str, test_result, testsize) != 0){
sq_pushbool(v, SQFalse);
return 1;
}
- d->ppu.memory.offset = 0;
- d->ppu.memory.size = 0;
+ p->memory.offset = 0;
+ p->memory.size = 0;
sq_pushbool(v, SQTrue);
return 1;
}
-static void memory_new_init(struct memory_driver *d, const char *area)
+static SQInteger return_true(HSQUIRRELVM v)
+{
+ sq_pushbool(v, SQFalse);
+ return 1;
+}
+
+static void memory_new_init(struct dump_memory_driver *d)
{
d->memory.offset = 0;
d->memory.data = Malloc(d->memory.size);
- d->gauge->value_set(d->gauge->bar, 0);
- d->gauge->range_set(d->gauge->bar, d->memory.size);
- d->gauge->label_set(d->gauge->label, area);
+ d->gauge.range_set(d->gauge.bar, d->memory.size);
+ d->gauge.value_set(d->gauge.bar, d->gauge.label, 0);
}
-//test »þ/1ÅÙÌܤΠcall ¤Ç»ÈÍÑ
+//test 時/1度目の call で使用
static SQInteger memory_new(HSQUIRRELVM v)
{
- struct dump_driver *d;
- SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
- if(SQ_FAILED(r)){
- return r;
- }
+ USERPOINTER_GET(d, r)
+
r = qr_argument_get(v, 2, &d->cpu.memory.size, &d->ppu.memory.size);
if(SQ_FAILED(r)){
return r;
}
-/* d->cpu.memory.offset = 0;
- d->cpu.memory.data = Malloc(d->cpu.memory.size);
- d->cpu.gauge->value_set(0);
- d->cpu.gauge->range_set(d->cpu.gauge->object, d->cpu.memory.size);
- d->ppu.memory.offset = 0;
- d->ppu.memory.data = Malloc(d->ppu.memory.size);
- d->cpu.gauge->value_set(0);
- d->ppu.gauge->range_set(d->ppu.gauge->object, d->ppu.memory.size);*/
- memory_new_init(&d->cpu, "CPU");
- memory_new_init(&d->ppu, "PPU");
+
+ memory_new_init(&d->cpu);
+ if(d->mode == MODE_ROM_DUMP){
+ memory_new_init(&d->ppu);
+ }
return 0;
}
-//dump »þ/2ÅÙÌܤΠcall ¤Ç nesfile_save ¤È¤·¤Æ»ÈÍÑ
+//dump 時/2度目の call で nesfile_save として使用
static SQInteger nesfile_save(HSQUIRRELVM v)
{
- struct dump_driver *d;
- SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
- if(SQ_FAILED(r)){
- return r;
- }
+ USERPOINTER_GET(d, r)
+
struct romimage image;
long mirrorfind;
r = qr_argument_get(v, 2, &image.mappernum, &mirrorfind);
image.ppu_rom = d->ppu.memory;
image.mirror = MIRROR_PROGRAMABLE;
if(mirrorfind == 1){
- if(d->vram_connection() == 0x05){
+ uint8_t c = d->control->vram_connection(d->handle);
+ if(DEBUG == 1){
+ d->log.append(d->log.object, wgT("vram connection %x\n"), c);
+ }
+/*
+kazzo 1.0 return value H:9 V:5
+kazzo 2.x return value H:C V:A
+*/
+ if(c == 0x05 || c == 0x0a){
image.mirror = MIRROR_VERTICAL;
}else{
image.mirror = MIRROR_HORIZONAL;
}
}
image.backupram = 0;
- nesfile_create(d->log, &image, d->target);
+ if(d->battery == true){
+ image.backupram = 1;
+ }
+ d->crc = nesfile_create(&d->log, &image, d->target);
nesbuffer_free(&image, 0); //0 is MODE_xxx_xxxx
d->cpu.memory.data = NULL;
return 0;
}
-//dump »þ/1ÅÙÌܤΠcall ¤Ç nesfile_save ¤È¤·¤Æ»ÈÍÑ
-static SQInteger length_check(HSQUIRRELVM v)
+static bool length_check_core(struct dump_config *d, struct dump_memory_driver *m, const wgChar * str)
{
- struct dump_driver *d;
- SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
- if(SQ_FAILED(r)){
- return r;
- }
- bool cpu = true, ppu = true;
- r = 0;
- if(d->cpu.memory.size != d->cpu.read_count){
- cpu = false;
- }
- char str[80];
- if(cpu == false){
- snprintf(str, 80, "cpu_romsize is not connected 0x%06x/0x%06x\n", (int) d->cpu.read_count, (int) d->cpu.memory.size);
- d->log->append(d->log->object, str);
+ bool ret = true;
+ if((m->read_count_bit & 0x7) != 0){
+ ret = false;
}
- if(d->ppu.memory.size != d->ppu.read_count){
- ppu = false;
+ m->read_count_byte += m->read_count_bit >> 3;
+ if(m->memory.size != m->read_count_byte){
+ ret = false;
}
- if(ppu == false){
- snprintf(str, 80, "ppu_romsize is not connected 0x%06x/0x%06x\n", (int) d->ppu.read_count, (int) d->ppu.memory.size);
- d->log->append(d->log->object, str);
+ if(ret == false){
+ d->log.append(d->log.object, wgT("%s is not connected 0x%06x.%d/0x%06x\n"), str, (int) m->read_count_byte, (int) m->read_count_bit & 7, (int) m->memory.size);
}
+
+ return ret;
+}
+
+//dump 時/1度目の call で nesfile_save として使用
+static SQInteger length_check(HSQUIRRELVM v)
+{
+ USERPOINTER_GET(d, r)
+
+ bool cpu = true, ppu = true;
+ r = 0;
+ cpu = length_check_core(d, &d->cpu, d->mode == MODE_ROM_DUMP ? wgT("board.cpu_rom.size") : wgT("board.cpu_ram.size"));
+ ppu = length_check_core(d, &d->ppu, wgT("board.ppu_rom.size"));
if(cpu == false || ppu == false){
- r = sq_throwerror(v, "script logical error");
+ r = sq_throwerror(v, wgT("script logical error"));
}
return r;
}
-static SQInteger read_count(HSQUIRRELVM v, struct textcontrol *l, struct memory_driver *t, const struct range *range_address, const struct range *range_length)
+static SQInteger read_count(HSQUIRRELVM v, const struct textcontrol *l, struct dump_memory_driver *t, const struct range *range_address, const struct range *range_length)
{
long address, length;
SQRESULT r = qr_argument_get(v, 2, &address, &length);
if(SQ_FAILED(r)){
return r;
}
- r = range_check(v, "length", length, range_length);
+ r = range_check(v, wgT("length"), length, range_length);
if(SQ_FAILED(r)){
return r;
}
if((address < range_address->start) || ((address + length) > range_address->end)){
- char str[80];
- snprintf(str, 80, "address range must be 0x%06x to 0x%06x", (int) range_address->start, (int) range_address->end);
- l->append(l->object, str);
- return sq_throwerror(v, "script logical error");;
+ l->append(l->object, wgT("address range must be 0x%06x to 0x%06x"), (int) range_address->start, (int) range_address->end);
+ return sq_throwerror(v, wgT("script logical error"));;
}
- t->read_count += length;
+ t->read_count_byte += length;
return 0;
}
static SQInteger cpu_read_count(HSQUIRRELVM v)
{
static const struct range range_address = {0x8000, 0x10000};
- //length == 0 ¤Ï Âоݥ¢¥É¥ì¥¹¤ò¸Æ¤ó¤Ç¡¢¥Ð¥Ã¥Õ¥¡¤Ë¤¤¤ì¤Ê¤¤¡£mmc2, mmc4 ¤Ç»ÈÍѤ¹¤ë¡£
+ //length == 0 は 対象アドレスを呼んで、バッファにいれない。mmc2, mmc4 で使用する。
static const struct range range_length = {0x0000, 0x4000};
- struct dump_driver *d;
- SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
- if(SQ_FAILED(r)){
- return r;
- }
- return read_count(v, d->log, &d->cpu, &range_address, &range_length);
+ USERPOINTER_GET(d, r)
+
+ return read_count(v, &d->log, &d->cpu, &range_address, &range_length);
}
static SQInteger ppu_read_count(HSQUIRRELVM v)
{
static const struct range range_address = {0x0000, 0x2000};
static const struct range range_length = {0x0001, 0x2000};
- struct dump_driver *d;
- SQRESULT r = qr_userpointer_get(v, (SQUserPointer) &d);
+ USERPOINTER_GET(d, r)
+
+ return read_count(v, &d->log, &d->ppu, &range_address, &range_length);
+}
+
+static SQInteger cpu_read_register_check(HSQUIRRELVM v)
+{
+ static const struct range range_address = {0x4800, 0x7fff};
+ static const struct range range_byte = {0, 0xff};
+ USERPOINTER_GET(d, r)
+
+ long address, byte;
+ r = qr_argument_get(v, 2, &address, &byte);
+ 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("byte"), byte, &range_byte);
+ if(SQ_FAILED(r)){
+ return r;
+ }
+
+ sq_pushinteger(v, byte);
+ return 1;
+}
+
+static SQInteger cpu_read_register(HSQUIRRELVM v)
+{
+ USERPOINTER_GET(d, r)
+ long address, dummy;
+ r = qr_argument_get(v, 2, &address, &dummy);
if(SQ_FAILED(r)){
return r;
}
- return read_count(v, d->log, &d->ppu, &range_address, &range_length);
+
+ uint8_t readdata;
+ d->cpu.access->memory_read(d->handle, &GAUGE_DUMMY, address, 1, &readdata);
+
+ sq_pushinteger(v, readdata);
+ return 1;
+}
+
+static SQInteger memory_size_set(HSQUIRRELVM v)
+{
+ USERPOINTER_GET(d, r)
+ r = qr_argument_get(v, 2, &d->cpu.memory.size, &d->ppu.memory.size);
+ return r;
}
-static bool script_execute(HSQUIRRELVM v, struct config_dump *c, struct dump_driver *d)
+static bool script_execute(HSQUIRRELVM v, struct dump_config *d)
{
bool ret = true;
- if(SQ_FAILED(sqstd_dofile(v, _SC("dumpcore.nut"), SQFalse, SQTrue))){
- d->log->append(d->log->object, "dump core script error\n");
- ret = false;
- }else if(SQ_FAILED(sqstd_dofile(v, _SC(c->script), SQFalse, SQTrue))){
- char str[80];
- snprintf(str, 80, "%s open error\n", c->script);
- d->log->append(d->log->object, str);
+ 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, "dump", (SQUserPointer) d, true,
- 3, c->mappernum, c->increase.cpu, c->increase.ppu
+ v, wgT("dump"), (SQUserPointer) d, d->script,
+ 3, d->mappernum, d->cpu.increase, d->ppu.increase
);
if(SQ_FAILED(r)){
ret = false;
}
return ret;
}
-void script_dump_execute(struct config_dump *c)
-{
- struct dump_driver d = {
- .cpu = {
- .memory = {
- .name = "program",
- .size = 0, .offset = 0,
- .attribute = MEMORY_ATTR_WRITE,
- .transtype = TRANSTYPE_FULL,
- .data = NULL
- },
- .read_count = 0,
- .write = c->reader->cpu_write_6502,
- .read = c->reader->cpu_read,
- .gauge = &c->gauge_cpu
- },
- .ppu = {
- .memory = {
- .name = "charcter",
- .size = 0, .offset = 0,
- .attribute = MEMORY_ATTR_WRITE,
- .transtype = TRANSTYPE_FULL,
- .data = NULL
- },
- .read_count = 0,
- .write = c->reader->ppu_write,
- .read = c->reader->ppu_read,
- .gauge = &c->gauge_ppu
- },
- .vram_connection = c->reader->vram_connection,
- .target = c->target,
- .progress = c->progress,
- .log = &c->log
- };
+
+static void dump_memory_driver_init(struct dump_memory_driver *dd, enum memory_attribute at)
+{
+ dd->memory.size = 0;
+ dd->memory.offset = 0;
+ dd->memory.attribute = at;
+ dd->memory.transtype = TRANSTYPE_FULL;
+ dd->memory.data = NULL;
+ dd->read_count_byte = 0;
+ dd->read_count_bit = 0;
+}
+
+bool script_dump_execute(struct dump_config *d)
+{
+ dump_memory_driver_init(&d->cpu, MEMORY_ATTR_WRITE);
+ d->cpu.memory.name = wgT("Program");
+
+ dump_memory_driver_init(&d->ppu, MEMORY_ATTR_WRITE);
+ d->ppu.memory.name = wgT("Charcter");
+
{
- HSQUIRRELVM v = qr_open(&c->log);
- qr_function_register_global(v, "ppu_ramfind", script_nop);
- qr_function_register_global(v, "cpu_write", cpu_write_check);
- qr_function_register_global(v, "memory_new", memory_new);
- qr_function_register_global(v, "nesfile_save", length_check);
- qr_function_register_global(v, "cpu_read", cpu_read_count);
- qr_function_register_global(v, "ppu_read", ppu_read_count);
- qr_function_register_global(v, "require", script_require);
- if(script_execute(v, c, &d) == false){
+ HSQUIRRELVM v = qr_open(&d->log);
+ qr_function_register_global(v, wgT("cpu_write"), cpu_write_check);
+ qr_function_register_global(v, wgT("memory_new"), memory_size_set);
+ qr_function_register_global(v, wgT("nesfile_save"), length_check);
+ qr_function_register_global(v, wgT("cpu_read"), cpu_read_count);
+ qr_function_register_global(v, wgT("ppu_read"), ppu_read_count);
+ qr_function_register_global(v, wgT("ppu_ramfind"), return_true);
+ if(script_execute(v, d) == false){
qr_close(v);
- return;
+ return false;
}
qr_close(v);
}
- if(c->progress == true){
- progress_init();
+
+ 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;
}
+/* 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(&c->log);
- qr_function_register_global(v, "memory_new", script_nop);
- qr_function_register_global(v, "nesfile_save", nesfile_save);
- qr_function_register_global(v, "cpu_write", cpu_write);
- qr_function_register_global(v, "cpu_read", cpu_read);
- qr_function_register_global(v, "ppu_read", ppu_read);
- qr_function_register_global(v, "ppu_ramfind", ppu_ramfind);
- qr_function_register_global(v, "require", script_require);
- script_execute(v, c, &d);
+ HSQUIRRELVM v = qr_open(&d->log);
+ qr_function_register_global(v, wgT("memory_new"), memory_new);
+ qr_function_register_global(v, wgT("nesfile_save"), nesfile_save);
+ qr_function_register_global(v, wgT("cpu_write"), cpu_write);
+ qr_function_register_global(v, wgT("cpu_read"), cpu_read);
+ qr_function_register_global(v, wgT("ppu_read"), ppu_read);
+ qr_function_register_global(v, wgT("ppu_ramfind"), ppu_ramfind);
+ script_execute(v, d);
+ qr_close(v);
+ }
+ 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;
}