summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--2020/info/27.md218
-rw-r--r--2020/organizers-notebook.org4
-rw-r--r--2020/subtitles/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8--vasilij-wasamasa-schneidermann-autogen.vtt913
-rw-r--r--2020/subtitles/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8--vasilij-wasamasa-schneidermann.vtt630
4 files changed, 848 insertions, 917 deletions
diff --git a/2020/info/27.md b/2020/info/27.md
index bc19e6c2..f2df923a 100644
--- a/2020/info/27.md
+++ b/2020/info/27.md
@@ -1,8 +1,9 @@
# State of Retro Gaming in Emacs
Vasilij "wasamasa" Schneidermann
-[[!template id=vid src="https://mirror.csclub.uwaterloo.ca/emacsconf/2020/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8--vasilij-wasamasa-schneidermann.webm"]]
-[Download compressed .webm video (7.2M)](https://mirror.csclub.uwaterloo.ca/emacsconf/2020/smaller/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8--vasilij-wasamasa-schneidermann--vp9-q56-video-original-audio.webm)
+[[!template vidid=mainVideo id=vid src="https://mirror.csclub.uwaterloo.ca/emacsconf/2020/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8--vasilij-wasamasa-schneidermann.webm"subtitles="/2020/subtitles/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8--vasilij-wasamasa-schneidermann.vtt"]]
+[Download compressed .webm video (7.2M)](https://mirror.csclub.uwaterloo.ca/emacsconf/2020/smaller/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8--vasilij-wasamasa-schneidermann--vp9-q56-video-original-audio.webm)
+[View transcript](#transcript)
- [chip8 demo - alien, .webm video, 720p, 2M](https://mirror.csclub.uwaterloo.ca/emacsconf/2020/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8-demo-alien--vasilij-wasamasa-schneidermann.webm)
- [chip8 demo - brix, .webm video, 720p, 1M](https://mirror.csclub.uwaterloo.ca/emacsconf/2020/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8-demo-brix--vasilij-wasamasa-schneidermann.webm)
@@ -71,3 +72,216 @@ constraints.
- Repository available at <https://depp.brause.cc/chip8.el/>.
- Blog post available at
<https://emacsninja.com/posts/smooth-video-game-emulation-in-emacs.html>.
+
+<a name="transcript"></a>
+# Transcript
+
+[[!template new="1" text="Hello everyone and welcome to my talk, &quot;The State of Retro Gaming and Emacs.&quot;" start="00:00:00.880" video="mainVideo" id=subtitle]]
+[[!template text="First of all, a little bit about myself." start="00:00:06.960" video="mainVideo" id=subtitle]]
+[[!template text="My name is Vasilij Schneidermann. I'm 28 years old." start="00:00:08.639" video="mainVideo" id=subtitle]]
+[[!template text="I work as a cyber security consultant at msg systems," start="00:00:12.000" video="mainVideo" id=subtitle]]
+[[!template text="and test other people's web applications" start="00:00:14.719" video="mainVideo" id=subtitle]]
+[[!template text="and review the source code for security problems." start="00:00:17.359" video="mainVideo" id=subtitle]]
+[[!template text="You can reach me by email." start="00:00:20.160" video="mainVideo" id=subtitle]]
+[[!template text="I have my own self-hosted git repositories," start="00:00:22.080" video="mainVideo" id=subtitle]]
+[[!template text="and I have a blog where you can occasionally find new posts by me" start="00:00:25.039" video="mainVideo" id=subtitle]]
+[[!template text="on all kinds of things, not just Emacs things." start="00:00:28.160" video="mainVideo" id=subtitle]]
+[[!template new="1" text="The motivation about this one..." start="00:00:32.160" video="mainVideo" id=subtitle]]
+[[!template text="I found that Emacs is the ultimate procrastination machine," start="00:00:34.559" video="mainVideo" id=subtitle]]
+[[!template text="and there are lots of fun demonstrations." start="00:00:37.600" video="mainVideo" id=subtitle]]
+[[!template text="I'll go over a few of them." start="00:00:39.600" video="mainVideo" id=subtitle]]
+[[!template text="For example, someone made a thing to order salad for himself online," start="00:00:41.200" video="mainVideo" id=subtitle]]
+[[!template text="so he doesn't have to walk over to the shop." start="00:00:45.840" video="mainVideo" id=subtitle]]
+[[!template text="There's plenty of IRC bots. There's some game things." start="00:00:48.239" video="mainVideo" id=subtitle]]
+[[!template text="There's an emulator for the Z-machine which you can use to play zork." start="00:00:51.760" video="mainVideo" id=subtitle]]
+[[!template new="1" text="And so I asked myself, at this point," start="00:00:55.600" video="mainVideo" id=subtitle]]
+[[!template text="can you actually emulate retro games at 60fps?" start="00:00:57.440" video="mainVideo" id=subtitle]]
+[[!template text="I looked around a bit and found some projects," start="00:00:59.920" video="mainVideo" id=subtitle]]
+[[!template text="but none that were actually able to do it at 60fps." start="00:01:02.079" video="mainVideo" id=subtitle]]
+[[!template text="So I set out to do my own one," start="00:01:06.159" video="mainVideo" id=subtitle]]
+[[!template text="and looked out for a console" start="00:01:08.000" video="mainVideo" id=subtitle]]
+[[!template text="that you can actually emulate at that speed," start="00:01:09.200" video="mainVideo" id=subtitle]]
+[[!template text="using Emacs with its very, very limited rendering." start="00:01:11.119" video="mainVideo" id=subtitle]]
+[[!template new="1" text="And here's the project, chip8.el." start="00:01:16.320" video="mainVideo" id=subtitle]]
+[[!template text="It's pretty much finished." start="00:01:19.200" video="mainVideo" id=subtitle]]
+[[!template text="It clocks into under 1000 source lines of code." start="00:01:20.560" video="mainVideo" id=subtitle]]
+[[!template text="It supports the superchip 8 extensions." start="00:01:24.000" video="mainVideo" id=subtitle]]
+[[!template text="It runs at full speed." start="00:01:26.159" video="mainVideo" id=subtitle]]
+[[!template text="All games behave okay, as far as I'm concerned," start="00:01:27.280" video="mainVideo" id=subtitle]]
+[[!template text="and yeah, I'm pretty happy with it." start="00:01:29.600" video="mainVideo" id=subtitle]]
+[[!template text="It's very much the hello world of emulation," start="00:01:31.680" video="mainVideo" id=subtitle]]
+[[!template text="and I might, maybe, do some other emulation projects in the future." start="00:01:34.479" video="mainVideo" id=subtitle]]
+[[!template new="1" text="Now, for the section which is the longest:" start="00:01:40.880" video="mainVideo" id=subtitle]]
+[[!template text="bunch of fun facts about chip8.el" start="00:01:43.360" video="mainVideo" id=subtitle]]
+[[!template text="which I've learned during this project." start="00:01:45.439" video="mainVideo" id=subtitle]]
+[[!template text="So what the hell is chip8 anyway?" start="00:01:49.200" video="mainVideo" id=subtitle]]
+[[!template text="First of all, unlike many other emulation game things," start="00:01:51.759" video="mainVideo" id=subtitle]]
+[[!template text="it's not a console, but a VM." start="00:01:54.960" video="mainVideo" id=subtitle]]
+[[!template text="It was designed for easy porting of home computer games." start="00:01:56.799" video="mainVideo" id=subtitle]]
+[[!template text="It wasn't terribly successful," start="00:02:00.000" video="mainVideo" id=subtitle]]
+[[!template text="but there's still a small community of enthusiasts writing games for it," start="00:02:02.320" video="mainVideo" id=subtitle]]
+[[!template text="and there are even a few demos." start="00:02:05.439" video="mainVideo" id=subtitle]]
+[[!template text="This VM has system specs." start="00:02:09.119" video="mainVideo" id=subtitle]]
+[[!template text="It has a very, very simple 8-bit cpu with 16 registers," start="00:02:11.039" video="mainVideo" id=subtitle]]
+[[!template text="and 36 fixed-size instructions." start="00:02:14.720" video="mainVideo" id=subtitle]]
+[[!template text="You have a whole 4 kilobyte of RAM." start="00:02:17.280" video="mainVideo" id=subtitle]]
+[[!template text="You have a stack with 16 return addresses." start="00:02:19.680" video="mainVideo" id=subtitle]]
+[[!template text="The resolution is 64 by 32 black/white pixels." start="00:02:22.080" video="mainVideo" id=subtitle]]
+[[!template new="1" text="Rendering is done by drawing sprites." start="00:02:25.760" video="mainVideo" id=subtitle]]
+[[!template text="These are drawn in XOR mode," start="00:02:28.000" video="mainVideo" id=subtitle]]
+[[!template text="meaning that if you draw a sprite and set a bit," start="00:02:29.200" video="mainVideo" id=subtitle]]
+[[!template text="it just flips over from black to white or white to black." start="00:02:31.840" video="mainVideo" id=subtitle]]
+[[!template text="For sound, you have a monotone buzzer that can just beep at one frequency." start="00:02:35.040" video="mainVideo" id=subtitle]]
+[[!template text="Most unusually, there's a hexadecimal keypad as input," start="00:02:39.360" video="mainVideo" id=subtitle]]
+[[!template text="so the keys are basically zero to nine and a to f." start="00:02:43.120" video="mainVideo" id=subtitle]]
+[[!template text="So how does this whole thing work?" start="00:02:48.480" video="mainVideo" id=subtitle]]
+[[!template text="It runs at an unspecified speed." start="00:02:50.720" video="mainVideo" id=subtitle]]
+[[!template text="You'll probably have to do some fine-tuning" start="00:02:52.400" video="mainVideo" id=subtitle]]
+[[!template text="to find the speed you're happy with." start="00:02:53.040" video="mainVideo" id=subtitle]]
+[[!template new="1" text="Sound and delay timers exist." start="00:02:56.080" video="mainVideo" id=subtitle]]
+[[!template text="They count down at 60fps down to 0." start="00:02:58.080" video="mainVideo" id=subtitle]]
+[[!template text="This is done so that you can play a sound at some specific time." start="00:03:01.120" video="mainVideo" id=subtitle]]
+[[!template text="The game itself is loaded with a fixed offset into RAM." start="00:03:05.120" video="mainVideo" id=subtitle]]
+[[!template text="The program counter is set to exactly that offset," start="00:03:07.840" video="mainVideo" id=subtitle]]
+[[!template text="and from there it enters the game loop" start="00:03:10.480" video="mainVideo" id=subtitle]]
+[[!template text="where it decodes an instruction," start="00:03:11.920" video="mainVideo" id=subtitle]]
+[[!template text="executes it for the side effects," start="00:03:13.280" video="mainVideo" id=subtitle]]
+[[!template text="and just loops and does this ad infinitum." start="00:03:14.800" video="mainVideo" id=subtitle]]
+[[!template new="1" text="So the game loop was the first thing where we ran into problems." start="00:03:19.599" video="mainVideo" id=subtitle]]
+[[!template text="The usual game approach is to do stuff," start="00:03:22.720" video="mainVideo" id=subtitle]]
+[[!template text="figure out how long to wait," start="00:03:25.120" video="mainVideo" id=subtitle]]
+[[!template text="wait for exactly that much, and repeat." start="00:03:26.640" video="mainVideo" id=subtitle]]
+[[!template text="This doesn't work well in Emacs at all, because, well," start="00:03:29.280" video="mainVideo" id=subtitle]]
+[[!template text="user input, basically." start="00:03:31.680" video="mainVideo" id=subtitle]]
+[[!template text="Emacs is designed to just do whatever it needs to do" start="00:03:34.959" video="mainVideo" id=subtitle]]
+[[!template text="whenever you enter user input" start="00:03:37.760" video="mainVideo" id=subtitle]]
+[[!template text="instead of doing things at one specific time." start="00:03:39.040" video="mainVideo" id=subtitle]]
+[[!template text="If you try to do interruptable sleep, well, you get unpredictable behavior." start="00:03:42.319" video="mainVideo" id=subtitle]]
+[[!template text="For example, it can be the timer doesn't run at all at the next time" start="00:03:46.640" video="mainVideo" id=subtitle]]
+[[!template text="because you've accidentally cancelled it." start="00:03:50.480" video="mainVideo" id=subtitle]]
+[[!template text="If you do uninterruptable sleep, it freezes instead ," start="00:03:52.560" video="mainVideo" id=subtitle]]
+[[!template text="which isn't what we want either." start="00:03:55.120" video="mainVideo" id=subtitle]]
+[[!template new="1" text="So I went for timers, which forced me to do inversion of control," start="00:03:56.720" video="mainVideo" id=subtitle]]
+[[!template text="meaning that I have to write code in the style" start="00:04:00.560" video="mainVideo" id=subtitle]]
+[[!template text="where it just calls timer," start="00:04:02.560" video="mainVideo" id=subtitle]]
+[[!template text="and this allows this input to happen" start="00:04:04.879" video="mainVideo" id=subtitle]]
+[[!template text="and for things to progress at roughly the speed I want to." start="00:04:06.560" video="mainVideo" id=subtitle]]
+[[!template text="So there's the timer function which is called at 60fps" start="00:04:11.040" video="mainVideo" id=subtitle]]
+[[!template text="and I have to be very careful to not do too much in it." start="00:04:14.159" video="mainVideo" id=subtitle]]
+[[!template text="And, say, this function executes CPU cycles," start="00:04:17.359" video="mainVideo" id=subtitle]]
+[[!template text="decrement the sound/delay registers, and redraw the screen." start="00:04:21.305" video="mainVideo" id=subtitle]]
+[[!template new="1" text="So to map this whole system to Emacs Lisp," start="00:04:26.479" video="mainVideo" id=subtitle]]
+[[!template text="I've used just integers and vectors" start="00:04:28.800" video="mainVideo" id=subtitle]]
+[[!template text="which contain even more integers." start="00:04:31.199" video="mainVideo" id=subtitle]]
+[[!template text="This is used for the RAM, registers," start="00:04:33.120" video="mainVideo" id=subtitle]]
+[[!template text="return stack, key state, screen," start="00:04:35.040" video="mainVideo" id=subtitle]]
+[[!template text="and so on and so forth." start="00:04:37.040" video="mainVideo" id=subtitle]]
+[[!template text="Basically, what you would do if you were writing C." start="00:04:38.508" video="mainVideo" id=subtitle]]
+[[!template text="All of this is stored in global variables." start="00:04:41.520" video="mainVideo" id=subtitle]]
+[[!template text="I'm not using any lists at all." start="00:04:43.360" video="mainVideo" id=subtitle]]
+[[!template text="As a side effect, there's no consing going on at all." start="00:04:45.600" video="mainVideo" id=subtitle]]
+[[!template text="There are no extra objects created" start="00:04:48.400" video="mainVideo" id=subtitle]]
+[[!template text="which would trigger garbage collection processes." start="00:04:50.080" video="mainVideo" id=subtitle]]
+[[!template text="Getting this right was rather tricky, actually," start="00:04:53.199" video="mainVideo" id=subtitle]]
+[[!template text="and there were some hidden garbage collection problems" start="00:04:55.600" video="mainVideo" id=subtitle]]
+[[!template text="which I had to resolve over time." start="00:04:58.240" video="mainVideo" id=subtitle]]
+[[!template new="1" text="So, decoding instructions." start="00:05:01.759" video="mainVideo" id=subtitle]]
+[[!template text="For this, you have to know that all instructions are two bytes long," start="00:05:03.759" video="mainVideo" id=subtitle]]
+[[!template text="and the arguments are encoded inside them." start="00:05:06.800" video="mainVideo" id=subtitle]]
+[[!template text="For example, the jump to address instruction" start="00:05:08.880" video="mainVideo" id=subtitle]]
+[[!template text="is encoded as one and three hex digits." start="00:05:11.440" video="mainVideo" id=subtitle]]
+[[!template text="The type is extracted masking with #xF000" start="00:05:15.120" video="mainVideo" id=subtitle]]
+[[!template text="and then shifting it by 12 bits." start="00:05:18.400" video="mainVideo" id=subtitle]]
+[[!template text="Mask means you perform the binary AND." start="00:05:20.400" video="mainVideo" id=subtitle]]
+[[!template text="You can do the same with the argument by masking with #0xFFF and no shift." start="00:05:23.520" video="mainVideo" id=subtitle]]
+[[!template text="If you do this long enough, you'll find common patterns." start="00:05:28.400" video="mainVideo" id=subtitle]]
+[[!template text="For example, addresses are always encoded like this" start="00:05:30.560" video="mainVideo" id=subtitle]]
+[[!template text="using the last three nibbles." start="00:05:32.639" video="mainVideo" id=subtitle]]
+[[!template text="In the code, you'll find a big cond" start="00:05:34.880" video="mainVideo" id=subtitle]]
+[[!template text="which dispatches on the type and executes it for the side effects." start="00:05:36.160" video="mainVideo" id=subtitle]]
+[[!template new="1" text="For testing, I've initially just executed the ROM until I've hit C-g," start="00:05:41.440" video="mainVideo" id=subtitle]]
+[[!template text="and then use the debug command to render the screen to a buffer." start="00:05:45.919" video="mainVideo" id=subtitle]]
+[[!template text="Later on, I found tiny ROMs that just display a static test screen," start="00:05:49.039" video="mainVideo" id=subtitle]]
+[[!template text="for example, logo, and looked whether it looked right." start="00:05:53.199" video="mainVideo" id=subtitle]]
+[[!template text="I added instructions as needed" start="00:05:57.280" video="mainVideo" id=subtitle]]
+[[!template text="and went through more and more and more ROMs." start="00:05:58.800" video="mainVideo" id=subtitle]]
+[[!template text="And later I wrote a unit test suite as a safety net." start="00:06:00.720" video="mainVideo" id=subtitle]]
+[[!template text="This unit test suite, it just sets up an empty emulator state," start="00:06:04.000" video="mainVideo" id=subtitle]]
+[[!template text="executes some instructions," start="00:06:07.840" video="mainVideo" id=subtitle]]
+[[!template text="and then looks whether the expected side effects have happened." start="00:06:09.199" video="mainVideo" id=subtitle]]
+[[!template new="1" text="For debugging, I usually use edebug, but this was super ineffective," start="00:06:14.880" video="mainVideo" id=subtitle]]
+[[!template text="because, well, you don't really want to step through big cons" start="00:06:18.319" video="mainVideo" id=subtitle]]
+[[!template text="doing side effects for every single cycle," start="00:06:21.600" video="mainVideo" id=subtitle]]
+[[!template text="when it can take like 100 cycles for things to happen." start="00:06:23.680" video="mainVideo" id=subtitle]]
+[[!template text="Therefore I've set up logging." start="00:06:26.880" video="mainVideo" id=subtitle]]
+[[!template text="Whenever I logged something and couldn't figure out the error," start="00:06:29.680" video="mainVideo" id=subtitle]]
+[[!template text="I compared my log output with the instrumented version of another emulator," start="00:06:32.639" video="mainVideo" id=subtitle]]
+[[!template text="and if the logs diverge, then I have figured out where the bug lies" start="00:06:37.039" video="mainVideo" id=subtitle]]
+[[!template text="and could look deeper into it." start="00:06:40.479" video="mainVideo" id=subtitle]]
+[[!template text="Future project idea might be a chip 8 debugger," start="00:06:42.720" video="mainVideo" id=subtitle]]
+[[!template text="but I doubt I'll ever go into it." start="00:06:44.960" video="mainVideo" id=subtitle]]
+[[!template new="1" text="For analysis, I initially wrote a disassembler," start="00:06:49.440" video="mainVideo" id=subtitle]]
+[[!template text="which is a very simple thing but super tedious," start="00:06:51.759" video="mainVideo" id=subtitle]]
+[[!template text="especially if you wanted to add advanced functionality," start="00:06:54.400" video="mainVideo" id=subtitle]]
+[[!template text="for example, analysis or thinking of what part is data," start="00:06:56.639" video="mainVideo" id=subtitle]]
+[[!template text="what part is code." start="00:06:58.720" video="mainVideo" id=subtitle]]
+[[!template text="I had this great idea for using the radare 2 framework" start="00:07:00.000" video="mainVideo" id=subtitle]]
+[[!template text="and adding analysis and disassembly plug-in for it." start="00:07:03.360" video="mainVideo" id=subtitle]]
+[[!template text="So I looked into this. Found, okay," start="00:07:06.479" video="mainVideo" id=subtitle]]
+[[!template text="you can write plugins in C" start="00:07:08.400" video="mainVideo" id=subtitle]]
+[[!template text="but also in Python, so I wrote one in Python," start="00:07:10.319" video="mainVideo" id=subtitle]]
+[[!template text="and then discovered there's actually an existing one in core," start="00:07:12.639" video="mainVideo" id=subtitle]]
+[[!template text="which you have to enable explicitly by passing an extra argument." start="00:07:14.720" video="mainVideo" id=subtitle]]
+[[!template text="I've tried it and found it's not exactly as good as my own one," start="00:07:18.400" video="mainVideo" id=subtitle]]
+[[!template text="so I improved this one and submitted pull requests" start="00:07:21.680" video="mainVideo" id=subtitle]]
+[[!template text="until it was at the same level." start="00:07:24.160" video="mainVideo" id=subtitle]]
+[[!template new="1" text="Rendering was the trickiest part of this whole thing," start="00:07:28.080" video="mainVideo" id=subtitle]]
+[[!template text="because, well, I decided against using a library." start="00:07:30.720" video="mainVideo" id=subtitle]]
+[[!template text="Not like there would have been any usable library for this." start="00:07:34.319" video="mainVideo" id=subtitle]]
+[[!template text="My usual approach of creating SVG files was too expensive." start="00:07:37.120" video="mainVideo" id=subtitle]]
+[[!template text="It just created too much garbage and took too long time." start="00:07:40.880" video="mainVideo" id=subtitle]]
+[[!template text="I then tried creating mutating strings." start="00:07:45.120" video="mainVideo" id=subtitle]]
+[[!template text="This was either too expensive, just like SVGs, or too complicated." start="00:07:47.360" video="mainVideo" id=subtitle]]
+[[!template text="I tried changing SVG tiles, which created gaps between the lines." start="00:07:52.479" video="mainVideo" id=subtitle]]
+[[!template text="Then I tried to create an xpm file which was backed by a bool vector" start="00:07:57.280" video="mainVideo" id=subtitle]]
+[[!template text="and mutating this bool vector," start="00:08:00.720" video="mainVideo" id=subtitle]]
+[[!template text="but the image caching effect" start="00:08:02.400" video="mainVideo" id=subtitle]]
+[[!template text="made it just every nth frame to appear," start="00:08:04.000" video="mainVideo" id=subtitle]]
+[[!template text="which wasn't good either." start="00:08:06.479" video="mainVideo" id=subtitle]]
+[[!template text="Then I had the idea to just use plain text" start="00:08:08.879" video="mainVideo" id=subtitle]]
+[[!template text="and paint the individual characters" start="00:08:11.440" video="mainVideo" id=subtitle]]
+[[!template text="with a different background color." start="00:08:13.120" video="mainVideo" id=subtitle]]
+[[!template text="This had perfect, perfect performance." start="00:08:14.800" video="mainVideo" id=subtitle]]
+[[!template text="There were many optimization attempts until I got there," start="00:08:17.120" video="mainVideo" id=subtitle]]
+[[!template text="and it was very, very stressful." start="00:08:19.280" video="mainVideo" id=subtitle]]
+[[!template text="I wasn't sure whether I would ever get to accept the performance at all." start="00:08:21.199" video="mainVideo" id=subtitle]]
+[[!template new="1" text="For sound, you only need to do a single beep," start="00:08:26.160" video="mainVideo" id=subtitle]]
+[[!template text="so technically, it shouldn't be difficult to emulate it." start="00:08:28.560" video="mainVideo" id=subtitle]]
+[[!template text="However, doing this is hard because" start="00:08:31.280" video="mainVideo" id=subtitle]]
+[[!template text="Emacs officially only supports synchronous playback of sounds." start="00:08:33.039" video="mainVideo" id=subtitle]]
+[[!template text="But there's also Emacs process, which you can launch in asynchronous way." start="00:08:37.200" video="mainVideo" id=subtitle]]
+[[!template text="So I looked into it and found that mplayer has a slave mode" start="00:08:41.360" video="mainVideo" id=subtitle]]
+[[!template text="and mpv supports listing on the fifo for commands." start="00:08:44.720" video="mainVideo" id=subtitle]]
+[[!template text="So I've created a pipe, started a paused MPV in loop mode," start="00:08:48.640" video="mainVideo" id=subtitle]]
+[[!template text="and always send in pause and unpause command to the FIFO," start="00:08:53.760" video="mainVideo" id=subtitle]]
+[[!template text="and that way I could control" start="00:08:56.560" video="mainVideo" id=subtitle]]
+[[!template text="when to start beeping and stop beeping." start="00:08:58.000" video="mainVideo" id=subtitle]]
+[[!template new="1" text="So yeah, that's it so far." start="00:09:02.640" video="mainVideo" id=subtitle]]
+[[!template text="It was a very educational experience." start="00:09:04.160" video="mainVideo" id=subtitle]]
+[[!template text="I have tried out a bunch of games which were," start="00:09:07.200" video="mainVideo" id=subtitle]]
+[[!template text="well, I almost say the worst ports of classic games I've ever tried." start="00:09:10.320" video="mainVideo" id=subtitle]]
+[[!template text="It wasn't terribly fun to play them," start="00:09:14.320" video="mainVideo" id=subtitle]]
+[[!template text="but was fun to improve the emulator" start="00:09:15.680" video="mainVideo" id=subtitle]]
+[[!template text="until, well, things worked good enough." start="00:09:18.555" video="mainVideo" id=subtitle]]
+[[!template text="I've learned a lot about how computers work at this level," start="00:09:21.760" video="mainVideo" id=subtitle]]
+[[!template text="so, maybe, maybe I'll in the future make another emulator," start="00:09:25.120" video="mainVideo" id=subtitle]]
+[[!template text="but I'm not sure whether anything more advanced, like an Intel 8080 emulator," start="00:09:28.880" video="mainVideo" id=subtitle]]
+[[!template text="will actually run in Emacs fast enough," start="00:09:34.000" video="mainVideo" id=subtitle]]
+[[!template text="but it's still an interesting idea," start="00:09:36.560" video="mainVideo" id=subtitle]]
+[[!template text="because then you could actually have an OS inside Emacs" start="00:09:37.839" video="mainVideo" id=subtitle]]
+[[!template text="and fulfill that one specific meme." start="00:09:40.800" video="mainVideo" id=subtitle]]
+[[!template text="But if I try to do most serious stuff," start="00:09:43.120" video="mainVideo" id=subtitle]]
+[[!template text="I'll probably use Chicken Scheme," start="00:09:45.440" video="mainVideo" id=subtitle]]
+[[!template text="which is my preferred language for serious projects," start="00:09:47.040" video="mainVideo" id=subtitle]]
+[[!template text="and write a NES game emulator." start="00:09:49.920" video="mainVideo" id=subtitle]]
+[[!template text="And that's it. Thank you." start="00:09:53.279" video="mainVideo" id=subtitle]]
diff --git a/2020/organizers-notebook.org b/2020/organizers-notebook.org
index b8b5f6d1..33a6118a 100644
--- a/2020/organizers-notebook.org
+++ b/2020/organizers-notebook.org
@@ -55,8 +55,8 @@ I modified the =subed= package to work with VTT files. The modified version is a
- [X] sachac [[./subtitles/emacsconf-2020--25-traverse-complex-json-structures-with-live-feedback-counsel-jq--zen-monk-alain-m-lafon-autogen.vtt]]
- [X] sachac [[./subtitles/emacsconf-2020--26-emacs-as-a-highschooler-how-it-changed-my-life--pierce-wang-autogen.vtt]]
- [ ] [[./subtitles/emacsconf-2020--26-emacs-as-a-highschooler-how-it-changed-my-life--questions--pierce-wang-autogen.vtt]]
-- [ ] sachac [[./subtitles/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8--vasilij-wasamasa-schneidermann-autogen.vtt]]
-- [ ] [[./subtitles/emacsconf-2020--28-welcome-to-the-dungeon--erik-elmshauser-corwin-brust-autogen.vtt]]
+- [X] sachac [[./subtitles/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8--vasilij-wasamasa-schneidermann-autogen.vtt]]
+- [ ] sachac [[./subtitles/emacsconf-2020--28-welcome-to-the-dungeon--erik-elmshauser-corwin-brust-autogen.vtt]]
- [ ] [[./subtitles/emacsconf-2020--30-a-tour-of-vterm--gabriele-bozzola-sbozzolo-autogen.vtt]]
- [ ] [[./subtitles/emacsconf-2020--30-a-tour-of-vterm--questions--gabriele-bozzola-sbozzolo-autogen.vtt]]
- [ ] [[./subtitles/emacsconf-2020--31-lakota-language-and-emacs--grant-shangreaux-autogen.vtt]]
diff --git a/2020/subtitles/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8--vasilij-wasamasa-schneidermann-autogen.vtt b/2020/subtitles/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8--vasilij-wasamasa-schneidermann-autogen.vtt
deleted file mode 100644
index 1d41f1e5..00000000
--- a/2020/subtitles/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8--vasilij-wasamasa-schneidermann-autogen.vtt
+++ /dev/null
@@ -1,913 +0,0 @@
-WEBVTT
-
-00:00:00.880 --> 00:00:02.879
-hello everyone and welcome to my talk
-
-00:00:02.879 --> 00:00:04.520
-state of retrogaming and Emacs
-
-00:00:04.520 --> 00:00:06.960
-[Music]
-
-00:00:06.960 --> 00:00:08.639
-first of all a little bit about myself
-
-00:00:08.639 --> 00:00:12.000
-my name is neilman I'm 28 years old
-
-00:00:12.000 --> 00:00:13.599
-I work as a cyber security consultant
-
-00:00:13.599 --> 00:00:15.200
-msg systems and
-
-00:00:15.200 --> 00:00:17.440
-test other people's web applications and
-
-00:00:17.440 --> 00:00:19.359
-review the source code for security
-
-00:00:19.359 --> 00:00:20.160
-problems
-
-00:00:20.160 --> 00:00:22.960
-you can reach me by email I have my own
-
-00:00:22.960 --> 00:00:25.039
-self-hosted git repositories
-
-00:00:25.039 --> 00:00:26.480
-and I have a blog where you can
-
-00:00:26.480 --> 00:00:28.480
-occasionally find new posts by me on all
-
-00:00:28.480 --> 00:00:32.160
-kinds of things not just emix things
-
-00:00:32.160 --> 00:00:34.800
-so but the motivation about this one I
-
-00:00:34.800 --> 00:00:36.480
-found that Emacs is the ultimate
-
-00:00:36.480 --> 00:00:38.079
-procrastination machine and there are
-
-00:00:38.079 --> 00:00:40.160
-lots of fun demonstrations I'll go over
-
-00:00:40.160 --> 00:00:41.200
-a few of them
-
-00:00:41.200 --> 00:00:44.160
-for example someone made a thing to
-
-00:00:44.160 --> 00:00:46.079
-order sell it for himself online so it
-
-00:00:46.079 --> 00:00:48.239
-doesn't have to walk over to the shop
-
-00:00:48.239 --> 00:00:50.879
-there's plenty rc bots there's some game
-
-00:00:50.879 --> 00:00:51.760
-things
-
-00:00:51.760 --> 00:00:53.520
-there's an emulator for the z machine
-
-00:00:53.520 --> 00:00:55.600
-which you can use to play zorg
-
-00:00:55.600 --> 00:00:57.600
-and so I asked myself at this point can
-
-00:00:57.600 --> 00:00:59.039
-you actually emulate retro games at
-
-00:00:59.039 --> 00:01:01.039
-60fps and it looked around a bit
-
-00:01:01.039 --> 00:01:02.800
-and found some projects but none that
-
-00:01:02.800 --> 00:01:04.479
-were actually able to
-
-00:01:04.479 --> 00:01:07.360
-do it at 60fps so I set out to do my own
-
-00:01:07.360 --> 00:01:08.000
-one
-
-00:01:08.000 --> 00:01:09.439
-and looked out for a console that you
-
-00:01:09.439 --> 00:01:11.119
-can actually emulate at that speed
-
-00:01:11.119 --> 00:01:13.439
-using emax with its very very limited
-
-00:01:13.439 --> 00:01:14.690
-rendering
-
-00:01:14.690 --> 00:01:16.320
-[Music]
-
-00:01:16.320 --> 00:01:19.520
-and here's the project chip8.el it's
-
-00:01:19.520 --> 00:01:20.560
-pretty much finished
-
-00:01:20.560 --> 00:01:22.880
-it clocks into under 1000 sourced lines
-
-00:01:22.880 --> 00:01:24.000
-of code
-
-00:01:24.000 --> 00:01:26.159
-it supports the superchip 8 extensions
-
-00:01:26.159 --> 00:01:28.080
-it runs at full speed all games behave
-
-00:01:28.080 --> 00:01:30.159
-okay as far as I'm concerned and
-
-00:01:30.159 --> 00:01:32.320
-yeah I'm pretty happy with it it's very
-
-00:01:32.320 --> 00:01:34.479
-much the hell world of emulation
-
-00:01:34.479 --> 00:01:37.040
-and I might maybe do some other
-
-00:01:37.040 --> 00:01:40.880
-emulation projects in the future
-
-00:01:40.880 --> 00:01:43.360
-now for the section which is the longest
-
-00:01:43.360 --> 00:01:45.439
-bunch of fun facts about ship a dot el
-
-00:01:45.439 --> 00:01:46.320
-which I've learned
-
-00:01:46.320 --> 00:01:49.759
-during this project so
-
-00:01:49.759 --> 00:01:52.240
-what the hell is debate anyway first of
-
-00:01:52.240 --> 00:01:54.640
-all unlike many other emulation game
-
-00:01:54.640 --> 00:01:56.799
-things it's not a console but a vm
-
-00:01:56.799 --> 00:01:58.560
-it was designed for easy parting of home
-
-00:01:58.560 --> 00:02:00.000
-computer games
-
-00:02:00.000 --> 00:02:02.560
-it wasn't terribly successful and but
-
-00:02:02.560 --> 00:02:03.680
-there's still a small community of
-
-00:02:03.680 --> 00:02:04.320
-enthusiasts
-
-00:02:04.320 --> 00:02:06.079
-writing games for it and there are even
-
-00:02:06.079 --> 00:02:09.119
-a few demos
-
-00:02:09.119 --> 00:02:11.920
-this vm has system specs it has a very
-
-00:02:11.920 --> 00:02:14.720
-very simple 8-bit cpu with 16 registers
-
-00:02:14.720 --> 00:02:14.959
-and
-
-00:02:14.959 --> 00:02:17.760
-36 fixed size instructions you have a
-
-00:02:17.760 --> 00:02:18.160
-whole
-
-00:02:18.160 --> 00:02:20.560
-4 kilobyte of ram you have a stack with
-
-00:02:20.560 --> 00:02:22.080
-16 return addresses
-
-00:02:22.080 --> 00:02:24.480
-the resolution is 64 by 32 black white
-
-00:02:24.480 --> 00:02:25.760
-pixels
-
-00:02:25.760 --> 00:02:28.000
-rendering is done by drawing sprites
-
-00:02:28.000 --> 00:02:29.440
-these are drawn in excel mode meaning
-
-00:02:29.440 --> 00:02:30.160
-that if you
-
-00:02:30.160 --> 00:02:32.239
-draw a sprite and set a bit it just
-
-00:02:32.239 --> 00:02:33.840
-flips over from black to white or white
-
-00:02:33.840 --> 00:02:35.040
-to black
-
-00:02:35.040 --> 00:02:36.560
-first one you have a modern buzz that
-
-00:02:36.560 --> 00:02:38.239
-can just beep at one
-
-00:02:38.239 --> 00:02:40.640
-frequency and most unusually there's a
-
-00:02:40.640 --> 00:02:43.120
-hexadecimal keypad as input
-
-00:02:43.120 --> 00:02:45.360
-so the keys are basically zero to nine
-
-00:02:45.360 --> 00:02:48.480
-and a to f
-
-00:02:48.480 --> 00:02:50.879
-so how does this whole thing work it
-
-00:02:50.879 --> 00:02:52.400
-runs an unspecified speed
-
-00:02:52.400 --> 00:02:53.599
-you'll probably have to do some fine
-
-00:02:53.599 --> 00:02:54.879
-tune you find the speed you're happy
-
-00:02:54.879 --> 00:02:56.080
-with
-
-00:02:56.080 --> 00:02:58.560
-sound and delay timers exist they count
-
-00:02:58.560 --> 00:03:01.120
-down at 60fps down to zero
-
-00:03:01.120 --> 00:03:02.879
-this is done so that you can play a
-
-00:03:02.879 --> 00:03:05.120
-sound at some specific time
-
-00:03:05.120 --> 00:03:06.640
-the game itself is loaded with a fixed
-
-00:03:06.640 --> 00:03:08.640
-offset into ram the program account is
-
-00:03:08.640 --> 00:03:10.480
-set to exactly that offset
-
-00:03:10.480 --> 00:03:11.920
-and from there it enters the game loop
-
-00:03:11.920 --> 00:03:13.840
-where decodes and instruction executes
-
-00:03:13.840 --> 00:03:15.519
-it for the side effects and just
-
-00:03:15.519 --> 00:03:18.130
-loops and does this at infinitum
-
-00:03:18.130 --> 00:03:19.599
-[Music]
-
-00:03:19.599 --> 00:03:21.920
-so the game was the first thing where
-
-00:03:21.920 --> 00:03:23.920
-into problems the usual game approach is
-
-00:03:23.920 --> 00:03:24.239
-to
-
-00:03:24.239 --> 00:03:26.640
-do stuff figure out how long to eight
-
-00:03:26.640 --> 00:03:28.239
-wait for exactly that much and
-
-00:03:28.239 --> 00:03:30.640
-repeat this doesn't work well in imax at
-
-00:03:30.640 --> 00:03:31.680
-all because well
-
-00:03:31.680 --> 00:03:34.959
-user input basically and
-
-00:03:34.959 --> 00:03:37.280
-Emacs is designed to just do whatever it
-
-00:03:37.280 --> 00:03:39.040
-needs to do whenever you enter use input
-
-00:03:39.040 --> 00:03:40.080
-instead of
-
-00:03:40.080 --> 00:03:42.799
-doing things at one specific time if you
-
-00:03:42.799 --> 00:03:43.440
-try to do
-
-00:03:43.440 --> 00:03:45.040
-interruptable sleep well you get
-
-00:03:45.040 --> 00:03:46.640
-unpredictable behavior
-
-00:03:46.640 --> 00:03:49.440
-for example can be the timer doesn't run
-
-00:03:49.440 --> 00:03:50.959
-at all at next time because you've
-
-00:03:50.959 --> 00:03:52.560
-accidentally cancelled it
-
-00:03:52.560 --> 00:03:54.400
-if you do uninterruptable sleep it's
-
-00:03:54.400 --> 00:03:55.760
-freezes instead which isn't what you
-
-00:03:55.760 --> 00:03:56.720
-want either
-
-00:03:56.720 --> 00:03:59.360
-so I went for timers which forced me to
-
-00:03:59.360 --> 00:04:00.560
-do inversion of control
-
-00:04:00.560 --> 00:04:02.159
-meaning that I have to write code in the
-
-00:04:02.159 --> 00:04:04.080
-style where it's just call it
-
-00:04:04.080 --> 00:04:06.159
-time and this allows this input to
-
-00:04:06.159 --> 00:04:07.200
-happen and to
-
-00:04:07.200 --> 00:04:09.120
-for things to progress at roughly the
-
-00:04:09.120 --> 00:04:11.040
-speed I want to
-
-00:04:11.040 --> 00:04:12.879
-so there's the skydiver function which
-
-00:04:12.879 --> 00:04:14.159
-is called a 60fps
-
-00:04:14.159 --> 00:04:16.000
-and I have to be very careful to not do
-
-00:04:16.000 --> 00:04:17.359
-too much in it
-
-00:04:17.359 --> 00:04:20.479
-and say this function execute cpu cycles
-
-00:04:20.479 --> 00:04:22.960
-decrypt the sound delay registers and
-
-00:04:22.960 --> 00:04:23.680
-redraw
-
-00:04:23.680 --> 00:04:27.759
-the screen so to map this whole system
-
-00:04:27.759 --> 00:04:28.800
-to mx lisp
-
-00:04:28.800 --> 00:04:31.199
-I've used just integers and vectors
-
-00:04:31.199 --> 00:04:33.120
-which contain even more integers
-
-00:04:33.120 --> 00:04:35.040
-this is used for the ram registers
-
-00:04:35.040 --> 00:04:37.759
-return stack key state screen and so on
-
-00:04:37.759 --> 00:04:39.120
-and so forth basically
-
-00:04:39.120 --> 00:04:41.520
-what you would do if you were writing c
-
-00:04:41.520 --> 00:04:42.800
-all of this is stored in global
-
-00:04:42.800 --> 00:04:44.560
-variables I'm not using any
-
-00:04:44.560 --> 00:04:46.479
-lists at all and as a side effect
-
-00:04:46.479 --> 00:04:48.400
-there's no constant going on at all
-
-00:04:48.400 --> 00:04:50.320
-there are no extra objects created which
-
-00:04:50.320 --> 00:04:51.120
-would trigger
-
-00:04:51.120 --> 00:04:53.919
-garbage collection pulses this getting
-
-00:04:53.919 --> 00:04:55.840
-this red was rather tricky actually and
-
-00:04:55.840 --> 00:04:56.720
-there were some
-
-00:04:56.720 --> 00:04:58.560
-in garbage collection problems which I
-
-00:04:58.560 --> 00:05:01.759
-had to resolve over time
-
-00:05:01.759 --> 00:05:04.320
-so the coding instructions for this you
-
-00:05:04.320 --> 00:05:05.520
-have to know that all instructions are
-
-00:05:05.520 --> 00:05:06.800
-two bytes long
-
-00:05:06.800 --> 00:05:08.880
-and the arguments encoded inside them
-
-00:05:08.880 --> 00:05:10.240
-for example the jump to address
-
-00:05:10.240 --> 00:05:11.440
-instruction
-
-00:05:11.440 --> 00:05:15.120
-is encoded as one and three hex digits
-
-00:05:15.120 --> 00:05:18.400
-the type is extracted masking with f000
-
-00:05:18.400 --> 00:05:20.800
-and then shifting it by 12 bits mask
-
-00:05:20.800 --> 00:05:21.680
-means the hd
-
-00:05:21.680 --> 00:05:24.000
-performance binary end you can do the
-
-00:05:24.000 --> 00:05:25.440
-same with the argument basement with
-
-00:05:25.440 --> 00:05:26.639
-zero fff
-
-00:05:26.639 --> 00:05:29.520
-and no shift if you do this long enough
-
-00:05:29.520 --> 00:05:31.039
-you'll find common patterns for example
-
-00:05:31.039 --> 00:05:32.639
-addresses are always encoded like this
-
-00:05:32.639 --> 00:05:35.280
-using the last three nibbles in the code
-
-00:05:35.280 --> 00:05:36.880
-you'll find a big count which dispatches
-
-00:05:36.880 --> 00:05:38.400
-on the type and executes it for the side
-
-00:05:38.400 --> 00:05:40.070
-effects
-
-00:05:40.070 --> 00:05:41.440
-[Music]
-
-00:05:41.440 --> 00:05:43.440
-for testing I've initially just accused
-
-00:05:43.440 --> 00:05:45.919
-the rom until I fit ctrl g
-
-00:05:45.919 --> 00:05:47.280
-and then use the debug command to run
-
-00:05:47.280 --> 00:05:49.039
-the screen to a buffer
-
-00:05:49.039 --> 00:05:51.360
-later on I found tiny roms that just
-
-00:05:51.360 --> 00:05:52.320
-display a static
-
-00:05:52.320 --> 00:05:55.680
-test screen for example logo and looked
-
-00:05:55.680 --> 00:05:57.280
-whether it looked right
-
-00:05:57.280 --> 00:05:59.199
-I added instructions as needed and went
-
-00:05:59.199 --> 00:06:00.960
-through more and more and more roms and
-
-00:06:00.960 --> 00:06:03.360
-later I wrote in unit test suite as a
-
-00:06:03.360 --> 00:06:05.199
-safety net and this unit test suite it
-
-00:06:05.199 --> 00:06:06.000
-just
-
-00:06:06.000 --> 00:06:08.400
-sets up an empty emulator state executes
-
-00:06:08.400 --> 00:06:10.080
-some instructions and then looks whether
-
-00:06:10.080 --> 00:06:10.400
-the
-
-00:06:10.400 --> 00:06:14.880
-expected side effects have happened
-
-00:06:14.880 --> 00:06:17.120
-for debugging I usually use e-debug but
-
-00:06:17.120 --> 00:06:19.120
-this was super ineffective because well
-
-00:06:19.120 --> 00:06:20.880
-you don't really want to step through
-
-00:06:20.880 --> 00:06:22.960
-big cons doing side effects for every
-
-00:06:22.960 --> 00:06:24.960
-single cycle when it can take like 100
-
-00:06:24.960 --> 00:06:26.880
-cycles for things to happen
-
-00:06:26.880 --> 00:06:29.680
-therefore I've set up logging and
-
-00:06:29.680 --> 00:06:31.360
-whenever I locked something
-
-00:06:31.360 --> 00:06:32.720
-and couldn't figure out the error I
-
-00:06:32.720 --> 00:06:33.919
-compared my lock output with
-
-00:06:33.919 --> 00:06:37.039
-instrumented version of another emulator
-
-00:06:37.039 --> 00:06:39.199
-and if the locks diverge then I have
-
-00:06:39.199 --> 00:06:40.880
-figured out where the bug lies and could
-
-00:06:40.880 --> 00:06:42.720
-look deeper into it
-
-00:06:42.720 --> 00:06:44.479
-future project idea might be a chip 8
-
-00:06:44.479 --> 00:06:46.639
-debugger but I doubt I'll ever
-
-00:06:46.639 --> 00:06:50.720
-go into it for analysis I initially
-
-00:06:50.720 --> 00:06:52.639
-wrote a disassembler which is a very
-
-00:06:52.639 --> 00:06:54.400
-simple thing but super tedious
-
-00:06:54.400 --> 00:06:56.160
-especially if you wanted to add advanced
-
-00:06:56.160 --> 00:06:57.599
-functionality for example analysis or
-
-00:06:57.599 --> 00:06:59.120
-thinking of what part is data what had
-
-00:06:59.120 --> 00:07:00.000
-this code
-
-00:07:00.000 --> 00:07:01.840
-and I had this great idea for using the
-
-00:07:01.840 --> 00:07:03.360
-radari 2 framework
-
-00:07:03.360 --> 00:07:05.120
-and adding analysis and disassembly
-
-00:07:05.120 --> 00:07:06.479
-plug-in for it
-
-00:07:06.479 --> 00:07:08.400
-so I looked into this found okay here
-
-00:07:08.400 --> 00:07:10.319
-where you can write plugins in c
-
-00:07:10.319 --> 00:07:12.160
-but also in python so I wrote one in
-
-00:07:12.160 --> 00:07:13.520
-python and then the scout there's
-
-00:07:13.520 --> 00:07:15.039
-actually existing one in core which you
-
-00:07:15.039 --> 00:07:17.440
-have to enable explicitly by passing its
-
-00:07:17.440 --> 00:07:19.599
-argument so I've tried it and found it's
-
-00:07:19.599 --> 00:07:21.840
-not exactly as good as my own one so
-
-00:07:21.840 --> 00:07:23.680
-improved this one and submitted pull
-
-00:07:23.680 --> 00:07:26.610
-requests until it was at the same level
-
-00:07:26.610 --> 00:07:28.080
-[Music]
-
-00:07:28.080 --> 00:07:30.160
-rendering was the trickiest part of this
-
-00:07:30.160 --> 00:07:31.360
-whole thing because
-
-00:07:31.360 --> 00:07:34.319
-well I decided against using a library
-
-00:07:34.319 --> 00:07:35.759
-not like there would have been any
-
-00:07:35.759 --> 00:07:37.120
-usable library for this
-
-00:07:37.120 --> 00:07:39.599
-my usual approach of accelerating svg
-
-00:07:39.599 --> 00:07:41.680
-file was too expensive it just created
-
-00:07:41.680 --> 00:07:45.120
-too much garbage and took too long time
-
-00:07:45.120 --> 00:07:47.360
-I then tried creating mutating strings
-
-00:07:47.360 --> 00:07:49.599
-this was either either too expensive
-
-00:07:49.599 --> 00:07:52.639
-just like svgs or too complicated I
-
-00:07:52.639 --> 00:07:55.039
-tried changing svg tiles which created
-
-00:07:55.039 --> 00:07:57.280
-gaps between the lines
-
-00:07:57.280 --> 00:07:59.520
-then I tried to create an xpm file which
-
-00:07:59.520 --> 00:08:00.720
-was backed by a bull vector
-
-00:08:00.720 --> 00:08:02.400
-administrating this bull vector
-
-00:08:02.400 --> 00:08:04.400
-but the image caching effect made it
-
-00:08:04.400 --> 00:08:06.879
-just every nth frame to appear which
-
-00:08:06.879 --> 00:08:10.000
-wasn't good either then I had the idea
-
-00:08:10.000 --> 00:08:11.440
-to just use plain text
-
-00:08:11.440 --> 00:08:13.280
-and paint the individual characters with
-
-00:08:13.280 --> 00:08:14.800
-a different background color this
-
-00:08:14.800 --> 00:08:17.120
-this had perfect perfect performance
-
-00:08:17.120 --> 00:08:18.479
-there were many optimization attempts
-
-00:08:18.479 --> 00:08:20.000
-until I got there and it was
-
-00:08:20.000 --> 00:08:21.840
-very very stressful I wasn't sure
-
-00:08:21.840 --> 00:08:23.199
-whether I would ever get to accept the
-
-00:08:23.199 --> 00:08:26.160
-performance at all
-
-00:08:26.160 --> 00:08:28.560
-for sound you only need to a single beep
-
-00:08:28.560 --> 00:08:30.319
-so technically it shouldn't be difficult
-
-00:08:30.319 --> 00:08:31.280
-to emulate it
-
-00:08:31.280 --> 00:08:33.519
-however doing this is hard because Emacs
-
-00:08:33.519 --> 00:08:34.880
-officially only supports synchronous
-
-00:08:34.880 --> 00:08:37.200
-playback of sounds
-
-00:08:37.200 --> 00:08:39.039
-but there's also emax process which you
-
-00:08:39.039 --> 00:08:41.360
-can launch in asynchronous way
-
-00:08:41.360 --> 00:08:43.519
-so I looked into it and found that
-
-00:08:43.519 --> 00:08:45.279
-employee has a slave mode and mpv
-
-00:08:45.279 --> 00:08:46.640
-supports listing on the
-
-00:08:46.640 --> 00:08:50.880
-fifo for commands so I've created a pipe
-
-00:08:50.880 --> 00:08:54.000
-started a past mpv in loop mode and
-
-00:08:54.000 --> 00:08:55.519
-always send in pause and pause command
-
-00:08:55.519 --> 00:08:58.000
-to the fifo and that way I could control
-
-00:08:58.000 --> 00:09:02.640
-when to start beeping and stop beeping
-
-00:09:02.640 --> 00:09:05.760
-so yeah that's it so far was a very
-
-00:09:05.760 --> 00:09:07.200
-educational experience
-
-00:09:07.200 --> 00:09:09.279
-I have tried out a bunch of games which
-
-00:09:09.279 --> 00:09:10.320
-were
-
-00:09:10.320 --> 00:09:12.640
-well I almost say the worst ports of
-
-00:09:12.640 --> 00:09:14.320
-classic games I've ever tried
-
-00:09:14.320 --> 00:09:15.839
-it wasn't terribly fun to play them but
-
-00:09:15.839 --> 00:09:18.320
-was fun to improve the emulator until
-
-00:09:18.320 --> 00:09:21.760
-well things worked good enough
-
-00:09:21.760 --> 00:09:23.279
-and I've learned a lot about how
-
-00:09:23.279 --> 00:09:25.120
-computers work at this level
-
-00:09:25.120 --> 00:09:27.760
-so maybe maybe I'll in the future make
-
-00:09:27.760 --> 00:09:28.880
-another emulator
-
-00:09:28.880 --> 00:09:31.920
-but uh I'm not sure whether anything
-
-00:09:31.920 --> 00:09:34.000
-more advanced like intel 8080 emulator
-
-00:09:34.000 --> 00:09:36.560
-will actually run mix fast enough
-
-00:09:36.560 --> 00:09:37.839
-but it's still an interesting idea
-
-00:09:37.839 --> 00:09:39.200
-because then you could actually have an
-
-00:09:39.200 --> 00:09:39.600
-os
-
-00:09:39.600 --> 00:09:41.680
-inside Emacs and fulfill that one
-
-00:09:41.680 --> 00:09:43.120
-specific meme
-
-00:09:43.120 --> 00:09:45.440
-but if I try to do most serious stuff
-
-00:09:45.440 --> 00:09:47.279
-I'll probably use chicken scheme which
-
-00:09:47.279 --> 00:09:48.000
-is my
-
-00:09:48.000 --> 00:09:49.920
-preferred language for serious projects
-
-00:09:49.920 --> 00:09:53.279
-and writing neso gamer emulator
-
-00:09:53.279 --> 00:09:57.839
-and that's it thank you
diff --git a/2020/subtitles/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8--vasilij-wasamasa-schneidermann.vtt b/2020/subtitles/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8--vasilij-wasamasa-schneidermann.vtt
new file mode 100644
index 00000000..3d655630
--- /dev/null
+++ b/2020/subtitles/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8--vasilij-wasamasa-schneidermann.vtt
@@ -0,0 +1,630 @@
+WEBVTT
+
+00:00:00.880 --> 00:00:04.520
+Hello everyone and welcome to my talk, "The State of Retro Gaming and Emacs."
+
+00:00:06.960 --> 00:00:08.639
+First of all, a little bit about myself.
+
+00:00:08.639 --> 00:00:12.000
+My name is Vasilij Schneidermann. I'm 28 years old.
+
+00:00:12.000 --> 00:00:14.719
+I work as a cyber security consultant at msg systems,
+
+00:00:14.719 --> 00:00:17.359
+and test other people's web applications
+
+00:00:17.359 --> 00:00:20.160
+and review the source code for security problems.
+
+00:00:20.160 --> 00:00:22.080
+You can reach me by email.
+
+00:00:22.080 --> 00:00:25.039
+I have my own self-hosted git repositories,
+
+00:00:25.039 --> 00:00:28.160
+and I have a blog where you can occasionally find new posts by me
+
+00:00:28.160 --> 00:00:32.160
+on all kinds of things, not just Emacs things.
+
+00:00:32.160 --> 00:00:34.559
+The motivation about this one...
+
+00:00:34.559 --> 00:00:37.600
+I found that Emacs is the ultimate procrastination machine,
+
+00:00:37.600 --> 00:00:39.600
+and there are lots of fun demonstrations.
+
+00:00:39.600 --> 00:00:41.200
+I'll go over a few of them.
+
+00:00:41.200 --> 00:00:45.840
+For example, someone made a thing to order salad for himself online,
+
+00:00:45.840 --> 00:00:48.239
+so he doesn't have to walk over to the shop.
+
+00:00:48.239 --> 00:00:51.760
+There's plenty of IRC bots. There's some game things.
+
+00:00:51.760 --> 00:00:55.600
+There's an emulator for the Z-machine
+which you can use to play zork.
+
+00:00:55.600 --> 00:00:57.440
+And so I asked myself, at this point,
+
+00:00:57.440 --> 00:00:59.920
+can you actually emulate retro games at 60fps?
+
+00:00:59.920 --> 00:01:02.079
+I looked around a bit and found some projects,
+
+00:01:02.079 --> 00:01:06.159
+but none that were actually able to do it at 60fps.
+
+00:01:06.159 --> 00:01:08.000
+So I set out to do my own one,
+
+00:01:08.000 --> 00:01:09.200
+and looked out for a console
+
+00:01:09.200 --> 00:01:11.119
+that you can actually emulate at that speed,
+
+00:01:11.119 --> 00:01:14.690
+using Emacs with its very, very limited rendering.
+
+00:01:16.320 --> 00:01:19.200
+And here's the project, chip8.el.
+
+00:01:19.200 --> 00:01:20.560
+It's pretty much finished.
+
+00:01:20.560 --> 00:01:24.000
+It clocks into under 1000 source lines of code.
+
+00:01:24.000 --> 00:01:26.159
+It supports the superchip 8 extensions.
+
+00:01:26.159 --> 00:01:27.280
+It runs at full speed.
+
+00:01:27.280 --> 00:01:29.600
+All games behave okay, as far as I'm concerned,
+
+00:01:29.600 --> 00:01:31.680
+and yeah, I'm pretty happy with it.
+
+00:01:31.680 --> 00:01:34.479
+It's very much the hello world of emulation,
+
+00:01:34.479 --> 00:01:40.880
+and I might, maybe, do some other emulation projects in the future.
+
+00:01:40.880 --> 00:01:43.360
+Now, for the section which is the longest:
+
+00:01:43.360 --> 00:01:45.439
+bunch of fun facts about chip8.el
+
+00:01:45.439 --> 00:01:49.200
+which I've learned during this project.
+
+00:01:49.200 --> 00:01:51.759
+So what the hell is chip8 anyway?
+
+00:01:51.759 --> 00:01:54.960
+First of all, unlike many other emulation game things,
+
+00:01:54.960 --> 00:01:56.799
+it's not a console, but a VM.
+
+00:01:56.799 --> 00:02:00.000
+It was designed for easy porting of home
+computer games.
+
+00:02:00.000 --> 00:02:02.320
+It wasn't terribly successful,
+
+00:02:02.320 --> 00:02:05.439
+but there's still a small community of enthusiasts writing games for it,
+
+00:02:05.439 --> 00:02:09.119
+and there are even a few demos.
+
+00:02:09.119 --> 00:02:11.039
+This VM has system specs.
+
+00:02:11.039 --> 00:02:14.720
+It has a very, very simple 8-bit cpu with 16 registers,
+
+00:02:14.720 --> 00:02:17.280
+and 36 fixed-size instructions.
+
+00:02:17.280 --> 00:02:19.680
+You have a whole 4 kilobyte of RAM.
+
+00:02:19.680 --> 00:02:22.080
+You have a stack with 16 return addresses.
+
+00:02:22.080 --> 00:02:25.760
+The resolution is 64 by 32 black/white pixels.
+
+00:02:25.760 --> 00:02:28.000
+Rendering is done by drawing sprites.
+
+00:02:28.000 --> 00:02:29.200
+These are drawn in XOR mode,
+
+00:02:29.200 --> 00:02:31.840
+meaning that if you draw a sprite and set a bit,
+
+00:02:31.840 --> 00:02:35.040
+it just flips over from black to white or white to black.
+
+00:02:35.040 --> 00:02:39.360
+For sound, you have a monotone buzzer that can just beep at one frequency.
+
+00:02:39.360 --> 00:02:43.120
+Most unusually, there's a hexadecimal keypad as input,
+
+00:02:43.120 --> 00:02:48.480
+so the keys are basically zero to nine and a to f.
+
+00:02:48.480 --> 00:02:50.720
+So how does this whole thing work?
+
+00:02:50.720 --> 00:02:52.400
+It runs at an unspecified speed.
+
+00:02:52.400 --> 00:02:53.040
+You'll probably have to do some fine-tuning
+
+00:02:53.040 --> 00:02:56.080
+to find the speed you're happy with.
+
+00:02:56.080 --> 00:02:58.080
+Sound and delay timers exist.
+
+00:02:58.080 --> 00:03:01.120
+They count down at 60fps down to 0.
+
+00:03:01.120 --> 00:03:05.120
+This is done so that you can play a sound at some specific time.
+
+00:03:05.120 --> 00:03:07.840
+The game itself is loaded with a fixed offset into RAM.
+
+00:03:07.840 --> 00:03:10.480
+The program counter is set to exactly that offset,
+
+00:03:10.480 --> 00:03:11.920
+and from there it enters the game loop
+
+00:03:11.920 --> 00:03:13.280
+where it decodes an instruction,
+
+00:03:13.280 --> 00:03:14.800
+executes it for the side effects,
+
+00:03:14.800 --> 00:03:18.130
+and just loops and does this ad infinitum.
+
+00:03:19.599 --> 00:03:22.720
+So the game loop was the first thing where we ran into problems.
+
+00:03:22.720 --> 00:03:25.120
+The usual game approach is to do stuff,
+
+00:03:25.120 --> 00:03:26.640
+figure out how long to wait,
+
+00:03:26.640 --> 00:03:29.280
+wait for exactly that much, and repeat.
+
+00:03:29.280 --> 00:03:31.680
+This doesn't work well in Emacs at all, because, well,
+
+00:03:31.680 --> 00:03:34.959
+user input, basically.
+
+00:03:34.959 --> 00:03:37.760
+Emacs is designed to just do whatever it needs to do
+
+00:03:37.760 --> 00:03:39.040
+whenever you enter user input
+
+00:03:39.040 --> 00:03:42.319
+instead of doing things at one specific time.
+
+00:03:42.319 --> 00:03:46.640
+If you try to do interruptable sleep, well, you get unpredictable behavior.
+
+00:03:46.640 --> 00:03:50.480
+For example, it can be the timer doesn't run at all at the next time
+
+00:03:50.480 --> 00:03:52.560
+because you've accidentally cancelled it.
+
+00:03:52.560 --> 00:03:55.120
+If you do uninterruptable sleep, it freezes instead ,
+
+00:03:55.120 --> 00:03:56.720
+which isn't what we want either.
+
+00:03:56.720 --> 00:04:00.560
+So I went for timers, which forced me to do inversion of control,
+
+00:04:00.560 --> 00:04:02.560
+meaning that I have to write code in the style
+
+00:04:02.560 --> 00:04:04.879
+where it just calls timer,
+
+00:04:04.879 --> 00:04:06.560
+and this allows this input to happen
+
+00:04:06.560 --> 00:04:11.040
+and for things to progress at roughly the speed I want to.
+
+00:04:11.040 --> 00:04:14.159
+So there's the timer function which is called at 60fps
+
+00:04:14.159 --> 00:04:17.359
+and I have to be very careful to not do too much in it.
+
+00:04:17.359 --> 00:04:21.305
+And, say, this function executes CPU cycles,
+
+00:04:21.305 --> 00:04:26.479
+decrement the sound/delay registers, and redraw the screen.
+
+00:04:26.479 --> 00:04:28.800
+So to map this whole system to Emacs Lisp,
+
+00:04:28.800 --> 00:04:31.199
+I've used just integers and vectors
+
+00:04:31.199 --> 00:04:33.120
+which contain even more integers.
+
+00:04:33.120 --> 00:04:35.040
+This is used for the RAM, registers,
+
+00:04:35.040 --> 00:04:37.040
+return stack, key state, screen,
+
+00:04:37.040 --> 00:04:38.508
+and so on and so forth.
+
+00:04:38.508 --> 00:04:41.520
+Basically, what you would do if you were writing C.
+
+00:04:41.520 --> 00:04:43.360
+All of this is stored in global variables.
+
+00:04:43.360 --> 00:04:45.600
+I'm not using any lists at all.
+
+00:04:45.600 --> 00:04:48.400
+As a side effect, there's no consing going on at all.
+
+00:04:48.400 --> 00:04:50.080
+There are no extra objects created
+
+00:04:50.080 --> 00:04:53.199
+which would trigger garbage collection processes.
+
+00:04:53.199 --> 00:04:55.600
+Getting this right was rather tricky, actually,
+
+00:04:55.600 --> 00:04:58.240
+and there were some hidden garbage collection problems
+
+00:04:58.240 --> 00:05:01.759
+which I had to resolve over time.
+
+00:05:01.759 --> 00:05:03.759
+So, decoding instructions.
+
+00:05:03.759 --> 00:05:06.800
+For this, you have to know that all instructions are two bytes long,
+
+00:05:06.800 --> 00:05:08.880
+and the arguments are encoded inside them.
+
+00:05:08.880 --> 00:05:11.440
+For example, the jump to address instruction
+
+00:05:11.440 --> 00:05:15.120
+is encoded as one and three hex digits.
+
+00:05:15.120 --> 00:05:18.400
+The type is extracted masking with #xF000
+
+00:05:18.400 --> 00:05:20.400
+and then shifting it by 12 bits.
+
+00:05:20.400 --> 00:05:23.520
+Mask means you perform the binary AND.
+
+00:05:23.520 --> 00:05:28.400
+You can do the same with the argument by masking with #0xFFF and no shift.
+
+00:05:28.400 --> 00:05:30.560
+If you do this long enough, you'll find common patterns.
+
+00:05:30.560 --> 00:05:32.639
+For example, addresses are always encoded like this
+
+00:05:32.639 --> 00:05:34.880
+using the last three nibbles.
+
+00:05:34.880 --> 00:05:36.160
+In the code, you'll find a big cond
+
+00:05:36.160 --> 00:05:40.070
+which dispatches on the type and executes it for the side effects.
+
+00:05:41.440 --> 00:05:45.919
+For testing, I've initially just executed the ROM until I've hit C-g,
+
+00:05:45.919 --> 00:05:49.039
+and then use the debug command to render the screen to a buffer.
+
+00:05:49.039 --> 00:05:53.199
+Later on, I found tiny ROMs that just display a static test screen,
+
+00:05:53.199 --> 00:05:57.280
+for example, logo, and looked whether it looked right.
+
+00:05:57.280 --> 00:05:58.800
+I added instructions as needed
+
+00:05:58.800 --> 00:06:00.720
+and went through more and more and more ROMs.
+
+00:06:00.720 --> 00:06:04.000
+And later I wrote a unit test suite as a safety net.
+
+00:06:04.000 --> 00:06:07.840
+This unit test suite, it just sets up an empty emulator state,
+
+00:06:07.840 --> 00:06:09.199
+executes some instructions,
+
+00:06:09.199 --> 00:06:14.880
+and then looks whether the expected side effects have happened.
+
+00:06:14.880 --> 00:06:18.319
+For debugging, I usually use edebug, but this was super ineffective,
+
+00:06:18.319 --> 00:06:21.600
+because, well, you don't really want to step through big cons
+
+00:06:21.600 --> 00:06:23.680
+doing side effects for every single cycle,
+
+00:06:23.680 --> 00:06:26.880
+when it can take like 100 cycles for things to happen.
+
+00:06:26.880 --> 00:06:29.680
+Therefore I've set up logging.
+
+00:06:29.680 --> 00:06:32.639
+Whenever I logged something and couldn't figure out the error,
+
+00:06:32.639 --> 00:06:37.039
+I compared my log output with the instrumented version of another emulator,
+
+00:06:37.039 --> 00:06:40.479
+and if the logs diverge, then I have figured out where the bug lies
+
+00:06:40.479 --> 00:06:42.720
+and could look deeper into it.
+
+00:06:42.720 --> 00:06:44.960
+Future project idea might be a chip 8 debugger,
+
+00:06:44.960 --> 00:06:49.440
+but I doubt I'll ever go into it.
+
+00:06:49.440 --> 00:06:51.759
+For analysis, I initially wrote a disassembler,
+
+00:06:51.759 --> 00:06:54.400
+which is a very simple thing but super tedious,
+
+00:06:54.400 --> 00:06:56.639
+especially if you wanted to add advanced functionality,
+
+00:06:56.639 --> 00:06:58.720
+for example, analysis or thinking of what part is data,
+
+00:06:58.720 --> 00:07:00.000
+what part is code.
+
+00:07:00.000 --> 00:07:03.360
+I had this great idea for using the radare 2 framework
+
+00:07:03.360 --> 00:07:06.479
+and adding analysis and disassembly plug-in for it.
+
+00:07:06.479 --> 00:07:08.400
+So I looked into this. Found, okay,
+
+00:07:08.400 --> 00:07:10.319
+you can write plugins in C
+
+00:07:10.319 --> 00:07:12.639
+but also in Python, so I wrote one in Python,
+
+00:07:12.639 --> 00:07:14.720
+and then discovered there's actually an existing one in core,
+
+00:07:14.720 --> 00:07:18.400
+which you have to enable explicitly by passing an extra argument.
+
+00:07:18.400 --> 00:07:21.680
+I've tried it and found it's not exactly as good as my own one,
+
+00:07:21.680 --> 00:07:24.160
+so I improved this one and submitted pull requests
+
+00:07:24.160 --> 00:07:26.610
+until it was at the same level.
+
+00:07:28.080 --> 00:07:30.720
+Rendering was the trickiest part of this whole thing,
+
+00:07:30.720 --> 00:07:34.319
+because, well, I decided against using a library.
+
+00:07:34.319 --> 00:07:37.120
+Not like there would have been any usable library for this.
+
+00:07:37.120 --> 00:07:40.880
+My usual approach of creating SVG files was too expensive.
+
+00:07:40.880 --> 00:07:45.120
+It just created too much garbage and took too long time.
+
+00:07:45.120 --> 00:07:47.360
+I then tried creating mutating strings.
+
+00:07:47.360 --> 00:07:52.479
+This was either too expensive, just like SVGs, or too complicated.
+
+00:07:52.479 --> 00:07:57.280
+I tried changing SVG tiles, which created gaps between the lines.
+
+00:07:57.280 --> 00:08:00.720
+Then I tried to create an xpm file which was backed by a bool vector
+
+00:08:00.720 --> 00:08:02.400
+and mutating this bool vector,
+
+00:08:02.400 --> 00:08:04.000
+but the image caching effect
+
+00:08:04.000 --> 00:08:06.479
+made it just every nth frame to appear,
+
+00:08:06.479 --> 00:08:08.879
+which wasn't good either.
+
+00:08:08.879 --> 00:08:11.440
+Then I had the idea to just use plain text
+
+00:08:11.440 --> 00:08:13.120
+and paint the individual characters
+
+00:08:13.120 --> 00:08:14.800
+with a different background color.
+
+00:08:14.800 --> 00:08:17.120
+This had perfect, perfect performance.
+
+00:08:17.120 --> 00:08:19.280
+There were many optimization attempts until I got there,
+
+00:08:19.280 --> 00:08:21.199
+and it was very, very stressful.
+
+00:08:21.199 --> 00:08:26.160
+I wasn't sure whether I would ever get to accept the performance at all.
+
+00:08:26.160 --> 00:08:28.560
+For sound you only need to do a single beep,
+
+00:08:28.560 --> 00:08:31.280
+so technically, it shouldn't be difficult to emulate it.
+
+00:08:31.280 --> 00:08:33.039
+However, doing this is hard because
+
+00:08:33.039 --> 00:08:37.200
+Emacs officially only supports synchronous playback of sounds.
+
+00:08:37.200 --> 00:08:41.360
+But there's also Emacs process, which you can launch in asynchronous way.
+
+00:08:41.360 --> 00:08:44.720
+So I looked into it and found that mplayer has a slave mode
+
+00:08:44.720 --> 00:08:48.640
+and mpv supports listing on the fifo for commands.
+
+00:08:48.640 --> 00:08:53.760
+So I've created a pipe, started a paused MPV in loop mode,
+
+00:08:53.760 --> 00:08:56.560
+and always send in pause and unpause command to the FIFO,
+
+00:08:56.560 --> 00:08:58.000
+and that way I could control
+
+00:08:58.000 --> 00:09:02.640
+when to start beeping and stop beeping.
+
+00:09:02.640 --> 00:09:04.160
+So yeah, that's it so far.
+
+00:09:04.160 --> 00:09:07.200
+It was a very educational experience.
+
+00:09:07.200 --> 00:09:10.320
+I have tried out a bunch of games which were,
+
+00:09:10.320 --> 00:09:14.320
+well, I almost say the worst ports of classic games I've ever tried.
+
+00:09:14.320 --> 00:09:15.680
+It wasn't terribly fun to play them,
+
+00:09:15.680 --> 00:09:18.555
+but was fun to improve the emulator
+
+00:09:18.555 --> 00:09:21.760
+until, well, things worked good enough.
+
+00:09:21.760 --> 00:09:25.120
+I've learned a lot about how computers work at this level,
+
+00:09:25.120 --> 00:09:28.880
+so, maybe, maybe I'll in the future make another emulator,
+
+00:09:28.880 --> 00:09:34.000
+but I'm not sure whether anything more advanced, like an Intel 8080 emulator,
+
+00:09:34.000 --> 00:09:36.560
+will actually run in Emacs fast enough,
+
+00:09:36.560 --> 00:09:37.839
+but it's still an interesting idea,
+
+00:09:37.839 --> 00:09:40.800
+because then you could actually have an OS inside Emacs
+
+00:09:40.800 --> 00:09:43.120
+and fulfill that one specific meme.
+
+00:09:43.120 --> 00:09:45.440
+But if I try to do most serious stuff,
+
+00:09:45.440 --> 00:09:47.040
+I'll probably use Chicken Scheme,
+
+00:09:47.040 --> 00:09:49.920
+which is my preferred language for serious projects,
+
+00:09:49.920 --> 00:09:53.279
+and write a NES game emulator.
+
+00:09:53.279 --> 00:09:57.839
+And that's it. Thank you.