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