Split Libretro into seperate repo
Libretro frontend and cores moved to https://github.com/ehmry/genode-libretro Fix #100
This commit is contained in:
committed by
Norman Feske
parent
47faf8c4f8
commit
16d6fbdb47
@@ -1,5 +0,0 @@
|
||||
LIBRETRO_PORT_DIR := $(call select_from_ports,libretro)
|
||||
|
||||
INC_DIR += $(LIBRETRO_PORT_DIR)/include
|
||||
|
||||
SYMBOLS = $(REP_DIR)/lib/symbols/libretro
|
||||
@@ -1,31 +0,0 @@
|
||||
LIBS = libretro libc libm stdcxx zlib
|
||||
|
||||
SHARED_LIB = yes
|
||||
|
||||
CC_OPT += \
|
||||
-O3 -D__LIBRETRO__ -DSOUND_QUALITY=0 -DPATH_MAX=1024 -DINLINE=inline -DPSS_STYLE=1 -DFCEU_VERSION_NUMERIC=9813 -DFRONTEND_SUPPORTS_RGB565 -DHAVE_ASPRINTF
|
||||
|
||||
CORE_DIR := $(call select_from_ports,fceumm-libretro)/src/libretro/fceumm/src
|
||||
-include $(CORE_DIR)/../Makefile.common
|
||||
|
||||
INC_DIR += \
|
||||
$(CORE_DIR)/drivers/libretro \
|
||||
$(CORE_DIR) \
|
||||
$(CORE_DIR)/input \
|
||||
$(CORE_DIR)/boards \
|
||||
$(CORE_DIR)/mappers
|
||||
|
||||
SRC_CC := $(notdir $(SOURCES_CXX))
|
||||
SRC_C := $(notdir $(SOURCES_C))
|
||||
|
||||
|
||||
vpath %.c $(CORE_DIR)
|
||||
vpath %.c $(CORE_DIR)/boards
|
||||
vpath %.c $(CORE_DIR)/drivers/libretro
|
||||
vpath %.c $(CORE_DIR)/drivers/libretro/libretro-common/compat
|
||||
vpath %.c $(CORE_DIR)/drivers/libretro/libretro-common/streams
|
||||
vpath %.c $(CORE_DIR)/input
|
||||
vpath %.c $(CORE_DIR)/mappers
|
||||
|
||||
|
||||
CC_CXX_WARN_STRICT =
|
||||
@@ -1,2 +0,0 @@
|
||||
|
||||
CC_CXX_WARN_STRICT =
|
||||
@@ -1,20 +0,0 @@
|
||||
LIBS = libc stdcxx
|
||||
|
||||
SHARED_LIB = yes
|
||||
|
||||
PORT_DIR := $(call select_from_ports,meteor-libretro)/src/libretro/meteor
|
||||
|
||||
CORE_DIR := $(PORT_DIR)
|
||||
-include $(PORT_DIR)/libretro/Makefile.common
|
||||
|
||||
CXX_DEF += -D__LIBRETRO__ -DNDEBUG -DFRONTEND_SUPPORTS_RGB565
|
||||
|
||||
CC_WARN += -Wno-parentheses
|
||||
|
||||
INC_DIR += $(PORT_DIR)/libretro $(PORT_DIR)/ameteor/include
|
||||
|
||||
SRC_CC := $(notdir $(SOURCES_CXX))
|
||||
|
||||
vpath %.cpp $(sort $(dir $(SOURCES_CXX)))
|
||||
|
||||
CC_CXX_WARN_STRICT =
|
||||
@@ -1,25 +0,0 @@
|
||||
LIBS = libretro libc libm stdcxx
|
||||
|
||||
SHARED_LIB = yes
|
||||
|
||||
PORT_DIR := $(call select_from_ports,nxengine-libretro)/src/lib/nxengine-libretro
|
||||
|
||||
CORE_DIR := $(PORT_DIR)/nxengine
|
||||
EXTRACTDIR := $(CORE_DIR)/extract-auto
|
||||
|
||||
-include $(PORT_DIR)/Makefile.common
|
||||
|
||||
CC_OPT = -DFRONTEND_SUPPORTS_RGB565
|
||||
|
||||
INC_DIR += \
|
||||
$(CORE_DIR) $(CORE_DIR)/graphics \
|
||||
$(CORE_DIR)/libretro $(CORE_DIR)/libretro/libretro-common/include \
|
||||
$(CORE_DIR)/sdl/include
|
||||
|
||||
SRC_C := $(notdir $(SOURCES_C))
|
||||
SRC_CC := $(notdir $(SOURCES_CXX))
|
||||
|
||||
vpath %.cpp $(sort $(dir $(SOURCES_CXX)))
|
||||
vpath %.c $(sort $(dir $(SOURCES_C)))
|
||||
|
||||
CC_CXX_WARN_STRICT =
|
||||
@@ -1,23 +0,0 @@
|
||||
LIBS = libretro libc libm stdcxx
|
||||
|
||||
SHARED_LIB = yes
|
||||
|
||||
CC_OPT += \
|
||||
-fno-rtti -pedantic \
|
||||
-DHAVE_STRINGS_H -DHAVE_STDINT_H -DRIGHTSHIFT_IS_SAR -D__LIBRETRO__ \
|
||||
-O3 -DNDEBUG
|
||||
|
||||
CORE_DIR := $(call select_from_ports,snes9x-libretro)/src/libretro/snes9x
|
||||
-include $(CORE_DIR)/libretro/Makefile.common
|
||||
|
||||
INC_DIR += $(CORE_DIR)/libretro $(CORE_DIR) $(CORE_DIR)/apu/ $(CORE_DIR)/apu/bapu
|
||||
|
||||
SRC_CC := $(notdir $(SOURCES_CXX))
|
||||
|
||||
vpath %.cpp $(CORE_DIR)/apu
|
||||
vpath %.cpp $(CORE_DIR)/apu/bapu/dsp
|
||||
vpath %.cpp $(CORE_DIR)/apu/bapu/smp
|
||||
vpath %.cpp $(CORE_DIR)/libretro
|
||||
vpath %.cpp $(CORE_DIR)
|
||||
|
||||
CC_CXX_WARN_STRICT =
|
||||
@@ -1,29 +0,0 @@
|
||||
LIBS = libc libm stdcxx
|
||||
|
||||
SHARED_LIB = yes
|
||||
|
||||
PORT_DIR := $(call select_from_ports,tyrquake-libretro)/src/libretro/tyrquake
|
||||
CORE_DIR := $(PORT_DIR)
|
||||
|
||||
-include $(PORT_DIR)/Makefile.common
|
||||
|
||||
INC_DIR += \
|
||||
$(REP_DIR)/src/libretro/tyrquake \
|
||||
$(PORT_DIR)/common \
|
||||
$(PORT_DIR)/libretro-common/include \
|
||||
|
||||
CC_OPT = \
|
||||
-DHAVE_STRINGS_H \
|
||||
-DHAVE_STDINT_H \
|
||||
-DHAVE_INTTYPES_H \
|
||||
-D__LIBRETRO__ \
|
||||
-DINLINE=inline \
|
||||
-DNQ_HACK \
|
||||
-DQBASEDIR=$(CORE_DIR) \
|
||||
-DTYR_VERSION=0.62
|
||||
|
||||
SRC_C := $(notdir $(SOURCES_C))
|
||||
|
||||
vpath %.c $(sort $(dir $(SOURCES_C)))
|
||||
|
||||
CC_CXX_WARN_STRICT =
|
||||
@@ -1 +0,0 @@
|
||||
a89e9e6d0c52d83075f2a81a99751d22e3e238c2
|
||||
@@ -1,11 +0,0 @@
|
||||
LICENSE := GPL2
|
||||
VERSION := dev
|
||||
DOWNLOADS := fceumm.archive
|
||||
|
||||
OWNER := libretro
|
||||
REPO := libretro-fceumm
|
||||
REV := 72e74d6fcc4f3173f5b3826e984d431fb39ae147
|
||||
URL(fceumm) := https://github.com/$(OWNER)/$(REPO)/archive/$(REV).tar.gz
|
||||
SHA(fceumm) := d13cd6996ce545def86c9f45025159ac23298ddb
|
||||
|
||||
DIR(fceumm) := src/libretro/fceumm
|
||||
@@ -1 +0,0 @@
|
||||
4af697b4dcae97201f56baf817497595df9ae3b4
|
||||
@@ -1,9 +0,0 @@
|
||||
LICENSE := MIT
|
||||
VERSION := 1.3.6
|
||||
DOWNLOADS := libretro.file
|
||||
|
||||
URL(libretro) := https://raw.githubusercontent.com/libretro/RetroArch/v1.3.6/libretro-common/include/libretro.h
|
||||
SHA(libretro) := 452485de627b9791b243a628c1ec3f6b8a90d2c0
|
||||
|
||||
DIRS := include
|
||||
DIR_CONTENT(include) := libretro.h
|
||||
@@ -1 +0,0 @@
|
||||
cf72badc0be2c5e20ec45453c5c75dc79bb366fd
|
||||
@@ -1,11 +0,0 @@
|
||||
LICENSE := GPL3
|
||||
VERSION := dev
|
||||
DOWNLOADS := meteor-libretro.archive
|
||||
|
||||
OWNER := libretro
|
||||
REPO := meteor-libretro
|
||||
REV := 21412cf2d3d727ed513cd4c382e4f52c02ccc947
|
||||
URL(meteor-libretro) := https://github.com/$(OWNER)/$(REPO)/archive/$(REV).tar.gz
|
||||
SHA(meteor-libretro) := dd0812344e399a80273a8e8402d5e2982a8d7d70
|
||||
|
||||
DIR(meteor-libretro) := src/libretro/meteor
|
||||
@@ -1 +0,0 @@
|
||||
7bda4d0d5b7d8bfb3cd5cd5258bbfad819e6a23e
|
||||
@@ -1,11 +0,0 @@
|
||||
LICENSE := Unknown
|
||||
VERSION := 1.0.0.6
|
||||
DOWNLOADS := nxengine-libretro.archive
|
||||
|
||||
OWNER := libretro
|
||||
REPO := nxengine-libretro
|
||||
REV := c0407ad1311796a028c269ee785f539ebc47e1cc
|
||||
URL(nxengine-libretro) := https://github.com/$(OWNER)/$(REPO)/archive/$(REV).tar.gz
|
||||
SHA(nxengine-libretro) := cf47a1320c3e2fa471f2c34581b76b2ca7d92172
|
||||
|
||||
DIR(nxengine-libretro) := src/lib/nxengine-libretro
|
||||
@@ -1 +0,0 @@
|
||||
112e02d21246ae41ca3b32f9e1c461727f7fce50
|
||||
@@ -1,10 +0,0 @@
|
||||
LICENSE := GPL3
|
||||
VERSION := dev
|
||||
DOWNLOADS := snes9x-libretro.archive
|
||||
|
||||
OWNER := libretro
|
||||
REPO := snes9x
|
||||
REV := f29f7b48b7548a88540a2d01683c37b1b55a74a2
|
||||
URL(snes9x-libretro) := https://github.com/$(OWNER)/$(REPO)/archive/$(REV).tar.gz
|
||||
SHA(snes9x-libretro) := afd9f9a3cae367207210caf619f3b449e4d9f70f
|
||||
DIR(snes9x-libretro) := src/libretro/snes9x
|
||||
@@ -1 +0,0 @@
|
||||
7e313a85de4e5600dca2fb7b8d16e6a1ec1a57f7
|
||||
@@ -1,11 +0,0 @@
|
||||
LICENSE := Unknown
|
||||
VERSION := dev
|
||||
DOWNLOADS := tyrquake-libretro.archive
|
||||
|
||||
OWNER := libretro
|
||||
REPO := tyrquake
|
||||
REV := 7f3c540a320b706031021bb187bb03bb4c326f88
|
||||
URL(tyrquake-libretro) := https://github.com/$(OWNER)/$(REPO)/archive/$(REV).tar.gz
|
||||
SHA(tyrquake-libretro) := 4ef1899ac6a66b476541064319df6d40c148fba2
|
||||
|
||||
DIR(tyrquake-libretro) := src/libretro/tyrquake
|
||||
@@ -1,10 +0,0 @@
|
||||
content: include/libretro.h LICENSE
|
||||
|
||||
PORT_DIR := $(call port_dir,$(REP_DIR)/ports/libretro)
|
||||
|
||||
include/libretro.h: $(PORT_DIR)/include/libretro.h
|
||||
mkdir $(dir $@)
|
||||
cp -r $< $@
|
||||
|
||||
LICENSE: include/libretro.h
|
||||
head -n 22 include/libretro.h > $@
|
||||
@@ -1 +0,0 @@
|
||||
2017-11-16 c8f71292a4ee5e7f312f10dbef5b79f0fb889795
|
||||
@@ -1 +0,0 @@
|
||||
FCE Ultra mappers modified, an emulator for the Nintendo Entertainment System
|
||||
@@ -1,3 +0,0 @@
|
||||
_/src/fceumm_libretro
|
||||
_/src/libc
|
||||
_/src/zlib
|
||||
@@ -1 +0,0 @@
|
||||
2017-11-27 7b23c5e758426526c248cc0f3c950fe6c0fd1ba5
|
||||
@@ -1 +0,0 @@
|
||||
Meteor emulator for the Game Boy Advance
|
||||
@@ -1,2 +0,0 @@
|
||||
_/src/meteor_libretro
|
||||
_/src/libc
|
||||
@@ -1 +0,0 @@
|
||||
2017-11-27 2b0c5d1bfc622a0b7cb10aa07cdb35f08a394063
|
||||
@@ -1,3 +0,0 @@
|
||||
Snes9x emulator for the Super Nintendo Entertainment System
|
||||
|
||||
http://www.snes9x.com/
|
||||
@@ -1,2 +0,0 @@
|
||||
_/src/snes9x_libretro
|
||||
_/src/libc
|
||||
@@ -1 +0,0 @@
|
||||
2017-11-27 228441601a48077e33274d70cbfd5466202ced8e
|
||||
@@ -1,3 +0,0 @@
|
||||
TyrQuake engine
|
||||
|
||||
http://disentchant.net/tyrquake/
|
||||
@@ -1,2 +0,0 @@
|
||||
_/src/libc
|
||||
_/src/tyrquake_libretro
|
||||
@@ -1 +0,0 @@
|
||||
2017-11-28 99f3d81ad18df7f6bd7c7142d3280f5b708e3b21
|
||||
@@ -1 +0,0 @@
|
||||
libretro
|
||||
@@ -1,14 +0,0 @@
|
||||
content: lib/mk/fceumm_libretro.mk src/libretro/fceumm LICENSE
|
||||
|
||||
CORE_DIR := $(call port_dir,$(REP_DIR)/ports/fceumm-libretro)/src/libretro/fceumm
|
||||
|
||||
lib/mk/fceumm_libretro.mk:
|
||||
$(mirror_from_rep_dir)
|
||||
|
||||
src/libretro/fceumm:
|
||||
$(mirror_from_rep_dir)
|
||||
cp -r $(CORE_DIR)/* $@
|
||||
echo "LIBS = fceumm_libretro" > $@/target.mk
|
||||
|
||||
LICENSE:
|
||||
cp $(CORE_DIR)/Copying LICENSE
|
||||
@@ -1 +0,0 @@
|
||||
2017-11-27 a0faa1146122f9c44500385c3dcb9c3f8e26a02a
|
||||
@@ -1,4 +0,0 @@
|
||||
libc
|
||||
so
|
||||
stdcxx
|
||||
zlib
|
||||
@@ -1,14 +0,0 @@
|
||||
content: lib/mk/meteor_libretro.mk src/libretro/meteor LICENSE
|
||||
|
||||
CORE_DIR := $(call port_dir,$(REP_DIR)/ports/meteor-libretro)/src/libretro/meteor
|
||||
|
||||
lib/mk/meteor_libretro.mk:
|
||||
$(mirror_from_rep_dir)
|
||||
|
||||
src/libretro/meteor:
|
||||
$(mirror_from_rep_dir)
|
||||
cp -r $(CORE_DIR)/* $@
|
||||
echo "LIBS = meteor_libretro" > $@/target.mk
|
||||
|
||||
LICENSE:
|
||||
cp $(CORE_DIR)/COPYING LICENSE
|
||||
@@ -1 +0,0 @@
|
||||
2017-11-27 cd297ae262c8628e505d8407ef3df840885ada6d
|
||||
@@ -1,3 +0,0 @@
|
||||
libc
|
||||
so
|
||||
stdcxx
|
||||
@@ -1,2 +0,0 @@
|
||||
SRC_DIR := src/app/retro_frontend
|
||||
include $(GENODE_DIR)/repos/base/recipes/src/content.inc
|
||||
@@ -1 +0,0 @@
|
||||
2017-11-27 5d0ed1ae158fe0b7d3f825b2d4815b8e98375866
|
||||
@@ -1,10 +0,0 @@
|
||||
audio_out_session
|
||||
base
|
||||
framebuffer_session
|
||||
input_session
|
||||
libc
|
||||
libretro
|
||||
os
|
||||
report_session
|
||||
timer_session
|
||||
vfs
|
||||
@@ -1 +0,0 @@
|
||||
libretro
|
||||
@@ -1,14 +0,0 @@
|
||||
content: lib/mk/snes9x_libretro.mk src/libretro/snes9x LICENSE
|
||||
|
||||
CORE_DIR := $(call port_dir,$(REP_DIR)/ports/snes9x-libretro)/src/libretro/snes9x
|
||||
|
||||
lib/mk/snes9x_libretro.mk:
|
||||
$(mirror_from_rep_dir)
|
||||
|
||||
src/libretro/snes9x:
|
||||
$(mirror_from_rep_dir)
|
||||
cp -r $(CORE_DIR)/* $@
|
||||
echo "LIBS = snes9x_libretro" > $@/target.mk
|
||||
|
||||
LICENSE:
|
||||
cp $(CORE_DIR)/docs/snes9x-license.txt LICENSE
|
||||
@@ -1 +0,0 @@
|
||||
2017-11-27 07d08e662af9e92c7fe7f386dfea53e2e25383a1
|
||||
@@ -1,4 +0,0 @@
|
||||
libc
|
||||
so
|
||||
stdcxx
|
||||
zlib
|
||||
@@ -1,14 +0,0 @@
|
||||
content: lib/mk/tyrquake_libretro.mk src/libretro/tyrquake LICENSE
|
||||
|
||||
CORE_DIR := $(call port_dir,$(REP_DIR)/ports/tyrquake-libretro)/src/libretro/tyrquake
|
||||
|
||||
lib/mk/tyrquake_libretro.mk:
|
||||
$(mirror_from_rep_dir)
|
||||
|
||||
src/libretro/tyrquake:
|
||||
$(mirror_from_rep_dir)
|
||||
cp -r $(CORE_DIR)/* $@
|
||||
echo "LIBS = tyrquake_libretro" > $@/target.mk
|
||||
|
||||
LICENSE:
|
||||
cp $(CORE_DIR)/gnu.txt LICENSE
|
||||
@@ -1 +0,0 @@
|
||||
2017-11-28 e8a8580e4458b13cc1f225b96e70f25a92c9582e
|
||||
@@ -1,3 +0,0 @@
|
||||
libc
|
||||
so
|
||||
stdcxx
|
||||
@@ -1,186 +0,0 @@
|
||||
# setting environment variable FORCE_QEMU permits running netperf in qemu
|
||||
set force_qemu [info exists ::env(FORCE_QEMU)]
|
||||
|
||||
if {[expr [have_include "power_on/qemu"] && !$force_qemu]} {
|
||||
puts "\Game emulation inside Qemu is not recommended.\n"
|
||||
exit
|
||||
}
|
||||
|
||||
set build_components {
|
||||
core init
|
||||
app/retro_frontend
|
||||
drivers/audio
|
||||
drivers/framebuffer
|
||||
drivers/input
|
||||
drivers/timer
|
||||
libretro/nxengine
|
||||
server/fb_upscale
|
||||
}
|
||||
|
||||
source ${genode_dir}/repos/base/run/platform_drv.inc
|
||||
# override default platform driver policy
|
||||
proc platform_drv_policy {} {
|
||||
return {
|
||||
<policy label_prefix="ps2_drv"> <device name="PS2"/> </policy>
|
||||
<policy label_prefix="usb_drv"> <pci class="USB"/> </policy>
|
||||
<policy label_prefix="fb_drv"> <pci class="VGA"/> </policy>
|
||||
<policy label_prefix="audio_drv"> <pci class="AUDIO"/> <pci class="HDAUDIO"/> </policy>}
|
||||
}
|
||||
|
||||
append_platform_drv_build_components
|
||||
|
||||
build $build_components
|
||||
|
||||
create_boot_directory
|
||||
|
||||
#
|
||||
# Generate config
|
||||
#
|
||||
|
||||
append config {
|
||||
<config verbose="yes">
|
||||
<default caps="256"/>
|
||||
<parent-provides>
|
||||
<service name="CPU"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="LOG"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="ROM"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>}
|
||||
|
||||
append_if [have_spec sdl] config {
|
||||
<start name="fb_sdl">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides>
|
||||
<service name="Input"/>
|
||||
<service name="Framebuffer"/>
|
||||
</provides>
|
||||
<config width="640" height="480"/>
|
||||
</start>
|
||||
<alias name="input_drv" child="fb_sdl"/>
|
||||
<alias name="fb_drv" child="fb_sdl"/>}
|
||||
|
||||
append_platform_drv_config
|
||||
|
||||
append_if [have_spec vesa] config {
|
||||
<start name="fb_drv">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="Framebuffer"/></provides>
|
||||
<config buffered="yes"> </config>
|
||||
<config width="640" height="480"/>
|
||||
</start>}
|
||||
|
||||
append_if [have_spec pl11x] config {
|
||||
<start name="fb_drv">
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<provides><service name="Framebuffer"/></provides>
|
||||
</start>}
|
||||
|
||||
append_if [have_spec ps2] config {
|
||||
<start name="ps2_drv">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Input"/></provides>
|
||||
</start>
|
||||
<alias name="input_drv" child="ps2_drv"/>}
|
||||
|
||||
append config {
|
||||
<start name="audio_drv">
|
||||
<binary name="} [audio_drv_binary] {"/>
|
||||
<resource name="RAM" quantum="8M"/>
|
||||
<provides> <service name="Audio_out"/> </provides>
|
||||
</start>
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
<start name="fb_upscale">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides> <service name="Framebuffer"/> </provides>
|
||||
<route>
|
||||
<service name="Framebuffer">
|
||||
<child name="fb_drv"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="report_rom">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides> <service name="Report"/> </provides>
|
||||
<config verbose="yes"/>
|
||||
</start>
|
||||
<start name="retro_frontend">
|
||||
<resource name="RAM" quantum="64M"/>
|
||||
<config core="nxengine_libretro.lib.so">
|
||||
<controller port="0" device="1">
|
||||
<map from="KEY_LEFT" to="LEFT"/>
|
||||
<map from="KEY_RIGHT" to="RIGHT"/>
|
||||
<map from="KEY_UP" to="UP"/>
|
||||
<map from="KEY_DOWN" to="DOWN"/>
|
||||
|
||||
<map from="KEY_Z" to="B"/>
|
||||
<map from="KEY_X" to="A"/>
|
||||
|
||||
<map from="KEY_ENTER" to="START"/>
|
||||
<map from="KEY_RIGHTSHIFT" to="SELECT"/>
|
||||
</controller>
|
||||
<libc stdout="/dev/log" stderr="/dev/log"/>
|
||||
<vfs>
|
||||
<dir name="dev"> <log/> </dir>
|
||||
<tar name="doukutsu.tar"/>
|
||||
<ram/>
|
||||
</vfs>
|
||||
</config>
|
||||
<route>
|
||||
<service name="Framebuffer">
|
||||
<child name="fb_upscale"/> </service>
|
||||
<service name="Input">
|
||||
<child name="input_drv"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
</config>}
|
||||
|
||||
install_config $config
|
||||
|
||||
if {![file exists bin/doukutsu.tar]} {
|
||||
puts ""
|
||||
puts "Please download a copy of the Cave Story game data from "
|
||||
puts " http://www.cavestory.org/download/cave-story.php"
|
||||
puts "and re-archive the zip contents to './bin/doukutsu.tar'. Afterwards run this script again."
|
||||
puts ""
|
||||
exit 1
|
||||
}
|
||||
|
||||
# generic modules
|
||||
append boot_modules {
|
||||
core init ld.lib.so
|
||||
} [audio_drv_binary] {
|
||||
fb_upscale
|
||||
libc.lib.so
|
||||
libm.lib.so
|
||||
nxengine_libretro.lib.so
|
||||
report_rom
|
||||
retro_frontend
|
||||
stdcxx.lib.so
|
||||
timer
|
||||
doukutsu.tar
|
||||
}
|
||||
|
||||
# platform-specific modules
|
||||
lappend_if [have_spec linux] boot_modules fb_sdl
|
||||
lappend_if [have_spec vesa] boot_modules fb_drv
|
||||
lappend_if [have_spec ps2] boot_modules ps2_drv
|
||||
lappend_if [have_spec pl11x] boot_modules fb_drv
|
||||
|
||||
append_platform_drv_boot_modules
|
||||
|
||||
build_boot_image $boot_modules
|
||||
|
||||
append qemu_args " -soundhw es1370 "
|
||||
|
||||
run_genode_until forever
|
||||
190
run/driar.run
190
run/driar.run
@@ -1,190 +0,0 @@
|
||||
# setting environment variable FORCE_QEMU permits running netperf in qemu
|
||||
set force_qemu [info exists ::env(FORCE_QEMU)]
|
||||
|
||||
if {[expr [have_include "power_on/qemu"] && !$force_qemu]} {
|
||||
puts "\Game emulation on Qemu is not recommended.\n"
|
||||
exit
|
||||
}
|
||||
|
||||
#
|
||||
# Check used commands
|
||||
#
|
||||
set wget [check_installed wget]
|
||||
set unzip [check_installed unzip]
|
||||
|
||||
create_boot_directory
|
||||
|
||||
import_from_depot genodelabs/src/[base_src] \
|
||||
genodelabs/pkg/fceumm_libretro \
|
||||
genodelabs/src/fb_upscale \
|
||||
genodelabs/src/init \
|
||||
genodelabs/src/report_rom \
|
||||
genodelabs/src/retro_frontend \
|
||||
|
||||
set build_components {
|
||||
drivers/audio
|
||||
drivers/framebuffer
|
||||
drivers/input
|
||||
}
|
||||
|
||||
source ${genode_dir}/repos/base/run/platform_drv.inc
|
||||
# override default platform driver policy
|
||||
proc platform_drv_policy {} {
|
||||
return {
|
||||
<policy label_prefix="ps2_drv"> <device name="PS2"/> </policy>
|
||||
<policy label_prefix="usb_drv"> <pci class="USB"/> </policy>
|
||||
<policy label_prefix="fb_drv"> <pci class="VGA"/> </policy>
|
||||
<policy label_prefix="audio_drv"> <pci class="AUDIO"/> <pci class="HDAUDIO"/> </policy>}
|
||||
}
|
||||
|
||||
append_platform_drv_build_components
|
||||
|
||||
build $build_components
|
||||
|
||||
#
|
||||
# Generate config
|
||||
#
|
||||
|
||||
append config {
|
||||
<config verbose="yes">
|
||||
<default caps="128"/>
|
||||
<parent-provides>
|
||||
<service name="CPU"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="LOG"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="ROM"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>}
|
||||
|
||||
append_if [have_spec sdl] config {
|
||||
<start name="fb_sdl">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides>
|
||||
<service name="Input"/>
|
||||
<service name="Framebuffer"/>
|
||||
</provides>
|
||||
<config width="640" height="480"/>
|
||||
</start>
|
||||
<alias name="input_drv" child="fb_sdl"/>
|
||||
<alias name="fb_drv" child="fb_sdl"/>}
|
||||
|
||||
append_platform_drv_config
|
||||
|
||||
append_if [have_spec vesa] config {
|
||||
<start name="fb_drv">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="Framebuffer"/></provides>
|
||||
<config buffered="yes"> </config>
|
||||
<config width="300" height="200"/>
|
||||
</start>}
|
||||
|
||||
append_if [have_spec pl11x] config {
|
||||
<start name="fb_drv">
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<provides><service name="Framebuffer"/></provides>
|
||||
</start>}
|
||||
|
||||
append_if [have_spec ps2] config {
|
||||
<start name="ps2_drv">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Input"/></provides>
|
||||
</start>
|
||||
<alias name="input_drv" child="ps2_drv"/>}
|
||||
|
||||
append config {
|
||||
<start name="audio_drv">
|
||||
<binary name="} [audio_drv_binary] {"/>
|
||||
<resource name="RAM" quantum="8M"/>
|
||||
<provides><service name="Audio_out"/></provides>
|
||||
</start>
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
<start name="fb_upscale">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides> <service name="Framebuffer"/> </provides>
|
||||
<route>
|
||||
<service name="Framebuffer">
|
||||
<child name="fb_drv"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="report_rom">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides> <service name="Report"/> </provides>
|
||||
<config verbose="yes"/>
|
||||
</start>
|
||||
<start name="retro_frontend">
|
||||
<resource name="RAM" quantum="64M"/>
|
||||
<config core="fceumm_libretro.lib.so">
|
||||
<game rom="Driar.nes"/>
|
||||
<libc stdout="/log" stderr="/log"/>
|
||||
<vfs> <log/> </vfs>
|
||||
<controller port="0" device="257">
|
||||
<map from="KEY_LEFT" to="LEFT"/>
|
||||
<map from="KEY_RIGHT" to="RIGHT"/>
|
||||
<map from="KEY_UP" to="UP"/>
|
||||
<map from="KEY_DOWN" to="DOWN"/>
|
||||
|
||||
<map from="KEY_Z" to="B"/>
|
||||
<map from="KEY_X" to="A"/>
|
||||
|
||||
<map from="KEY_ENTER" to="START"/>
|
||||
<map from="KEY_RIGHTSHIFT" to="SELECT"/>
|
||||
</controller>
|
||||
</config>
|
||||
<route>
|
||||
<service name="Framebuffer">
|
||||
<child name="fb_upscale"/> </service>
|
||||
<service name="Input">
|
||||
<child name="input_drv"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
</config>}
|
||||
|
||||
install_config $config
|
||||
|
||||
#
|
||||
# Download and extract a test ROM
|
||||
#
|
||||
if {![file exist bin/driar.zip]} {
|
||||
set zip_url "http://driar.se/driar/driar.zip"
|
||||
catch { exec $wget $zip_url -O bin/driar.zip }
|
||||
}
|
||||
if {![file exist bin/Driar.nes]} {
|
||||
catch { exec $unzip -o bin/driar.zip -d bin }
|
||||
}
|
||||
|
||||
# generic modules
|
||||
append boot_modules {
|
||||
Driar.nes
|
||||
} [audio_drv_binary] {
|
||||
}
|
||||
|
||||
# platform-specific modules
|
||||
lappend_if [have_spec linux] boot_modules fb_sdl
|
||||
lappend_if [have_spec vesa] boot_modules fb_drv
|
||||
lappend_if [have_spec ps2] boot_modules ps2_drv
|
||||
lappend_if [have_spec pl11x] boot_modules fb_drv
|
||||
|
||||
append_platform_drv_boot_modules
|
||||
|
||||
build_boot_image $boot_modules
|
||||
|
||||
append qemu_args " -soundhw es1370 "
|
||||
|
||||
puts "\n################\n"
|
||||
set txt [open "bin/Driar.txt" r]
|
||||
puts [read $txt]
|
||||
close $txt
|
||||
puts "\n################\n"
|
||||
|
||||
run_genode_until forever
|
||||
172
run/meteor.run
172
run/meteor.run
@@ -1,172 +0,0 @@
|
||||
# setting environment variable FORCE_QEMU permits running netperf in qemu
|
||||
set force_qemu [info exists ::env(FORCE_QEMU)]
|
||||
|
||||
if {[expr [have_include "power_on/qemu"] && !$force_qemu]} {
|
||||
puts "\Game emulation on Qemu is not recommended.\n"
|
||||
exit
|
||||
}
|
||||
|
||||
create_boot_directory
|
||||
|
||||
import_from_depot \
|
||||
genodelabs/src/[base_src] \
|
||||
genodelabs/pkg/[drivers_interactive_pkg] \
|
||||
genodelabs/pkg/meteor_libretro \
|
||||
genodelabs/src/fb_upscale \
|
||||
genodelabs/src/init \
|
||||
genodelabs/src/report_rom \
|
||||
genodelabs/src/retro_frontend \
|
||||
|
||||
|
||||
set build_components {
|
||||
drivers/audio
|
||||
}
|
||||
|
||||
source ${genode_dir}/repos/base/run/platform_drv.inc
|
||||
# override default platform driver policy
|
||||
proc platform_drv_policy {} {
|
||||
return {
|
||||
<policy label_prefix="ps2_drv"> <device name="PS2"/> </policy>
|
||||
<policy label_prefix="usb_drv"> <pci class="USB"/> </policy>
|
||||
<policy label_prefix="fb_drv"> <pci class="VGA"/> </policy>
|
||||
<policy label_prefix="audio_drv"> <pci class="AUDIO"/> <pci class="HDAUDIO"/> </policy>}
|
||||
}
|
||||
|
||||
build $build_components
|
||||
|
||||
|
||||
#
|
||||
# Generate config
|
||||
#
|
||||
|
||||
append config {
|
||||
<config verbose="yes">
|
||||
<default caps="128"/>
|
||||
<parent-provides>
|
||||
<service name="CPU"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="LOG"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="ROM"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>}
|
||||
|
||||
append_if [have_spec sdl] config {
|
||||
<start name="fb_sdl">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides>
|
||||
<service name="Input"/>
|
||||
<service name="Framebuffer"/>
|
||||
</provides>
|
||||
<config width="640" height="480"/>
|
||||
</start>
|
||||
<alias name="input_drv" child="fb_sdl"/>
|
||||
<alias name="fb_drv" child="fb_sdl"/>}
|
||||
|
||||
append_platform_drv_config
|
||||
|
||||
append_if [have_spec vesa] config {
|
||||
<start name="fb_drv">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="Framebuffer"/></provides>
|
||||
<config buffered="yes"> </config>
|
||||
<config width="300" height="200"/>
|
||||
</start>}
|
||||
|
||||
append_if [have_spec pl11x] config {
|
||||
<start name="fb_drv">
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<provides><service name="Framebuffer"/></provides>
|
||||
</start>}
|
||||
|
||||
append_if [have_spec ps2] config {
|
||||
<start name="ps2_drv">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Input"/></provides>
|
||||
</start>
|
||||
<alias name="input_drv" child="ps2_drv"/>}
|
||||
|
||||
append config {
|
||||
<start name="audio_drv">
|
||||
<binary name="} [audio_drv_binary] {"/>
|
||||
<resource name="RAM" quantum="8M"/>
|
||||
<provides><service name="Audio_out"/></provides>
|
||||
</start>
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
<start name="fb_upscale">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides> <service name="Framebuffer"/> </provides>
|
||||
<route>
|
||||
<service name="Framebuffer">
|
||||
<child name="fb_drv"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="report_rom">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides> <service name="Report"/> </provides>
|
||||
<config verbose="yes"/>
|
||||
</start>
|
||||
<start name="retro_frontend">
|
||||
<resource name="RAM" quantum="64M"/>
|
||||
<config core="meteor_libretro.lib.so">
|
||||
<game rom="game.gba"/>
|
||||
<controller port="0" device="1">
|
||||
<map from="KEY_LEFT" to="LEFT"/>
|
||||
<map from="KEY_RIGHT" to="RIGHT"/>
|
||||
<map from="KEY_UP" to="UP"/>
|
||||
<map from="KEY_DOWN" to="DOWN"/>
|
||||
|
||||
<map from="KEY_A" to="L"/>
|
||||
<map from="KEY_S" to="R"/>
|
||||
<map from="KEY_Z" to="B"/>
|
||||
<map from="KEY_X" to="A"/>
|
||||
|
||||
<map from="KEY_ENTER" to="START"/>
|
||||
<map from="KEY_RIGHTSHIFT" to="SELECT"/>
|
||||
</controller>
|
||||
<libc stdout="/log" stderr="/log"/>
|
||||
<vfs>
|
||||
<log/>
|
||||
</vfs>
|
||||
</config>
|
||||
<route>
|
||||
<service name="Framebuffer">
|
||||
<child name="fb_upscale"/> </service>
|
||||
<service name="Input">
|
||||
<child name="input_drv"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
</config>}
|
||||
|
||||
install_config $config
|
||||
|
||||
if {![file exists bin/game.gba]} {
|
||||
puts ""
|
||||
puts "A Game Boy Advance cartridge image must be provided at 'bin/game.gba'"
|
||||
puts ""
|
||||
exit 1
|
||||
}
|
||||
|
||||
# generic modules
|
||||
append boot_modules {
|
||||
} [audio_drv_binary] {
|
||||
game.gba
|
||||
}
|
||||
|
||||
append_platform_drv_boot_modules
|
||||
|
||||
build_boot_image $boot_modules
|
||||
|
||||
append qemu_args " -soundhw es1370 "
|
||||
|
||||
run_genode_until forever
|
||||
@@ -1,191 +0,0 @@
|
||||
# setting environment variable FORCE_QEMU permits running netperf in qemu
|
||||
set force_qemu [info exists ::env(FORCE_QEMU)]
|
||||
|
||||
if {[expr [have_include "power_on/qemu"] && !$force_qemu]} {
|
||||
puts "\Game emulation on Qemu is not recommended.\n"
|
||||
exit
|
||||
}
|
||||
|
||||
#
|
||||
# Check used commands
|
||||
#
|
||||
set wget [check_installed wget]
|
||||
set unzip [check_installed unzip]
|
||||
|
||||
create_boot_directory
|
||||
|
||||
import_from_depot genodelabs/src/[base_src] \
|
||||
genodelabs/pkg/snes9x_libretro \
|
||||
genodelabs/src/fb_upscale \
|
||||
genodelabs/src/init \
|
||||
genodelabs/src/report_rom \
|
||||
genodelabs/src/retro_frontend \
|
||||
|
||||
set build_components {
|
||||
drivers/audio
|
||||
drivers/framebuffer
|
||||
drivers/input
|
||||
}
|
||||
|
||||
source ${genode_dir}/repos/base/run/platform_drv.inc
|
||||
# override default platform driver policy
|
||||
proc platform_drv_policy {} {
|
||||
return {
|
||||
<policy label_prefix="ps2_drv"> <device name="PS2"/> </policy>
|
||||
<policy label_prefix="usb_drv"> <pci class="USB"/> </policy>
|
||||
<policy label_prefix="fb_drv"> <pci class="VGA"/> </policy>
|
||||
<policy label_prefix="audio_drv"> <pci class="AUDIO"/> <pci class="HDAUDIO"/> </policy>}
|
||||
|
||||
}
|
||||
|
||||
append_platform_drv_build_components
|
||||
|
||||
build $build_components
|
||||
|
||||
#
|
||||
# Generate config
|
||||
#
|
||||
|
||||
append config {
|
||||
<config verbose="yes">
|
||||
<default caps="128"/>
|
||||
<parent-provides>
|
||||
<service name="CPU"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="LOG"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="ROM"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>}
|
||||
|
||||
append_if [have_spec sdl] config {
|
||||
<start name="fb_sdl">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides>
|
||||
<service name="Input"/>
|
||||
<service name="Framebuffer"/>
|
||||
</provides>
|
||||
<config width="640" height="480"/>
|
||||
</start>
|
||||
<alias name="input_drv" child="fb_sdl"/>
|
||||
<alias name="fb_drv" child="fb_sdl"/>}
|
||||
|
||||
append_platform_drv_config
|
||||
|
||||
append_if [have_spec vesa] config {
|
||||
<start name="fb_drv">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="Framebuffer"/></provides>
|
||||
<config buffered="yes"> </config>
|
||||
<config width="300" height="200"/>
|
||||
</start>}
|
||||
|
||||
append_if [have_spec pl11x] config {
|
||||
<start name="fb_drv">
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<provides><service name="Framebuffer"/></provides>
|
||||
</start>}
|
||||
|
||||
append_if [have_spec ps2] config {
|
||||
<start name="ps2_drv">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Input"/></provides>
|
||||
</start>
|
||||
<alias name="input_drv" child="ps2_drv"/>}
|
||||
|
||||
append config {
|
||||
<start name="audio_drv">
|
||||
<binary name="} [audio_drv_binary] {"/>
|
||||
<resource name="RAM" quantum="8M"/>
|
||||
<provides><service name="Audio_out"/></provides>
|
||||
</start>
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
<start name="fb_upscale">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides> <service name="Framebuffer"/> </provides>
|
||||
<route>
|
||||
<service name="Framebuffer">
|
||||
<child name="fb_drv"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="report_rom">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides> <service name="Report"/> </provides>
|
||||
<config verbose="yes"/>
|
||||
</start>
|
||||
<start name="retro_frontend">
|
||||
<resource name="RAM" quantum="64M"/>
|
||||
<config core="snes9x_libretro.lib.so">
|
||||
<game rom="superbossgaiden.sfc"/>
|
||||
<libc stdout="/log" stderr="/log"/>
|
||||
<vfs> <log/> </vfs>
|
||||
<controller port="0" device="1">
|
||||
<map from="KEY_LEFT" to="LEFT"/>
|
||||
<map from="KEY_RIGHT" to="RIGHT"/>
|
||||
<map from="KEY_UP" to="UP"/>
|
||||
<map from="KEY_DOWN" to="DOWN"/>
|
||||
|
||||
<map from="KEY_A" to="L"/>
|
||||
<map from="KEY_S" to="R"/>
|
||||
<map from="KEY_Z" to="B"/>
|
||||
<map from="KEY_X" to="A"/>
|
||||
|
||||
<map from="KEY_ENTER" to="START"/>
|
||||
<map from="KEY_RIGHTSHIFT" to="SELECT"/>
|
||||
</controller>
|
||||
</config>
|
||||
<route>
|
||||
<service name="Framebuffer">
|
||||
<child name="fb_upscale"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
</config>}
|
||||
|
||||
install_config $config
|
||||
|
||||
#
|
||||
# Download and extract a test ROM
|
||||
#
|
||||
if {![file exist "bin/superbossgaiden.sfc"]} {
|
||||
if {![file exist bin/superbossgaiden.zip]} {
|
||||
puts "Downloading Super Boss Gaiden (J).zip..."
|
||||
set zip_url "https://superbossgaiden.superfamicom.org/Super%20Boss%20Gaiden%20(J).zip"
|
||||
catch { exec $wget $zip_url -O bin/superbossgaiden.zip }
|
||||
}
|
||||
|
||||
puts "Extracting superbossgaiden.sfc..."
|
||||
exec mkdir bin/tmp
|
||||
exec $unzip -o bin/superbossgaiden.zip -d bin/tmp
|
||||
exec mv "bin/tmp/ROM-Version/Super Boss Gaiden (J) (V1.0).sfc" "bin/superbossgaiden.sfc"
|
||||
exec rm -rf bin/tmp
|
||||
}
|
||||
|
||||
# generic modules
|
||||
append boot_modules {
|
||||
superbossgaiden.sfc
|
||||
} [audio_drv_binary] {
|
||||
}
|
||||
|
||||
# platform-specific modules
|
||||
lappend_if [have_spec linux] boot_modules fb_sdl
|
||||
lappend_if [have_spec vesa] boot_modules fb_drv
|
||||
lappend_if [have_spec ps2] boot_modules ps2_drv
|
||||
lappend_if [have_spec pl11x] boot_modules fb_drv
|
||||
|
||||
append_platform_drv_boot_modules
|
||||
|
||||
build_boot_image $boot_modules
|
||||
|
||||
append qemu_args " -soundhw es1370 "
|
||||
|
||||
run_genode_until forever
|
||||
136
run/tyrquake.run
136
run/tyrquake.run
@@ -1,136 +0,0 @@
|
||||
# setting environment variable FORCE_QEMU permits running netperf in qemu
|
||||
set force_qemu [info exists ::env(FORCE_QEMU)]
|
||||
|
||||
if {[expr [have_include "power_on/qemu"] && !$force_qemu]} {
|
||||
puts "\Game emulation inside Qemu is not recommended.\n"
|
||||
exit
|
||||
}
|
||||
|
||||
#
|
||||
# Check used commands
|
||||
#
|
||||
set wget [check_installed wget]
|
||||
set unzip [check_installed unzip]
|
||||
|
||||
create_boot_directory
|
||||
|
||||
import_from_depot \
|
||||
genodelabs/src/[base_src] \
|
||||
genodelabs/pkg/[drivers_interactive_pkg] \
|
||||
genodelabs/pkg/tyrquake_libretro \
|
||||
genodelabs/src/fb_upscale \
|
||||
genodelabs/src/init \
|
||||
genodelabs/src/report_rom \
|
||||
genodelabs/src/retro_frontend \
|
||||
|
||||
#
|
||||
# Generate config
|
||||
#
|
||||
|
||||
append config {
|
||||
<config verbose="yes">
|
||||
<default caps="128"/>
|
||||
<parent-provides>
|
||||
<service name="CPU"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="LOG"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="ROM"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>
|
||||
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
|
||||
<start name="drivers" caps="1000">
|
||||
<resource name="RAM" quantum="32M"/>
|
||||
<binary name="init"/>
|
||||
<route>
|
||||
<service name="ROM" label="config"> <parent label="drivers.config"/> </service>
|
||||
<service name="Timer"> <child name="timer"/> </service>
|
||||
<any-service> <parent/> </any-service>
|
||||
</route>
|
||||
<provides>
|
||||
<service name="Input"/>
|
||||
<service name="Framebuffer"/>
|
||||
</provides>
|
||||
</start>
|
||||
|
||||
<start name="fb_upscale">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides> <service name="Framebuffer"/> </provides>
|
||||
<route>
|
||||
<service name="Framebuffer">
|
||||
<child name="drivers"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="report_rom">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides> <service name="Report"/> </provides>
|
||||
<config verbose="yes"/>
|
||||
</start>
|
||||
<start name="retro_frontend">
|
||||
<resource name="RAM" quantum="64M"/>
|
||||
<config core="tyrquake_libretro.lib.so">
|
||||
<libc stdout="/dev/log" stderr="/dev/log"/>
|
||||
<vfs>
|
||||
<tar name="quake.tar"/>
|
||||
<dir name="dev"> <log/> </dir>
|
||||
<dir name="id1"> <tar name="quake.tar"/> </dir>
|
||||
<ram/>
|
||||
</vfs>
|
||||
<variables>
|
||||
<variable key="tyrquake_colored_lighting" value="disabled"/>
|
||||
<variable key="tyrquake_resolution" value="640x400"/>
|
||||
</variables>
|
||||
<controller port="0" device="3"/>
|
||||
</config>
|
||||
<route>
|
||||
<service name="Framebuffer">
|
||||
<child name="fb_upscale"/> </service>
|
||||
<service name="Input">
|
||||
<child name="drivers"/> </service>
|
||||
<service name="Report">
|
||||
<child name="report_rom"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
</config>}
|
||||
|
||||
install_config $config
|
||||
|
||||
#
|
||||
# Download and extract shareware Quake
|
||||
#
|
||||
if {![file exist "bin/quake.tar"]} {
|
||||
if {![file exist bin/quake_sw.zip]} {
|
||||
puts "Downloading shareware Quake..."
|
||||
set zip_url "https://archive.org/download/quakeshareware/QUAKE_SW.zip"
|
||||
catch { exec $wget $zip_url -O bin/quake_sw.zip }
|
||||
}
|
||||
|
||||
puts "Extracting Quake data..."
|
||||
exec mkdir -p bin/tmp/quake
|
||||
exec $unzip -o bin/quake_sw.zip -d bin/tmp
|
||||
exec mv "bin/tmp/QUAKE_SW/ID1/CONFIG.CFG" "bin/tmp/quake/config.cfg"
|
||||
exec mv "bin/tmp/QUAKE_SW/ID1/PAK0.PAK" "bin/tmp/quake/pak0.pak"
|
||||
exec tar cf bin/quake.tar -C bin/tmp/quake .
|
||||
exec rm -rf bin/tmp
|
||||
}
|
||||
|
||||
# generic modules
|
||||
build_boot_image {
|
||||
quake.tar
|
||||
}
|
||||
|
||||
append qemu_args " -soundhw es1370 "
|
||||
|
||||
run_genode_until forever
|
||||
@@ -1,222 +0,0 @@
|
||||
The `retro_frontend` component is a runtime for Libretro.
|
||||
It is the Genode analogue to the `Retroarch` reference frontend.
|
||||
|
||||
A Libretro core is a game or other application that implements the Libretro API,
|
||||
and in this case, is linked as a dynamic library. The runtime frontend loads a
|
||||
core and installs callbacks that allow the core to draw to a framebuffer, poll
|
||||
input, play audio, and reconfigure itself. The core executes not by its own main
|
||||
loop but is driven by the fronted to match a framerate recommended by the core.
|
||||
This architecture allows for game engines and emulators to further abstract
|
||||
their operating system interactions and hopefully improve their long-term binary
|
||||
compatibility.
|
||||
|
||||
|
||||
Shortcomings
|
||||
############
|
||||
|
||||
To begin with, most features present in Retroarch are not found in this
|
||||
frontend. Some are appropriate to internalize and others are best
|
||||
implemented as additional components.
|
||||
|
||||
To list a few :
|
||||
- Analog input axes
|
||||
- Mouse input axes
|
||||
- Hardware accelerated rendering
|
||||
- Pixel format conversion
|
||||
- Shaders and pixel upscalers
|
||||
- Time acceleration and dilation
|
||||
- State rewinding
|
||||
- Remote input over IP
|
||||
- High-quality audio resampling
|
||||
- User interface for frontend management
|
||||
|
||||
Patches are welcome!
|
||||
|
||||
|
||||
Required environment
|
||||
####################
|
||||
|
||||
'retro_frontend' requires at minimum 'Framebuffer' and 'Timer' services.
|
||||
'Input' and 'Audio_out' are optional. For use with 'Nitpicker' the 'nit_fb'
|
||||
component will provide 'Framebuffer' and 'Input'. The frontend uses
|
||||
core-specific framebuffer dimensions so use of the 'fb_upscale' component
|
||||
is recommended to zoom framebuffer dimensions to a match. Multiple 'Input'
|
||||
sessions are requested when the frontend is configured with multiple
|
||||
controllers.
|
||||
|
||||
|
||||
Configuration
|
||||
#############
|
||||
|
||||
The most important configuration option is the core, this is an attribute on
|
||||
the top-level configuration XML node. The filename specified here is loaded
|
||||
via a ROM session as a dynamic library.
|
||||
! <config core="core_libretro.lib.so">
|
||||
! ...
|
||||
! </config>
|
||||
|
||||
The second most import option is game data. A `game` node within the configuration
|
||||
specifies game to be loaded by a ROM image or by path. A third 'meta' option is
|
||||
present, its meaning is core-specific and is seldom used. When no 'game' node is
|
||||
present a game path of "/" is assumed.
|
||||
|
||||
Load by ROM:
|
||||
! <config ...>
|
||||
! <game rom="cartridge.bin"/>
|
||||
! ...
|
||||
! </config>
|
||||
|
||||
Load by path:
|
||||
! <config ...>
|
||||
! <game path="/assets"/>
|
||||
! ...
|
||||
! </config>
|
||||
|
||||
|
||||
Input
|
||||
=====
|
||||
|
||||
The frontend supports multiple controllers and maps input codes from Genode to
|
||||
Libretro. Controllers are specified by 'controller' nodes within the configuration.
|
||||
|
||||
For each controller it is recommended to specify a device type. The frontend and
|
||||
core will assume by default that the controller is a joypad and will likely only
|
||||
poll for joypad input. Defining a device type at the frontend does not restrict
|
||||
or mask controller input from other types, but determines which inputs the core
|
||||
will poll and how inputs are interpreted. There are several basic device types
|
||||
and cores may define special device types by subclassing from a basic type. A
|
||||
ore will publish its device types and descriptions through the frontend via the
|
||||
'controllers' report described later in this document. Cores may additionally
|
||||
publish textual descriptions of each button on each port via an 'input' report.
|
||||
|
||||
Base supported device types:
|
||||
1 | Joypad
|
||||
2 | Mouse (axes not supported)
|
||||
3 | Keyboard
|
||||
|
||||
Mapping input to a Libretro keyboard on port 0, a joypad with remapping to port 1,
|
||||
and a joypad derived device on port 2:
|
||||
! <config ...>
|
||||
! <controller port="0" device="3"/>
|
||||
! <controller port="1" device="1">
|
||||
! <map from="BTN_TR" to="R2"/>
|
||||
! <map from="BTN_TR2" to="R"/>
|
||||
! <map from="BTN_TL" to="L2"/>
|
||||
! <map from="BTN_TL2" to="L"/>
|
||||
! </controller>
|
||||
! <controller port="2" device="257"/>
|
||||
! </config>
|
||||
|
||||
Port 1 in the example above port show four key remappings. In this example
|
||||
the four trigger or bumper buttons on a gamepad are vertically reversed.
|
||||
The 'from' attribute on a 'map' node indicates a Genode input code and the
|
||||
'to' attribute indicates a Libretro input code. Genode input codes may be
|
||||
determined externally using the 'test-input' component and Libretro input
|
||||
codes may be found in 'input' report described later. Mappings may only
|
||||
be made within the base device. Mapping keyboards to joypads is supported
|
||||
but remapping keyboard keys is not. The 'input_merger' component may be
|
||||
used to externally remap the Libretro keyboard type.
|
||||
|
||||
|
||||
Variables
|
||||
=========
|
||||
|
||||
Cores usually request their own configuration options from the frontend
|
||||
and these are in turn resolved from the XML configuration provided to
|
||||
the frontend. These options are published by the core via the frontend
|
||||
'variables' report described later. A 'variable' node within the
|
||||
configuration binds a configuration value to a configuration key.
|
||||
|
||||
! <config ... >
|
||||
! <variable key="region" value="PAL"/>
|
||||
! ...
|
||||
! </config>
|
||||
|
||||
|
||||
C runtime
|
||||
=========
|
||||
|
||||
The frontend provides a POSIX environment for cores like any other
|
||||
component linked to the Genode C runtime. In this regard the frontend
|
||||
should be configured with a VFS and connections for standard I/O.
|
||||
|
||||
! <config core="...">
|
||||
! <vfs>
|
||||
! <tar name="..."/>
|
||||
! <dir name="dev"> <log/> </dir>
|
||||
! </vfs>
|
||||
! <libc stdout="/dev/log" stderr="/dev/log"/>
|
||||
! </config>
|
||||
|
||||
|
||||
Reports
|
||||
#######
|
||||
|
||||
The frontend published information from the core in the form of 'Report'
|
||||
sessions. The reports are 'variables' 'controllers', and 'inputs'.
|
||||
|
||||
|
||||
Variables
|
||||
=========
|
||||
|
||||
The variables report contains pairs of keys and possible values. These inform
|
||||
what variables should be included in the configuration passed to the frontend.
|
||||
Valid options for a given variable are seperated by the '|' character.
|
||||
|
||||
! <variables>
|
||||
! <variable key="nospritelimit" value="No Sprite Limit; disabled|enabled"/>
|
||||
! <variable key="overscan_v" value="Crop Overscan (Vertical); enabled|disabled"/>
|
||||
! <variable key="region" value="Region Override; Auto|NTSC|PAL|Dendy"/>
|
||||
! </variables>
|
||||
|
||||
|
||||
Controllers
|
||||
===========
|
||||
|
||||
The controllers report conveys which device types a core recognizes or expects
|
||||
and informs how inputs to the frontend should be configured.
|
||||
|
||||
! <controllers>
|
||||
! <controller port="0">
|
||||
! <type desc="Gamepad" id="1"/>
|
||||
! <type desc="Keyboard/Mouse" id="3"/>
|
||||
! <type desc="Zapper" id="258"/>
|
||||
! </controller>
|
||||
! </controllers>
|
||||
|
||||
|
||||
Inputs
|
||||
======
|
||||
|
||||
The input report describes the function of different inputs over different
|
||||
controller ports. The value of an 'id' attribute on a descriptor node may
|
||||
be used to map from a Genode input to a Libretro input as described
|
||||
previously.
|
||||
|
||||
! <inputs>
|
||||
! <descriptor port="0" device="JOYPAD" index="0" id="LEFT" description="D-Pad Left"/>
|
||||
! <descriptor port="0" device="JOYPAD" index="0" id="UP" description="D-Pad Up"/>
|
||||
! <.../>
|
||||
! <descriptor port="0" device="JOYPAD" index="0" id="SELECT" description="Toggle console"/>
|
||||
! <descriptor port="0" device="JOYPAD" index="0" id="START" description="Menu"/>
|
||||
! </inputs>
|
||||
|
||||
|
||||
Runtime
|
||||
#######
|
||||
|
||||
Pausing
|
||||
========
|
||||
|
||||
The frontend recognizes the *Pause* key found on standard keyboards and
|
||||
acts accordingly. When the frontend pauses the core is halted and
|
||||
save RAM is dumped to file for games that are loaded from ROM. When a
|
||||
game warns "do not turn of the power" it is recommended to tap pause
|
||||
twice after the warning to dump the RAM. When unpausing the frontend
|
||||
will load back save RAM and resynchronize the framebuffer and audio-out
|
||||
buffer, so giving *Pause* a double tap can also fix laggy audio.
|
||||
|
||||
Please note that the *Pause* key is usually only found on keyboards.
|
||||
When connected directly to gamepad input drivers an additional
|
||||
controller port would need to be defined and routed to an 'Input'
|
||||
session where a keyboard is present to enable pause support.
|
||||
@@ -1,253 +0,0 @@
|
||||
/*
|
||||
* \brief Retro_frontend audio
|
||||
* \author Emery Hemingway
|
||||
* \date 2016-12-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _RETRO_FRONTEND__AUDIO_H_
|
||||
#define _RETRO_FRONTEND__AUDIO_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <audio_out_session/connection.h>
|
||||
#include <base/attached_ram_dataspace.h>
|
||||
#include <base/thread.h>
|
||||
#include <util/reconstructible.h>
|
||||
|
||||
#include "core.h"
|
||||
|
||||
namespace Retro_frontend {
|
||||
|
||||
template <typename TYPE, Genode::size_t CAPACITY>
|
||||
struct Ring_buffer;
|
||||
struct Stereo_out;
|
||||
|
||||
enum { LEFT, RIGHT, NUM_CHANNELS };
|
||||
|
||||
enum {
|
||||
SHIFT = 16,
|
||||
SHIFT_ONE = 1 << SHIFT
|
||||
};
|
||||
|
||||
unsigned audio_shift_factor = SHIFT_ONE;
|
||||
static unsigned audio_input_period = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ring buffer using virtual addressing and Buffer Overflow™ technology
|
||||
*/
|
||||
template <typename TYPE, Genode::size_t CAPACITY>
|
||||
struct Retro_frontend::Ring_buffer : Genode::Lock
|
||||
{
|
||||
enum { BUFFER_SIZE = sizeof(TYPE)*CAPACITY };
|
||||
|
||||
Genode::addr_t map_first;
|
||||
Genode::addr_t map_second;
|
||||
|
||||
TYPE *buffer;
|
||||
|
||||
Genode::size_t wpos = 0;
|
||||
Genode::size_t rpos = 0;
|
||||
|
||||
Genode::Ram_dataspace_capability buffer_ds = genv->ram().alloc(BUFFER_SIZE);
|
||||
|
||||
Ring_buffer()
|
||||
{
|
||||
{
|
||||
/* a hack to find the right sized void in the address space */
|
||||
Genode::Attached_ram_dataspace filler(genv->ram(), genv->rm(), BUFFER_SIZE*2);
|
||||
map_first = (Genode::addr_t)filler.local_addr<TYPE>();
|
||||
}
|
||||
|
||||
map_second = map_first+BUFFER_SIZE;
|
||||
|
||||
/* attach the buffer in two consecutive regions */
|
||||
map_first = genv->rm().attach_at(buffer_ds, map_first, BUFFER_SIZE);
|
||||
map_second = genv->rm().attach_at(buffer_ds, map_second, BUFFER_SIZE);
|
||||
if ((map_first+BUFFER_SIZE) != map_second) {
|
||||
Genode::error("failed to map ring buffer to consecutive regions");
|
||||
throw Genode::Exception();
|
||||
}
|
||||
|
||||
buffer = (TYPE *)map_first;
|
||||
}
|
||||
|
||||
~Ring_buffer()
|
||||
{
|
||||
genv->rm().detach(map_second);
|
||||
genv->rm().detach(map_first);
|
||||
genv->ram().free(buffer_ds);
|
||||
}
|
||||
|
||||
Genode::size_t read_avail() const
|
||||
{
|
||||
if (wpos > rpos) return wpos - rpos;
|
||||
else return (wpos - rpos + CAPACITY) % CAPACITY;
|
||||
}
|
||||
|
||||
Genode::size_t write_avail() const
|
||||
{
|
||||
if (wpos > rpos) return ((rpos - wpos + CAPACITY) % CAPACITY) - 2;
|
||||
else if (wpos < rpos) return rpos - wpos;
|
||||
else return CAPACITY - 2;
|
||||
}
|
||||
|
||||
Genode::size_t write(TYPE const *src, Genode::size_t len)
|
||||
{
|
||||
using Genode::size_t;
|
||||
|
||||
len = Genode::min(len, write_avail());
|
||||
|
||||
TYPE *wbuf = &buffer[wpos];
|
||||
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
wbuf[i] = src[i];
|
||||
|
||||
wpos = (wpos + len) % CAPACITY;
|
||||
return len;
|
||||
}
|
||||
|
||||
void drain_period(float *periodl, float *periodr)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
size_t const avail = read_avail();
|
||||
|
||||
if (avail < audio_input_period*2) {
|
||||
Genode::memset(periodl, 0x00, sizeof(float)*Audio_out::PERIOD);
|
||||
Genode::memset(periodr, 0x00, sizeof(float)*Audio_out::PERIOD);
|
||||
return;
|
||||
}
|
||||
|
||||
int16_t *rbuf = &buffer[rpos];
|
||||
|
||||
size_t buf_off;
|
||||
for (size_t pkt_off = 0; pkt_off < Audio_out::PERIOD; ++pkt_off)
|
||||
{
|
||||
buf_off = 2*((pkt_off*audio_shift_factor)>>SHIFT);
|
||||
periodl[pkt_off] = rbuf[buf_off+0] / 32768.0f;
|
||||
periodr[pkt_off] = rbuf[buf_off+1] / 32768.0f;
|
||||
}
|
||||
|
||||
rpos = (rpos+audio_input_period*2) % CAPACITY;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Thread for converting samples at the core sample rate
|
||||
* to the native sample rate
|
||||
*/
|
||||
struct Retro_frontend::Stereo_out : Genode::Thread
|
||||
{
|
||||
Audio_out::Connection left;
|
||||
Audio_out::Connection right;
|
||||
|
||||
Ring_buffer<int16_t, 4096> buffer;
|
||||
|
||||
Genode::Lock run_lock { Genode::Lock::LOCKED };
|
||||
|
||||
bool running = false;
|
||||
|
||||
void entry() override;
|
||||
|
||||
Stereo_out()
|
||||
:
|
||||
Genode::Thread(*genv, "audio-sync", 8*1024,
|
||||
genv->cpu().affinity_space().location_of_index(1),
|
||||
Weight(Genode::Cpu_session::Weight::DEFAULT_WEIGHT-1),
|
||||
genv->cpu()),
|
||||
left( *genv, "left", false, true),
|
||||
right(*genv, "right", false, true)
|
||||
{
|
||||
start();
|
||||
}
|
||||
|
||||
void start_stream()
|
||||
{
|
||||
running = true;
|
||||
run_lock.unlock();
|
||||
}
|
||||
|
||||
void stop_stream()
|
||||
{
|
||||
running = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static Genode::Constructible<Retro_frontend::Stereo_out> stereo_out;
|
||||
|
||||
|
||||
void audio_sample_noop(int16_t left, int16_t right) { }
|
||||
|
||||
|
||||
/* not called in pratice */
|
||||
void audio_sample_callback(int16_t left, int16_t right)
|
||||
{
|
||||
stereo_out->buffer.lock();
|
||||
stereo_out->buffer.write(&left, 1);
|
||||
stereo_out->buffer.write(&right, 1);
|
||||
stereo_out->buffer.unlock();
|
||||
}
|
||||
|
||||
|
||||
size_t audio_sample_batch_noop(const int16_t *data, size_t frames) { return 0; }
|
||||
|
||||
|
||||
size_t audio_sample_batch_callback(const int16_t *data, size_t frames)
|
||||
{
|
||||
Genode::Lock::Guard guard(stereo_out->buffer);
|
||||
return stereo_out->buffer.write(data, frames*2)/2;
|
||||
}
|
||||
|
||||
|
||||
void Retro_frontend::Stereo_out::entry()
|
||||
{
|
||||
Audio_out::Packet *p[NUM_CHANNELS];
|
||||
|
||||
for (;;) {
|
||||
run_lock.lock();
|
||||
|
||||
p[LEFT] = left.stream()->next();
|
||||
|
||||
/* stuff the buffer a bit */
|
||||
for (auto i = 0; i < 4; ++i)
|
||||
p[LEFT] = left.stream()->next(p[LEFT]);
|
||||
|
||||
left.start();
|
||||
right.start();
|
||||
|
||||
while (running) {
|
||||
unsigned const ppos = left.stream()->packet_position(p[LEFT]);
|
||||
p[RIGHT] = right.stream()->get(ppos);
|
||||
|
||||
buffer.lock();
|
||||
buffer.drain_period(p[LEFT]->content(), p[RIGHT]->content());
|
||||
buffer.unlock();
|
||||
|
||||
left.submit(p[LEFT]);
|
||||
right.submit(p[RIGHT]);
|
||||
|
||||
p[LEFT] = left.stream()->next(p[LEFT]);
|
||||
|
||||
left.wait_for_progress();
|
||||
}
|
||||
|
||||
/* empty the buffer to resync when started again */
|
||||
while (!p[LEFT]->played())
|
||||
left.wait_for_progress();
|
||||
|
||||
left.stop();
|
||||
right.stop();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* \brief Libretro frontend
|
||||
* \author Emery Hemingway
|
||||
* \date 2016-07-03
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <libc/component.h>
|
||||
|
||||
/* Local includes */
|
||||
#include "config.h"
|
||||
#include "environment.h"
|
||||
#include "dispatcher.h"
|
||||
|
||||
namespace Retro_frontend {
|
||||
|
||||
static Dispatcher *dispatcher;
|
||||
|
||||
void toggle_pause() {
|
||||
dispatcher->toggle_pause(); }
|
||||
|
||||
void shutdown()
|
||||
{
|
||||
dispatcher->deinit();
|
||||
genv->parent().exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* each core will drive the stack differently, so be generous */
|
||||
Genode::size_t Component::stack_size() { return 64*1024*sizeof(Genode::addr_t); }
|
||||
|
||||
void Libc::Component::construct(Libc::Env &env)
|
||||
{
|
||||
using namespace Retro_frontend;
|
||||
|
||||
genv = &env;
|
||||
|
||||
config_rom.construct(env, "config");
|
||||
|
||||
static Dispatcher inst;
|
||||
dispatcher = &inst;
|
||||
|
||||
/* load and initialize core, configure signal handlers */
|
||||
dispatcher->handle_config();
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* \brief Libretro configuration
|
||||
* \author Emery Hemingway
|
||||
* \date 2017-11-03
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _RETRO_FRONTEND__CONFIG_H_
|
||||
#define _RETRO_FRONTEND__CONFIG_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
|
||||
namespace Retro_frontend {
|
||||
|
||||
static unsigned config_version = 0;
|
||||
|
||||
static Genode::Constructible<Genode::Attached_rom_dataspace> config_rom;
|
||||
|
||||
Genode::Xml_node config_variables()
|
||||
{
|
||||
try {
|
||||
return config_rom->xml().sub_node("variables");
|
||||
} catch (...) {
|
||||
return Genode::Xml_node("<variables/>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,174 +0,0 @@
|
||||
/*
|
||||
* \brief Libretro frontend
|
||||
* \author Emery Hemingway
|
||||
* \date 2017-11-04
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _RETRO_FRONTEND__CORE_H_
|
||||
#define _RETRO_FRONTEND__CORE_H_
|
||||
|
||||
#include <base/debug.h>
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/shared_object.h>
|
||||
#include <base/component.h>
|
||||
#include <base/log.h>
|
||||
|
||||
#include <libretro.h>
|
||||
|
||||
namespace Retro_frontend {
|
||||
|
||||
static Genode::Env *genv;
|
||||
|
||||
typedef void (*Retro_set_environment)(retro_environment_t);
|
||||
typedef void (*Retro_set_video_refresh)(retro_video_refresh_t);
|
||||
typedef void (*Retro_set_audio_sample)(retro_audio_sample_t);
|
||||
typedef void (*Retro_set_audio_sample_batch)(retro_audio_sample_batch_t);
|
||||
typedef void (*Retro_set_input_poll)(retro_input_poll_t);
|
||||
typedef void (*Retro_set_input_state)(retro_input_state_t);
|
||||
typedef void (*Retro_init)(void);
|
||||
typedef void (*Retro_deinit)(void);
|
||||
typedef unsigned (*Retro_api_version)(void);
|
||||
typedef void (*Retro_get_system_info)(struct retro_system_info *info);
|
||||
typedef void (*Retro_get_system_av_info)(struct retro_system_av_info *info);
|
||||
typedef void (*Retro_set_controller_port_device)(unsigned port, unsigned device);
|
||||
typedef void (*Retro_reset)(void);
|
||||
typedef void (*Retro_run)(void);
|
||||
typedef size_t (*Retro_serialize_size)(void);
|
||||
typedef bool (*Retro_serialize)(void *data, size_t size);
|
||||
typedef bool (*Retro_unserialize)(const void *data, size_t size);
|
||||
typedef void (*Retro_cheat_reset)(void);
|
||||
typedef void (*Retro_cheat_set)(unsigned index, bool enabled, const char *code);
|
||||
typedef bool (*Retro_load_game)(const struct retro_game_info *game);
|
||||
typedef bool (*Retro_load_game_special)(
|
||||
unsigned game_type,
|
||||
const struct retro_game_info *info, size_t num_info
|
||||
);
|
||||
typedef void (*Retro_unload_game)(void);
|
||||
typedef unsigned (*Retro_get_region)(void);
|
||||
typedef void *(*Retro_get_memory_data)(unsigned id);
|
||||
typedef size_t (*Retro_get_memory_size)(unsigned id);
|
||||
|
||||
Retro_init retro_init;
|
||||
Retro_deinit retro_deinit;
|
||||
Retro_load_game retro_load_game;
|
||||
Retro_unload_game retro_unload_game;
|
||||
|
||||
Retro_get_system_av_info retro_get_system_av_info;
|
||||
|
||||
Retro_get_memory_data retro_get_memory_data;
|
||||
Retro_get_memory_size retro_get_memory_size;
|
||||
|
||||
Retro_set_controller_port_device retro_set_controller_port_device;
|
||||
|
||||
Retro_get_system_info retro_get_system_info;
|
||||
|
||||
Retro_set_environment retro_set_environment;
|
||||
|
||||
Retro_set_video_refresh retro_set_video_refresh;
|
||||
|
||||
Retro_set_audio_sample retro_set_audio_sample;
|
||||
Retro_set_audio_sample_batch retro_set_audio_sample_batch;
|
||||
|
||||
Retro_set_input_poll retro_set_input_poll;
|
||||
Retro_set_input_state retro_set_input_state;
|
||||
|
||||
Retro_run retro_run;
|
||||
|
||||
struct Core;
|
||||
};
|
||||
|
||||
|
||||
/*************************
|
||||
** callback prototypes **
|
||||
*************************/
|
||||
|
||||
bool environment_callback(unsigned cmd, void *data);
|
||||
|
||||
void input_poll_callback();
|
||||
|
||||
int16_t input_state_callback(unsigned port, unsigned device,
|
||||
unsigned index, unsigned id);
|
||||
|
||||
void video_refresh_callback(const void *data,
|
||||
unsigned src_width, unsigned src_height,
|
||||
size_t src_pitch);
|
||||
|
||||
void audio_sample_noop(int16_t left, int16_t right);
|
||||
void audio_sample_callback(int16_t left, int16_t right);
|
||||
size_t audio_sample_batch_noop(const int16_t *data, size_t frames);
|
||||
size_t audio_sample_batch_callback(const int16_t *data, size_t frames);
|
||||
|
||||
void log_printf_callback(retro_log_level level, const char *fmt, ...);
|
||||
|
||||
|
||||
struct Retro_frontend::Core
|
||||
{
|
||||
typedef Genode::String<128> Name;
|
||||
|
||||
Genode::Shared_object so;
|
||||
|
||||
Name const name;
|
||||
|
||||
Core(Genode::Allocator &alloc, Name const &name)
|
||||
: so(*genv, alloc, name.string(),
|
||||
Genode::Shared_object::BIND_LAZY,
|
||||
Genode::Shared_object::DONT_KEEP),
|
||||
name(name)
|
||||
{
|
||||
unsigned api_version = so.lookup<Retro_api_version>("retro_api_version")();
|
||||
if (api_version != RETRO_API_VERSION) {
|
||||
Genode::error("core ", name,
|
||||
" uses unsupported API version ", api_version);
|
||||
throw Genode::Shared_object::Invalid_rom_module();
|
||||
}
|
||||
|
||||
retro_init = so.lookup<Retro_init>("retro_init");
|
||||
retro_deinit = so.lookup<Retro_deinit>("retro_deinit");
|
||||
|
||||
retro_load_game = so.lookup<Retro_load_game>("retro_load_game");
|
||||
retro_unload_game = so.lookup<Retro_unload_game>("retro_unload_game");
|
||||
|
||||
retro_get_system_av_info = so.lookup<Retro_get_system_av_info>("retro_get_system_av_info");
|
||||
|
||||
retro_get_memory_data = so.lookup<Retro_get_memory_data>("retro_get_memory_data");
|
||||
retro_get_memory_size = so.lookup<Retro_get_memory_size>("retro_get_memory_size");
|
||||
|
||||
retro_set_controller_port_device = so.lookup<Retro_set_controller_port_device>("retro_set_controller_port_device");
|
||||
retro_run = so.lookup<Retro_run>("retro_run");
|
||||
|
||||
retro_get_system_info = so.lookup<Retro_get_system_info>
|
||||
("retro_get_system_info");
|
||||
|
||||
retro_set_environment = so.lookup<Retro_set_environment>
|
||||
("retro_set_environment");
|
||||
|
||||
retro_init = so.lookup<Retro_init>("retro_init");
|
||||
|
||||
retro_set_video_refresh = so.lookup<Retro_set_video_refresh>("retro_set_video_refresh");
|
||||
|
||||
retro_set_audio_sample = so.lookup<Retro_set_audio_sample>("retro_set_audio_sample");
|
||||
retro_set_audio_sample_batch = so.lookup<Retro_set_audio_sample_batch>("retro_set_audio_sample_batch");
|
||||
|
||||
retro_set_input_poll = so.lookup<Retro_set_input_poll>("retro_set_input_poll");
|
||||
|
||||
retro_set_input_state = so.lookup<Retro_set_input_state>("retro_set_input_state");
|
||||
}
|
||||
};
|
||||
|
||||
namespace Retro_frontend {
|
||||
|
||||
static Genode::Constructible<Core> core;
|
||||
|
||||
void toggle_pause();
|
||||
void shutdown();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,419 +0,0 @@
|
||||
/*
|
||||
* \brief Libretro signal dispatcher
|
||||
* \author Emery Hemingway
|
||||
* \date 2017-11-03
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _RETRO_FRONTEND__DISPATCHER_H_
|
||||
#define _RETRO_FRONTEND__DISPATCHER_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <timer_session/connection.h>
|
||||
#include <base/heap.h>
|
||||
#include <libc/component.h>
|
||||
|
||||
/* Local includes */
|
||||
#include "audio.h"
|
||||
#include "config.h"
|
||||
#include "input.h"
|
||||
#include "framebuffer.h"
|
||||
#include "memory.h"
|
||||
|
||||
namespace Retro_frontend { struct Dispatcher; }
|
||||
|
||||
|
||||
struct Retro_frontend::Dispatcher
|
||||
{
|
||||
/***************
|
||||
** Game data **
|
||||
***************/
|
||||
|
||||
struct Game_failed { };
|
||||
|
||||
retro_game_info game_info;
|
||||
|
||||
typedef Genode::String<64> Rom_name;
|
||||
typedef Genode::String<128> Game_path;
|
||||
Rom_name rom_name;
|
||||
Game_path game_path;
|
||||
Game_path game_meta;
|
||||
|
||||
/**
|
||||
* Class to contain game ROM and RAM
|
||||
*/
|
||||
struct Cartridge {
|
||||
|
||||
Genode::Attached_rom_dataspace rom;
|
||||
|
||||
typedef Genode::String<128> Filename;
|
||||
|
||||
Filename const save_filename;
|
||||
Filename const rtc_filename;
|
||||
|
||||
Memory_file save_file {
|
||||
RETRO_MEMORY_SAVE_RAM, save_filename.string() };
|
||||
Memory_file rtc_file {
|
||||
RETRO_MEMORY_RTC, rtc_filename.string() };
|
||||
|
||||
Cartridge(Rom_name const &rom_name)
|
||||
:
|
||||
rom(*genv, rom_name.string()),
|
||||
save_filename( "/", rom_name.string(), ".save"),
|
||||
rtc_filename( "/", rom_name.string(), ".rtc")
|
||||
{
|
||||
load_memory();
|
||||
}
|
||||
|
||||
~Cartridge() { save_memory(); }
|
||||
|
||||
void refresh(Memory_file &memory)
|
||||
{
|
||||
void *data = retro_get_memory_data(memory.id);
|
||||
auto size = retro_get_memory_size(memory.id);
|
||||
if (data && size) {
|
||||
memory.data = data;
|
||||
memory.size = size;
|
||||
}
|
||||
}
|
||||
|
||||
void load_memory()
|
||||
{
|
||||
Genode::log("loading RAM from ", save_filename);
|
||||
refresh(save_file);
|
||||
refresh(rtc_file);
|
||||
|
||||
save_file.read();
|
||||
rtc_file.read();
|
||||
}
|
||||
|
||||
void save_memory()
|
||||
{
|
||||
Genode::log("saving RAM to ", save_filename);
|
||||
refresh(save_file);
|
||||
save_file.write();
|
||||
|
||||
refresh(rtc_file);
|
||||
rtc_file.write();
|
||||
}
|
||||
};
|
||||
|
||||
Genode::Constructible<Cartridge> cartridge;
|
||||
|
||||
|
||||
/**
|
||||
* Run core initialization
|
||||
*/
|
||||
void init_core(Genode::Xml_node const &config)
|
||||
{
|
||||
if (framebuffer.constructed())
|
||||
framebuffer.destruct();
|
||||
|
||||
if (stereo_out.constructed())
|
||||
stereo_out.destruct();
|
||||
|
||||
retro_system_info sys_info;
|
||||
|
||||
/****************
|
||||
** Initialize **
|
||||
****************/
|
||||
{
|
||||
retro_get_system_info(&sys_info);
|
||||
|
||||
Genode::log("Name: ", sys_info.library_name,
|
||||
"\nVersion: ", sys_info.library_version,
|
||||
"\nExtensions: ", sys_info.valid_extensions ?
|
||||
sys_info.valid_extensions : "");
|
||||
|
||||
/* reset keyboard callback */
|
||||
keyboard_callback = nullptr;
|
||||
retro_set_environment(environment_callback);
|
||||
|
||||
retro_init();
|
||||
}
|
||||
|
||||
|
||||
/***********************
|
||||
** Install callbacks **
|
||||
***********************/
|
||||
{
|
||||
retro_set_video_refresh(video_refresh_callback);
|
||||
|
||||
retro_set_audio_sample(audio_sample_noop);
|
||||
retro_set_audio_sample_batch(audio_sample_batch_noop);
|
||||
|
||||
retro_set_input_poll(input_poll_callback);
|
||||
retro_set_input_state(input_state_callback);
|
||||
}
|
||||
|
||||
|
||||
/******************************
|
||||
** Load game data into core **
|
||||
******************************/
|
||||
|
||||
{
|
||||
game_info.path = "";
|
||||
game_info.data = NULL;
|
||||
game_info.size = 0;
|
||||
game_info.meta = "";
|
||||
|
||||
try {
|
||||
Genode::Xml_node game_node = config.sub_node("game");
|
||||
|
||||
rom_name = game_node.attribute_value("rom", Rom_name());
|
||||
game_path = game_node.attribute_value("path", Game_path());
|
||||
game_meta = game_node.attribute_value("meta", Rom_name());
|
||||
} catch (Genode::Xml_node::Nonexistent_sub_node) {}
|
||||
|
||||
if (rom_name != "") {
|
||||
Genode::log("loading game from ROM '", rom_name, "'");
|
||||
cartridge.construct(rom_name);
|
||||
game_info.data = cartridge->rom.local_addr<const void>();
|
||||
game_info.size = cartridge->rom.size();
|
||||
} else if (game_path != "") {
|
||||
Genode::log("loading game from path '", game_path, "'");
|
||||
game_info.path = game_path.string();
|
||||
} else {
|
||||
game_info.path = "/";
|
||||
}
|
||||
|
||||
game_info.meta = game_meta.string();
|
||||
|
||||
if (sys_info.need_fullpath && (game_info.path == NULL))
|
||||
game_info.path = "/";
|
||||
|
||||
if (!(game_info.path || game_info.data)) {
|
||||
/* some cores don't need game data */
|
||||
Genode::error("no game content loaded");
|
||||
}
|
||||
|
||||
if (!(retro_load_game(&game_info))) {
|
||||
Genode::error("failed to load game data");
|
||||
throw Game_failed();
|
||||
}
|
||||
}
|
||||
|
||||
/******************
|
||||
** Get A/V info **
|
||||
******************/
|
||||
{
|
||||
retro_system_av_info av_info;
|
||||
retro_get_system_av_info(&av_info);
|
||||
|
||||
Genode::log("game geometry: ", av_info.geometry.max_width, "x", av_info.geometry.max_height);
|
||||
|
||||
Genode::log("FPS of video content: ", av_info.timing.fps, "Hz");
|
||||
Genode::log("Sampling rate of audio: ", av_info.timing.sample_rate, "Hz");
|
||||
|
||||
framebuffer.construct(av_info.geometry);
|
||||
|
||||
if (av_info.timing.sample_rate > 0.0) try {
|
||||
stereo_out.construct();
|
||||
retro_set_audio_sample(audio_sample_callback);
|
||||
retro_set_audio_sample_batch(audio_sample_batch_callback);
|
||||
|
||||
double ratio = (double)Audio_out::SAMPLE_RATE / av_info.timing.sample_rate;
|
||||
|
||||
audio_shift_factor = SHIFT_ONE / ratio;
|
||||
audio_input_period = Audio_out::PERIOD * (1.0f / ratio);
|
||||
} catch (...) {
|
||||
Genode::error("failed to initialize Audio_out sessions");
|
||||
}
|
||||
|
||||
quarter_fps = av_info.timing.fps / 4;
|
||||
fb_sync_sample_count = 0;
|
||||
|
||||
framebuffer->session.sync_sigh(fb_sync_sampler);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************
|
||||
** Deinitialize core **
|
||||
***********************/
|
||||
|
||||
void deinit()
|
||||
{
|
||||
/* XXX: what happens to SAVE_RAM as the game is unloaded? */
|
||||
if (cartridge.constructed())
|
||||
cartridge->save_memory();
|
||||
retro_unload_game();
|
||||
if (cartridge.constructed())
|
||||
cartridge.destruct();
|
||||
retro_deinit();
|
||||
}
|
||||
|
||||
Genode::Heap heap { genv->ram(), genv->rm() };
|
||||
|
||||
|
||||
/************
|
||||
** Config **
|
||||
************/
|
||||
|
||||
Genode::Signal_handler<Dispatcher> config_handler {
|
||||
genv->ep(), *this, &Dispatcher::handle_config };
|
||||
|
||||
void handle_config()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
++config_version;
|
||||
auto const config = config_rom->xml();
|
||||
|
||||
|
||||
/***********************
|
||||
** Load and map core **
|
||||
***********************/
|
||||
{
|
||||
auto const core_name = config.attribute_value("core", Core::Name());
|
||||
|
||||
if (core.constructed() && core->name != core_name) {
|
||||
deinit();
|
||||
core.destruct();
|
||||
}
|
||||
|
||||
if (!core.constructed())
|
||||
core.construct(heap, core_name);
|
||||
|
||||
Libc::with_libc([&] () { init_core(config); });
|
||||
}
|
||||
|
||||
/* initialize controller sessions and mappings */
|
||||
initialize_controllers(heap, config);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************
|
||||
** Signal handler to advance core by one frame **
|
||||
*************************************************/
|
||||
|
||||
Timer::Connection timer { *genv };
|
||||
|
||||
/* switch to application context and advance the core */
|
||||
void run() { Libc::with_libc([&] () { retro_run(); }); }
|
||||
|
||||
Genode::Signal_handler<Dispatcher> core_runner
|
||||
{ genv->ep(), *this, &Dispatcher::run };
|
||||
|
||||
|
||||
/***********************************
|
||||
** Frame counting signal handler **
|
||||
***********************************/
|
||||
|
||||
int quarter_fps = 0;
|
||||
unsigned long sample_start;
|
||||
int fb_sync_sample_count = 0;
|
||||
|
||||
/**
|
||||
* Sample the framebuffer sync for a quarter-second
|
||||
* to determine if it matches the FPS
|
||||
*/
|
||||
void fb_sync_sample()
|
||||
{
|
||||
++fb_sync_sample_count;
|
||||
|
||||
if (fb_sync_sample_count == 1) {
|
||||
sample_start = timer.elapsed_ms();
|
||||
} else if (fb_sync_sample_count == quarter_fps) {
|
||||
fb_sync_sample_count = 0;
|
||||
|
||||
float sync_ms = (timer.elapsed_ms() - sample_start)/quarter_fps;
|
||||
float want_ms = 250.0 / quarter_fps;
|
||||
float diff = want_ms - sync_ms;
|
||||
|
||||
/* allow a generous two millisecond difference in FPS */
|
||||
if (diff > 2.0 || diff < -2.0) {
|
||||
framebuffer->session.sync_sigh(Genode::Signal_context_capability());
|
||||
Genode::warning("framebuffer sync unsuitable, "
|
||||
"using alternative timing source");
|
||||
timer.sigh(core_runner);
|
||||
timer.trigger_periodic(250000 / quarter_fps);
|
||||
} else {
|
||||
Genode::log("using framebuffer sync as timing source");
|
||||
framebuffer->session.sync_sigh(core_runner);
|
||||
}
|
||||
|
||||
/* start the audio streams */
|
||||
if (stereo_out.constructed()) {
|
||||
stereo_out->start_stream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Genode::Signal_handler<Dispatcher> fb_sync_sampler
|
||||
{ genv->ep(), *this, &Dispatcher::fb_sync_sample };
|
||||
|
||||
|
||||
/***********
|
||||
** Pause **
|
||||
***********/
|
||||
|
||||
bool paused = false;
|
||||
|
||||
void poll_controllers()
|
||||
{
|
||||
/* this callback pauses and unpauses the frontend */
|
||||
Libc::with_libc([] () { input_poll_callback(); });
|
||||
}
|
||||
|
||||
Genode::Signal_handler<Dispatcher> unpause_handler
|
||||
{ genv->ep(), *this, &Dispatcher::poll_controllers };
|
||||
|
||||
void pause()
|
||||
{
|
||||
paused = true;
|
||||
|
||||
/* save the game RAM */
|
||||
if (cartridge.constructed())
|
||||
cartridge->save_memory();
|
||||
|
||||
/* let the audio buffer drain and stop */
|
||||
if (stereo_out.constructed())
|
||||
stereo_out->stop_stream();
|
||||
|
||||
/* disable the framebuffer signals */
|
||||
framebuffer->session.sync_sigh(
|
||||
Genode::Signal_context_capability());
|
||||
|
||||
/* disable the timer signals */
|
||||
timer.sigh(Genode::Signal_context_capability());
|
||||
|
||||
/* install a handler to unpause from the controllers */
|
||||
input_sigh(unpause_handler);
|
||||
}
|
||||
|
||||
void unpause()
|
||||
{
|
||||
paused = false;
|
||||
|
||||
if (cartridge.constructed())
|
||||
cartridge->load_memory();
|
||||
|
||||
/* disable the unpause signaling */
|
||||
input_sigh(Genode::Signal_context_capability());
|
||||
|
||||
/* resync and run */
|
||||
framebuffer->session.sync_sigh(fb_sync_sampler);
|
||||
}
|
||||
|
||||
void toggle_pause()
|
||||
{
|
||||
if (paused)
|
||||
unpause();
|
||||
else
|
||||
pause();
|
||||
}
|
||||
|
||||
Dispatcher()
|
||||
{
|
||||
config_rom->sigh(config_handler);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,317 +0,0 @@
|
||||
/*
|
||||
* \brief Interface to Genode services
|
||||
* \author Emery Hemingway
|
||||
* \date 2016-07-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _RETRO_FRONTEND__ENVIRONMENT_H_
|
||||
#define _RETRO_FRONTEND__ENVIRONMENT_H_
|
||||
|
||||
/* local includes */
|
||||
#include "framebuffer.h"
|
||||
#include "input.h"
|
||||
#include "log.h"
|
||||
#include "core.h"
|
||||
|
||||
/* Genode includes */
|
||||
#include <os/reporter.h>
|
||||
#include <base/sleep.h>
|
||||
|
||||
|
||||
namespace Retro_frontend {
|
||||
static unsigned variables_version = 0;
|
||||
}
|
||||
|
||||
|
||||
bool environment_callback(unsigned cmd, void *data)
|
||||
{
|
||||
using namespace Retro_frontend;
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case RETRO_ENVIRONMENT_GET_OVERSCAN:
|
||||
Genode::warning("instructing core not to overscan");
|
||||
*((bool *)data) = false;
|
||||
return true;
|
||||
|
||||
case RETRO_ENVIRONMENT_GET_CAN_DUPE:
|
||||
{
|
||||
bool *b = (bool*)data;
|
||||
*b = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
case RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL:
|
||||
{
|
||||
const unsigned *level = (const unsigned*)data;
|
||||
Genode::warning("frontend reports a suggested performance level of \"", *level, "\"");
|
||||
return true;
|
||||
}
|
||||
|
||||
case RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY:
|
||||
case RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY:
|
||||
case RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY:
|
||||
{
|
||||
char **path = (char **)data;
|
||||
*path = (char *)"/";
|
||||
return true;
|
||||
}
|
||||
|
||||
case RETRO_ENVIRONMENT_SET_PIXEL_FORMAT:
|
||||
{
|
||||
const retro_pixel_format *format = (retro_pixel_format *)data;
|
||||
if (*format == RETRO_PIXEL_FORMAT_RGB565)
|
||||
return true;
|
||||
else {
|
||||
char const *s = "";
|
||||
switch (*format) {
|
||||
case RETRO_PIXEL_FORMAT_0RGB1555: s = "0RGB1555"; break;
|
||||
case RETRO_PIXEL_FORMAT_XRGB8888: s = "XRGB8888"; break;
|
||||
case RETRO_PIXEL_FORMAT_RGB565: s = "RGB565"; break;
|
||||
case RETRO_PIXEL_FORMAT_UNKNOWN: break;
|
||||
}
|
||||
Genode::error("core uses unsupported pixel format ", s);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
case RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS:
|
||||
{
|
||||
static Genode::Reporter input_reporter { *genv, "inputs", "inputs", 8192 };
|
||||
|
||||
try { input_reporter.enabled(true); }
|
||||
catch (...) {
|
||||
Genode::error("input descriptors not reported");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* TODO: translate device, index, and id to a string descriptor */
|
||||
|
||||
Genode::Reporter::Xml_generator gen(input_reporter, [&] () {
|
||||
for (const struct retro_input_descriptor *desc = (retro_input_descriptor*)data;
|
||||
(desc && (desc->description != NULL)); ++desc)
|
||||
{
|
||||
char const *device_str = "UNKNOWN";
|
||||
switch (desc->device) {
|
||||
case RETRO_DEVICE_JOYPAD:
|
||||
device_str = "JOYPAD"; break;
|
||||
case RETRO_DEVICE_MOUSE:
|
||||
device_str = "MOUSE"; break;
|
||||
case RETRO_DEVICE_KEYBOARD:
|
||||
device_str = "KEYBOARD"; break;
|
||||
case RETRO_DEVICE_LIGHTGUN:
|
||||
device_str = "LIGHTGUN"; break;
|
||||
case RETRO_DEVICE_ANALOG:
|
||||
device_str = "ANALOG"; break;
|
||||
case RETRO_DEVICE_POINTER:
|
||||
device_str = "POINTER"; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
gen.node("descriptor", [&] () {
|
||||
gen.attribute("port", desc->port);
|
||||
gen.attribute("device", device_str);
|
||||
gen.attribute("index", desc->index);
|
||||
gen.attribute("id", lookup_input_text(desc->device, desc->id));
|
||||
gen.attribute("description", desc->description);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case RETRO_ENVIRONMENT_SHUTDOWN:
|
||||
shutdown();
|
||||
/* can't return here, this is a callback */
|
||||
Genode::sleep_forever();
|
||||
|
||||
case RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK:
|
||||
{
|
||||
auto *out = (retro_keyboard_callback const *)data;
|
||||
keyboard_callback = out->callback;
|
||||
return true;
|
||||
}
|
||||
|
||||
case RETRO_ENVIRONMENT_GET_VARIABLE:
|
||||
{
|
||||
retro_variable *out = (retro_variable*)data;
|
||||
Genode::warning("RETRO_ENVIRONMENT_GET_VARIABLE ", out->key);
|
||||
|
||||
out->value = NULL;
|
||||
|
||||
static char var_buf[256];
|
||||
|
||||
typedef Genode::String<32> String;
|
||||
auto const f = [&] (Genode::Xml_node const &in) {
|
||||
if (in.attribute_value("key", String()) == out->key &&
|
||||
in.has_attribute("value"))
|
||||
{
|
||||
in.attribute("value").value(var_buf, sizeof(var_buf));
|
||||
out->value = var_buf;
|
||||
}
|
||||
};
|
||||
|
||||
config_variables().for_each_sub_node("variable", f);
|
||||
|
||||
variables_version = config_version;
|
||||
return out->value != NULL;
|
||||
}
|
||||
|
||||
case RETRO_ENVIRONMENT_SET_VARIABLES:
|
||||
{
|
||||
/**********************************
|
||||
** Report variables set by core **
|
||||
**********************************/
|
||||
|
||||
static Genode::Reporter variable_reporter { *genv, "variables", "variables", 8192 };
|
||||
try { variable_reporter.enabled(true); }
|
||||
catch (...) {
|
||||
Genode::error("core variables not reported");
|
||||
return false;
|
||||
}
|
||||
|
||||
Genode::Reporter::Xml_generator gen(variable_reporter, [&] () {
|
||||
for (const struct retro_variable *var = (retro_variable*)data;
|
||||
(var && (var->key != NULL) && (var->value != NULL)); ++var)
|
||||
{
|
||||
gen.node("variable", [&] () {
|
||||
gen.attribute("key", var->key);
|
||||
gen.attribute("value", var->value);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE:
|
||||
*((bool *)data) = (variables_version != config_version);
|
||||
return true;
|
||||
|
||||
case RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME:
|
||||
return false;
|
||||
|
||||
case RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE:
|
||||
return false;
|
||||
|
||||
case RETRO_ENVIRONMENT_GET_LOG_INTERFACE:
|
||||
{
|
||||
retro_log_callback *cb = (retro_log_callback*)data;
|
||||
cb->log = log_printf_callback;
|
||||
return true;
|
||||
}
|
||||
|
||||
case RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO:
|
||||
{
|
||||
static Genode::Reporter subsystem_reporter { *genv, "subsystems", "subsystems", 8192 };
|
||||
try { subsystem_reporter.enabled(true); }
|
||||
catch (...) {
|
||||
Genode::error("core subsystems not reported");
|
||||
return false;
|
||||
}
|
||||
|
||||
Genode::Reporter::Xml_generator gen(subsystem_reporter, [&] () {
|
||||
for (const retro_subsystem_info *info = (retro_subsystem_info*)data;
|
||||
(info && (info->desc)); ++info)
|
||||
{
|
||||
gen.node("subsystem", [&] () {
|
||||
gen.attribute("desc", info->desc);
|
||||
gen.attribute("num_roms", info->num_roms);
|
||||
gen.attribute("id", info->id);
|
||||
for (unsigned i = 0; i < info->num_roms; ++i) {
|
||||
const retro_subsystem_rom_info *rom_info =
|
||||
&info->roms[i];
|
||||
gen.node("rom", [&] () {
|
||||
gen.attribute("desc", rom_info->desc);
|
||||
gen.attribute("valid_extensions", rom_info->valid_extensions);
|
||||
gen.attribute("need_fullpath", rom_info->need_fullpath);
|
||||
gen.attribute("block_extract", rom_info->block_extract);
|
||||
gen.attribute("required", rom_info->required);
|
||||
for (unsigned j = 0; j < rom_info->num_memory; ++j) {
|
||||
const retro_subsystem_memory_info *memory =
|
||||
&rom_info->memory[i];
|
||||
gen.node("memory", [&] () {
|
||||
gen.attribute("extension", memory->extension);
|
||||
gen.attribute("type", memory->type);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
case RETRO_ENVIRONMENT_SET_CONTROLLER_INFO:
|
||||
{
|
||||
controller_info = (const retro_controller_info*)data;
|
||||
|
||||
static Genode::Reporter controller_reporter { *genv, "controllers" };
|
||||
try { controller_reporter.enabled(true); }
|
||||
catch (...) {
|
||||
Genode::error("controller info not reported");
|
||||
return true;
|
||||
}
|
||||
|
||||
Genode::Reporter::Xml_generator gen(controller_reporter, [&] () {
|
||||
unsigned index = 0;
|
||||
for (const retro_controller_info *info = (retro_controller_info*)data;
|
||||
(info && (info->types)); ++info)
|
||||
{
|
||||
gen.node("controller", [&] () {
|
||||
gen.attribute("port", index);
|
||||
for (unsigned i = 0; i < info->num_types; ++i) {
|
||||
const retro_controller_description *type =
|
||||
&info->types[i];
|
||||
gen.node("type", [&] () {
|
||||
gen.attribute("desc", type->desc);
|
||||
gen.attribute("id", type->id);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case RETRO_ENVIRONMENT_GET_USERNAME:
|
||||
{
|
||||
*(char const **)data = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
case RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER:
|
||||
{
|
||||
retro_framebuffer *fb = (retro_framebuffer*)data;
|
||||
|
||||
if (!framebuffer.constructed())
|
||||
return false;
|
||||
|
||||
::Framebuffer::Mode mode = framebuffer->mode;
|
||||
|
||||
fb->width = (unsigned)mode.width();
|
||||
fb->height = (unsigned)mode.height();
|
||||
fb->data = framebuffer->ds.local_addr<void>();
|
||||
fb->pitch = mode.width() * 2;
|
||||
fb->format = RETRO_PIXEL_FORMAT_RGB565;
|
||||
fb->memory_flags = RETRO_MEMORY_TYPE_CACHED;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Genode::warning(__func__, "(",cmd,") is unhandled");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* \brief Libretro framebuffer
|
||||
* \author Emery Hemingway
|
||||
* \date 2017-11-03
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _RETRO_FRONTEND__FRAMEBUFFER_H_
|
||||
#define _RETRO_FRONTEND__FRAMEBUFFER_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <framebuffer_session/connection.h>
|
||||
#include <base/attached_dataspace.h>
|
||||
#include <log_session/log_session.h>
|
||||
|
||||
#include "core.h"
|
||||
|
||||
namespace Retro_frontend { struct Framebuffer; }
|
||||
|
||||
struct Retro_frontend::Framebuffer
|
||||
{
|
||||
::Framebuffer::Connection session;
|
||||
|
||||
::Framebuffer::Mode mode;
|
||||
|
||||
Genode::Attached_dataspace ds;
|
||||
|
||||
Genode::Signal_handler<Framebuffer> mode_handler
|
||||
{ genv->ep(), *this, &Framebuffer::update_mode };
|
||||
|
||||
void update_mode()
|
||||
{
|
||||
mode = session.mode();
|
||||
|
||||
/* shutdown if the framebuffer is reduced to nil */
|
||||
if ((mode.width() == 0) && (mode.height() == 0))
|
||||
Libc::with_libc([&] () { shutdown(); });
|
||||
}
|
||||
|
||||
Framebuffer(retro_game_geometry geom)
|
||||
: session(*genv, ::Framebuffer::Mode(
|
||||
geom.base_width, geom.base_height,
|
||||
::Framebuffer::Mode::RGB565)),
|
||||
ds(genv->rm(), session.dataspace())
|
||||
{
|
||||
session.mode_sigh(mode_handler);
|
||||
update_mode();
|
||||
}
|
||||
};
|
||||
|
||||
namespace Retro_frontend {
|
||||
static Genode::Constructible<Framebuffer> framebuffer;
|
||||
}
|
||||
|
||||
|
||||
void video_refresh_callback(const void *data,
|
||||
unsigned src_width, unsigned src_height,
|
||||
size_t src_pitch)
|
||||
{
|
||||
using namespace Retro_frontend;
|
||||
using namespace Genode;
|
||||
|
||||
if (!framebuffer.constructed() || data == NULL) return;
|
||||
|
||||
uint8_t const *src = (uint8_t const*)data;
|
||||
uint8_t *dst = framebuffer->ds.local_addr<uint8_t>();
|
||||
|
||||
unsigned const dst_width = framebuffer->mode.width();
|
||||
unsigned const dst_height = framebuffer->mode.height();
|
||||
|
||||
unsigned const width = min(src_width, dst_width);
|
||||
unsigned const height = min(src_height, dst_height);
|
||||
|
||||
if (dst != src) {
|
||||
::size_t dst_pitch = dst_width<<1; /* x2 */
|
||||
|
||||
for (unsigned y = 0; y < height; ++y)
|
||||
memcpy(&dst[y*dst_pitch], &src[y*src_pitch], dst_pitch);
|
||||
}
|
||||
|
||||
framebuffer->session.refresh(0, 0, width, height);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,388 +0,0 @@
|
||||
/*
|
||||
* \brief Libretro input mapping
|
||||
* \author Emery Hemingway
|
||||
* \date 2016-07-08
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _RETRO_FRONTEND__INPUT_H_
|
||||
#define _RETRO_FRONTEND__INPUT_H_
|
||||
|
||||
/* local includes */
|
||||
#include "core.h"
|
||||
|
||||
/* Genode includes */
|
||||
#include <input_session/connection.h>
|
||||
#include <input/event_queue.h>
|
||||
|
||||
#include "input_maps.h"
|
||||
|
||||
namespace Retro_frontend {
|
||||
|
||||
#include <libretro.h>
|
||||
|
||||
const retro_controller_info *controller_info = nullptr;
|
||||
|
||||
/* callback to feed keyboard events to core */
|
||||
static retro_keyboard_event_t keyboard_callback;
|
||||
|
||||
/* Genode keyboard mapped to Libretro keyboard */
|
||||
static retro_key key_map[Input::Keycode::KEY_MAX];
|
||||
|
||||
/* array of currently configured controllers */
|
||||
enum { PORT_MAX = 7 };
|
||||
struct Controller;
|
||||
Controller *controllers[PORT_MAX+1] = { nullptr, };
|
||||
|
||||
typedef Genode::String<32> Keyname;
|
||||
|
||||
int lookup_genode_code(Keyname const &name)
|
||||
{
|
||||
using namespace Input;
|
||||
|
||||
/* not the fastest way to do this, just the most terse */
|
||||
for (int code = 0; code < Input::Keycode::KEY_MAX; ++code)
|
||||
if (name == key_name((Input::Keycode)code)) return code;
|
||||
return Input::KEY_UNKNOWN;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct Retro_frontend::Controller
|
||||
{
|
||||
bool input_state[Input::Keycode::KEY_MAX];
|
||||
|
||||
enum { JOYPAD_MAP_LEN = RETRO_DEVICE_ID_JOYPAD_R3 + 1 };
|
||||
int16_t joypad_map[JOYPAD_MAP_LEN];
|
||||
|
||||
enum { MOUSE_MAP_LEN = RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN + 1 };
|
||||
int16_t mouse_map[MOUSE_MAP_LEN];
|
||||
int16_t mouse_x = 0;
|
||||
int16_t mouse_y = 0;
|
||||
|
||||
/* TODO: analog axes */
|
||||
|
||||
Input::Connection input_conn;
|
||||
|
||||
Genode::Attached_dataspace input_ds;
|
||||
|
||||
Input::Event const * const events =
|
||||
input_ds.local_addr<Input::Event>();
|
||||
|
||||
uint16_t keymods = RETROKMOD_NONE;
|
||||
|
||||
/**
|
||||
* Use the 'label' attribute on an input configuration as a session
|
||||
* label with a fallback to the port number.
|
||||
*/
|
||||
typedef Genode::String<Genode::Session_label::capacity()> Label;
|
||||
static Label port_label(Genode::Xml_node const &config)
|
||||
{
|
||||
if (config.has_attribute("label"))
|
||||
return config.attribute_value("label", Label());
|
||||
else
|
||||
return config.attribute_value("port", Label());
|
||||
}
|
||||
|
||||
Controller(Genode::Xml_node const &config, unsigned port)
|
||||
: input_conn(*genv, port_label(config).string()),
|
||||
input_ds(genv->rm(), input_conn.dataspace())
|
||||
{
|
||||
using namespace Input;
|
||||
|
||||
Genode::memset(input_state, 0x00, sizeof(input_state));
|
||||
|
||||
unsigned device = config.attribute_value("device", 0UL);
|
||||
unsigned device_class = RETRO_DEVICE_MASK & device;
|
||||
|
||||
if (controller_info) {
|
||||
/* validate that the controller conforms to the core expectations */
|
||||
bool valid = false;
|
||||
for (const retro_controller_info *info = controller_info;
|
||||
(info && (info->types)); ++info)
|
||||
{
|
||||
for (unsigned i = 0; i < info->num_types; ++i) {
|
||||
const retro_controller_description *type = &info->types[i];
|
||||
if (type->id == device) {
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (valid)
|
||||
retro_set_controller_port_device(port, device);
|
||||
else
|
||||
Genode::error("controller ", port, " device ", device, " is not valid for core");
|
||||
}
|
||||
|
||||
/* set default joypad mapping */
|
||||
joypad_map[RETRO_DEVICE_ID_JOYPAD_B] = Keycode::BTN_B;
|
||||
joypad_map[RETRO_DEVICE_ID_JOYPAD_Y] = Keycode::BTN_Y;
|
||||
joypad_map[RETRO_DEVICE_ID_JOYPAD_SELECT] = Keycode::BTN_SELECT;
|
||||
joypad_map[RETRO_DEVICE_ID_JOYPAD_START] = Keycode::BTN_START;
|
||||
joypad_map[RETRO_DEVICE_ID_JOYPAD_UP] = Keycode::BTN_FORWARD;
|
||||
joypad_map[RETRO_DEVICE_ID_JOYPAD_DOWN] = Keycode::BTN_BACK;
|
||||
joypad_map[RETRO_DEVICE_ID_JOYPAD_LEFT] = Keycode::BTN_LEFT;
|
||||
joypad_map[RETRO_DEVICE_ID_JOYPAD_RIGHT] = Keycode::BTN_RIGHT;
|
||||
joypad_map[RETRO_DEVICE_ID_JOYPAD_A] = Keycode::BTN_A;
|
||||
joypad_map[RETRO_DEVICE_ID_JOYPAD_X] = Keycode::BTN_X;
|
||||
joypad_map[RETRO_DEVICE_ID_JOYPAD_L] = Keycode::BTN_TL;
|
||||
joypad_map[RETRO_DEVICE_ID_JOYPAD_R] = Keycode::BTN_TR;
|
||||
joypad_map[RETRO_DEVICE_ID_JOYPAD_L2] = Keycode::BTN_TL2;
|
||||
joypad_map[RETRO_DEVICE_ID_JOYPAD_R2] = Keycode::BTN_TR2;
|
||||
joypad_map[RETRO_DEVICE_ID_JOYPAD_L3] = Keycode::BTN_THUMBL;
|
||||
joypad_map[RETRO_DEVICE_ID_JOYPAD_R3] = Keycode::BTN_THUMBR;
|
||||
|
||||
/* set default mouse mapping */;
|
||||
mouse_map[RETRO_DEVICE_ID_MOUSE_LEFT] = Keycode::BTN_LEFT;
|
||||
mouse_map[RETRO_DEVICE_ID_MOUSE_RIGHT] = Keycode::BTN_RIGHT;
|
||||
mouse_map[RETRO_DEVICE_ID_MOUSE_WHEELUP] = Keycode::BTN_GEAR_UP;
|
||||
mouse_map[RETRO_DEVICE_ID_MOUSE_WHEELDOWN] = Keycode::BTN_GEAR_DOWN;
|
||||
mouse_map[RETRO_DEVICE_ID_MOUSE_MIDDLE] = Keycode::BTN_MIDDLE;
|
||||
|
||||
auto map_fn = [&] (Genode::Xml_node map_node) {
|
||||
using namespace Genode;
|
||||
using namespace Input;
|
||||
|
||||
Keyname const from = map_node.attribute_value("from", Keyname());
|
||||
Keyname const to = map_node.attribute_value("to", Keyname());
|
||||
|
||||
if ((from == "") || (to == "")) {
|
||||
error("ignoring ", map_node);
|
||||
return;
|
||||
}
|
||||
|
||||
int from_code = lookup_genode_code(from);
|
||||
int to_code = lookup_input_code(device_class, to.string());
|
||||
|
||||
if (from_code == KEY_UNKNOWN) {
|
||||
error("unknown key ", from.string());
|
||||
return;
|
||||
}
|
||||
if (to_code == RETROK_LAST) {
|
||||
error("unknown key ", to.string());
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* to_code and from_code are mapped reversed from the
|
||||
* frontend and oriented from the core perspective
|
||||
*/
|
||||
switch (device_class) {
|
||||
case RETRO_DEVICE_JOYPAD:
|
||||
if (to_code < JOYPAD_MAP_LEN) {
|
||||
joypad_map[to_code] = from_code;
|
||||
} else {
|
||||
Genode::error(to, " is not mapped for joypads");
|
||||
}
|
||||
break;
|
||||
case RETRO_DEVICE_MOUSE:
|
||||
if (to_code < MOUSE_MAP_LEN) {
|
||||
mouse_map[to_code] = from_code;
|
||||
} else {
|
||||
Genode::error(to, " is not mapped for mice");
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
Genode::error(map_node, " is invalid for device ",
|
||||
device, " class ", device_class);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
config.for_each_sub_node("map", map_fn);
|
||||
}
|
||||
|
||||
/* TODO: analog axes */
|
||||
|
||||
void poll()
|
||||
{
|
||||
using namespace Input;
|
||||
|
||||
unsigned num_events = input_conn.flush();
|
||||
for (unsigned i = 0; i < num_events; ++i) {
|
||||
Input::Event const &ev = events[i];
|
||||
|
||||
bool v = 0; /* assume a release */
|
||||
|
||||
switch (ev.type()) {
|
||||
|
||||
case Event::Type::MOTION:
|
||||
/* TODO */
|
||||
continue;
|
||||
|
||||
case Event::Type::PRESS:
|
||||
v = 1; /* not a release */
|
||||
|
||||
case Event::Type::RELEASE: {
|
||||
int code = ev.code();
|
||||
if (code >= 0 && code < Input::KEY_MAX) {
|
||||
retro_mod mod = RETROKMOD_NONE;
|
||||
|
||||
switch (code) {
|
||||
case Input::KEY_PAUSE:
|
||||
if (!v) /* pause/unpause on key release */
|
||||
toggle_pause();
|
||||
break;
|
||||
|
||||
case Input::KEY_LEFTSHIFT:
|
||||
case Input::KEY_RIGHTSHIFT:
|
||||
mod = RETROKMOD_SHIFT; break;
|
||||
|
||||
case Input::KEY_LEFTCTRL:
|
||||
case Input::KEY_RIGHTCTRL:
|
||||
mod = RETROKMOD_CTRL; break;
|
||||
|
||||
case Input::KEY_LEFTALT:
|
||||
case Input::KEY_RIGHTALT:
|
||||
mod = RETROKMOD_ALT; break;
|
||||
|
||||
case Input::KEY_LEFTMETA:
|
||||
case Input::KEY_RIGHTMETA:
|
||||
mod = RETROKMOD_META; break;
|
||||
|
||||
case Input::KEY_NUMLOCK:
|
||||
mod = RETROKMOD_NUMLOCK; break;
|
||||
|
||||
case Input::KEY_CAPSLOCK:
|
||||
mod = RETROKMOD_CAPSLOCK; break;
|
||||
|
||||
case Input::KEY_SCROLLLOCK:
|
||||
mod = RETROKMOD_SCROLLOCK; break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (mod)
|
||||
keymods = (keymods | mod) - (v ? 0 : mod);
|
||||
|
||||
input_state[code] = v;
|
||||
|
||||
if (keyboard_callback) {
|
||||
/*
|
||||
* the keyboard_callback may drive the core
|
||||
* but this context is a libretro callback
|
||||
* so 'with_libc' must be in effect
|
||||
*/
|
||||
unsigned rk = key_map[code];
|
||||
if (rk != RETROK_UNKNOWN) {
|
||||
keyboard_callback(v, rk, 0, keymods);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case Event::Type::CHARACTER:
|
||||
if (keyboard_callback) {
|
||||
/* event only supports UTF-8? */
|
||||
keyboard_callback(v, RETROK_UNKNOWN, ev.utf8().b0, RETROKMOD_NONE);
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
namespace Retro_frontend {
|
||||
|
||||
void initialize_controllers(Genode::Allocator &alloc,
|
||||
Genode::Xml_node config)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
Genode::memset(key_map, 0x00, sizeof(key_map));
|
||||
for (int i = 0; default_keymap[i].gk < Input::KEY_MAX; ++i) {
|
||||
key_map[default_keymap[i].gk] = (retro_key)default_keymap[i].rk;
|
||||
}
|
||||
|
||||
for (int i = 0; i <= PORT_MAX; ++i) {
|
||||
if (controllers[i] != nullptr) {
|
||||
destroy(alloc, controllers[i]);
|
||||
controllers[i] = nullptr;
|
||||
retro_set_controller_port_device(i, RETRO_DEVICE_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
config.for_each_sub_node("controller", [&] (Xml_node const &input_node) {
|
||||
unsigned port = input_node.attribute_value("port", 0U);
|
||||
unsigned device = input_node.attribute_value("device", 0U);
|
||||
|
||||
if (controllers[port] != nullptr) {
|
||||
error("controller port ", port, " is already configured");
|
||||
return;
|
||||
}
|
||||
|
||||
controllers[port] = new (alloc) Controller(input_node, port);
|
||||
if (device != RETRO_DEVICE_NONE)
|
||||
retro_set_controller_port_device(port, device);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void input_poll_callback()
|
||||
{
|
||||
for (int i = 0; i <= PORT_MAX; ++i) {
|
||||
if (controllers[i])
|
||||
controllers[i]->poll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int16_t input_state_callback(unsigned port, unsigned device,
|
||||
unsigned index, unsigned id)
|
||||
{
|
||||
Controller *ctrl = (port < PORT_MAX) ? controllers[port] : 0;
|
||||
|
||||
if (ctrl) switch (RETRO_DEVICE_MASK & device) {
|
||||
case RETRO_DEVICE_JOYPAD:
|
||||
if (id < Controller::JOYPAD_MAP_LEN) {
|
||||
auto code = ctrl->joypad_map[id];
|
||||
if (code < Input::KEY_MAX) {
|
||||
return ctrl->input_state[code];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RETRO_DEVICE_MOUSE:
|
||||
switch (id) {
|
||||
case RETRO_DEVICE_ID_MOUSE_X:
|
||||
return ctrl->mouse_x;
|
||||
case RETRO_DEVICE_ID_MOUSE_Y:
|
||||
return ctrl->mouse_y;
|
||||
default:
|
||||
if (id < Controller::MOUSE_MAP_LEN) {
|
||||
auto code = ctrl->mouse_map[id];
|
||||
if (code < Input::KEY_MAX) {
|
||||
return ctrl->input_state[code];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* install a handler to wake the frontend from input events */
|
||||
void input_sigh(Genode::Signal_context_capability sig)
|
||||
{
|
||||
for (int i = 0; i <= PORT_MAX; ++i) {
|
||||
if (controllers[i])
|
||||
controllers[i]->input_conn.sigh(sig);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,383 +0,0 @@
|
||||
/*
|
||||
* \brief Libretro input mapping
|
||||
* \author Emery Hemingway
|
||||
* \date 2016-07-08
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _RETRO_FRONTEND__INPUT_MAPS_H_
|
||||
#define _RETRO_FRONTEND__INPUT_MAPS_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <input/keycodes.h>
|
||||
|
||||
namespace Retro_frontend {
|
||||
#include <libretro.h>
|
||||
|
||||
struct retro_input_text_map
|
||||
{
|
||||
int code;
|
||||
char const *text;
|
||||
};
|
||||
|
||||
static const struct retro_input_text_map joypad_text_map[] = {
|
||||
{ RETRO_DEVICE_ID_JOYPAD_B, "B" },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_Y, "Y" },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_SELECT, "SELECT" },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_START, "START" },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_UP, "UP" },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_DOWN, "DOWN" },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_LEFT, "LEFT" },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_RIGHT, "RIGHT" },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_A, "A" },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_X, "X" },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_L, "L" },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_R, "R" },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_L2, "L2" },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_R2, "R2" },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_L3, "L3" },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_R3, "R3" },
|
||||
{ -1, "" },
|
||||
};
|
||||
|
||||
static const struct retro_input_text_map mouse_text_map[] = {
|
||||
{ RETRO_DEVICE_ID_MOUSE_LEFT, "LEFT" },
|
||||
{ RETRO_DEVICE_ID_MOUSE_RIGHT, "RIGHT" },
|
||||
{ RETRO_DEVICE_ID_MOUSE_WHEELUP, "WHEELUP" },
|
||||
{ RETRO_DEVICE_ID_MOUSE_WHEELDOWN, "WHEELDOWN" },
|
||||
{ RETRO_DEVICE_ID_MOUSE_MIDDLE, "MIDDLE" },
|
||||
{ RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP, "HORIZ_WHEELUP" },
|
||||
{ RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN, "HORIZ_WHEELDOWN" },
|
||||
{ -1, "" },
|
||||
};
|
||||
|
||||
static const struct retro_input_text_map keyboard_text_map[] = {
|
||||
{ RETROK_UNKNOWN, "UNKNOWN" },
|
||||
{ RETROK_FIRST, "FIRST" },
|
||||
{ RETROK_BACKSPACE, "BACKSPACE" },
|
||||
{ RETROK_TAB, "TAB" },
|
||||
{ RETROK_CLEAR, "CLEAR" },
|
||||
{ RETROK_RETURN, "RETURN" },
|
||||
{ RETROK_PAUSE, "PAUSE" },
|
||||
{ RETROK_ESCAPE, "ESCAPE" },
|
||||
{ RETROK_SPACE, "SPACE" },
|
||||
{ RETROK_EXCLAIM, "EXCLAIM" },
|
||||
{ RETROK_QUOTEDBL, "QUOTEDBL" },
|
||||
{ RETROK_HASH, "HASH" },
|
||||
{ RETROK_DOLLAR, "DOLLAR" },
|
||||
{ RETROK_AMPERSAND, "AMPERSAND" },
|
||||
{ RETROK_QUOTE, "QUOTE" },
|
||||
{ RETROK_LEFTPAREN, "LEFTPAREN" },
|
||||
{ RETROK_RIGHTPAREN, "RIGHTPAREN" },
|
||||
{ RETROK_ASTERISK, "ASTERISK" },
|
||||
{ RETROK_PLUS, "PLUS" },
|
||||
{ RETROK_COMMA, "COMMA" },
|
||||
{ RETROK_MINUS, "MINUS" },
|
||||
{ RETROK_PERIOD, "PERIOD" },
|
||||
{ RETROK_SLASH, "SLASH" },
|
||||
{ RETROK_0, "0" },
|
||||
{ RETROK_1, "1" },
|
||||
{ RETROK_2, "2" },
|
||||
{ RETROK_3, "3" },
|
||||
{ RETROK_4, "4" },
|
||||
{ RETROK_5, "5" },
|
||||
{ RETROK_6, "6" },
|
||||
{ RETROK_7, "7" },
|
||||
{ RETROK_8, "8" },
|
||||
{ RETROK_9, "9" },
|
||||
{ RETROK_COLON, "COLON" },
|
||||
{ RETROK_SEMICOLON, "SEMICOLON" },
|
||||
{ RETROK_LESS, "LESS" },
|
||||
{ RETROK_EQUALS, "EQUALS" },
|
||||
{ RETROK_GREATER, "GREATER" },
|
||||
{ RETROK_QUESTION, "QUESTION" },
|
||||
{ RETROK_AT, "AT" },
|
||||
{ RETROK_LEFTBRACKET, "LEFTBRACKET" },
|
||||
{ RETROK_BACKSLASH, "BACKSLASH" },
|
||||
{ RETROK_RIGHTBRACKET, "RIGHTBRACKET" },
|
||||
{ RETROK_CARET, "CARET" },
|
||||
{ RETROK_UNDERSCORE, "UNDERSCORE" },
|
||||
{ RETROK_BACKQUOTE, "BACKQUOTE" },
|
||||
{ RETROK_a, "a" },
|
||||
{ RETROK_b, "b" },
|
||||
{ RETROK_c, "c" },
|
||||
{ RETROK_d, "d" },
|
||||
{ RETROK_e, "e" },
|
||||
{ RETROK_f, "f" },
|
||||
{ RETROK_g, "g" },
|
||||
{ RETROK_h, "h" },
|
||||
{ RETROK_i, "i" },
|
||||
{ RETROK_j, "j" },
|
||||
{ RETROK_k, "k" },
|
||||
{ RETROK_l, "l" },
|
||||
{ RETROK_m, "m" },
|
||||
{ RETROK_n, "n" },
|
||||
{ RETROK_o, "o" },
|
||||
{ RETROK_p, "p" },
|
||||
{ RETROK_q, "q" },
|
||||
{ RETROK_r, "r" },
|
||||
{ RETROK_s, "s" },
|
||||
{ RETROK_t, "t" },
|
||||
{ RETROK_u, "u" },
|
||||
{ RETROK_v, "v" },
|
||||
{ RETROK_w, "w" },
|
||||
{ RETROK_x, "x" },
|
||||
{ RETROK_y, "y" },
|
||||
{ RETROK_z, "z" },
|
||||
{ RETROK_DELETE, "DELETE" },
|
||||
|
||||
{ RETROK_KP0, "KP0" },
|
||||
{ RETROK_KP1, "KP1" },
|
||||
{ RETROK_KP2, "KP2" },
|
||||
{ RETROK_KP3, "KP3" },
|
||||
{ RETROK_KP4, "KP4" },
|
||||
{ RETROK_KP5, "KP5" },
|
||||
{ RETROK_KP6, "KP6" },
|
||||
{ RETROK_KP7, "KP7" },
|
||||
{ RETROK_KP8, "KP8" },
|
||||
{ RETROK_KP9, "KP9" },
|
||||
{ RETROK_KP_PERIOD, "KP_PERIOD" },
|
||||
{ RETROK_KP_DIVIDE, "KP_DIVIDE" },
|
||||
{ RETROK_KP_MULTIPLY, "KP_MULTIPLY" },
|
||||
{ RETROK_KP_MINUS, "KP_MINUS" },
|
||||
{ RETROK_KP_PLUS, "KP_PLUS" },
|
||||
{ RETROK_KP_ENTER, "KP_ENTER" },
|
||||
{ RETROK_KP_EQUALS, "KP_EQUALS" },
|
||||
|
||||
{ RETROK_UP, "UP" },
|
||||
{ RETROK_DOWN, "DOWN" },
|
||||
{ RETROK_RIGHT, "RIGHT" },
|
||||
{ RETROK_LEFT, "LEFT" },
|
||||
{ RETROK_INSERT, "INSERT" },
|
||||
{ RETROK_HOME, "HOME" },
|
||||
{ RETROK_END, "END" },
|
||||
{ RETROK_PAGEUP, "PAGEUP" },
|
||||
{ RETROK_PAGEDOWN, "PAGEDOWN" },
|
||||
|
||||
{ RETROK_F1, "F1" },
|
||||
{ RETROK_F2, "F2" },
|
||||
{ RETROK_F3, "F3" },
|
||||
{ RETROK_F4, "F4" },
|
||||
{ RETROK_F5, "F5" },
|
||||
{ RETROK_F6, "F6" },
|
||||
{ RETROK_F7, "F7" },
|
||||
{ RETROK_F8, "F8" },
|
||||
{ RETROK_F9, "F9" },
|
||||
{ RETROK_F10, "F10" },
|
||||
{ RETROK_F11, "F11" },
|
||||
{ RETROK_F12, "F12" },
|
||||
{ RETROK_F13, "F13" },
|
||||
{ RETROK_F14, "F14" },
|
||||
{ RETROK_F15, "F15" },
|
||||
|
||||
{ RETROK_NUMLOCK, "NUMLOCK" },
|
||||
{ RETROK_CAPSLOCK, "CAPSLOCK" },
|
||||
{ RETROK_SCROLLOCK, "SCROLLOCK" },
|
||||
{ RETROK_RSHIFT, "RSHIFT" },
|
||||
{ RETROK_LSHIFT, "LSHIFT" },
|
||||
{ RETROK_RCTRL, "RCTRL" },
|
||||
{ RETROK_LCTRL, "LCTRL" },
|
||||
{ RETROK_RALT, "RALT" },
|
||||
{ RETROK_LALT, "LALT" },
|
||||
{ RETROK_RMETA, "RMETA" },
|
||||
{ RETROK_LMETA, "LMETA" },
|
||||
{ RETROK_LSUPER, "LSUPER" },
|
||||
{ RETROK_RSUPER, "RSUPER" },
|
||||
{ RETROK_MODE, "MODE" },
|
||||
{ RETROK_COMPOSE, "COMPOSE" },
|
||||
|
||||
{ RETROK_HELP, "HELP" },
|
||||
{ RETROK_PRINT, "PRINT" },
|
||||
{ RETROK_SYSREQ, "SYSREQ" },
|
||||
{ RETROK_BREAK, "BREAK" },
|
||||
{ RETROK_MENU, "MENU" },
|
||||
{ RETROK_POWER, "POWER" },
|
||||
{ RETROK_EURO, "EURO" },
|
||||
{ RETROK_UNDO, "UNDO" },
|
||||
{ -1, "" },
|
||||
};
|
||||
|
||||
char const *lookup_input_text(int device, int code)
|
||||
{
|
||||
retro_input_text_map const *map;
|
||||
char const *placeholder = "UNKNOWN";
|
||||
|
||||
switch (device) {
|
||||
case RETRO_DEVICE_JOYPAD:
|
||||
map = &joypad_text_map[0]; break;
|
||||
case RETRO_DEVICE_MOUSE:
|
||||
map = &mouse_text_map[0]; break;
|
||||
case RETRO_DEVICE_KEYBOARD:
|
||||
map = &keyboard_text_map[0]; break;
|
||||
default:
|
||||
return placeholder;
|
||||
}
|
||||
|
||||
for (int i = 0; *map[i].text; ++i) {
|
||||
if (map[i].code == code)
|
||||
return map[i].text;
|
||||
}
|
||||
return placeholder;
|
||||
}
|
||||
|
||||
|
||||
unsigned lookup_input_code(int device, char const *text)
|
||||
{
|
||||
retro_input_text_map const *map;
|
||||
|
||||
switch (device) {
|
||||
case RETRO_DEVICE_JOYPAD:
|
||||
map = &joypad_text_map[0]; break;
|
||||
case RETRO_DEVICE_MOUSE:
|
||||
map = &mouse_text_map[0]; break;
|
||||
case RETRO_DEVICE_KEYBOARD:
|
||||
map = &keyboard_text_map[0]; break;
|
||||
default: return RETROK_LAST;
|
||||
}
|
||||
|
||||
for (int i = 0; *map[i].text; ++i) {
|
||||
if (Genode::strcmp(map[i].text, text) == 0)
|
||||
return map[i].code;
|
||||
}
|
||||
return RETROK_LAST;
|
||||
}
|
||||
|
||||
|
||||
struct genode_retro_map
|
||||
{
|
||||
enum Input::Keycode gk;
|
||||
unsigned rk;
|
||||
};
|
||||
|
||||
static const struct genode_retro_map default_keymap[] = {
|
||||
{ Input::KEY_ESC, RETROK_ESCAPE },
|
||||
{ Input::KEY_1, RETROK_1 },
|
||||
{ Input::KEY_2, RETROK_2 },
|
||||
{ Input::KEY_3, RETROK_3 },
|
||||
{ Input::KEY_4, RETROK_4 },
|
||||
{ Input::KEY_5, RETROK_5 },
|
||||
{ Input::KEY_6, RETROK_6 },
|
||||
{ Input::KEY_7, RETROK_7 },
|
||||
{ Input::KEY_8, RETROK_8 },
|
||||
{ Input::KEY_9, RETROK_9 },
|
||||
{ Input::KEY_0, RETROK_0 },
|
||||
{ Input::KEY_MINUS, RETROK_MINUS },
|
||||
{ Input::KEY_EQUAL, RETROK_EQUALS },
|
||||
{ Input::KEY_BACKSPACE, RETROK_BACKSPACE },
|
||||
{ Input::KEY_TAB, RETROK_TAB },
|
||||
{ Input::KEY_Q, RETROK_q },
|
||||
{ Input::KEY_W, RETROK_w },
|
||||
{ Input::KEY_E, RETROK_e },
|
||||
{ Input::KEY_R, RETROK_r },
|
||||
{ Input::KEY_T, RETROK_t },
|
||||
{ Input::KEY_Y, RETROK_y },
|
||||
{ Input::KEY_U, RETROK_u },
|
||||
{ Input::KEY_I, RETROK_i },
|
||||
{ Input::KEY_O, RETROK_o },
|
||||
{ Input::KEY_P, RETROK_p },
|
||||
{ Input::KEY_LEFTBRACE, RETROK_LEFTBRACKET },
|
||||
{ Input::KEY_RIGHTBRACE, RETROK_RIGHTBRACKET },
|
||||
{ Input::KEY_ENTER, RETROK_RETURN },
|
||||
{ Input::KEY_LEFTCTRL, RETROK_LCTRL },
|
||||
{ Input::KEY_A, RETROK_a },
|
||||
{ Input::KEY_S, RETROK_s },
|
||||
{ Input::KEY_D, RETROK_d },
|
||||
{ Input::KEY_F, RETROK_f },
|
||||
{ Input::KEY_G, RETROK_g },
|
||||
{ Input::KEY_H, RETROK_h },
|
||||
{ Input::KEY_J, RETROK_j },
|
||||
{ Input::KEY_K, RETROK_k },
|
||||
{ Input::KEY_L, RETROK_l },
|
||||
{ Input::KEY_SEMICOLON, RETROK_SEMICOLON },
|
||||
{ Input::KEY_APOSTROPHE, RETROK_QUOTE },
|
||||
{ Input::KEY_GRAVE, RETROK_BACKQUOTE },
|
||||
{ Input::KEY_LEFTSHIFT, RETROK_LSHIFT },
|
||||
{ Input::KEY_BACKSLASH, RETROK_BACKSLASH },
|
||||
{ Input::KEY_Z, RETROK_z },
|
||||
{ Input::KEY_X, RETROK_x },
|
||||
{ Input::KEY_C, RETROK_c },
|
||||
{ Input::KEY_V, RETROK_v },
|
||||
{ Input::KEY_B, RETROK_b },
|
||||
{ Input::KEY_N, RETROK_n },
|
||||
{ Input::KEY_M, RETROK_m },
|
||||
{ Input::KEY_COMMA, RETROK_COMMA },
|
||||
{ Input::KEY_DOT, RETROK_PERIOD },
|
||||
{ Input::KEY_SLASH, RETROK_SLASH },
|
||||
{ Input::KEY_RIGHTSHIFT, RETROK_RSHIFT },
|
||||
{ Input::KEY_KPASTERISK, RETROK_KP_MULTIPLY },
|
||||
{ Input::KEY_LEFTALT, RETROK_LALT },
|
||||
{ Input::KEY_SPACE, RETROK_SPACE },
|
||||
{ Input::KEY_CAPSLOCK, RETROK_CAPSLOCK },
|
||||
{ Input::KEY_F1, RETROK_F1 },
|
||||
{ Input::KEY_F2, RETROK_F2 },
|
||||
{ Input::KEY_F3, RETROK_F3 },
|
||||
{ Input::KEY_F4, RETROK_F4 },
|
||||
{ Input::KEY_F5, RETROK_F5 },
|
||||
{ Input::KEY_F6, RETROK_F6 },
|
||||
{ Input::KEY_F7, RETROK_F7 },
|
||||
{ Input::KEY_F8, RETROK_F8 },
|
||||
{ Input::KEY_F9, RETROK_F9 },
|
||||
{ Input::KEY_F10, RETROK_F10 },
|
||||
{ Input::KEY_NUMLOCK, RETROK_NUMLOCK },
|
||||
{ Input::KEY_SCROLLLOCK, RETROK_SCROLLOCK },
|
||||
{ Input::KEY_KP7, RETROK_KP7 },
|
||||
{ Input::KEY_KP8, RETROK_KP8 },
|
||||
{ Input::KEY_KP9, RETROK_KP9 },
|
||||
{ Input::KEY_KPMINUS, RETROK_KP_MINUS },
|
||||
{ Input::KEY_KP4, RETROK_KP4 },
|
||||
{ Input::KEY_KP5, RETROK_KP5 },
|
||||
{ Input::KEY_KP6, RETROK_KP6 },
|
||||
{ Input::KEY_KPPLUS, RETROK_KP_PLUS },
|
||||
{ Input::KEY_KP1, RETROK_KP1 },
|
||||
{ Input::KEY_KP2, RETROK_KP2 },
|
||||
{ Input::KEY_KP3, RETROK_KP3 },
|
||||
{ Input::KEY_KP0, RETROK_KP0 },
|
||||
{ Input::KEY_KPDOT, RETROK_KP_PERIOD },
|
||||
|
||||
{ Input::KEY_F11, RETROK_F11 },
|
||||
{ Input::KEY_F12, RETROK_F12 },
|
||||
{ Input::KEY_KPENTER, RETROK_KP_ENTER },
|
||||
{ Input::KEY_RIGHTCTRL, RETROK_RCTRL },
|
||||
{ Input::KEY_KPSLASH, RETROK_KP_DIVIDE },
|
||||
{ Input::KEY_SYSRQ, RETROK_SYSREQ },
|
||||
{ Input::KEY_RIGHTALT, RETROK_RALT },
|
||||
{ Input::KEY_HOME, RETROK_HOME },
|
||||
{ Input::KEY_UP, RETROK_UP },
|
||||
{ Input::KEY_PAGEUP, RETROK_PAGEUP },
|
||||
{ Input::KEY_LEFT, RETROK_LEFT },
|
||||
{ Input::KEY_RIGHT, RETROK_RIGHT },
|
||||
{ Input::KEY_END, RETROK_END },
|
||||
{ Input::KEY_DOWN, RETROK_DOWN },
|
||||
{ Input::KEY_PAGEDOWN, RETROK_PAGEDOWN },
|
||||
{ Input::KEY_INSERT, RETROK_INSERT },
|
||||
{ Input::KEY_DELETE, RETROK_DELETE },
|
||||
{ Input::KEY_POWER, RETROK_POWER },
|
||||
{ Input::KEY_KPEQUAL, RETROK_KP_EQUALS },
|
||||
{ Input::KEY_KPPLUSMINUS, RETROK_KP_MINUS },
|
||||
|
||||
{ Input::KEY_LEFTMETA, RETROK_LMETA },
|
||||
{ Input::KEY_RIGHTMETA, RETROK_RMETA },
|
||||
{ Input::KEY_COMPOSE, RETROK_COMPOSE },
|
||||
|
||||
{ Input::KEY_UNDO, RETROK_UNDO },
|
||||
{ Input::KEY_HELP, RETROK_HELP },
|
||||
{ Input::KEY_MENU, RETROK_MENU },
|
||||
|
||||
{ Input::KEY_F13, RETROK_F13 },
|
||||
{ Input::KEY_F14, RETROK_F14 },
|
||||
{ Input::KEY_F15, RETROK_F15 },
|
||||
|
||||
{ Input::KEY_BREAK, RETROK_BREAK },
|
||||
{ Input::KEY_MAX, RETROK_LAST },
|
||||
{ Input::KEY_MAX, RETROK_LAST },
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* \brief Libretro frontend
|
||||
* \author Emery Hemingway
|
||||
* \date 2017-11-04
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _RETRO_FRONTEND__LOG_H_
|
||||
#define _RETRO_FRONTEND__LOG_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/log.h>
|
||||
|
||||
/* vsnprintf */
|
||||
#include <stdio.h>
|
||||
|
||||
#include "core.h"
|
||||
|
||||
void log_printf_callback(retro_log_level level, const char *fmt, ...)
|
||||
{
|
||||
using namespace Retro_frontend;
|
||||
|
||||
char buf[Genode::Log_session::MAX_STRING_LEN];
|
||||
|
||||
va_list vp;
|
||||
va_start(vp, fmt);
|
||||
int n = ::vsnprintf(buf, sizeof(buf), fmt, vp);
|
||||
va_end(vp);
|
||||
|
||||
if (n)
|
||||
buf[n-1] = '\0'; /* trim newline */
|
||||
char const *msg = buf;
|
||||
|
||||
switch (level) {
|
||||
case RETRO_LOG_DEBUG: Genode::log("Debug: ", msg); return;
|
||||
case RETRO_LOG_INFO: Genode::log(msg); return;
|
||||
case RETRO_LOG_WARN: Genode::warning(msg); return;
|
||||
case RETRO_LOG_ERROR: Genode::error(msg); return;
|
||||
case RETRO_LOG_DUMMY: Genode::log("Dummy: ", msg); return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* \brief Libretro persistent memory file
|
||||
* \author Emery Hemingway
|
||||
* \date 2017-11-17
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _RETRO_FRONTEND__MEMORY_H_
|
||||
#define _RETRO_FRONTEND__MEMORY_H_
|
||||
|
||||
/* Libc includes */
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace Retro_frontend {
|
||||
|
||||
struct Memory_file
|
||||
{
|
||||
void *data = nullptr;
|
||||
size_t size = 0;
|
||||
unsigned const id;
|
||||
char const *path;
|
||||
int fd = -1;
|
||||
|
||||
Genode::size_t file_size()
|
||||
{
|
||||
struct stat s;
|
||||
s.st_size = 0;
|
||||
stat(path, &s);
|
||||
return s.st_size;
|
||||
}
|
||||
|
||||
bool open_file_for_data()
|
||||
{
|
||||
if (!(data && size))
|
||||
return false;
|
||||
|
||||
if (fd == -1)
|
||||
fd = ::open(path, O_RDWR|O_CREAT);
|
||||
return fd != -1;
|
||||
}
|
||||
|
||||
Memory_file(unsigned id, char const *filename)
|
||||
: id(id), path(filename)
|
||||
{ }
|
||||
|
||||
~Memory_file() { if (fd != -1) close(fd); }
|
||||
|
||||
void read()
|
||||
{
|
||||
if (open_file_for_data()) {
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
size_t remain = Genode::min(size, file_size());
|
||||
size_t offset = 0;
|
||||
do {
|
||||
ssize_t n = ::read(fd, ((char*)data)+offset, remain);
|
||||
if (n == -1) {
|
||||
Genode::error("failed to read from ", path);
|
||||
break;
|
||||
}
|
||||
remain -= n;
|
||||
offset += n;
|
||||
} while (remain);
|
||||
}
|
||||
}
|
||||
|
||||
void write()
|
||||
{
|
||||
if (open_file_for_data()) {
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
ftruncate(fd, size);
|
||||
size_t remain = size;
|
||||
size_t offset = 0;
|
||||
do {
|
||||
ssize_t n = ::write(fd, ((char const *)data)+offset, remain);
|
||||
if (n == -1) {
|
||||
Genode::error("failed to write to ", path);
|
||||
break;
|
||||
}
|
||||
remain -= n;
|
||||
offset += n;
|
||||
} while (remain);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,9 +0,0 @@
|
||||
TARGET = retro_frontend
|
||||
SRC_CC = component.cc
|
||||
LIBS = base libc
|
||||
|
||||
LIBRETRO_INC := $(call select_from_ports,libretro)/include
|
||||
|
||||
INC_DIR += $(LIBRETRO_INC)
|
||||
|
||||
CC_CXX_WARN_STRICT =
|
||||
@@ -1,7 +0,0 @@
|
||||
TARGET = fceumm
|
||||
LIBS = fceumm_libretro
|
||||
SRC_CC = main.cc
|
||||
|
||||
vpath %.cc $(call select_from_repositories,src/test/libports)
|
||||
|
||||
CC_CXX_WARN_STRICT =
|
||||
@@ -1,7 +0,0 @@
|
||||
TARGET = meteor_libretro-dummy
|
||||
LIBS = meteor_libretro
|
||||
SRC_CC = main.cc
|
||||
|
||||
vpath %.cc $(call select_from_repositories,src/test/libports)
|
||||
|
||||
CC_CXX_WARN_STRICT =
|
||||
@@ -1,7 +0,0 @@
|
||||
TARGET = nxengine
|
||||
LIBS = nxengine_libretro
|
||||
SRC_CC = main.cc
|
||||
|
||||
vpath %.cc $(call select_from_repositories,src/test/libports)
|
||||
|
||||
CC_CXX_WARN_STRICT =
|
||||
@@ -1,7 +0,0 @@
|
||||
TARGET = snes9x
|
||||
LIBS = snes9x_libretro
|
||||
SRC_CC = main.cc
|
||||
|
||||
vpath %.cc $(call select_from_repositories,src/test/libports)
|
||||
|
||||
CC_CXX_WARN_STRICT =
|
||||
@@ -1,7 +0,0 @@
|
||||
#ifndef BOOLEAN_H
|
||||
#define BOOLEAN_H
|
||||
|
||||
/* known to contain a 'bool' type */
|
||||
#include <libretro.h>
|
||||
|
||||
#endif
|
||||
@@ -1,7 +0,0 @@
|
||||
TARGET = tyrquake
|
||||
LIBS = tyrquake_libretro
|
||||
SRC_CC = main.cc
|
||||
|
||||
vpath %.cc $(call select_from_repositories,src/test/libports)
|
||||
|
||||
CC_CXX_WARN_STRICT =
|
||||
Reference in New Issue
Block a user