1 Zoom - A Z-Machine 2 ----// 8888 \\---- 3 4by Andrew Hunter 5 6 Zoom was originally designed as an experiment into writing fast 7 bytecode interpreters, just over 3 years ago (first checkin into 8 the CVS repository was on 19/11/2000). Last time I timed it, it 9 could run up to around 2x faster than frotz, depending on what 10 code was being executed. It's changed a lot since then, as the 11 emphasis is now on designing a good user interface for the 12 interpreter. As I changed my main machine from a Linux PC to a 13 PowerMac about a year ago, and for another reason that will be 14 revealed later in the year, the recent development focus has been 15 on producing a Cocoa interface. 16 17 Send any bug reports to andrew@logicalshift.co.uk, and anything 18 else to andrew@logicalshift.co.uk. Zoom's homepage can be 19 located at http://www.logicalshift.co.uk/unix/zoom/ 20 21 You can get the latest version of the source code at any time 22 using git: 23 24 git clone http://code.logicalshift.co.uk/zoom/zoom.git 25 git submodule init 26 git submodule update 27 28Versions 29======== 30 31 This is version 1.1.5 of Zoom. As the components have gained an 32 increasing tendency to change at different rates, I've given them 33 separate versions: 34 35 Zoom interpreter core: 1.1.5 36 X11 interface: 1.1.5 37 Windows interface: 0.9.99beta5 38 Carbon interface: 1.0.1 39 Cocoa interface: 2.1.5 40 ZoomPlugins: 1.1.5 41 Spotlight importer: 1.5 42 QuickLook plugin: 1.1.5 43 CocoaGlk version: 1.0.8 44 Glulxe version: 0.4.7 45 46 Note that Zoom's display system underwent a fairly major change 47 between 1.0.0 and 1.0.1 due to the addition of version 6 support. This 48 means that the Windows version of Zoom will not compile any longer. 49 The 2.0 version of the Cocoa interface refers to the version number 50 displayed in the About box for the Macintosh version of Zoom. 51 52Compiling Zoom 53============== 54 55 (See later for Cocoa) 56 57 To get a full-featured interpreter under X windows or Carbon, 58 you'll want to have at least libpng installed. For X, having an 59 X server with Xrender and Xft is a good idea. T1Lib is optional, 60 but appears to provide improved rendering quality over Xft (which 61 seems to have great difficulties with hinting). 62 63 With all the libraries installed, ./configure && make should be 64 all that's required to build Zoom for either X or Mac OS X (Carbon). 65 Please report any build problems to the bugs address listed 66 above: Zoom should work on a reasonably wide variety of systems. 67 68 You can also build the Carbon version of Zoom by opening the 69 Zoom.pbproj file in Project Builder. The Cocoa version of Zoom has 70 to be built with XCode, using the ZoomCocoa.xcode file. Building 71 with project builder may cause problems with yacc generating corrupt 72 files, producing many spurious errors (XCode does not appear to have 73 these problems). If this occurs, delete the relevant files from 74 the build/Zoom.build/DerivedSources directory. 75 76 You may want to try the --enable-new-terp option to configure: 77 this enables an experimental new interpreter design. This gives 78 gcc's optimiser a much easier time of things (improving compile 79 times considerably). This style of interpreter produces a slight 80 (almost insignificant) performance hit. 81 82 I've experienced problems with gcc 3's optimiser: specifically, 83 it reduces the speed of some instructions by a factor of up to 84 6 (0OPs, usually, for some reason - see the results of NopMark in 85 zmark). No idea why at all - this effect is most marked with the 86 new interpreter style. Note that compiling the interpreter can be 87 a great workout for your system; on my Mac OS X machine, it needs 88 nearly 1Gb of memory to compile successfully with gcc 3.3. 89 Earlier versions of gcc require much less memory; I have 90 successfully compiled under x86 linux on a machine with 32Mb 91 of memory and gcc 2.95; the PPC version of gcc seems to require 92 much more memory for optimisation than the standard version, too. 93 Regardless, at least 256Mb of memory is recommended for those 94 that wish to compile Zoom. 95 96Compiling Zoom (Cocoa) 97====================== 98 99 Before compiling, you will need to have a version of the expat 100 library unpacked into the directory containing the Zoom source 101 directory. Use a symbolic link, or rename this directory 'expat'. 102 Currently, the Zoom binaries link against expat 1.95.8: later 103 versions may also work. (Zoom is statically linked against expat 104 as it was an optional install on versions of OS X prior to 10.3) 105 106 You will also need the babel utility and the Sparkle library in the 107 directory containing the Zoom source code. 108 109 Finally, you will need the dependencies in the depend directory: this 110 means CocoaGlk at the moment. The easiest way to get these is to use git: 111 in the depends directory type this: 112 113 git clone http://code.logicalshift.co.uk/zoom/cocoaglk.git CocoaGlk 114 115 If you want to use the versions that correspond to a specific release, 116 use git checkout with the version number. For example, git checkout 117 v1.1.5. Note that CocoaGlk requires you to download versions of the 118 git and glulxe interpreters to compile it. 119 120 Rather than use the configure/automake process for this, I have 121 elected to use Xcode: to compile the new version of Zoom, load the 122 ZoomCocoa.xcode project into Xcode and hit build. Note that Xcode 123 seems to have a hard time running Yacc; if the build fails with 124 many weird errors, you will have to manually delete the relevant 125 DerivedSources (hidden in build/ZoomCocoa.build/ZoomServer.build). 126 There also seems to be an occasional problem with precompiled headers 127 that will produce similar problems (errors in Carbon headers this 128 time), but simply restarting the build process will fix this - you 129 are much more likely to see problems with building the Yacc sources. 130 131Using Zoom (X-Windows) 132====================== 133 134 Running Zoom is fairly simple - zoom <filename> should do the 135 trick, where <filename> is a Z-Code file (modern files created by 136 Inform tend to have a .z5 or .z8 filename, original Infocom files 137 tend to have a .dat or .zip filename - note that the .zip stands 138 for 'Z-Code Interpreter', not PKZip as you might think). Assuming 139 you haven't tinkered with zmachine.h, Zoom will support Z-Code 140 versions 3, 4, 5, 6, 7 and 8. As of version 1.0.1beta1, version 141 6 is fully supported, as is the Standard v1.1draft6. Unicode 142 support is also much improved from this release. 143 144 Zoom needs a configuration file called '.zoomrc' in your home 145 directory. This file tells Zoom about the colours and fonts it 146 should use, and also identifies game titles. It consists of many 147 entries of the form 'game "mygame" 12.345678 { options }', where 148 'mygame' is the text that appears in the title bar, and { options } 149 is the options for this game (in curly brackets). You can omit the 150 options altogether if you want the options to be the same as the 151 default. There is also exactly one default block, which has the 152 form 'default "%s (%i.%.6s)" { options }'. The default block must 153 define the interpreter number and revision, at least 4 fonts, and 154 the default set of colours: 155 156 # Standard settings - applies to all interpreters 157 # (Note, font 4 must always be fixed-pitch) 158 default "%s (%i.%.6s)" 159 { 160 interpreter 1 161 revision Z 162 163 font 1 "-*-helvetica-medium-r-*-*-14-*-*-*-*-*-*-*" roman 164 font 2 "-*-helvetica-bold-r-*-*-14-*-*-*-*-*-*-*" bold 165 font 3 "-*-helvetica-medium-o-*-*-14-*-*-*-*-*-*-*" italic 166 font 4 "-*-courier-medium-r-*-*-14-*-*-*-*-*-*-*" fixed 167 font 5 "-*-courier-bold-r-*-*-14-*-*-*-*-*-*-*" fixed-bold 168 font 6 "-*-courier-medium-o-*-*-14-*-*-*-*-*-*-*" fixed-italic 169 font 7 "-*-courier-bold-o-*-*-14-*-*-*-*-*-*-*" fixed-bold-italic 170 font 8 "-*-helvetica-bold-o-*-*-14-*-*-*-*-*-*-*" bold-italic 171 font 9 "font3" symbolic 172 173 colours (0,0,0), (255,0,0), (0,255,0), (255,255,0), (0,0,255), 174 (255,0,255), (0,255,255), (255,255,204), 175 # These are the colours provided by DOS interpreters 176 (187, 187, 187), (136, 136, 136), (68, 68, 68) 177 178 size 80, 30 179 180 gamedir "/usr/local/share/games/zcode" 181 savedir "/home/me/zcode/save" 182 } 183 184 This illustrates most of the available options. Unless you have a 185 particular reason for setting the interpreter number and revision, 186 the values given should do a reasonable job (version 6 games, and 187 Beyond Zork benefit from setting the interpreter number). 188 189 Fonts are defined using statements of the form: 190 191 font <num> "<name>" <style> 192 193 Where <num> specifies the font number (note that font 4 *must* be 194 a fixed-pitch font), and <style> is a list of style attributes 195 (attributes can be seperated by commas). A style attribute is one 196 of 'roman', 'bold', 'italic', 'fixed' or 'symbolic', or a combination 197 made by combining attributes with hyphens, for example 'fixed-bold'. If 198 you don't specify a font with a given combination of style 199 attributes, Zoom will use font 1 (for normal text) or font 4 (for 200 fixed pitch text). You can work out font names with the aid of 201 xfontsel. The special font name 'font3' refers to the built-in 202 symbolic font. 203 204 Colours are defined using a list of values of the form (R, G, 205 B). There should be at least 8 colours, coresponding to the 206 Infocom colour scheme, and there can be up to 11 (corresponding 207 to the colour scheme allowed by various interpreter versions): 208 209 0 = black 210 1 = red 211 2 = green 212 3 = yellow 213 4 = blue 214 5 = magenta 215 6 = cyan 216 7 = white 217 (I prefer cream to white, but that's a matter of personal preference) 218 8 = light grey (amiga) dark grey (DOS) 219 9 = medium grey (amiga) 220 10 = dark grey (amiga) 221 222 Colour 0 is the first specified in the list, and the rest follow 223 in sequence. 224 225 size <n>, <m> sets the size of the display to (n x m) 226 characters. These characters are the size of the fixed-pitch font 227 (font 4). For a version 6 game, the graphics file can be specified 228 using a command like 229 230 resources "/home/me/infocom/zorkzero/ZORK0/ZORK0.blb" 231 232 Presently only Blorb graphics files are supported. While I'm aware 233 of Blorb 1.1, I am somewhat hesitant to include JPEG support until 234 the current patent unpleasentness is resolved. 235 236 Zoom will load sound effects, but won't really do anything with them 237 at the moment. 238 239 If Zoom is run without a game specified, it will try to look in the 240 directory specified by 'gamedir', and list all of the games it finds 241 in there (games are assumed to be in files with a .z? extension) as 242 a menu, giving a choice as to which one to run. 'savedir' gives the 243 default directory for saving and restoring files. 244 245 Each game can be specified with a block like this, or the block 246 can be omitted. If you do specify a block for a game, the options 247 there override the defaults. For example: 248 249 game "Planetfall (Solid Gold edition)" 10.880531 250 251 might have no options, so it runs as the default - but, 252 253 game "Beyond Zork" 47.870915, 49.870917, 51.870923, 57.871221 254 { 255 interpreter 5 256 revision Z 257 258 savedir "/home/me/zcode/beyond" 259 } 260 261 specifies that Beyond Zork requires a different intepreter number 262 and should save its games into '/home/me/zcode/beyond' by default 263 - note that you can also specify different colour schemes and 264 fonts here (with fonts you can give a partial specification, so 265 just adding, say, 'font 1 "-weird-font" roman' would cause Zoom to 266 use that font instead of the default font 1, but keep the defaults 267 for the rest) 268 269 An example .zoomrc file can be found in the source distribution as 270 'zoomrc' 271 272Xft problems 273============ 274 275 XRender and Xft might well provide nice anti-aliased fonts, but 276 unfortunately, Xft doesn't provide any 'font not found' mechanism, 277 instead choosing a default font. When Xft is not setup, in particular 278 when there is no XftConfig file, this can result in the same font 279 being used for anything. The troubleshooting section of the manual 280 describes how to create an XftConfig file. The poor man's solution 281 is simply to specify 'antialias no' in .zoomrc. 282 283Zoom and Windows 284================ 285 286 *** THE WINDOWS DRIVER IS DEAD *** 287 288 Feel free to volunteer to resurrect it... 289 290 This version of Zoom now supports windows through the mingw32 library 291 (and to a lesser extent with Borland's C compiler). The windows display 292 library is a complete rewrite, and uses the techniques I discussed in 293 an raif posting to allow the window to be resized while a game is running. 294 These techniques are not without their penalty, however, and this version 295 of Zoom cannot be compiled with v6 support, and tends to redraw some 296 displays much slower than the X version. It also starts v3 games in the 297 top left of the screen instead of the bottom left, which is strictly 298 speaking against the standard, but saves me some fiddling. 299 300 The zoomrc has the format as described above. A windows font is described 301 using a string such as: 302 303 'Arial' 10 b 304 305 Which is Arial, 10pt, bold. The font name MUST be in single quotes ('). The 306 optional specifiers at the end can be left out entirely, or can be a 307 combination of: 308 309 b - bold 310 B - extra bold 311 i - italic 312 u - underline 313 f - fixed-pitch 314 315 The font specifiers in the example could then be: 316 317 font 1 "'Arial' 10" roman 318 font 2 "'Arial' 10 b" bold 319 font 3 "'Arial' 10 i" italic 320 font 4 "'Courier New' 10 f" fixed 321 font 5 "'Courier New' 10 fb" fixed-bold 322 font 6 "'Courier New' 10 fi" fixed-italic 323 font 7 "'Courier New' 10 fbi" fixed-bold-italic 324 font 8 "'Arial' bi" bold-italic 325 font 9 "font3" symbolic 326 327 (Note that the special font name 'font3' still specifies the built-in 328 version of font 3) 329 330Zoom and Mac OS X 331================= 332 333 This has been variously fixed and updated, along with everything else. 334 The Quartz renderer is to be preferred, for the higher-quality 335 rendering and best support for Unicode. Version 6 games (and blorb) 336 are supported in this port: images are *always* rendered using 337 Quartz. 338 339Why it goes fast 340================ 341 342 Specialisation is a formal name for an optimisation strategy that 343 removes layers of interpretation from a program. A classic example 344 is the standard C printf statement: 345 346 printf("Foo %i bar %s baz\n", i, s); 347 348 The usual technique is for the runtime system to parse the string 349 and insert the values of i and s appropriately. A specialised 350 version of this statement would note that the format string is 351 /constant/, and never changes, so a specialised version of that 352 printf statement would evaluate the format string at compile time 353 and output simpler routines that just print 'Foo ', then i, then ' 354 bar ', followed by s and ' baz\n'. 355 356 Zoom's particular specialisation is to note that many of the 357 bytecodes can only appear in limited combinations, so instead of 358 testing for the opcodes and then working out what the various bits 359 mean, Zoom simply tests for all possible values in an enormous 360 switch statement (or three) - this process is applied to the 361 opcodes themselves and their arguments. In addition, various 362 opcodes can be 'branch' opcodes or 'store' opcodes, etc. A custom 363 decoding routine is written for each and every opcode. 364 365 This would obviously take rather a long time to do by hand, but the 366 code is actually generated automatically by a helper program 367 (general purpose programs like this are known as 'partial 368 evaluators', but I'm not sure if the name applies to helper 369 programs such as the one used here). The code has to be generated 370 individually for different ZCode versions, and a consequence of 371 this is the rather large size of the Zoom executable (it's strongly 372 recommended you strip it to get rid of the excessively large 373 debugging tables :-) 374 375 Note that Zoom also makes extensive use of function inlining 376 (supported in C by gcc) to give an extra speed boost (actually 377 only an extra few %). If you compile in support for many Z-Code 378 versions, you may find that turning it off (by uncommenting the 379 '#define inline' in interp.c) will decrease the executable size 380 somewhat - as a side note, Zoom also depends on the compiler having 381 a few sensible optimisation strategies for its speed. Turning 382 optimisation off is probably never a good idea, as (under gcc under 383 x86 Linux) that increases the size of the executable and gives 384 quite a performance hit on those switch statements. 385 386 That's actually about it. Zoom is probably actually slower than 387 frotz in a few areas, I'll get round to writing a few benchmarks to 388 check them out and see what can be improved. 389 390Z-Machine extensions 391==================== 392 393 Zoom provides a selection of extensions to the Z-Machine: 394 395start_timer (EXT:128) (no arguments, neither branch nor store) 396 This makes a note of the time this instruction is used. Normally this 397 will be the CPU clock time returned by clock(). 398 399stop_timer (EXT:129) 400 This makes a note of the time this instruction is used, storing it 401 seperately from the time marked by start_timer. 402 403read_timer (EXT:130) (store) 404 This stores the difference between the start time and end time, as 405 defined by using the instruction above, in the variable. This time is 406 in centiseconds. 407 408print_timer (EXT:131) 409 This displays the difference between the start time and end time as a 410 decimal number of seconds, to centisecond precision. 411 412 If you want to add your own extensions for some nefarious purpose, all 413 opcodes are defined in src/zcode.ops, with definitions like: 414 415OPCODE "print_unicode" EXT:0x0b ARGS:1 VERSION 5,7,8 416%{ 417 stream_printc(argblock.arg[0]); 418%} 419 420 Extended ops are only available in v4+ games and the Z-Machine 421 specification suggests that you only use extended opcodes that are greater 422 than 0x80 to add new instructions. 423