0:00:00.880,0:00:04.520
hello everyone and welcome to my talk
0:00:02.879,0:00:06.960
state of retrogaming and Emacs
0:00:04.520,0:00:08.639
[Music]
0:00:06.960,0:00:12.000
first of all a little bit about myself
0:00:08.639,0:00:13.599
my name is neilman I'm 28 years old
0:00:12.000,0:00:15.200
I work as a cyber security consultant
0:00:13.599,0:00:17.440
msg systems and
0:00:15.200,0:00:19.359
test other people's web applications and
0:00:17.440,0:00:20.160
review the source code for security
0:00:19.359,0:00:22.960
problems
0:00:20.160,0:00:25.039
you can reach me by email I have my own
0:00:22.960,0:00:26.480
self-hosted git repositories
0:00:25.039,0:00:28.480
and I have a blog where you can
0:00:26.480,0:00:32.160
occasionally find new posts by me on all
0:00:28.480,0:00:34.800
kinds of things not just emix things
0:00:32.160,0:00:36.480
so but the motivation about this one I
0:00:34.800,0:00:38.079
found that Emacs is the ultimate
0:00:36.480,0:00:40.160
procrastination machine and there are
0:00:38.079,0:00:41.200
lots of fun demonstrations I'll go over
0:00:40.160,0:00:44.160
a few of them
0:00:41.200,0:00:46.079
for example someone made a thing to
0:00:44.160,0:00:48.239
order sell it for himself online so it
0:00:46.079,0:00:50.879
doesn't have to walk over to the shop
0:00:48.239,0:00:51.760
there's plenty rc bots there's some game
0:00:50.879,0:00:53.520
things
0:00:51.760,0:00:55.600
there's an emulator for the z machine
0:00:53.520,0:00:57.600
which you can use to play zorg
0:00:55.600,0:00:59.039
and so I asked myself at this point can
0:00:57.600,0:01:01.039
you actually emulate retro games at
0:00:59.039,0:01:02.800
60fps and it looked around a bit
0:01:01.039,0:01:04.479
and found some projects but none that
0:01:02.800,0:01:07.360
were actually able to
0:01:04.479,0:01:08.000
do it at 60fps so I set out to do my own
0:01:07.360,0:01:09.439
one
0:01:08.000,0:01:11.119
and looked out for a console that you
0:01:09.439,0:01:13.439
can actually emulate at that speed
0:01:11.119,0:01:14.690
using emax with its very very limited
0:01:13.439,0:01:16.320
rendering
0:01:14.690,0:01:19.520
[Music]
0:01:16.320,0:01:20.560
and here's the project chip8.el it's
0:01:19.520,0:01:22.880
pretty much finished
0:01:20.560,0:01:24.000
it clocks into under 1000 sourced lines
0:01:22.880,0:01:26.159
of code
0:01:24.000,0:01:28.080
it supports the superchip 8 extensions
0:01:26.159,0:01:30.159
it runs at full speed all games behave
0:01:28.080,0:01:32.320
okay as far as I'm concerned and
0:01:30.159,0:01:34.479
yeah I'm pretty happy with it it's very
0:01:32.320,0:01:37.040
much the hell world of emulation
0:01:34.479,0:01:40.880
and I might maybe do some other
0:01:37.040,0:01:43.360
emulation projects in the future
0:01:40.880,0:01:45.439
now for the section which is the longest
0:01:43.360,0:01:46.320
bunch of fun facts about ship a dot el
0:01:45.439,0:01:49.759
which I've learned
0:01:46.320,0:01:52.240
during this project so
0:01:49.759,0:01:54.640
what the hell is debate anyway first of
0:01:52.240,0:01:56.799
all unlike many other emulation game
0:01:54.640,0:01:58.560
things it's not a console but a vm
0:01:56.799,0:02:00.000
it was designed for easy parting of home
0:01:58.560,0:02:02.560
computer games
0:02:00.000,0:02:03.680
it wasn't terribly successful and but
0:02:02.560,0:02:04.320
there's still a small community of
0:02:03.680,0:02:06.079
enthusiasts
0:02:04.320,0:02:09.119
writing games for it and there are even
0:02:06.079,0:02:11.920
a few demos
0:02:09.119,0:02:14.720
this vm has system specs it has a very
0:02:11.920,0:02:14.959
very simple 8-bit cpu with 16 registers
0:02:14.720,0:02:17.760
and
0:02:14.959,0:02:18.160
36 fixed size instructions you have a
0:02:17.760,0:02:20.560
whole
0:02:18.160,0:02:22.080
4 kilobyte of ram you have a stack with
0:02:20.560,0:02:24.480
16 return addresses
0:02:22.080,0:02:25.760
the resolution is 64 by 32 black white
0:02:24.480,0:02:28.000
pixels
0:02:25.760,0:02:29.440
rendering is done by drawing sprites
0:02:28.000,0:02:30.160
these are drawn in excel mode meaning
0:02:29.440,0:02:32.239
that if you
0:02:30.160,0:02:33.840
draw a sprite and set a bit it just
0:02:32.239,0:02:35.040
flips over from black to white or white
0:02:33.840,0:02:36.560
to black
0:02:35.040,0:02:38.239
first one you have a modern buzz that
0:02:36.560,0:02:40.640
can just beep at one
0:02:38.239,0:02:43.120
frequency and most unusually there's a
0:02:40.640,0:02:45.360
hexadecimal keypad as input
0:02:43.120,0:02:48.160
so the keys are basically zero to nine
0:02:45.360,0:02:48.160
and a to f
0:02:48.480,0:02:52.400
so how does this whole thing work it
0:02:50.879,0:02:53.599
runs an unspecified speed
0:02:52.400,0:02:54.879
you'll probably have to do some fine
0:02:53.599,0:02:56.080
tune you find the speed you're happy
0:02:54.879,0:02:58.560
with
0:02:56.080,0:03:01.120
sound and delay timers exist they count
0:02:58.560,0:03:02.879
down at 60fps down to zero
0:03:01.120,0:03:05.120
this is done so that you can play a
0:03:02.879,0:03:06.640
sound at some specific time
0:03:05.120,0:03:08.640
the game itself is loaded with a fixed
0:03:06.640,0:03:10.480
offset into ram the program account is
0:03:08.640,0:03:11.920
set to exactly that offset
0:03:10.480,0:03:13.840
and from there it enters the game loop
0:03:11.920,0:03:15.519
where decodes and instruction executes
0:03:13.840,0:03:18.130
it for the side effects and just
0:03:15.519,0:03:19.599
loops and does this at infinitum
0:03:18.130,0:03:21.920
[Music]
0:03:19.599,0:03:23.920
so the game was the first thing where
0:03:21.920,0:03:24.239
into problems the usual game approach is
0:03:23.920,0:03:26.640
to
0:03:24.239,0:03:28.239
do stuff figure out how long to eight
0:03:26.640,0:03:30.640
wait for exactly that much and
0:03:28.239,0:03:31.680
repeat this doesn't work well in imax at
0:03:30.640,0:03:34.959
all because well
0:03:31.680,0:03:37.280
user input basically and
0:03:34.959,0:03:39.040
Emacs is designed to just do whatever it
0:03:37.280,0:03:40.080
needs to do whenever you enter use input
0:03:39.040,0:03:42.799
instead of
0:03:40.080,0:03:43.440
doing things at one specific time if you
0:03:42.799,0:03:45.040
try to do
0:03:43.440,0:03:46.640
interruptable sleep well you get
0:03:45.040,0:03:49.440
unpredictable behavior
0:03:46.640,0:03:50.959
for example can be the timer doesn't run
0:03:49.440,0:03:52.560
at all at next time because you've
0:03:50.959,0:03:54.400
accidentally cancelled it
0:03:52.560,0:03:55.760
if you do uninterruptable sleep it's
0:03:54.400,0:03:56.720
freezes instead which isn't what you
0:03:55.760,0:03:59.360
want either
0:03:56.720,0:04:00.560
so I went for timers which forced me to
0:03:59.360,0:04:02.159
do inversion of control
0:04:00.560,0:04:04.080
meaning that I have to write code in the
0:04:02.159,0:04:06.159
style where it's just call it
0:04:04.080,0:04:07.200
time and this allows this input to
0:04:06.159,0:04:09.120
happen and to
0:04:07.200,0:04:11.040
for things to progress at roughly the
0:04:09.120,0:04:12.879
speed I want to
0:04:11.040,0:04:14.159
so there's the skydiver function which
0:04:12.879,0:04:16.000
is called a 60fps
0:04:14.159,0:04:17.359
and I have to be very careful to not do
0:04:16.000,0:04:20.479
too much in it
0:04:17.359,0:04:22.960
and say this function execute cpu cycles
0:04:20.479,0:04:23.680
decrypt the sound delay registers and
0:04:22.960,0:04:27.759
redraw
0:04:23.680,0:04:28.800
the screen so to map this whole system
0:04:27.759,0:04:31.199
to mx lisp
0:04:28.800,0:04:33.120
I've used just integers and vectors
0:04:31.199,0:04:35.040
which contain even more integers
0:04:33.120,0:04:37.759
this is used for the ram registers
0:04:35.040,0:04:39.120
return stack key state screen and so on
0:04:37.759,0:04:41.520
and so forth basically
0:04:39.120,0:04:42.800
what you would do if you were writing c
0:04:41.520,0:04:44.560
all of this is stored in global
0:04:42.800,0:04:46.479
variables I'm not using any
0:04:44.560,0:04:48.400
lists at all and as a side effect
0:04:46.479,0:04:50.320
there's no constant going on at all
0:04:48.400,0:04:51.120
there are no extra objects created which
0:04:50.320,0:04:53.919
would trigger
0:04:51.120,0:04:55.840
garbage collection pulses this getting
0:04:53.919,0:04:56.720
this red was rather tricky actually and
0:04:55.840,0:04:58.560
there were some
0:04:56.720,0:05:01.680
in garbage collection problems which I
0:04:58.560,0:05:01.680
had to resolve over time
0:05:01.759,0:05:05.520
so the coding instructions for this you
0:05:04.320,0:05:06.800
have to know that all instructions are
0:05:05.520,0:05:08.880
two bytes long
0:05:06.800,0:05:10.240
and the arguments encoded inside them
0:05:08.880,0:05:11.440
for example the jump to address
0:05:10.240,0:05:15.120
instruction
0:05:11.440,0:05:18.400
is encoded as one and three hex digits
0:05:15.120,0:05:20.800
the type is extracted masking with f000
0:05:18.400,0:05:21.680
and then shifting it by 12 bits mask
0:05:20.800,0:05:24.000
means the hd
0:05:21.680,0:05:25.440
performance binary end you can do the
0:05:24.000,0:05:26.639
same with the argument basement with
0:05:25.440,0:05:29.520
zero fff
0:05:26.639,0:05:31.039
and no shift if you do this long enough
0:05:29.520,0:05:32.639
you'll find common patterns for example
0:05:31.039,0:05:35.280
addresses are always encoded like this
0:05:32.639,0:05:36.880
using the last three nibbles in the code
0:05:35.280,0:05:38.400
you'll find a big count which dispatches
0:05:36.880,0:05:40.070
on the type and executes it for the side
0:05:38.400,0:05:41.440
effects
0:05:40.070,0:05:43.440
[Music]
0:05:41.440,0:05:45.919
for testing I've initially just accused
0:05:43.440,0:05:47.280
the rom until I fit ctrl g
0:05:45.919,0:05:49.039
and then use the debug command to run
0:05:47.280,0:05:51.360
the screen to a buffer
0:05:49.039,0:05:52.320
later on I found tiny roms that just
0:05:51.360,0:05:55.680
display a static
0:05:52.320,0:05:57.280
test screen for example logo and looked
0:05:55.680,0:05:59.199
whether it looked right
0:05:57.280,0:06:00.960
I added instructions as needed and went
0:05:59.199,0:06:03.360
through more and more and more roms and
0:06:00.960,0:06:05.199
later I wrote in unit test suite as a
0:06:03.360,0:06:06.000
safety net and this unit test suite it
0:06:05.199,0:06:08.400
just
0:06:06.000,0:06:10.080
sets up an empty emulator state executes
0:06:08.400,0:06:10.400
some instructions and then looks whether
0:06:10.080,0:06:13.840
the
0:06:10.400,0:06:13.840
expected side effects have happened
0:06:14.880,0:06:19.120
for debugging I usually use e-debug but
0:06:17.120,0:06:20.880
this was super ineffective because well
0:06:19.120,0:06:22.960
you don't really want to step through
0:06:20.880,0:06:24.960
big cons doing side effects for every
0:06:22.960,0:06:26.880
single cycle when it can take like 100
0:06:24.960,0:06:29.680
cycles for things to happen
0:06:26.880,0:06:31.360
therefore I've set up logging and
0:06:29.680,0:06:32.720
whenever I locked something
0:06:31.360,0:06:33.919
and couldn't figure out the error I
0:06:32.720,0:06:37.039
compared my lock output with
0:06:33.919,0:06:39.199
instrumented version of another emulator
0:06:37.039,0:06:40.880
and if the locks diverge then I have
0:06:39.199,0:06:42.720
figured out where the bug lies and could
0:06:40.880,0:06:44.479
look deeper into it
0:06:42.720,0:06:46.639
future project idea might be a chip 8
0:06:44.479,0:06:50.720
debugger but I doubt I'll ever
0:06:46.639,0:06:52.639
go into it for analysis I initially
0:06:50.720,0:06:54.400
wrote a disassembler which is a very
0:06:52.639,0:06:56.160
simple thing but super tedious
0:06:54.400,0:06:57.599
especially if you wanted to add advanced
0:06:56.160,0:06:59.120
functionality for example analysis or
0:06:57.599,0:07:00.000
thinking of what part is data what had
0:06:59.120,0:07:01.840
this code
0:07:00.000,0:07:03.360
and I had this great idea for using the
0:07:01.840,0:07:05.120
radari 2 framework
0:07:03.360,0:07:06.479
and adding analysis and disassembly
0:07:05.120,0:07:08.400
plug-in for it
0:07:06.479,0:07:10.319
so I looked into this found okay here
0:07:08.400,0:07:12.160
where you can write plugins in c
0:07:10.319,0:07:13.520
but also in python so I wrote one in
0:07:12.160,0:07:15.039
python and then the scout there's
0:07:13.520,0:07:17.440
actually existing one in core which you
0:07:15.039,0:07:19.599
have to enable explicitly by passing its
0:07:17.440,0:07:21.840
argument so I've tried it and found it's
0:07:19.599,0:07:23.680
not exactly as good as my own one so
0:07:21.840,0:07:26.610
improved this one and submitted pull
0:07:23.680,0:07:28.080
requests until it was at the same level
0:07:26.610,0:07:30.160
[Music]
0:07:28.080,0:07:31.360
rendering was the trickiest part of this
0:07:30.160,0:07:34.319
whole thing because
0:07:31.360,0:07:35.759
well I decided against using a library
0:07:34.319,0:07:37.120
not like there would have been any
0:07:35.759,0:07:39.599
usable library for this
0:07:37.120,0:07:41.680
my usual approach of accelerating svg
0:07:39.599,0:07:45.120
file was too expensive it just created
0:07:41.680,0:07:47.360
too much garbage and took too long time
0:07:45.120,0:07:49.599
I then tried creating mutating strings
0:07:47.360,0:07:52.639
this was either either too expensive
0:07:49.599,0:07:55.039
just like svgs or too complicated I
0:07:52.639,0:07:57.280
tried changing svg tiles which created
0:07:55.039,0:07:59.520
gaps between the lines
0:07:57.280,0:08:00.720
then I tried to create an xpm file which
0:07:59.520,0:08:02.400
was backed by a bull vector
0:08:00.720,0:08:04.400
administrating this bull vector
0:08:02.400,0:08:06.879
but the image caching effect made it
0:08:04.400,0:08:10.000
just every nth frame to appear which
0:08:06.879,0:08:11.440
wasn't good either then I had the idea
0:08:10.000,0:08:13.280
to just use plain text
0:08:11.440,0:08:14.800
and paint the individual characters with
0:08:13.280,0:08:17.120
a different background color this
0:08:14.800,0:08:18.479
this had perfect perfect performance
0:08:17.120,0:08:20.000
there were many optimization attempts
0:08:18.479,0:08:21.840
until I got there and it was
0:08:20.000,0:08:23.199
very very stressful I wasn't sure
0:08:21.840,0:08:26.160
whether I would ever get to accept the
0:08:23.199,0:08:28.560
performance at all
0:08:26.160,0:08:30.319
for sound you only need to a single beep
0:08:28.560,0:08:31.280
so technically it shouldn't be difficult
0:08:30.319,0:08:33.519
to emulate it
0:08:31.280,0:08:34.880
however doing this is hard because Emacs
0:08:33.519,0:08:37.200
officially only supports synchronous
0:08:34.880,0:08:39.039
playback of sounds
0:08:37.200,0:08:41.360
but there's also emax process which you
0:08:39.039,0:08:43.519
can launch in asynchronous way
0:08:41.360,0:08:45.279
so I looked into it and found that
0:08:43.519,0:08:46.640
employee has a slave mode and mpv
0:08:45.279,0:08:50.880
supports listing on the
0:08:46.640,0:08:54.000
fifo for commands so I've created a pipe
0:08:50.880,0:08:55.519
started a past mpv in loop mode and
0:08:54.000,0:08:58.000
always send in pause and pause command
0:08:55.519,0:09:01.839
to the fifo and that way I could control
0:08:58.000,0:09:01.839
when to start beeping and stop beeping
0:09:02.640,0:09:07.200
so yeah that's it so far was a very
0:09:05.760,0:09:09.279
educational experience
0:09:07.200,0:09:10.320
I have tried out a bunch of games which
0:09:09.279,0:09:12.640
were
0:09:10.320,0:09:14.320
well I almost say the worst ports of
0:09:12.640,0:09:15.839
classic games I've ever tried
0:09:14.320,0:09:18.320
it wasn't terribly fun to play them but
0:09:15.839,0:09:21.760
was fun to improve the emulator until
0:09:18.320,0:09:23.279
well things worked good enough
0:09:21.760,0:09:25.120
and I've learned a lot about how
0:09:23.279,0:09:27.760
computers work at this level
0:09:25.120,0:09:28.880
so maybe maybe I'll in the future make
0:09:27.760,0:09:31.920
another emulator
0:09:28.880,0:09:34.000
but uh I'm not sure whether anything
0:09:31.920,0:09:36.560
more advanced like intel 8080 emulator
0:09:34.000,0:09:37.839
will actually run mix fast enough
0:09:36.560,0:09:39.200
but it's still an interesting idea
0:09:37.839,0:09:39.600
because then you could actually have an
0:09:39.200,0:09:41.680
os
0:09:39.600,0:09:43.120
inside Emacs and fulfill that one
0:09:41.680,0:09:45.440
specific meme
0:09:43.120,0:09:47.279
but if I try to do most serious stuff
0:09:45.440,0:09:48.000
I'll probably use chicken scheme which
0:09:47.279,0:09:49.920
is my
0:09:48.000,0:09:53.279
preferred language for serious projects
0:09:49.920,0:09:57.839
and writing neso gamer emulator
0:09:53.279,0:09:57.839
and that's it thank you