Index: emu/lcd.c
===================================================================
--- emu/lcd.c	(revision f51359cad4cdb056e52aae47198e502a43439d3a)
+++ emu/lcd.c	(revision c8a92ef10ca66a7efcfcd6cfde3c4686bb9d1863)
@@ -22,16 +22,10 @@
 #define ver3(...) _ver(lcd_verbose, 2, __VA_ARGS__)
 
-#define WIN_W (1634 * 2 / 3)
-#define WIN_H (342 * 2 / 3)
-
-#define CON_W 86
-#define CON_H 9
+#define WIN_W (510 * 2)
+#define WIN_H (64 * 2)
 
 #define CON_BGR 0x00000000
-#define CON_BEL 0x00808080
-#define CON_CUR 0x00e87000
+#define CON_DRW 0xFFFFFFFF
 #define CON_FGR ((SDL_Color){ .r = 255, .b = 255, .g = 255, .a = 255 })
-
-#define BEL_CYC 10000
 
 #define	G_INIT		0x40
@@ -54,9 +48,20 @@
 #define	G_CRSFRM	0x5D
 
-static uint8_t mem[CON_H][CON_W + 1];
+#define TXT_W 85
+#define TXT_H 8
+
+#define GFX_W 85
+#define GFX_H 64
+
+#define BASE_TXT 0x0000
+#define BASE_GFX 0x2000
+
+static uint8_t mem_txt[TXT_H * TXT_W];
+static uint8_t mem_gfx[GFX_H * GFX_W];
 
 static SDL_Window *win;
 static SDL_Renderer *ren;
 static SDL_atomic_t frame;
+static SDL_atomic_t clear;
 
 static uint32_t render = 0;
@@ -68,10 +73,11 @@
 static SDL_Surface *sur;
 
-static int32_t cur_x = 0, cur_y = 0;
-static int32_t bel = 0;
+static SDL_Surface *gfx_sur;
+
+static int32_t cur = 0;
+static int32_t cur_c = 0;
+static int32_t dir = 1;
 
 static int32_t current_op = 0x00;
-static uint32_t cur_ad = 0;
-static int32_t cur_ad_c = 0;
 
 static uint32_t last_val = 0x00;
@@ -80,154 +86,24 @@
 static int32_t mult_val_c = 0;
 
-static void (*cursdir)(void);
-
 int32_t lcd_verbose = 0;
 
