C64 emulation on STM32F429 Discovery board with builtin LCD and USB keyboard support (OTG). More info at davevw.com and/or github.com/davervw

Dependencies:   LCD_DISCO_F429ZI BSP_DISCO_F429ZI USBHOST

Revision:
9:a0c6747e539f
Parent:
7:dce21deeac6c
Child:
10:95591a8ad254
--- a/emuc64.cpp	Wed Apr 15 05:34:25 2020 +0000
+++ b/emuc64.cpp	Thu Apr 16 06:38:02 2020 +0000
@@ -79,11 +79,13 @@
 //static int startup_state = 0;
 //LocalFileSystem local("local");
 
+// array allows multiple keys/modifiers pressed at one time
 static int scan_codes[9] = { 64, 64, 64, 64, 64, 64, 64, 64, 64 } ;
 
 // USB key code to C64 keyboard scan code, plus shift modifiers
 // +256 means to apply L.Shift
 // -512 means to take away Shift
+// +1024 means to apply RESTORE
 static int usb_to_c64[2][100] = {
 { // normal/other modifier
 	64, 64,	64,	64, 10, 28, 20, 18, 14, 21, // na, na, na, na, a, b, c, d, e, f
@@ -93,7 +95,7 @@
 	1, 63, 0, 58, 60, 43, 53, 256+45, 256+50, 48, // RET, STOP, DEL, CTRL, SPC, -, =, [, ], £
 	64, 50, 256+24, 64, 47, 44, 55, 64, 4, 256+4, // na, ;, ', na, ,, ., /, na, f1, f2
 	5, 256+5, 6, 256+6, 3, 256+3, 64, 64, 64, 64, // f3, f4, f5, f6, f7, f8, na, na, na, na
-	64, 64, 63, 256+0, 51, 64, 0, 64, 64, 2, // na, na, STOP, INS, HM, na, DEL, na, na, RT
+	1024+64, 64, 63, 256+0, 51, 64, 0, 64, 64, 2, // RESTORE, na, STOP, INS, HM, na, DEL, na, na, RT
 	256+2, 7, 256+7, 64, 55, 49, 43, 40, 1, 56, // LT, DN, UP, na, /, *, -, +, ENTER, 1
 	59, 8, 11, 16, 19, 24, 27, 32, 35, 44 // 2, 3, 4, 5, 6, 7, 8, 9, 0, . (keypad)
 },
@@ -105,18 +107,22 @@
 	1, 63, 0, 58, 60, 512+57, 512+40, 256+45, 256+50, 48, // RET, STOP, DEL, CTRL, SPC, L.Arrow, +, [, ], £
 	64, 512+45, 256+59, 64, 47, 44, 55, 64, 4, 256+4, // na, :, ", na, ,, ., /, na, f1, f2
 	5, 256+5, 6, 256+6, 3, 256+3, 64, 64, 64, 64, // f3, f4, f5, f6, f7, f8, na, na, na, na
-	64, 64, 63, 256+0, 51, 64, 0, 64, 64, 2, // na, na, STOP, INS, HM, na, DEL, na, na, RT
+	1024+64, 64, 63, 256+0, 51, 64, 0, 64, 64, 2, // RESTORE, na, STOP, INS, HM, na, DEL, na, na, RT
 	256+2, 7, 256+7, 64, 55, 49, 43, 40, 1, 56, // LT, DN, UP, na, /, *, -, +, ENTER, 1
 	59, 8, 11, 16, 19, 24, 27, 32, 35, 44 // 2, 3, 4, 5, 6, 7, 8, 9, 0, . (keypad)
 }
 };
 
+// Resources
+// See Keyboard/Keypad Page (0x07) of https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf
+// See Commodore 64 Keycodes in Appendix of https://archive.org/details/Compute_s_Mapping_the_64_and_64C/
+
 // The initial goal of the keyboard tables and logic is to provide access to at 
 // least the following keys from a standard USB keyboard, symbolic mapping more 
 // like a PC (not positional)
 // USB keyboard support is provided by USBHOST library and STM32F429 BSP
 //
