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