-static void scroll(void)
-{
-	memmove(mem, mem + 1, (CON_H - 1) * (CON_W + 1));
-	memset(mem + (CON_H - 1), ' ', CON_W);
-}
-
-static void forw(void)
-{
-	if (cur_x < CON_W - 1) {
-		++cur_x;
+
+void lcd_sdl(void)
+{
+	ver3("lcd_sdl()");
+
+	if (SDL_AtomicGet(&clear)) {
+		if (SDL_SetRenderDrawColor(ren, 0x00, 0x00, 0x00, 0xff) < 0) {
+			fail("SDL_SetRenderDrawColor() failed: %s", SDL_GetError());
+		}
+
+		if (SDL_RenderClear(ren) < 0) {
+			fail("SDL_RenderClear() failed: %s", SDL_GetError());
+		}
+
+		SDL_RenderPresent(ren);
+		SDL_AtomicSet(&clear, 0);
 		return;
 	}
-
-	if (cur_y == CON_H - 1) {
-		cur_x = 0;
-		scroll();
-		return;
-	}
-
-	cur_x = 0;
-	++cur_y;
-}
-
-static void back(void)
-{
-	if (cur_x > 0) {
-		--cur_x;
-		return;
-	}
-
-	if (cur_y == 0) {
-		return;
-	}
-
-	cur_x = CON_W - 1;
-	--cur_y;
-}
-
-static void up(void)
-{
-	if (cur_y > 0) {
-		--cur_y;
-		return;
-	}
-
-	// TODO: What happens when cursor out of bounds
-}
-
-static void down(void)
-{
-	if (cur_y < CON_H - 1) {
-		++cur_y;
-		return;
-	}
-
-	// TODO: What happens when cursor out of bounds
-}
-
-static void mvcur(uint32_t cur_addr) {
-	uint32_t n_cur_x = cur_addr % 85;
-	uint32_t n_cur_y = cur_addr / 85;
-
-	ver2("lcd cur x %u\n", n_cur_x);
-	ver2("lcd cur y %u\n", n_cur_y);
-
-	if (n_cur_x < CON_W - 1) {
-		cur_x = (int32_t) n_cur_x;
-	}
-	else {
-		err("invalid x cursor pos in lcd %u:%d", n_cur_x, CON_W);
-	}
-
-	if (n_cur_y < CON_H - 1) {
-		cur_y = (int32_t) n_cur_y;
-	}
-	else {
-		cur_x = 0;
-		cur_y = 9;
-		err("invalid y cursor pos in lcd %u:%d", n_cur_y, CON_H);
-	}
-}
-
-static void echo(uint8_t c)
-{
-	if (c >127) {
-		return;
-	}
-	else if (c < 32) {
-		switch (c) {
-		case '\r':
-			cur_x = 0;
-			break;
-
-		case '\n':
-			down();
-			break;
-
-		case '\b':
-			back();
-			break;
-
-		case '\a':
-			bel = BEL_CYC;
-			break;
-
-		case 0:
-			mem[cur_y][cur_x] = ' ';
-			(*cursdir)();
-			break;
-
-		case 28:
-			// TODO
-			echo('^');
-			echo((uint8_t)(c + '@'));
-			break;
-
-		default:
-			echo('^');
-			echo((uint8_t)(c + '@'));
-			ver2("lcd default case echo %u", c);
-			return;
-		}
-	}
-	else {
-		mem[cur_y][cur_x] = c;
-		(*cursdir)();
-	}
-
-	if (render) {
-		SDL_AtomicAdd(&frame, 1);
-	}
-}
-
-static void clear_mem(void) {
-	for (int32_t y = 0; y < CON_H; ++y) {
-		for (int32_t x = 0; x < CON_W; ++x) {
-			mem[y][x] = ' ';
-		}
-
-		mem[y][CON_W] = 0;
-	}
-}
-
-void lcd_sdl(void)
-{
-	ver3("lcd_sdl()");
 
 	static int32_t last = 0;
@@ -241,19 +117,10 @@
 	last = now;
 
-	if (SDL_FillRect(sur, NULL, bel == 0 ? CON_BGR : CON_BEL) < 0) {
+	if (SDL_FillRect(sur, NULL, CON_BGR) < 0) {
 		fail("SDL_FillRect() failed: %s", SDL_GetError());
 	}
 
-	if (SDL_FillRect(sur, &(SDL_Rect){
-		.x = cur_x * fon_w,
-		.y = cur_y * fon_h,
-		.w = fon_w,
-		.h = fon_h
-	}, CON_CUR) < 0) {
-		fail("SDL_FillRect() failed: %s", SDL_GetError());
-	}
-
-	for (int32_t y = 0; y < CON_H; ++y) {
-		char line[CON_W + 1];
+	for (int32_t y = 0; y < TXT_H; ++y) {
+		char line[TXT_W + 1];
 
 		if (SDL_LockMutex(cpu_mutex) < 0) {
@@ -261,5 +128,6 @@
 		}
 
-		memcpy(line, mem[y], CON_W + 1);
+		memcpy(line, mem_txt + y * TXT_W, TXT_W);
+		line[TXT_W] = 0;
 
 		if (SDL_UnlockMutex(cpu_mutex) < 0) {
@@ -276,5 +144,5 @@
 			.x = 0,
 			.y = y * fon_h,
-			.w = CON_W * fon_w,
+			.w = TXT_W * fon_w,
 			.h = fon_h
 		})) {
@@ -295,5 +163,38 @@
 	}
 
+	for (int32_t y = 0; y < GFX_H * GFX_W; ++y) {
+		for (int32_t p = 7; p > 1; --p) {
+			uint32_t col = CON_BGR;
+			if ((mem_gfx[y] & (1 << p)) > 0) {
+				col = CON_DRW;
+			}
+
+			if (SDL_FillRect(gfx_sur, &(SDL_Rect){
+				.x = y % 85 * fon_w + (8 - p) * fon_w / 6,
+				.y = y / 85 * fon_h / 8,
+				.w = fon_w / 6 + 1,
+				.h = fon_h / 8 + 1
+			}, col) < 0) {
+				fail("SDL_FillRect() failed: %s", SDL_GetError());
+			}
+		}
+	}
+
+	SDL_Texture *gfx_tex = SDL_CreateTextureFromSurface(ren, gfx_sur);
+
+	if (gfx_tex == NULL) {
+		fail("SDL_CreateTextureFromSurface() failed: %s", SDL_GetError());
+	}
+
+	if (SDL_SetTextureBlendMode(gfx_tex, SDL_BLENDMODE_ADD) < 0) {
+		fail("SDL_SetTextureBlendMode() failed: %s", SDL_GetError());
+	}
+
+	if (SDL_RenderCopy(ren, gfx_tex, NULL, NULL) < 0) {
+		fail("SDL_RenderCopy() failed: %s", SDL_GetError());
+	}
+
 	SDL_DestroyTexture(tex);
+	SDL_DestroyTexture(gfx_tex);
 	SDL_RenderPresent(ren);
 }
@@ -317,4 +218,6 @@
 	}
 
+	SDL_AtomicSet(&clear, 0);
+
 	SDL_AtomicSet(&frame, 1);
 
@@ -337,6 +240,6 @@
 	}
 
-	sur_w = CON_W * fon_w;
-	sur_h = CON_H * fon_h;
+	sur_w = TXT_W * fon_w;
+	sur_h = TXT_H * fon_h;
 
 	sur = SDL_CreateRGBSurface(0, sur_w, sur_h, 32, 0, 0, 0, 0);
@@ -346,6 +249,13 @@
 	}
 
