mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-06-03 19:29:32 +00:00
working on new unified MAME support
This commit is contained in:
parent
b344590917
commit
3b13a472bc
|
@ -8,31 +8,19 @@ local stopped = false
|
|||
function mamedbg.init()
|
||||
cpu = manager:machine().devices[":maincpu"]
|
||||
mem = cpu.spaces["program"]
|
||||
debugger = manager:machine():debugger()
|
||||
machine = manager:machine()
|
||||
debugger = machine:debugger()
|
||||
mamedbg.reset()
|
||||
emu.register_periodic(function ()
|
||||
if debugging then
|
||||
if not stopped then
|
||||
--debugger:command("symlist")
|
||||
--log = debugger.consolelog
|
||||
--for i=1,#log do print(log[i]) end
|
||||
--print(string.format("%4x", cpu.state["PC"].value))
|
||||
--manager:machine():save("state")
|
||||
emu.pause()
|
||||
stopped = true
|
||||
-- callback to JS via console i/o
|
||||
mamedbg.printstate()
|
||||
print(">>>debug_stopped")
|
||||
print("1")
|
||||
end
|
||||
if debugging and not stopped then
|
||||
--print(debugger.execution_state)
|
||||
lastBreakState = machine.buffer_save()
|
||||
emu.pause()
|
||||
stopped = true
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function mamedbg.printstate()
|
||||
for k,v in pairs(cpu.state) do print(">>>cpu_"..k); print(v.value) end
|
||||
end
|
||||
|
||||
function mamedbg.reset()
|
||||
debugging = false
|
||||
stopped = false
|
||||
|
@ -47,8 +35,12 @@ function mamedbg.is_stopped()
|
|||
return debugging and stopped
|
||||
end
|
||||
|
||||
function mamedbg.continue()
|
||||
debugger:command("g")
|
||||
end
|
||||
|
||||
function mamedbg.runTo(addr)
|
||||
debugger:command("g " .. string.format("%x", addr))
|
||||
debugger:command(string.format("g %x", addr))
|
||||
mamedbg.start()
|
||||
end
|
||||
|
||||
|
@ -67,4 +59,16 @@ function mamedbg.step()
|
|||
mamedbg.start()
|
||||
end
|
||||
|
||||
function string.fromhex(str)
|
||||
return (str:gsub('..', function (cc)
|
||||
return string.char(tonumber(cc, 16))
|
||||
end))
|
||||
end
|
||||
|
||||
function string.tohex(str)
|
||||
return (str:gsub('.', function (c)
|
||||
return string.format('%02X', string.byte(c))
|
||||
end))
|
||||
end
|
||||
|
||||
print("parsed Lua debugger script")
|
||||
|
|
File diff suppressed because one or more lines are too long
BIN
mame/mame8bitws.wasm
Normal file
BIN
mame/mame8bitws.wasm
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
30
package-lock.json
generated
30
package-lock.json
generated
|
@ -40,7 +40,7 @@
|
|||
"@types/sizzle": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz",
|
||||
"integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==",
|
||||
"integrity": "sha1-qBG4wY4rq6t9VCszZYh64uTZ3kc=",
|
||||
"dev": true
|
||||
},
|
||||
"abab": {
|
||||
|
@ -58,7 +58,7 @@
|
|||
"acorn-globals": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.0.tgz",
|
||||
"integrity": "sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw==",
|
||||
"integrity": "sha1-47b42jwVUqla5idXH33Wkju1QQM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"acorn": "^6.0.1",
|
||||
|
@ -129,7 +129,7 @@
|
|||
"asn1": {
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
|
||||
"integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
|
||||
"integrity": "sha1-jSR136tVO7M+d7VOWeiAu4ziMTY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safer-buffer": "~2.1.0"
|
||||
|
@ -239,7 +239,7 @@
|
|||
"browser-stdout": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
|
||||
"integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
|
||||
"integrity": "sha1-uqVZ7hTO1zRSIputcyZGfGH6vWA=",
|
||||
"dev": true
|
||||
},
|
||||
"btoa": {
|
||||
|
@ -404,7 +404,7 @@
|
|||
"cssstyle": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.1.1.tgz",
|
||||
"integrity": "sha512-364AI1l/M5TYcFH83JnOH/pSqgaNnKmYgKrm0didZMGKWjQB60dymwWy1rKUgL3J1ffdq9xVi2yGLHdSjjSNog==",
|
||||
"integrity": "sha1-GLA4qcRNZfeo5CimU7n2/kL69fs=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cssom": "0.3.x"
|
||||
|
@ -466,7 +466,7 @@
|
|||
"diff": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
|
||||
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
|
||||
"integrity": "sha1-gAwN0eCov7yVg1wgKtIg/jF+WhI=",
|
||||
"dev": true
|
||||
},
|
||||
"domexception": {
|
||||
|
@ -562,7 +562,7 @@
|
|||
"escodegen": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.0.tgz",
|
||||
"integrity": "sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==",
|
||||
"integrity": "sha1-snqTiUgdW/1b7Hb3ux6z+PRVZYk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esprima": "^3.1.3",
|
||||
|
@ -593,7 +593,7 @@
|
|||
"extend": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
|
||||
"integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=",
|
||||
"dev": true
|
||||
},
|
||||
"extsprintf": {
|
||||
|
@ -756,7 +756,7 @@
|
|||
"growl": {
|
||||
"version": "1.10.5",
|
||||
"resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
|
||||
"integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
|
||||
"integrity": "sha1-8nNdwig2dPpnR4sQGBBZNVw2nl4=",
|
||||
"dev": true
|
||||
},
|
||||
"har-schema": {
|
||||
|
@ -1282,7 +1282,7 @@
|
|||
"oauth-sign": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
|
||||
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
|
||||
"integrity": "sha1-R6ewFrqmi1+g7PPe4IqFxnmsZFU=",
|
||||
"dev": true
|
||||
},
|
||||
"object-inspect": {
|
||||
|
@ -1422,7 +1422,7 @@
|
|||
"pngjs": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz",
|
||||
"integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==",
|
||||
"integrity": "sha1-mcp9clll+2VYFOr2XzjxK72/VV8=",
|
||||
"dev": true
|
||||
},
|
||||
"prelude-ls": {
|
||||
|
@ -1452,7 +1452,7 @@
|
|||
"qs": {
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
|
||||
"integrity": "sha1-yzroBuh0BERYTvFUzo7pjUA/PjY=",
|
||||
"dev": true
|
||||
},
|
||||
"readdirp": {
|
||||
|
@ -1472,7 +1472,7 @@
|
|||
"request": {
|
||||
"version": "2.88.0",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
|
||||
"integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
|
||||
"integrity": "sha1-nC/KT301tZLv5Xx/ClXoEFIST+8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"aws-sign2": "~0.7.0",
|
||||
|
@ -1583,7 +1583,7 @@
|
|||
"semver": {
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
|
||||
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
|
||||
"integrity": "sha1-eQp89v6lRZuslhELKbYEEtyP+Ws=",
|
||||
"dev": true
|
||||
},
|
||||
"set-blocking": {
|
||||
|
@ -1794,7 +1794,7 @@
|
|||
"uuid": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
|
||||
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==",
|
||||
"integrity": "sha1-G0r0lV6zB3xQHCOHL8ZROBFYcTE=",
|
||||
"dev": true
|
||||
},
|
||||
"verror": {
|
||||
|
|
|
@ -645,41 +645,43 @@ export abstract class BaseMAMEPlatform {
|
|||
romdata : Uint8Array;
|
||||
video;
|
||||
running = false;
|
||||
console_vars : {[varname:string]:string} = {};
|
||||
console_varname : string;
|
||||
initluavars : boolean = false;
|
||||
luadebugscript : string;
|
||||
js_lua_string;
|
||||
onBreakpointHit;
|
||||
mainElement : HTMLElement;
|
||||
timer : AnimationTimer;
|
||||
|
||||
constructor(mainElement) {
|
||||
this.mainElement = mainElement;
|
||||
}
|
||||
|
||||
luareset() {
|
||||
this.console_vars = {};
|
||||
this.timer = new AnimationTimer(20, this.poll.bind(this));
|
||||
}
|
||||
|
||||
// http://docs.mamedev.org/techspecs/luaengine.html
|
||||
luacall(s) {
|
||||
this.console_varname = null;
|
||||
//Module.ccall('_Z13js_lua_stringPKc', 'void', ['string'], [s+""]);
|
||||
if (!this.js_lua_string) this.js_lua_string = Module.cwrap('_Z13js_lua_stringPKc', 'void', ['string']);
|
||||
this.js_lua_string(s || "");
|
||||
luacall(s:string) : string {
|
||||
if (!this.js_lua_string) this.js_lua_string = Module.cwrap('_Z13js_lua_stringPKc', 'string', ['string']);
|
||||
return this.js_lua_string(s || "");
|
||||
}
|
||||
|
||||
_pause() {
|
||||
this.running = false;
|
||||
this.timer.stop();
|
||||
}
|
||||
pause() {
|
||||
if (this.loaded && this.running) {
|
||||
this.luacall('emu.pause()');
|
||||
this.running = false;
|
||||
this._pause();
|
||||
}
|
||||
}
|
||||
|
||||
_resume() {
|
||||
this.luacall('emu.unpause()');
|
||||
this.running = true;
|
||||
this.timer.start();
|
||||
}
|
||||
resume() {
|
||||
if (this.loaded && !this.running) { // TODO
|
||||
this.luacall('emu.unpause()');
|
||||
this.running = true;
|
||||
this._resume();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -697,13 +699,7 @@ export abstract class BaseMAMEPlatform {
|
|||
|
||||
bufferConsoleOutput(s) {
|
||||
if (typeof s !== 'string') return;
|
||||
if (s.startsWith(">>>")) {
|
||||
console.log(s);
|
||||
var toks = s.split(' ', 3);
|
||||
this.console_vars[toks[1]] = toks[2];
|
||||
} else {
|
||||
console.log(s);
|
||||
}
|
||||
console.log(s);
|
||||
}
|
||||
|
||||
startModule(mainElement, opts) {
|
||||
|
@ -819,6 +815,11 @@ export abstract class BaseMAMEPlatform {
|
|||
document.getElementsByTagName('head')[0].appendChild(script);
|
||||
console.log("created script element");
|
||||
});
|
||||
// for debugging via browser console
|
||||
window['mamelua'] = (s:string) => {
|
||||
this.initlua();
|
||||
return this.luacall(s);
|
||||
};
|
||||
}
|
||||
|
||||
loadROMFile(data) {
|
||||
|
@ -842,6 +843,8 @@ export abstract class BaseMAMEPlatform {
|
|||
}
|
||||
}
|
||||
|
||||
// DEBUGGING SUPPORT
|
||||
|
||||
initlua() {
|
||||
if (!this.initluavars) {
|
||||
this.luacall(this.luadebugscript);
|
||||
|
@ -850,68 +853,116 @@ export abstract class BaseMAMEPlatform {
|
|||
}
|
||||
}
|
||||
|
||||
// DEBUGGING SUPPORT
|
||||
/*
|
||||
readAddress(a) {
|
||||
readAddress(a:number) : number {
|
||||
this.initlua();
|
||||
this.luacall('print(">>> mem8 " .. mem:read_u8(' + a + '))');
|
||||
return parseInt(this.console_vars.mem8);
|
||||
return parseInt(this.luacall('return mem:read_u8(' + a + ')'));
|
||||
}
|
||||
|
||||
preserveState() {
|
||||
var state = {c:{}};
|
||||
for (var k in this.console_vars) {
|
||||
if (k.startsWith("cpu_")) {
|
||||
var v = parseInt(this.console_vars[k][0]);
|
||||
state.c[k.slice(4)] = v;
|
||||
}
|
||||
getCPUReg(reg:string) {
|
||||
this.initlua();
|
||||
return parseInt(this.luacall('return cpu.state.'+reg+'.value'));
|
||||
}
|
||||
|
||||
getPC() : number {
|
||||
return this.getCPUReg('PC');
|
||||
}
|
||||
|
||||
getSP() : number {
|
||||
return this.getCPUReg('SP');
|
||||
}
|
||||
|
||||
isStable() { return true; }
|
||||
|
||||
getCPUState() {
|
||||
return {
|
||||
PC:this.getPC(),
|
||||
SP:this.getSP(),
|
||||
A:this.getCPUReg('A'),
|
||||
X:this.getCPUReg('X'),
|
||||
Y:this.getCPUReg('Y'),
|
||||
//flags:this.getCPUReg('CURFLAGS'),
|
||||
};
|
||||
}
|
||||
|
||||
grabState(expr:string) {
|
||||
this.initlua();
|
||||
return {
|
||||
c:this.getCPUState(),
|
||||
buf:this.luacall("return string.tohex(" + expr + ")")
|
||||
}
|
||||
// TODO: memory?
|
||||
return state;
|
||||
}
|
||||
|
||||
saveState() {
|
||||
this.luareset();
|
||||
this.luacall('mamedbg.printstate()');
|
||||
return this.preserveState();
|
||||
return this.grabState("manager:machine():buffer_save()");
|
||||
}
|
||||
|
||||
loadState(state) {
|
||||
this.initlua();
|
||||
return this.luacall("manager:machine():buffer_load(string.fromhex('" + state.buf + "'))");
|
||||
}
|
||||
|
||||
poll() {
|
||||
if (this.onBreakpointHit && this.luacall("return tostring(mamedbg.is_stopped())") == 'true') {
|
||||
this._pause();
|
||||
//this.luacall("manager:machine():buffer_load(lastBreakState)");
|
||||
var state = this.grabState("lastBreakState");
|
||||
this.onBreakpointHit(state);
|
||||
}
|
||||
}
|
||||
clearDebug() {
|
||||
this.onBreakpointHit = null;
|
||||
if (this.loaded) {
|
||||
this.initlua();
|
||||
this.luacall('mamedbg.reset()');
|
||||
}
|
||||
}
|
||||
getDebugCallback() {
|
||||
return this.onBreakpointHit;// TODO?
|
||||
}
|
||||
setupDebug(callback) {
|
||||
if (this.loaded) { // TODO?
|
||||
this.initlua();
|
||||
this.luareset();
|
||||
}
|
||||
this.onBreakpointHit = callback;
|
||||
}
|
||||
debugcmd(s) {
|
||||
this.initlua()
|
||||
this.luacall(s);
|
||||
this._resume();
|
||||
}
|
||||
runToPC(pc) {
|
||||
this.luacall('mamedbg.runTo(' + pc + ')');
|
||||
this.resume();
|
||||
this.debugcmd('mamedbg.runTo(' + pc + ')');
|
||||
}
|
||||
runToVsync() {
|
||||
this.luacall('mamedbg.runToVsync()');
|
||||
this.resume();
|
||||
this.debugcmd('mamedbg.runToVsync()');
|
||||
}
|
||||
runUntilReturn() {
|
||||
this.luacall('mamedbg.runUntilReturn()');
|
||||
this.resume();
|
||||
this.debugcmd('mamedbg.runUntilReturn()');
|
||||
}
|
||||
// TODO
|
||||
runEval() {
|
||||
this.reset();
|
||||
this.step();
|
||||
}
|
||||
step() {
|
||||
this.luacall('mamedbg.step()');
|
||||
this.resume();
|
||||
this.debugcmd('mamedbg.step()');
|
||||
}
|
||||
getDebugCategories() {
|
||||
return ['CPU'];
|
||||
}
|
||||
getDebugInfo(category:string, state:EmuState) : string {
|
||||
switch (category) {
|
||||
case 'CPU': return this.cpuStateToLongString(state.c);
|
||||
}
|
||||
}
|
||||
// TODO: other than z80
|
||||
cpuStateToLongString(c) {
|
||||
if (c.HL)
|
||||
return cpuStateToLongString_Z80(c);
|
||||
else
|
||||
return null; // TODO
|
||||
return cpuStateToLongString_6502(c); // TODO
|
||||
}
|
||||
disassemble(pc:number, read:(addr:number)=>number) : DisasmLine {
|
||||
// TODO: z80
|
||||
return disassemble6502(pc, read(pc), read(pc+1), read(pc+2));
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
//TODO: how to get stack_end?
|
||||
|
|
|
@ -27,7 +27,7 @@ class Apple2MAMEPlatform extends BaseMAMEPlatform implements Platform {
|
|||
|
||||
start () {
|
||||
this.startModule(this.mainElement, {
|
||||
jsfile:'mameapple2e.js',
|
||||
jsfile:'mame8bitws.js',
|
||||
biosfile:['apple2e.zip'],
|
||||
//cfgfile:'nes.cfg',
|
||||
driver:'apple2e',
|
||||
|
|
|
@ -806,7 +806,7 @@ class Atari800MAMEPlatform extends Atari8MAMEPlatform implements Platform {
|
|||
loadROM(title, data) {
|
||||
if (!this.started) {
|
||||
this.startModule(this.mainElement, {
|
||||
jsfile:'mameatari400.js',
|
||||
jsfile:'mame8bitws.js',
|
||||
biosfile:'a800xl.zip',
|
||||
cfgfile:'a800xl.cfg',
|
||||
driver:'a800xl',
|
||||
|
@ -843,7 +843,7 @@ class Atari5200MAMEPlatform extends Atari8MAMEPlatform implements Platform {
|
|||
loadROM(title, data) {
|
||||
if (!this.started) {
|
||||
this.startModule(this.mainElement, {
|
||||
jsfile:'mameatari400.js',
|
||||
jsfile:'mame8bitws.js',
|
||||
biosfile:'a5200/5200.rom',
|
||||
cfgfile:'a5200.cfg',
|
||||
driver:'a5200',
|
||||
|
|
|
@ -43,7 +43,7 @@ class ColecoVisionMAMEPlatform extends BaseMAMEPlatform implements Platform {
|
|||
|
||||
start() {
|
||||
this.startModule(this.mainElement, {
|
||||
jsfile: 'mamecoleco.js',
|
||||
jsfile: 'mame8bitws.js',
|
||||
cfgfile: 'coleco.cfg',
|
||||
biosfile: 'coleco/313 10031-4005 73108a.u2',
|
||||
driver: 'coleco',
|
||||
|
|
|
@ -496,7 +496,7 @@ class NESMAMEPlatform extends BaseMAMEPlatform implements Platform {
|
|||
loadROM(title, data) {
|
||||
if (!this.started) {
|
||||
this.startModule(this.mainElement, {
|
||||
jsfile:'mamenes.js',
|
||||
jsfile:'mame8bitws.js',
|
||||
//cfgfile:'nes.cfg',
|
||||
driver:'nes',
|
||||
width:256,
|
||||
|
|
|
@ -405,7 +405,7 @@ class VCSMAMEPlatform extends BaseMAMEPlatform implements Platform {
|
|||
|
||||
start = function() {
|
||||
this.startModule(this.mainElement, {
|
||||
jsfile:'mamea2600.js',
|
||||
jsfile:'mame8bitws.js',
|
||||
driver:'a2600',
|
||||
width:176*2,
|
||||
height:223,
|
||||
|
|
Loading…
Reference in New Issue
Block a user