-// STOP(ESC) F1 F2 F3 F4 F5 F6 F7 F8                                  Run/Stop(Pause/Break)
+// STOP(ESC) F1 F2 F3 F4 F5 F6 F7 F8            Restore(PrtScr/SysRq) Run/Stop(Pause/Break)
 //           1! 2@ 3# 4$ 5% 6^ 7& 8* 9( 0) -_ += Del/Ins(Back)    Ins Hme/Clr     / * -
 // Ctrl(Tab) Q  W  E  R  T  Y  U  I  O  P  [  ]  £ (\)            Del           7 8 9 +
 //           A  S  D  F  G  H  J  K  L  ;: '" Return(ENTER)                     4 5 6
@@ -145,17 +151,17 @@
 	if (len == 8)
 	{ 
 		if ((data[0] & 0x11) != 0) // PC Ctrl => Commodore
-			scan_codes[6] = 61;
+			scan_codes[6] = 61; // usb hid buffer supports 6 simultaneous keys, put modifier in next available slot
 		else
 			scan_codes[6] = 64;
 			
 		if ((data[0] & 2) != 0) // LShift
-			scan_codes[7] = 15;
+			scan_codes[7] = 15; // usb hid buffer supports 6 simultaneous keys, put modifier in next available slot
 		else
 			scan_codes[7] = 64;
 			
 		if ((data[0] & 0x20) != 0) // RShift
-			scan_codes[8] = 52;
+			scan_codes[8] = 52; // usb hid buffer supports 6 simultaneous keys, put modifier in next available slot
 		else
 			scan_codes[8] = 64;
 
@@ -163,23 +169,27 @@
 	    {
 			if (data[i+2] < 100)
 			{
-				scan_codes[i] = usb_to_c64[((data[0] & 0x22) != 0) ? 1 : 0][data[i+2]]; // L.Shift/R.Shift handled by a different table
+				scan_codes[i] = usb_to_c64[((data[0] & 0x22) != 0) ? 1 : 0][data[i+2]]; // Normal vs. Shift
 				if ((scan_codes[i] & 256) != 0)
 					scan_codes[7] = 15; // LShift
-				if (i==0 && (scan_codes[i] & 512) != 0)
+				if (i==0 && (scan_codes[i] & 512) != 0) // remove shift flag works only if key is first non-modifier pressed
+				{
 					scan_codes[7] = 64; // No LShift
-				scan_codes[i] &= 127; // take out shift codes
-				//printf(" %d", scan_code);
-				fflush(stdout);
+					scan_codes[8] = 64; // No RShift
+				}
+				if (scan_codes[i] != 64)
+				{
+					printf(" %d", scan_codes[i]);
+					fflush(stdout);
+				}
 			}
 			else
 				scan_codes[i] = 64;
 		}
-			
-//		printf("C64 scan_code = %d\n", scan_code);
 	}
 }
 
+// CREDIT: keyboard_task() borrowed from USBHOST sample program main.cpp at https://os.mbed.com/teams/ST/code/Nucleo_usbhost/
 void keyboard_task(void const *)
 {
     USBHostKeyboard keyboard;
@@ -252,8 +262,31 @@
 //	return result;
 //}
 
+// remembering state because NMI is edge triggered false->true
+static bool NMI = false;
+
 bool ExecutePatch(void)
 {
+	int found_NMI = 0;
+	for (int i=0; !found_NMI && i<9; ++i)
+		if (scan_codes[i] == 1024+64)
+			found_NMI = 1;
+	
+	if (NMI)
+	{
+		if (!found_NMI)
+			NMI = false; // reset when not pressed
+	}
+	else if (found_NMI) // newly pressed, detected edge
+	{
+		NMI = true; // set so won't trigger again until cleared
+		Push(HI(PC));
+		Push(LO(PC));
+		PHP();
+		PC = (ushort)(GetMemory(0xFFFA) + (GetMemory(0xFFFB) << 8)); // JMP(NMI)
+		return true; // overriden, and PC changed, so caller should reloop before execution to allow breakpoint/trace/ExecutePatch/etc.
+	}
+	
 //	if (PC == 0xFFD2) // CHROUT
 //	{
 //		CBM_Console_WriteChar((char)A);
@@ -1119,10 +1152,11 @@
 			
 			for (int i=0; i<9; ++i)
 			{
-				if (scan_codes[i] < 64)
-				{
-					int col = scan_codes[i] / 8;
-					int row = scan_codes[i] % 8;
+				int scan_code = scan_codes[i] & 127; // remove any modifiers
+				if (scan_code < 64)
+				{			
+					int col = scan_code / 8;
+					int row = scan_code % 8;
 					
 					if ((io[0xC00] & (1 << col)) == 0)
 						value |= (1 << row);