-	clear_mem();
-
+	gfx_sur = SDL_CreateRGBSurface(0, sur_w, sur_h, 32, 0, 0, 0, 0);
+
+	if (gfx_sur == NULL) {
+		fail("SDL_CreateRGBSurface() failed: %s", SDL_GetError());
+	}
+
+	for (int32_t y = 0; y < TXT_W * TXT_H; ++y) {
+		mem_txt[y] = ' ';
+	}
 }
 
@@ -355,4 +265,5 @@
 
 	SDL_FreeSurface(sur);
+	SDL_FreeSurface(gfx_sur);
 	TTF_CloseFont(fon);
 
@@ -375,6 +286,13 @@
 	switch (current_op) {
 		case G_MREAD:
-			ver2("lcd current op: %d\n", current_op);
-			rv = mem[cur_y][cur_x];
+			if (cur >= BASE_TXT && cur < BASE_TXT + TXT_W * TXT_H) {
+				rv = mem_txt[cur - BASE_TXT];
+			}
+			else if (cur >= BASE_GFX && cur < BASE_TXT + GFX_W * GFX_H) {
+				rv = mem_gfx[cur - BASE_GFX];
+			}
+			else {
+				rv = 0x00;
+			}
 			break;
 
@@ -388,7 +306,6 @@
 void lcd_write(uint32_t off, int32_t sz, uint32_t val)
 {
-
-	if(last_val != val && mult_val_c > 0) {
-		if(mult_val_c > 1) {
+	if (last_val != val && mult_val_c > 0) {
+		if (mult_val_c > 1) {
 			ver2("lcd wr %u:%d 0x%0*x was called %u more times", last_off, last_sz * 8, last_sz * 2, last_val, mult_val_c);
 		}
@@ -400,5 +317,5 @@
 		mult_val_c = 0;
 	}
-	else if(last_val == val && mult_val_c >= 0) {
+	else if (last_val == val && mult_val_c >= 0) {
 		++mult_val_c;
 	}
@@ -414,20 +331,40 @@
 		switch (current_op) {
 			case G_MWRITE:
-					echo((uint8_t)val);
+					if (cur >= BASE_TXT && cur < BASE_TXT + TXT_W * TXT_H) {
+						if (val == 0) {
+							mem_txt[cur - BASE_TXT] = ' ';
+						}
+						else {
+							mem_txt[cur - BASE_TXT] = (uint8_t) val;
+						}
+
+						cur += dir;
+
+						if (render) {
+							SDL_AtomicAdd(&frame, 1);
+						}
+					}
+					else if (cur >= BASE_GFX && cur < BASE_GFX + GFX_W * GFX_H) {
+						mem_gfx[cur - BASE_GFX] = (uint8_t) val;
+						cur += dir;
+
+						if (render) {
+							SDL_AtomicAdd(&frame, 1);
+						}
+					}
+					else {
+						err("Invalid cur value %d", cur);
+					}
 				break;
 
 			case G_CRSWR:
-				if (cur_ad_c == 0) {
-					cur_ad = val;
-					cur_ad_c++;
-				} else if (cur_ad_c == 1) {
-					cur_ad = cur_ad | (val << 8);
-					mvcur(cur_ad);
-					cur_ad_c = 0;
+				if (cur_c == 0) {
+					cur = (int32_t) val;
+					cur_c++;
 				}
-				break;
-
-			case G_DSPON:
-				// TODO Configure blinking of cursor(s)
+				else if (cur_c == 1) {
+					cur = cur | ((int32_t) val << 8);
+					cur_c = 0;
+				}
 				break;
 
@@ -443,15 +380,15 @@
 
 			case G_CRSMRT:
-				cursdir = &forw;
+				dir = 1;
 				current_op = G_CRSMRT;
 				break;
 
 			case G_CRSMUP:
-				cursdir = &up;
+				dir = -85;
 				current_op = G_CRSMUP;
 				break;
 
 			case G_CRSMDN:
-				cursdir = &down;
+				dir = 85;
 				current_op = G_CRSMDN;
 				break;
@@ -466,11 +403,5 @@
 
 			case G_DSPOFF:
-				if (SDL_SetRenderDrawColor(ren, 0x00, 0x00, 0x00, 0xff) < 0) {
-					fail("SDL_SetRenderDrawColor() failed: %s", SDL_GetError());
-				}
-				if (SDL_RenderClear(ren) < 0) {
-					fail("SDL_RenderClear() failed: %s", SDL_GetError());
-				}
-				SDL_RenderPresent(ren);
+				SDL_AtomicSet(&clear, 1);
 				render = 0;
 				current_op = G_DSPOFF;
@@ -482,9 +413,4 @@
 				break;
 
-			case G_CRSFRM:
-				// TODO Setup Cursor Form...
-				current_op = 0x00;
-				break;
-
 			default:
 				current_op = 0x00;
