Index: emu/lcd.c
===================================================================
--- emu/lcd.c	(revision 7ba68aa081f33679f2e35fce2c70ba837488ff85)
+++ emu/lcd.c	(revision 5475ecffc7e57c236384c2d970e1fea0538c9460)
@@ -22,9 +22,9 @@
 #define ver3(...) _ver(lcd_verbose, 2, __VA_ARGS__)
 
-#define WIN_W (1520 * 2 / 3)
-#define WIN_H (950 * 2 / 3)
+#define WIN_W (1634 * 2 / 3)
+#define WIN_H (342 * 2 / 3)
 
 #define CON_W 86
-#define CON_H 25
+#define CON_H 9
 
 #define CON_BGR 0x00000000
@@ -47,5 +47,6 @@
 #define	G_ERASE		0x52
 #define	G_SLEEP		0x53
-#define	G_DSPCTL	0x58
+#define	G_DSPOFF	0x58
+#define	G_DSPON		0x59
 #define	G_HSCRL		0x5A
 #define	G_OVRLAY	0x5B
@@ -59,4 +60,6 @@
 static SDL_atomic_t frame;
 
+static uint32_t render = 0;
+
 static TTF_Font *fon;
 static int32_t fon_w, fon_h;
@@ -72,4 +75,11 @@
 static int32_t cur_ad_c = 0;
 
+static uint32_t last_val = 0x00;
+static uint32_t last_off = 0;
+static int32_t last_sz = -1;
+static int32_t mult_val_c = 0;
+
+static void (*cursdir)(void);
+
 int32_t lcd_verbose = 0;
 
@@ -112,4 +122,14 @@
 }
 
+static void up(void)
+{
+	if (cur_y > 0) {
+		--cur_y;
+		return;
+	}
+
+	// TODO: What happens when cursor out of bounds
+}
+
 static void down(void)
 {
@@ -119,5 +139,5 @@
 	}
 
-	scroll();
+	// TODO: What happens when cursor out of bounds
 }
 
@@ -126,6 +146,7 @@
 	uint32_t n_cur_y = cur_addr / 85;
 
-	printf("Cur x %u\n", n_cur_x);
-	printf("Cur y %u\n", n_cur_y);
+	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;
@@ -139,4 +160,6 @@
 	}
 	else {
+		cur_x = 0;
+		cur_y = 9;
 		err("invalid y cursor pos in lcd %u:%d", n_cur_y, CON_H);
 	}
@@ -145,5 +168,8 @@
 static void echo(uint8_t c)
 {
-	if (c < 32) {
+	if (c >127) {
+		return;
+	}
+	else if (c < 32) {
 		switch (c) {
 		case '\r':
@@ -165,5 +191,5 @@
 		case 0:
 			mem[cur_y][cur_x] = ' ';
-			forw();
+			(*cursdir)();
 			break;
 
@@ -183,8 +209,20 @@
 	else {
 		mem[cur_y][cur_x] = c;
-		forw();
-	}
-
-	SDL_AtomicAdd(&frame, 1);
+		(*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;
+	}
 }
 
@@ -308,11 +346,5 @@
 	}
 
-	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;
-	}
+	clear_mem();
 
 }
@@ -343,7 +375,8 @@
 	switch (current_op) {
 		case G_MREAD:
-			printf("current op: %d\n", current_op);
+			ver2("lcd current op: %d\n", current_op);
 			rv = mem[cur_y][cur_x];
 			break;
+
 		default:
 			rv = 0x00;
@@ -355,5 +388,26 @@
 void lcd_write(uint32_t off, int32_t sz, uint32_t val)
 {
-	ver2("lcd wr %u:%d 0x%0*x", off, sz * 8, sz * 2, val);
+
+	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);
+		}
+		else {
+			ver2("lcd wr %u:%d 0x%0*x", last_off, last_sz * 8, last_sz * 2, last_val);
+		}
+
+		ver2("lcd wr %u:%d 0x%0*x", off, sz * 8, sz * 2, val);
+		mult_val_c = 0;
+	}
+	else if(last_val == val && mult_val_c >= 0) {
+		++mult_val_c;
+	}
+	else {
+		ver2("lcd wr %u:%d 0x%0*x", off, sz * 8, sz * 2, val);
+	}
+
+	last_val = val;
+	last_off = off;
+	last_sz = sz;
 
 	if (off == 0) {
@@ -362,4 +416,5 @@
 					echo((uint8_t)val);
 				break;
+
 			case G_CRSWR:
 				if (cur_ad_c == 0) {
@@ -372,4 +427,9 @@
 				}
 				break;
+
+			case G_DSPON:
+				// TODO Configure blinking of cursor(s)
+				break;
+
 			default:
 				break;
@@ -381,13 +441,50 @@
 				current_op = G_MWRITE;
 				break;
+
 			case G_CRSMRT:
-				forw();
-				break;
+				cursdir = &forw;
+				current_op = G_CRSMRT;
+				break;
+
+			case G_CRSMUP:
+				cursdir = &up;
+				current_op = G_CRSMUP;
+				break;
+
+			case G_CRSMDN:
+				cursdir = &down;
+				current_op = G_CRSMDN;
+				break;
+
 			case G_CRSWR:
 				current_op = G_CRSWR;
 				break;
+
 			case G_MREAD:
 				current_op = G_MREAD;
 				break;
+
+			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);
+				render = 0;
+				current_op = G_DSPOFF;
+				break;
+
+			case G_DSPON:
+				render = 1;
+				current_op = G_DSPON;
+				break;
+
+			case G_CRSFRM:
+				// TODO Setup Cursor Form...
+				current_op = 0x00;
+				break;
+
 			default:
 				current_op = 0x00;
