diff --git a/NesUEFI/Makefile b/NesUEFI/Makefile index 145a4af..5c5d8c2 100644 --- a/NesUEFI/Makefile +++ b/NesUEFI/Makefile @@ -40,6 +40,8 @@ OVMF_DIR = ../OVMF CC = gcc OBJCOPY = objcopy +BUILDDIR = bin + %.efi: %.so $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ -j .rela -j .reloc -S --target=$(FORMAT) $*.so $@ diff --git a/NesUEFI/NesUEFI.img b/NesUEFI/NesUEFI.img index 2f12648..6f7ad4c 100644 Binary files a/NesUEFI/NesUEFI.img and b/NesUEFI/NesUEFI.img differ diff --git a/NesUEFI/driver/graphics.c b/NesUEFI/driver/graphics.c index 39adf86..d5d58c0 100644 --- a/NesUEFI/driver/graphics.c +++ b/NesUEFI/driver/graphics.c @@ -175,8 +175,7 @@ void graphics_clear_framebuffer(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop){ } } -EFI_STATUS -graphics_draw_bitmap( EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, +EFI_STATUS graphics_draw_bitmap( EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, int x_offset, int y_offset, EFI_HANDLE *bmp_buffer){ diff --git a/NesUEFI/driver/keyboard.c b/NesUEFI/driver/keyboard.c index 15cb34c..cbdb14a 100644 --- a/NesUEFI/driver/keyboard.c +++ b/NesUEFI/driver/keyboard.c @@ -5,30 +5,40 @@ #include "kernel.h" #include "keyboard.h" -EFI_STATUS keyboard_poll(){ - if(!kernel.keyboard_event_handler) return EFI_INVALID_PARAMETER; +static char key_state[128],key_pressed[128]; - EFI_INPUT_KEY efi_input_key; - EFI_STATUS rc; - while(1){ - rc = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &efi_input_key); - if(rc == EFI_SUCCESS){ - if(efi_input_key.UnicodeChar){ - kernel.keyboard_event_handler(efi_input_key.UnicodeChar); - } else{ - kernel.keyboard_event_handler(efi_input_key.ScanCode); - } - } - - else { - return rc; - } - } - return rc; +static inline UINT8 inportb(UINT16 port) { + UINT8 r; + asm("inb %1, %0" : "=a" (r) : "dN" (port)); + return r; } EFI_STATUS keyboard_init(void (*handler)(UINT32 key)){ if(!handler) return EFI_INVALID_PARAMETER; kernel.keyboard_event_handler = handler; + memset(key_state, 0x00, 128); + memset(key_pressed, 0x00, 128); return EFI_SUCCESS; } + +bool get_key(int scancode) { + bool res; + res = key_state[scancode] | key_pressed[scancode]; + key_pressed[scancode]=0; + return res; +} + +void keyboard_poll() { + UINT8 scancode = (UINT8) inportb(0x60); + if (scancode & 0x80){ + scancode &= 0x7f; + if(key_state[scancode] == 1){ + kernel.keyboard_event_handler(scancode); + } + key_state[scancode]=0; + } + else { + key_state[scancode]=1; + key_pressed[scancode]=1; + } +} diff --git a/NesUEFI/driver/keyboard.h b/NesUEFI/driver/keyboard.h index df46c57..aba5d31 100644 --- a/NesUEFI/driver/keyboard.h +++ b/NesUEFI/driver/keyboard.h @@ -4,7 +4,8 @@ #include #include -EFI_STATUS keyboard_poll(); +bool get_key(int scancode); +void keyboard_poll(); EFI_STATUS keyboard_init(void (*handler)(UINT32 key)); #endif \ No newline at end of file diff --git a/NesUEFI/hal/nes.h b/NesUEFI/hal/nes.h index f5ad659..16d51e8 100644 --- a/NesUEFI/hal/nes.h +++ b/NesUEFI/hal/nes.h @@ -1,14 +1,14 @@ #define NES_FPS 60 #define NES_SCREEN_WIDTH 256 #define NES_SCREEN_HEIGHT 240 -#define NES_SCREEN_ZOOM 3 +#define NES_SCREEN_ZOOM 2 -#define KEY_A 0x6b // k -#define KEY_B 0x6a // j -#define KEY_SELECT 0x75 // u -#define KEY_START 0x69 // i -#define KEY_UP 0x77 // w -#define KEY_DOWN 0x73 // s -#define KEY_LEFT 0x61 // a -#define KEY_RIGHT 0x64 // d -#define KEY_REBOOT 0x72 // r \ No newline at end of file +#define KEY_A 37 // k +#define KEY_B 36 // j +#define KEY_SELECT 22 // u +#define KEY_START 23 // i +#define KEY_UP 17 // w +#define KEY_DOWN 31 // s +#define KEY_LEFT 30 // a +#define KEY_RIGHT 32 // d +#define KEY_REBOOT 19 // r \ No newline at end of file diff --git a/NesUEFI/hal/nes_gfx_hal.c b/NesUEFI/hal/nes_gfx_hal.c index a6a6f3e..c0c8f50 100644 --- a/NesUEFI/hal/nes_gfx_hal.c +++ b/NesUEFI/hal/nes_gfx_hal.c @@ -3,7 +3,7 @@ #include "../ui/adafruit_gfx.h" #include -UINT32 _nes_screen_buffer_prev[(NES_SCREEN_WIDTH) * (NES_SCREEN_HEIGHT) + 1]; +// UINT32 _nes_screen_buffer_prev[(NES_SCREEN_WIDTH) * (NES_SCREEN_HEIGHT) + 1]; UINT32 _nes_screen_buffer_current[(NES_SCREEN_WIDTH) * (NES_SCREEN_HEIGHT) + 1]; @@ -21,13 +21,13 @@ void nes_set_bg(int colour){ void nes_gfx_swap(){ for (int i = 0; i < NES_SCREEN_WIDTH*NES_SCREEN_HEIGHT; ++i){ - if((_nes_screen_buffer_current[i] != _nes_screen_buffer_prev[i]) ){ + // if((_nes_screen_buffer_current[i] != _nes_screen_buffer_prev[i]) ){ int x_offset = (kernel.graphics->Mode->Info->HorizontalResolution - NES_SCREEN_WIDTH*NES_SCREEN_ZOOM)/2 +1; int y_offset = (kernel.graphics->Mode->Info->VerticalResolution - NES_SCREEN_HEIGHT*NES_SCREEN_ZOOM)/2; - _nes_screen_buffer_prev[i] = _nes_screen_buffer_current[i]; + // _nes_screen_buffer_prev[i] = _nes_screen_buffer_current[i]; fillRect( x_offset + (i%NES_SCREEN_WIDTH)*NES_SCREEN_ZOOM, y_offset + (i/NES_SCREEN_WIDTH)*NES_SCREEN_ZOOM, NES_SCREEN_ZOOM, NES_SCREEN_ZOOM, _nes_screen_buffer_current[i]); - } + // } } } \ No newline at end of file diff --git a/NesUEFI/hal/nes_key_hal.c b/NesUEFI/hal/nes_key_hal.c index 40c78db..6c0ea12 100644 --- a/NesUEFI/hal/nes_key_hal.c +++ b/NesUEFI/hal/nes_key_hal.c @@ -4,70 +4,28 @@ #include "../emulator/key.h" #include "../driver/keyboard.h" - -bool _key_state[10]; - -void hal_nes_key_clear(){ - memset(_key_state, 0x00, sizeof(_key_state)); -} - -void hal_nes_ctrl_key_clear(){ - _key_state[NES_KEY_UP] = false; - _key_state[NES_KEY_LEFT] = false; - _key_state[NES_KEY_DOWN] = false; - _key_state[NES_KEY_RIGHT] = false; - _key_state[NES_KEY_SELECT] = false; - _key_state[NES_KEY_START] = false; - // _key_state[NES_KEY_B] = false; // Otherwise Mario will not jump long - _key_state[NES_KEY_A] = false; - _key_state[NES_KEY_REBOOT] = false; -} - -void hal_nes_set_key(uint32_t key){ - hal_nes_key_clear(); - switch(key){ - case KEY_UP: - _key_state[NES_KEY_UP] = true; - break; - - case KEY_LEFT: - _key_state[NES_KEY_LEFT] = true; - break; - - case KEY_DOWN: - _key_state[NES_KEY_DOWN] = true; - break; - - case KEY_RIGHT: - _key_state[NES_KEY_RIGHT] = true; - break; - - case KEY_SELECT: - _key_state[NES_KEY_SELECT] = true; - break; - - case KEY_START: - _key_state[NES_KEY_START] = true; - break; - - case KEY_B: - _key_state[NES_KEY_B] = true; - break; - - case KEY_A: - _key_state[NES_KEY_A] = true; - break; - - case KEY_REBOOT: - _key_state[NES_KEY_REBOOT] = true; - break; - +int hal_nes_get_key(uint16_t key){ + switch (key) + { + case 0: // On / Off + return 1; + case 1: // A + return get_key(37);//K + case 2: // B + return get_key(36);;//J + case 3: // SELECT + return get_key(22);//U + case 4: // START + return get_key(23);//I + case 5: // UP + return get_key(17);//W + case 6: // DOWN + return get_key(31);//S + case 7: // LEFT + return get_key(30);//A + case 8: // RIGHT + return get_key(32);//D default: - break; + return 1; } -} - -bool hal_nes_get_key(uint16_t key){ - if(!key) return true; // Power default on - return _key_state[key]; } \ No newline at end of file diff --git a/NesUEFI/hal/nes_key_hal.h b/NesUEFI/hal/nes_key_hal.h index 67d72e9..d945616 100644 --- a/NesUEFI/hal/nes_key_hal.h +++ b/NesUEFI/hal/nes_key_hal.h @@ -6,22 +6,6 @@ #include "nes.h" -typedef enum nes_key_t { - NES_KEY_POWER, - NES_KEY_A, - NES_KEY_B, - NES_KEY_SELECT, - NES_KEY_START, - NES_KEY_UP, - NES_KEY_DOWN, - NES_KEY_LEFT, - NES_KEY_RIGHT, - NES_KEY_REBOOT -} nes_key_t; - -void hal_nes_key_clear(); -void hal_nes_set_key(uint32_t key); -bool hal_nes_get_key(uint16_t key); -void hal_nes_ctrl_key_clear(); +int hal_nes_get_key(uint16_t key); #endif \ No newline at end of file diff --git a/NesUEFI/main.c b/NesUEFI/main.c index 011a519..2da1f28 100644 --- a/NesUEFI/main.c +++ b/NesUEFI/main.c @@ -55,11 +55,9 @@ efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab){ list_file_browser(); keyboard_init(ui_key_handler); - #if 1 - unsigned long last_frame = 0; while(1){ - rc = keyboard_poll(); + keyboard_poll(); const unsigned long now = (unsigned long)timer_ticks(); if ((now - last_frame) > TICK_PER_SECOND/NES_FPS){ last_frame = now; @@ -70,8 +68,6 @@ efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab){ } } - #endif // #if 1 - Print(L"EFI EXIT : %r\n", rc); return EFI_SUCCESS; } diff --git a/NesUEFI/main.efi b/NesUEFI/main.efi index 35a6e6d..85ced30 100755 Binary files a/NesUEFI/main.efi and b/NesUEFI/main.efi differ diff --git a/NesUEFI/ui/ui_gfx.c b/NesUEFI/ui/ui_gfx.c index cf36aad..62def84 100644 --- a/NesUEFI/ui/ui_gfx.c +++ b/NesUEFI/ui/ui_gfx.c @@ -163,12 +163,11 @@ void render_splash_screen(){ } void ui_key_handler(uint32_t key){ - if (g_ui_state == UI_STATE_MENU){ + if(g_ui_state == UI_STATE_MENU){ render_menu(key); } - else if (g_ui_state == UI_STATE_PLAY){ - hal_nes_set_key(key); - if (key == 'r'){ + else if(g_ui_state == UI_STATE_PLAY){ + if(key == KEY_REBOOT){ g_ui_state = UI_STATE_SPLASH; } } diff --git a/OVMF/OVMF_VARS-pure-efi.fd b/OVMF/OVMF_VARS-pure-efi.fd index 234d6fe..c1c8602 100644 Binary files a/OVMF/OVMF_VARS-pure-efi.fd and b/OVMF/OVMF_VARS-pure-efi.fd differ diff --git a/README.md b/README.md index cbc1642..e549f41 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,8 @@ - # NesUEFI - A bootable NES Emulator running on UEFI ![alt text](/splash.bmp "splash") -**NesUEFI** is a **NES Emulator running without an operating system** directly on **Unified Extensible Firmware Interface (UEFI).** Simply place **NesUEFI** and nes roms in a pendrive and play. **NesUEFI file browser** will show the available roms. The core drivers (Graphics, File System, Keyboard, Timer) are written in c using **GNU-EFI** and the emulator part is a port of [LiteNES](https://github.com/NJU-ProjectN/LiteNES). Adafruit GFX Graphics Library is ported for GNU-EFI ecosystem in C for high level graphics operations and text rendering. +**NesUEFI** is a **NES Emulator running without an operating system** directly on **Unified Extensible Firmware Interface (UEFI).** Simply place **NesUEFI** and nes roms in a pendrive and play. **NesUEFI file browser** will show the available roms. The core drivers (Graphics, File System, Timer) are written in c using **GNU-EFI** and the emulator part is a port of [LiteNES](https://github.com/NJU-ProjectN/LiteNES). Adafruit GFX Graphics Library is ported for GNU-EFI ecosystem in C for high level graphics operations and text rendering. # Compile NesUEFI ## Requirements @@ -68,7 +67,8 @@ Technically NesUEFI should not mess with your system. But you should at least kn - Copy **bootx64.efi** or **bootia32.efi** to boot folder. - For **64 bit** application the pendrive should look like this : **/efi/boot/bootx64.efi** - For **32 bit** application the pendrive should look like this : **/efi/boot/bootia32.efi** -- Simply place your roms in the pendrive. **NesUEFI file browser** will show the available roms. +- Copy **splash.bmp** on the root folder of the pendrive +- Copy your .nes roms in the pendrive. # Demo on Real Hardware Video Coming Soon @@ -87,8 +87,8 @@ Video Coming Soon ## Known Issues - Mappers are not implemented yet. - It does not support Audio emulation yet. -- EFI only have a simple text input protocol. So it only recognizes input character but not keystroke. So key press and release events are emulated by holding down a key until a new key is pressed. Otherwise we can not emulate multi key press events. - Only single player is supported. +- NesUEFI only supports PS/2 keyboard. Most of the laptop keyboards should support it. ## Tested Games Below games are currently tested on real hardware. But NesUEFI is not only limited to these games. It should technically run all the classic roms that use mapper 0. [Here](https://nesdir.github.io/mapper0.html) is a list of mapper 0 games.