Split Libretro into seperate repo

Libretro frontend and cores moved to
https://github.com/ehmry/genode-libretro

Fix #100
This commit is contained in:
Emery Hemingway
2018-03-10 13:37:15 +01:00
committed by Norman Feske
parent 47faf8c4f8
commit 16d6fbdb47
74 changed files with 0 additions and 3731 deletions

View File

@@ -1,5 +0,0 @@
LIBRETRO_PORT_DIR := $(call select_from_ports,libretro)
INC_DIR += $(LIBRETRO_PORT_DIR)/include
SYMBOLS = $(REP_DIR)/lib/symbols/libretro

View File

@@ -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 =

View File

@@ -1,2 +0,0 @@
CC_CXX_WARN_STRICT =

View File

@@ -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 =

View File

@@ -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 =

View File

@@ -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 =

View File

@@ -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 =

View File

@@ -1 +0,0 @@
a89e9e6d0c52d83075f2a81a99751d22e3e238c2

View File

@@ -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

View File

@@ -1 +0,0 @@
4af697b4dcae97201f56baf817497595df9ae3b4

View File

@@ -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

View File

@@ -1 +0,0 @@
cf72badc0be2c5e20ec45453c5c75dc79bb366fd

View File

@@ -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

View File

@@ -1 +0,0 @@
7bda4d0d5b7d8bfb3cd5cd5258bbfad819e6a23e

View File

@@ -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

View File

@@ -1 +0,0 @@
112e02d21246ae41ca3b32f9e1c461727f7fce50

View File

@@ -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

View File

@@ -1 +0,0 @@
7e313a85de4e5600dca2fb7b8d16e6a1ec1a57f7

View File

@@ -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

View File

@@ -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 > $@

View File

@@ -1 +0,0 @@
2017-11-16 c8f71292a4ee5e7f312f10dbef5b79f0fb889795

View File

@@ -1 +0,0 @@
FCE Ultra mappers modified, an emulator for the Nintendo Entertainment System

View File

@@ -1,3 +0,0 @@
_/src/fceumm_libretro
_/src/libc
_/src/zlib

View File

@@ -1 +0,0 @@
2017-11-27 7b23c5e758426526c248cc0f3c950fe6c0fd1ba5

View File

@@ -1 +0,0 @@
Meteor emulator for the Game Boy Advance

View File

@@ -1,2 +0,0 @@
_/src/meteor_libretro
_/src/libc

View File

@@ -1 +0,0 @@
2017-11-27 2b0c5d1bfc622a0b7cb10aa07cdb35f08a394063

View File

@@ -1,3 +0,0 @@
Snes9x emulator for the Super Nintendo Entertainment System
http://www.snes9x.com/

View File

@@ -1,2 +0,0 @@
_/src/snes9x_libretro
_/src/libc

View File

@@ -1 +0,0 @@
2017-11-27 228441601a48077e33274d70cbfd5466202ced8e

View File

@@ -1,3 +0,0 @@
TyrQuake engine
http://disentchant.net/tyrquake/

View File

@@ -1,2 +0,0 @@
_/src/libc
_/src/tyrquake_libretro

View File

@@ -1 +0,0 @@
2017-11-28 99f3d81ad18df7f6bd7c7142d3280f5b708e3b21

View File

@@ -1 +0,0 @@
libretro

View File

@@ -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

View File

@@ -1 +0,0 @@
2017-11-27 a0faa1146122f9c44500385c3dcb9c3f8e26a02a

View File

@@ -1,4 +0,0 @@
libc
so
stdcxx
zlib

View File

@@ -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

View File

@@ -1 +0,0 @@
2017-11-27 cd297ae262c8628e505d8407ef3df840885ada6d

View File

@@ -1,3 +0,0 @@
libc
so
stdcxx

View File

@@ -1,2 +0,0 @@
SRC_DIR := src/app/retro_frontend
include $(GENODE_DIR)/repos/base/recipes/src/content.inc

View File

@@ -1 +0,0 @@
2017-11-27 5d0ed1ae158fe0b7d3f825b2d4815b8e98375866

View File

@@ -1,10 +0,0 @@
audio_out_session
base
framebuffer_session
input_session
libc
libretro
os
report_session
timer_session
vfs

View File

@@ -1 +0,0 @@
libretro

View File

@@ -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

View File

@@ -1 +0,0 @@
2017-11-27 07d08e662af9e92c7fe7f386dfea53e2e25383a1

View File

@@ -1,4 +0,0 @@
libc
so
stdcxx
zlib

View File

@@ -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

View File

@@ -1 +0,0 @@
2017-11-28 e8a8580e4458b13cc1f225b96e70f25a92c9582e

View File

@@ -1,3 +0,0 @@
libc
so
stdcxx

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 =

View File

@@ -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 =

View File

@@ -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 =

View File

@@ -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 =

View File

@@ -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 =

View File

@@ -1,7 +0,0 @@
#ifndef BOOLEAN_H
#define BOOLEAN_H
/* known to contain a 'bool' type */
#include <libretro.h>
#endif

View File

@@ -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 =