Tic-80: A viable way to support RaspberryPi (with baremetal)

Created on 7 Jun 2018  路  10Comments  路  Source: nesbox/TIC-80

So the idea is to support RaspberryPi using baremetal mode, that is, without any operating system and talking directly to the hardware.
The nice thing about baremetal is that you have full control of the hardware, full speed, zero boot time, a single process, etc. The bad things is that you have to figure out how to talk to each individual piece of hardware, which would be a huge task per se.
Fortunately there's a project called Circle that already does most of the job, it supports USB (mouse, keyboard, gamepad), audio, screen access, etc. There's plenty of examples for each specific feature.
In particular you have direct access to memory mapped video of the Broadcom video chip, so you just write to a pointer and get things on the screen, completely sidestepping all the usual layers (sdl,opengl,kernel space etc).
Another project built on top of Circle provides the C and C++ standard libraries built on top of it, providing basic dependencies to build stuff (like Lua)

So to port TIC for this platform all it's left to do is changing its "system interface" from SDL to circle specific functions ("easily" extractable from the samples). As nesbox said, TIC is pretty insulated from SDL and changing the undelying "engine" should be feasible.

There's already a ZX spectrum emulator that is built around this exact technique (sources are not yet available but should be published, sooner or later).

I made some experiments (on RPi Zero W) months ago and i managed to:

  • set the video mode to arbitrary resolution (ie 320x200) at 8 bit, which gets automatically scaled by the video chip
  • putting some stuff on screen
  • compile Lua and interface with it

I have yet to do any performace test but i'm pretty sure that the gain (over regular linux+rpi) will be huge, possibly even enabling RPi Zero as a platform.

It's still a lot of work, and ARM has other weak points to deal with (like unaligned memory access), but i think it's at least feasible. I for once would love to see a computer instantly booting into TIC, and i know there's interest for a "portable" TIC console that could theoretically be built around this.

I'll do some more experiments but if anyone wants to join/discuss/contribute, feel free :)

Most helpful comment

A little update on the project: i managed to get the full studio to compile, now the rpi "boots into" tic80 editor (which is pretty awesome, really feels like a console). I adjusted the rgb output, wired up keyboard support at 90%. All of the "primitive" functions in fs.c needs to be rewritten using circle custom api, i've currently done just the bare minimum to get the "load" command working, so i can now load, edit and run a cart (but no save).

I'm having some minor issue with the keyboard dropping some keypresses but i think it's just some kind of race condition on the input object, (the handler being called during the tick()). Another minor issue is some light flickering which probably just need some tuning with the order of operations and vsync. At worst i could implement a backbuffer.

I've already integrate the rather comprehensive gamepad support of Circle into the system, i just need to wire it to the input. Mouse should be straightforward.

The only big thing left to tackle is audio, the problem here is that i'm totally uninformed about how audio works in general, so it will take some time.

I tried all my games and some other carts like 8-bit panda and they all runs smooth. 3D demos runs very choppy, i think between the trigonometric functions and the context switching of every pix() call, it's too much for the Rpi2's Arm. It would be interesting to see the performances on an Rpi3.

Btw, i'm working in single core mode, technically could use the rpi multicore to do some things in parallel but beside screen copying and input handlers there's not much to be parallelized, i don't think it's worth the effort.

All 10 comments

Have you thought about using FPGA custom chipset instead of off the shelf solution?

So i've recently seen that the tic80 codebase has been cleaned up and modularized so i gave this idea another shot

I managed to compile TIC80 with the arm toolchain by adding this file arm-gcc-toolchain.cmake and doing cmake -DCMAKE_TOOLCHAIN_FILE=arm-gcc-toolchain.cmake .
Then i was able to do make tic80core and generate the following serie of libs:

libgiflib.a liblpeg.a liblua.a libsquirrel.a libtic80core.a libwren.a

I then tryed to use them in a circle-stdlib sample, by importing tic80 includes and trying to call tic80_create().
Here the linker exploded with a serie of unresolved references. Those references are mostly to math stuff.

