trunk/src/emu/luaengine.c
| r30925 | r30926 | |
| 39 | 39 | #define luai_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) |
| 40 | 40 | #define luai_writeline() (luai_writestring("\n", 1), fflush(stdout)) |
| 41 | 41 | |
| 42 | const char *const lua_engine::tname_ioport = "lua.ioport"; |
| 43 | lua_engine* lua_engine::luaThis = NULL; |
| 44 | |
| 45 | |
| 42 | 46 | static void lstop(lua_State *L, lua_Debug *ar) |
| 43 | 47 | { |
| 44 | 48 | (void)ar; /* unused arg. */ |
| r30925 | r30926 | |
| 115 | 119 | return 0; /* else... */ |
| 116 | 120 | } |
| 117 | 121 | |
| 118 | | int emu_gamename(lua_State *L) |
| 122 | lua_engine::hook::hook() |
| 119 | 123 | { |
| 120 | | lua_pushstring(L, machine_manager::instance()->machine()->system().description); |
| 124 | L = NULL; |
| 125 | cb = -1; |
| 126 | } |
| 127 | |
| 128 | void lua_engine::hook::set(lua_State *_L, int idx) |
| 129 | { |
| 130 | if (L) |
| 131 | luaL_unref(L, LUA_REGISTRYINDEX, cb); |
| 132 | |
| 133 | if (lua_isnil(_L, idx)) { |
| 134 | L = NULL; |
| 135 | cb = -1; |
| 136 | |
| 137 | } else { |
| 138 | L = _L; |
| 139 | lua_pushvalue(_L, idx); |
| 140 | cb = luaL_ref(_L, LUA_REGISTRYINDEX); |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | lua_State *lua_engine::hook::precall() |
| 145 | { |
| 146 | lua_State *T = lua_newthread(L); |
| 147 | lua_rawgeti(T, LUA_REGISTRYINDEX, cb); |
| 148 | return T; |
| 149 | } |
| 150 | |
| 151 | void lua_engine::hook::call(lua_engine *engine, lua_State *T, int nparam) |
| 152 | { |
| 153 | engine->resume(T, nparam, L); |
| 154 | } |
| 155 | |
| 156 | void lua_engine::resume(lua_State *L, int nparam, lua_State *root) |
| 157 | { |
| 158 | int s = lua_resume(L, NULL, nparam); |
| 159 | switch(s) { |
| 160 | case LUA_OK: |
| 161 | if(!root) { |
| 162 | std::map<lua_State *, std::pair<lua_State *, int> >::iterator i = thread_registry.find(L); |
| 163 | if(i != thread_registry.end()) { |
| 164 | luaL_unref(i->second.first, LUA_REGISTRYINDEX, i->second.second); |
| 165 | thread_registry.erase(i); |
| 166 | } |
| 167 | } else |
| 168 | lua_pop(root, 1); |
| 169 | break; |
| 170 | |
| 171 | case LUA_YIELD: |
| 172 | if(root) { |
| 173 | int id = luaL_ref(root, LUA_REGISTRYINDEX); |
| 174 | thread_registry[L] = std::pair<lua_State *, int>(root, id); |
| 175 | } |
| 176 | break; |
| 177 | |
| 178 | default: |
| 179 | osd_printf_error("[LUA ERROR] %s\n", lua_tostring(L, -1)); |
| 180 | lua_pop(L, 1); |
| 181 | break; |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | void lua_engine::resume(void *_L, INT32 param) |
| 186 | { |
| 187 | resume(static_cast<lua_State *>(_L)); |
| 188 | } |
| 189 | |
| 190 | int lua_engine::l_ioport_write(lua_State *L) |
| 191 | { |
| 192 | ioport_field *field = static_cast<ioport_field *>(getparam(L, 1, tname_ioport)); |
| 193 | luaL_argcheck(L, lua_isnumber(L, 2), 2, "value expected"); |
| 194 | field->set_value(lua_tointeger(L, 2)); |
| 195 | return 0; |
| 196 | } |
| 197 | |
| 198 | //------------------------------------------------- |
| 199 | // emu_gamename - returns game full name |
| 200 | //------------------------------------------------- |
| 201 | |
| 202 | int lua_engine::l_emu_gamename(lua_State *L) |
| 203 | { |
| 204 | lua_pushstring(L, luaThis->machine().system().description); |
| 121 | 205 | return 1; |
| 122 | 206 | } |
| 123 | 207 | |
| r30925 | r30926 | |
| 125 | 209 | // emu_keypost - post keys to natural keyboard |
| 126 | 210 | //------------------------------------------------- |
| 127 | 211 | |
| 128 | | int emu_keypost(lua_State *L) |
| 212 | int lua_engine::l_emu_keypost(lua_State *L) |
| 129 | 213 | { |
| 130 | 214 | const char *keys = luaL_checkstring(L,1); |
| 131 | | machine_manager::instance()->machine()->ioport().natkeyboard().post_utf8(keys); |
| 215 | luaThis->machine().ioport().natkeyboard().post_utf8(keys); |
| 132 | 216 | return 1; |
| 133 | 217 | } |
| 134 | 218 | |
| 135 | | int emu_exit(lua_State *L) |
| 219 | int lua_engine::l_emu_time(lua_State *L) |
| 136 | 220 | { |
| 137 | | machine_manager::instance()->machine()->schedule_exit(); |
| 221 | lua_pushnumber(L, luaThis->machine().time().as_double()); |
| 138 | 222 | return 1; |
| 139 | 223 | } |
| 140 | 224 | |
| 141 | | int emu_start(lua_State *L) |
| 225 | void lua_engine::emu_after_done(void *_h, INT32 param) |
| 142 | 226 | { |
| 227 | hook *h = static_cast<hook *>(_h); |
| 228 | h->call(this, h->precall(), 0); |
| 229 | delete h; |
| 230 | } |
| 231 | |
| 232 | int lua_engine::emu_after(lua_State *L) |
| 233 | { |
| 234 | luaL_argcheck(L, lua_isnumber(L, 1), 1, "waiting duration expected"); |
| 235 | struct hook *h = new hook; |
| 236 | h->set(L, 2); |
| 237 | machine().scheduler().timer_set(attotime::from_double(lua_tonumber(L, 1)), timer_expired_delegate(FUNC(lua_engine::emu_after_done), this), 0, h); |
| 238 | return 0; |
| 239 | } |
| 240 | |
| 241 | int lua_engine::l_emu_after(lua_State *L) |
| 242 | { |
| 243 | return luaThis->emu_after(L); |
| 244 | } |
| 245 | |
| 246 | int lua_engine::emu_wait(lua_State *L) |
| 247 | { |
| 248 | luaL_argcheck(L, lua_isnumber(L, 1), 1, "waiting duration expected"); |
| 249 | machine().scheduler().timer_set(attotime::from_double(lua_tonumber(L, 1)), timer_expired_delegate(FUNC(lua_engine::resume), this), 0, L); |
| 250 | return lua_yieldk(L, 0, 0, 0); |
| 251 | } |
| 252 | |
| 253 | int lua_engine::l_emu_wait(lua_State *L) |
| 254 | { |
| 255 | return luaThis->emu_wait(L); |
| 256 | } |
| 257 | |
| 258 | void lua_engine::output_notifier(const char *outname, INT32 value) |
| 259 | { |
| 260 | if (hook_output_cb.active()) { |
| 261 | lua_State *L = hook_output_cb.precall(); |
| 262 | lua_pushstring(L, outname); |
| 263 | lua_pushnumber(L, value); |
| 264 | hook_output_cb.call(this, L, 2); |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | void lua_engine::s_output_notifier(const char *outname, INT32 value, void *param) |
| 269 | { |
| 270 | static_cast<lua_engine *>(param)->output_notifier(outname, value); |
| 271 | } |
| 272 | |
| 273 | void lua_engine::emu_hook_output(lua_State *L) |
| 274 | { |
| 275 | luaL_argcheck(L, lua_isfunction(L, 1), 1, "callback function expected"); |
| 276 | hook_output_cb.set(L, 1); |
| 277 | |
| 278 | if (!output_notifier_set) { |
| 279 | output_set_notifier(NULL, s_output_notifier, this); |
| 280 | output_notifier_set = true; |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | int lua_engine::l_emu_hook_output(lua_State *L) |
| 285 | { |
| 286 | luaThis->emu_hook_output(L); |
| 287 | return 0; |
| 288 | } |
| 289 | |
| 290 | |
| 291 | void *lua_engine::checkparam(lua_State *L, int idx, const char *tname) |
| 292 | { |
| 293 | const char *name; |
| 294 | |
| 295 | if(!lua_getmetatable(L, idx)) |
| 296 | return 0; |
| 297 | |
| 298 | lua_rawget(L, LUA_REGISTRYINDEX); |
| 299 | name = lua_tostring(L, -1); |
| 300 | if(!name || strcmp(name, tname)) { |
| 301 | lua_pop(L, 1); |
| 302 | return 0; |
| 303 | } |
| 304 | lua_pop(L, 1); |
| 305 | |
| 306 | return *static_cast<void **>(lua_touserdata(L, idx)); |
| 307 | } |
| 308 | |
| 309 | void *lua_engine::getparam(lua_State *L, int idx, const char *tname) |
| 310 | { |
| 311 | void *p = checkparam(L, idx, tname); |
| 312 | char msg[256]; |
| 313 | sprintf(msg, "%s expected", tname); |
| 314 | luaL_argcheck(L, p, idx, msg); |
| 315 | return p; |
| 316 | } |
| 317 | |
| 318 | void lua_engine::push(lua_State *L, void *p, const char *tname) |
| 319 | { |
| 320 | void **pp = static_cast<void **>(lua_newuserdata(L, sizeof(void *))); |
| 321 | *pp = p; |
| 322 | luaL_getmetatable(L, tname); |
| 323 | lua_setmetatable(L, -2); |
| 324 | } |
| 325 | |
| 326 | int lua_engine::l_emu_exit(lua_State *L) |
| 327 | { |
| 328 | luaThis->machine().schedule_exit(); |
| 329 | return 1; |
| 330 | } |
| 331 | |
| 332 | int lua_engine::l_emu_start(lua_State *L) |
| 333 | { |
| 143 | 334 | const char *system_name = luaL_checkstring(L,1); |
| 144 | 335 | |
| 145 | 336 | int index = driver_list::find(system_name); |
| 146 | 337 | if (index != -1) { |
| 147 | 338 | machine_manager::instance()->schedule_new_driver(driver_list::driver(index)); |
| 148 | | machine_manager::instance()->machine()->schedule_hard_reset(); |
| 339 | luaThis->machine().schedule_hard_reset(); |
| 149 | 340 | } |
| 150 | 341 | return 1; |
| 151 | 342 | } |
| 152 | 343 | |
| 153 | | static const struct luaL_Reg emu_funcs [] = |
| 154 | | { |
| 155 | | { "gamename", emu_gamename }, |
| 156 | | { "keypost", emu_keypost }, |
| 157 | | { "exit", emu_exit }, |
| 158 | | { "start", emu_start }, |
| 159 | | { NULL, NULL } /* sentinel */ |
| 160 | | }; |
| 161 | | |
| 162 | 344 | //------------------------------------------------- |
| 163 | 345 | // luaopen_emu - connect emu section lib |
| 164 | 346 | //------------------------------------------------- |
| 165 | 347 | |
| 166 | | static int luaopen_emu ( lua_State * L ) |
| 348 | int lua_engine::luaopen_emu(lua_State *L) |
| 167 | 349 | { |
| 350 | static const struct luaL_Reg emu_funcs [] = { |
| 351 | { "gamename", l_emu_gamename }, |
| 352 | { "keypost", l_emu_keypost }, |
| 353 | { "hook_output", l_emu_hook_output }, |
| 354 | { "time", l_emu_time }, |
| 355 | { "wait", l_emu_wait }, |
| 356 | { "after", l_emu_after }, |
| 357 | { "exit", l_emu_exit }, |
| 358 | { "start", l_emu_start }, |
| 359 | { NULL, NULL } /* sentinel */ |
| 360 | }; |
| 361 | |
| 168 | 362 | luaL_newlib(L, emu_funcs); |
| 169 | 363 | return 1; |
| 170 | 364 | } |
| 171 | 365 | |
| 366 | int lua_engine::luaopen_ioport(lua_State *L) |
| 367 | { |
| 368 | static const struct luaL_Reg ioport_funcs [] = { |
| 369 | { "write", l_ioport_write }, |
| 370 | { NULL, NULL } /* sentinel */ |
| 371 | }; |
| 172 | 372 | |
| 373 | luaL_newmetatable(L, tname_ioport); |
| 374 | lua_pushvalue(L, -1); |
| 375 | lua_pushstring(L, tname_ioport); |
| 376 | lua_rawset(L, LUA_REGISTRYINDEX); |
| 377 | lua_pushstring(L, "__index"); |
| 378 | lua_pushvalue(L, -2); |
| 379 | lua_settable(L, -3); |
| 380 | luaL_setfuncs(L, ioport_funcs, 0); |
| 381 | return 1; |
| 382 | } |
| 383 | |
| 173 | 384 | struct msg { |
| 174 | 385 | astring text; |
| 175 | 386 | int ready; |
| r30925 | r30926 | |
| 245 | 456 | |
| 246 | 457 | lua_engine::lua_engine() |
| 247 | 458 | { |
| 459 | m_machine = NULL; |
| 460 | luaThis = this; |
| 248 | 461 | m_lua_state = luaL_newstate(); /* create state */ |
| 462 | output_notifier_set = false; |
| 463 | |
| 249 | 464 | luaL_checkversion(m_lua_state); |
| 250 | 465 | lua_gc(m_lua_state, LUA_GCSTOP, 0); /* stop collector during initialization */ |
| 251 | 466 | luaL_openlibs(m_lua_state); /* open libraries */ |
| 252 | 467 | |
| 253 | 468 | luaopen_lsqlite3(m_lua_state); |
| 254 | 469 | luaL_requiref(m_lua_state, "emu", luaopen_emu, 1); |
| 255 | | |
| 470 | |
| 471 | luaopen_ioport(m_lua_state); |
| 472 | |
| 256 | 473 | lua_gc(m_lua_state, LUA_GCRESTART, 0); |
| 257 | 474 | msg.ready = 0; |
| 258 | 475 | msg.status = 0; |
| r30925 | r30926 | |
| 269 | 486 | close(); |
| 270 | 487 | } |
| 271 | 488 | |
| 489 | |
| 490 | void lua_engine::update_machine() |
| 491 | { |
| 492 | lua_newtable(m_lua_state); |
| 493 | if (m_machine!=NULL) |
| 494 | { |
| 495 | // Create the ioport array |
| 496 | ioport_port *port = machine().ioport().first_port(); |
| 497 | while(port) { |
| 498 | ioport_field *field = port->first_field(); |
| 499 | while(field) { |
| 500 | if(field->name()) { |
| 501 | push(m_lua_state, field, tname_ioport); |
| 502 | lua_setfield(m_lua_state, -2, field->name()); |
| 503 | } |
| 504 | field = field->next(); |
| 505 | } |
| 506 | port = port->next(); |
| 507 | } |
| 508 | } |
| 509 | lua_setglobal(m_lua_state, "ioport"); |
| 510 | } |
| 511 | |
| 272 | 512 | //------------------------------------------------- |
| 273 | 513 | // initialize - initialize lua hookup to emu engine |
| 274 | 514 | //------------------------------------------------- |
| r30925 | r30926 | |
| 326 | 566 | // execute - load and execute script |
| 327 | 567 | //------------------------------------------------- |
| 328 | 568 | |
| 329 | | void lua_engine::execute(const char *filename) |
| 569 | void lua_engine::load_script(const char *filename) |
| 330 | 570 | { |
| 331 | 571 | int s = luaL_loadfile(m_lua_state, filename); |
| 332 | | s = docall(0, 0); |
| 333 | 572 | report(s); |
| 334 | | lua_settop(m_lua_state, 0); |
| 573 | start(); |
| 335 | 574 | } |
| 336 | 575 | |
| 337 | 576 | //------------------------------------------------- |
| 338 | 577 | // execute_string - execute script from string |
| 339 | 578 | //------------------------------------------------- |
| 340 | 579 | |
| 341 | | void lua_engine::execute_string(const char *value) |
| 580 | void lua_engine::load_string(const char *value) |
| 342 | 581 | { |
| 343 | 582 | int s = luaL_loadstring(m_lua_state, value); |
| 344 | | s = docall(0, 0); |
| 345 | 583 | report(s); |
| 346 | | lua_settop(m_lua_state, 0); |
| 584 | start(); |
| 347 | 585 | } |
| 586 | |
| 587 | //------------------------------------------------- |
| 588 | // start - execute the loaded script |
| 589 | //------------------------------------------------- |
| 590 | |
| 591 | void lua_engine::start() |
| 592 | { |
| 593 | resume(m_lua_state); |
| 594 | } |
| 595 | |
trunk/src/emu/luaengine.h
| r30925 | r30926 | |
| 17 | 17 | #ifndef __LUA_ENGINE_H__ |
| 18 | 18 | #define __LUA_ENGINE_H__ |
| 19 | 19 | |
| 20 | #include <map> |
| 21 | |
| 20 | 22 | struct lua_State; |
| 21 | 23 | |
| 22 | 24 | class lua_engine |
| r30925 | r30926 | |
| 27 | 29 | ~lua_engine(); |
| 28 | 30 | |
| 29 | 31 | void initialize(); |
| 30 | | void execute(const char *filename); |
| 31 | | void execute_string(const char *value); |
| 32 | | void close(); |
| 32 | void load_script(const char *filename); |
| 33 | void load_string(const char *value); |
| 33 | 34 | |
| 34 | 35 | void serve_lua(); |
| 35 | 36 | void periodic_check(); |
| 36 | | private: |
| 37 | |
| 38 | void resume(lua_State *L, int nparam = 0, lua_State *root = NULL); |
| 39 | void set_machine(running_machine *machine) { m_machine = machine; update_machine(); } |
| 40 | private: |
| 41 | struct hook { |
| 42 | lua_State *L; |
| 43 | int cb; |
| 44 | |
| 45 | hook(); |
| 46 | void set(lua_State *L, int idx); |
| 47 | lua_State *precall(); |
| 48 | void call(lua_engine *engine, lua_State *T, int nparam); |
| 49 | bool active() const { return L != NULL; } |
| 50 | }; |
| 51 | |
| 52 | static const char *const tname_ioport; |
| 53 | |
| 54 | // internal state |
| 55 | lua_State *m_lua_state; |
| 56 | running_machine * m_machine; |
| 57 | |
| 58 | hook hook_output_cb; |
| 59 | bool output_notifier_set; |
| 60 | |
| 61 | static lua_engine* luaThis; |
| 62 | |
| 63 | std::map<lua_State *, std::pair<lua_State *, int> > thread_registry; |
| 64 | |
| 65 | running_machine &machine() const { return *m_machine; } |
| 66 | |
| 67 | void update_machine(); |
| 68 | void output_notifier(const char *outname, INT32 value); |
| 69 | static void s_output_notifier(const char *outname, INT32 value, void *param); |
| 70 | |
| 71 | void emu_after_done(void *_h, INT32 param); |
| 72 | int emu_after(lua_State *L); |
| 73 | int emu_wait(lua_State *L); |
| 74 | void emu_hook_output(lua_State *L); |
| 75 | |
| 76 | static int l_ioport_write(lua_State *L); |
| 77 | static int l_emu_after(lua_State *L); |
| 78 | static int l_emu_wait(lua_State *L); |
| 79 | static int l_emu_time(lua_State *L); |
| 80 | static int l_emu_gamename(lua_State *L); |
| 81 | static int l_emu_keypost(lua_State *L); |
| 82 | static int l_emu_hook_output(lua_State *L); |
| 83 | static int l_emu_exit(lua_State *L); |
| 84 | static int l_emu_start(lua_State *L); |
| 85 | |
| 86 | void resume(void *L, INT32 param); |
| 87 | void report_errors(int status); |
| 88 | void start(); |
| 89 | static int luaopen_emu(lua_State *L); |
| 90 | static int luaopen_ioport(lua_State *L); |
| 91 | void close(); |
| 92 | |
| 93 | static void *checkparam(lua_State *L, int idx, const char *tname); |
| 94 | static void *getparam(lua_State *L, int idx, const char *tname); |
| 95 | static void push(lua_State *L, void *p, const char *tname); |
| 96 | |
| 37 | 97 | int report(int status); |
| 38 | 98 | int docall(int narg, int nres); |
| 39 | 99 | int incomplete(int status) ; |
| 40 | | private: |
| 41 | | // internal state |
| 42 | | lua_State* m_lua_state; |
| 43 | 100 | }; |
| 44 | 101 | |
| 45 | 102 | #endif /* __LUA_ENGINE_H__ */ |