From ae9951418344772189a7a3f9840028731cdc4c17 Mon Sep 17 00:00:00 2001 From: mooz Date: Sun, 18 Nov 2018 22:13:04 +0100 Subject: [PATCH] Added standalone version of the uPD7801 compiler. --- CMakeLists.txt | 34 +++++++ l7801.c | 222 +++++++++++++++++++++++++++++++++++++++++++ scv.l65 => scv.l7801 | 0 3 files changed, 256 insertions(+) create mode 100644 l7801.c rename scv.l65 => scv.l7801 (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c9469f..9aa4d46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,3 +117,37 @@ endif() target_link_libraries(embed ${LINKLIBS}) target_link_libraries(${PROJECT_NAME} ${LINKLIBS}) + +set(L7801_SOURCES + ${L65_SOURCE_DIR}/lfs.c + ${L65_SOURCE_DIR}/lpeg.c + ${L65_SOURCE_DIR}/l7801.c + ) +set(L7801_HEADERS + ${L65_HEADERS} + ) + +set(L7801_FILES ${L65_SOURCE_DIR}/scv.l7801) + +set(L7801_SCRIPTS + ${L65_SOURCE_DIR}/asm.lua + ${L65_SOURCE_DIR}/uPD7801.lua + ${L65_SOURCE_DIR}/dkjson.lua + ${L65_SOURCE_DIR}/l7801.lua + ${L65_BINARY_DIR}/l65cfg.lua + ${L65_SOURCE_DIR}/re.lua + ${L7801_FILES} + ) + +add_custom_command( + OUTPUT ${L65_BINARY_DIR}/scripts_7801.h + COMMAND embed -o ${L65_BINARY_DIR}/scripts_7801.h ${L7801_SCRIPTS} + DEPENDS embed ${L7801_SCRIPTS} +) +add_custom_target(prereq_7801 DEPENDS ${L65_BINARY_DIR}/scripts_7801.h) +add_executable(l7801 ${L7801_SOURCES} ${L7801_HEADERS} ${L7801_FILES}) +add_dependencies(l7801 prereq_7801) +set_property(TARGET l7801 PROPERTY C_STANDARD 99) +target_include_directories(l7801 PRIVATE "${L7801_SOURCE_DIR}" "${L65_BINARY_DIR}") +target_link_libraries(l7801 ${LINKLIBS}) + diff --git a/l7801.c b/l7801.c new file mode 100644 index 0000000..a403714 --- /dev/null +++ b/l7801.c @@ -0,0 +1,222 @@ +#include +#include +#include + +#define STB_IMAGE_IMPLEMENTATION +#define STBI_ONLY_PNG +#define STBI_NO_FAILURE_STRINGS +#include "stb_image.h" + +#define LUA_IMPLEMENTATION +#include "lua.h" +#include "scripts_7801.h" + +extern int luaopen_lpeg(lua_State *L); +extern int luaopen_lfs(lua_State *L); + +// l7801 lib +static int r_s32be(uint8_t **b) { uint8_t *p = *b; int v = ((int)(p[0]))<<24 | ((int)(p[1]))<<16 | ((int)p[2])<<8 | p[3]; *b += 4; return v; } +typedef struct { int len, nam; } chunk_s; +static chunk_s r_chunk(uint8_t **b) { int len = r_s32be(b), nam = r_s32be(b); chunk_s c = { len, nam }; return c; } +static int open_image(lua_State *L) +{ + const char *filename = luaL_checkstring(L, 1); + FILE *file = fopen(filename, "rb"); + if (!file) + { + lua_pushnil(L); + lua_pushfstring(L, "failed to open file %s", filename); + return 2; + } + fseek(file, 0, SEEK_END); + size_t sz = ftell(file); + fseek(file, 0, SEEK_SET); + uint8_t *png = malloc(sz); + fread(png, sz, 1, file); + fclose(file); + static uint8_t png_sig[8] = { 137,80,78,71,13,10,26,10 }; + if (memcmp(png, png_sig, 8) != 0) + { + free(png); + lua_pushnil(L); + lua_pushfstring(L, "file %s is not a PNG", filename); + return 2; + } + uint8_t *b = png + 8; + int w, h; + uint8_t *d = 0; long d_sz = 0; +#define CHUNK_NAM(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) + for (;;) + { + chunk_s chunk = r_chunk(&b); + switch (chunk.nam) + { + case CHUNK_NAM('I','H','D','R'): { + w = r_s32be(&b); h = r_s32be(&b); + if (b[0] != 8 || b[1] != 3) + { + free(png); + lua_pushnil(L); + lua_pushfstring(L, "PNG file %s must be 8b indexed", filename); + return 2; + } + b += 9; + } break; + case CHUNK_NAM('I','D','A','T'): { + d = realloc(d, d_sz + chunk.len); + memcpy(d + d_sz, b, chunk.len); + d_sz += chunk.len; + b += chunk.len+4; + } break; + case CHUNK_NAM('I','E','N','D'): { + free(png); + if (!d) + { + lua_pushnil(L); + lua_pushfstring(L, "invalid PNG file %s", filename); + return 2; + } + int px_sz; + uint8_t *px_raw = (uint8_t*)stbi_zlib_decode_malloc_guesssize_headerflag((void*)d, d_sz, (w+1) * h, &px_sz, 1); + free(d); + uint8_t *px = calloc(w,h); + uint8_t *px0 = px, *px_raw0 = px_raw; + for (int y = 0; y < h; ++y) + { + int filter = *px_raw++; + #define prev (x==0 ? 0 : px[x-1]) + #define up (px[x-w]) + #define prevup (x==0 ? 0 : px[x-w-1]) + switch (filter) + { + case 0: memcpy(px, px_raw, w); break; + case 1: for (int x = 0; x < w; ++x) { px[x] = px_raw[x] + prev; } break; + case 2: for (int x = 0; x < w; ++x) { px[x] = px_raw[x] + up; } break; + case 3: for (int x = 0; x < w; ++x) { px[x] = px_raw[x] + ((prev+up)>>1); } break; + case 4: for (int x = 0; x < w; ++x) { px[x] = px_raw[x] + stbi__paeth(prev,up,prevup); } break; + } + #undef prev + #undef up + #undef prevup + px += w; + px_raw += w; + } + STBI_FREE(px_raw0); + + lua_createtable(L, w*h, 3); + lua_pushstring(L, filename); + lua_setfield(L, -2, "filename"); + lua_pushinteger(L, w); + lua_setfield(L, -2, "width"); + lua_pushinteger(L, h); + lua_setfield(L, -2, "height"); + for (int i = 0; i < w*h; ++i) + { + lua_pushinteger(L, px0[i]); + lua_rawseti(L, -2, i+1); + } + free(px0); + return 1; + } + default: + b += chunk.len+4; + } + } +#undef CHUNK_NAM + if (d) free(d); + free(png); + lua_pushnil(L); + lua_pushfstring(L, "invalid PNG file %s", filename); + return 2; +} +static const struct luaL_Reg l7801lib[] = { + {"image", open_image}, + {NULL, NULL}, +}; +static int luaopen_l7801(lua_State *L) +{ + luaL_newlib(L, l7801lib); + return 1; +} + +#define SRC_LUA(name) { #name, 0, script_ ## name ## _lua, sizeof(script_ ## name ## _lua) } +#define SRC_L7801(name) { #name, 1, script_ ## name ## _l7801, sizeof(script_ ## name ## _l7801) } +static struct script { const char *name; int t; const char *data; size_t sz; } embedded[] = { + SRC_LUA(dkjson), + SRC_LUA(l65cfg), + SRC_LUA(re), + SRC_L7801(scv), +}; +#undef SRC_LUA +#undef SRC_L7801 + +static int getembedded(lua_State *L) +{ + const char *name = lua_tostring(L, 1); + for (struct script *s = embedded, *e = s + sizeof(embedded) / sizeof(embedded[0]); s != e; ++s) + { + if (!strcmp(s->name, name)) + { + lua_pushlstring(L, s->data, s->sz); + lua_pushboolean(L, s->t); + return 2; + } + } + return 0; +} + +static int msghandler(lua_State *L) +{ + const char *msg = lua_tostring(L, 1); + if (msg == NULL) + { + if (luaL_callmeta(L, 1, "__tostring") && lua_type(L, -1) == LUA_TSTRING) + return 1; + msg = lua_pushfstring(L, "(error object is a %s value)", luaL_typename(L, 1)); + } + luaL_traceback(L, L, msg, 1); + return 1; +} + +int main(int argc, char *argv[]) +{ + lua_State *L = luaL_newstate(); + luaL_openlibs(L); + luaL_requiref(L, "lpeg", luaopen_lpeg, 1); lua_pop(L, 1); + luaL_requiref(L, "lfs", luaopen_lfs, 1); lua_pop(L, 1); + luaL_requiref(L, "l7801", luaopen_l7801, 1); lua_pop(L, 1); + + // preload embedded lua scripts + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); + luaL_loadbufferx(L, script_asm_lua, sizeof(script_asm_lua), "asm.lua", "b"); + lua_setfield(L, -2, "asm"); + luaL_loadbufferx(L, script_uPD7801_lua, sizeof(script_uPD7801_lua), "uPD7801.lua", "b"); + lua_setfield(L, -2, "uPD7801"); + lua_pop(L, 1); + + // error handler + lua_pushcfunction(L, msghandler); + // l65.lua script + luaL_loadbufferx(L, script_l7801_lua, sizeof(script_l7801_lua), "l7801.lua", "b"); + // arg[] table + lua_createtable(L, argc-1, 2); + lua_pushcfunction(L, getembedded); // pass embedded script lookup function as arg[-1] + lua_rawseti(L, -2, -1); + for (int i = 0; i < argc; i++) lua_pushstring(L, argv[i]), lua_rawseti(L, -2, i); + lua_pushvalue(L, -1); + lua_setglobal(L, "arg"); + // ... arguments + { int i; for (i = 1; i < argc; ++i) lua_rawgeti(L, -i, i); lua_remove(L, -i); } + // call l7801 + int status = lua_pcall(L, argc-1, 0, -argc-1); + if (status != LUA_OK) + { + const char *msg = lua_tostring(L, -1); + fprintf(stderr, "%s\n", msg); + lua_pop(L, 1); + } + lua_pop(L, 1); // remove msghandler + lua_close(L); + return status; +} + diff --git a/scv.l65 b/scv.l7801 similarity index 100% rename from scv.l65 rename to scv.l7801