For what i understand (i'm no expert in c building), they may originate from the fact that circle use newlib as the standard C library instead of glibc or whatever. So TIC80 is being built against libc and circle against newlib.

I've tried to make TIC codebase use newlib but i can't understand where to modify the build files. Anybody can point me ?

Also, is it possible to compile TIC80 with just LUA and no other language? I've seen some defines in tic80_config.h but it still compiles all wren, squirrel etc.

We use only CMakeLists.txt to configure the build.
To build tic80core with only Lua, add TIC_BUILD_WITH_LUA definition and remove dependencies with other libs here https://github.com/nesbox/TIC-80/blob/master/CMakeLists.txt#L188
It should look like this

################################
# TIC-80 core
################################

set(TIC80CORE_DIR src)
set(TIC80CORE_SRC
    ${TIC80CORE_DIR}/tic80.c
    ${TIC80CORE_DIR}/tic.c 
    ${TIC80CORE_DIR}/tools.c 
    ${TIC80CORE_DIR}/luaapi.c 
    ${TIC80CORE_DIR}/ext/gif.c
    3rd-party/blip-buf/blip_buf.c # TODO: link it as lib?
)

add_library(tic80core STATIC ${TIC80CORE_SRC})

target_compile_definitions(tic80core PRIVATE TIC_BUILD_WITH_LUA)

target_include_directories(tic80core PRIVATE include)
target_include_directories(tic80core PRIVATE 3rd-party/blip-buf)
target_include_directories(tic80core PRIVATE 3rd-party/lua-5.3.1/src)
target_include_directories(tic80core PRIVATE 3rd-party/giflib-5.1.4/lib)

add_dependencies(tic80core lua giflib)
target_link_libraries(tic80core lua giflib)

if(LINUX)
    target_link_libraries(tic80core m)
endif()

Great, thank you! I'll try this evening.
Another couple questions on the architecture (i hope i can ask here):

Am i right that i can just ignore data in tic80->sound if i don't want to implement sound yet ? Looks like they're meant to be fed to the audio system.

What format is tic80->screen ? Some kind of RGBA i guess ?

Also i have to commend how clean you modularize the code, being able to compile tic80core with no dependency on any graphic libs is great

Sure, you can ignore tic80->sound

Am i right that i can just ignore data in tic80->sound if i don't want to implement sound yet ? Looks like they're meant to be fed to the audio system.

yes, RGBA

What format is tic80->screen ? Some kind of RGBA i guess ?

Guys i did it (kinda)!

You can already try something: you need a Raspberry Pi 2, just extract this into the SD and you should be ready to go. There's a cart included, but you can switch your own. Only basic input is supported (z, x and the cursors).
The palette might be off (let me know, i think it can depend on the board revision) and it's all in debug mode. Performances are ok for normal games.

(There's a small delay at start to read the debug information, the cart should start in 5 seconds)

This is just a proof of concept but the circle runtime support all that's needed (gamepad, mouse, keyboard, audio), so it's just a matter of wiring all together.

So it was surprisingly not hard to port, but i had to fight some configuration problems. Also in trying to build an optimized version i broken something and now i can't seem to build tic the correct way anymore :D Looks like CMake has a memory on its own, it remember things even after i removed all its working files?

Well let me know how it works, if anyone is interested i can post a build howto

I've set up a repo with code and instructions:

https://github.com/msx80/BareMetalTic80/

A little update on the project: i managed to get the full studio to compile, now the rpi "boots into" tic80 editor (which is pretty awesome, really feels like a console). I adjusted the rgb output, wired up keyboard support at 90%. All of the "primitive" functions in fs.c needs to be rewritten using circle custom api, i've currently done just the bare minimum to get the "load" command working, so i can now load, edit and run a cart (but no save).

I'm having some minor issue with the keyboard dropping some keypresses but i think it's just some kind of race condition on the input object, (the handler being called during the tick()). Another minor issue is some light flickering which probably just need some tuning with the order of operations and vsync. At worst i could implement a backbuffer.

I've already integrate the rather comprehensive gamepad support of Circle into the system, i just need to wire it to the input. Mouse should be straightforward.

The only big thing left to tackle is audio, the problem here is that i'm totally uninformed about how audio works in general, so it will take some time.

I tried all my games and some other carts like 8-bit panda and they all runs smooth. 3D demos runs very choppy, i think between the trigonometric functions and the context switching of every pix() call, it's too much for the Rpi2's Arm. It would be interesting to see the performances on an Rpi3.

Btw, i'm working in single core mode, technically could use the rpi multicore to do some things in parallel but beside screen copying and input handlers there's not much to be parallelized, i don't think it's worth the effort.

@msx80
Good news, thank you for keeping us informed.
As for audio, usually, it's easy, you have to open audio device with specific sample rate and copy TIC produced samples to the audio device buffer.

dup of #912

Was this page helpful?
0 / 5 - 0 ratings