Browse Source

first commit

master
asie 10 months ago
commit
b774aa4f7e
20 changed files with 4360 additions and 0 deletions
  1. 674
    0
      COPYING
  2. 16
    0
      NOTICE
  3. 38
    0
      README.md
  4. 37
    0
      src/config.h
  5. 1620
    0
      src/cpu.c
  6. 131
    0
      src/cpu.h
  7. 134
    0
      src/curses_glue.c
  8. 39
    0
      src/emscripten_glue.js
  9. 105
    0
      src/posix_glue.c
  10. 30
    0
      src/types.h
  11. 697
    0
      src/zzt.c
  12. 104
    0
      src/zzt.h
  13. 9
    0
      web/ZipLoader.min.js
  14. BIN
      web/ascii.png
  15. BIN
      web/loading.png
  16. 566
    0
      web/zzt.js
  17. 62
    0
      web/zzt_kbdmap.js
  18. 65
    0
      web/zzt_preload.js
  19. 3
    0
      zeta_curses.sh
  20. 30
    0
      zeta_wasm.sh

+ 674
- 0
COPYING View File

@@ -0,0 +1,674 @@
1
+                    GNU GENERAL PUBLIC LICENSE
2
+                       Version 3, 29 June 2007
3
+
4
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
5
+ Everyone is permitted to copy and distribute verbatim copies
6
+ of this license document, but changing it is not allowed.
7
+
8
+                            Preamble
9
+
10
+  The GNU General Public License is a free, copyleft license for
11
+software and other kinds of works.
12
+
13
+  The licenses for most software and other practical works are designed
14
+to take away your freedom to share and change the works.  By contrast,
15
+the GNU General Public License is intended to guarantee your freedom to
16
+share and change all versions of a program--to make sure it remains free
17
+software for all its users.  We, the Free Software Foundation, use the
18
+GNU General Public License for most of our software; it applies also to
19
+any other work released this way by its authors.  You can apply it to
20
+your programs, too.
21
+
22
+  When we speak of free software, we are referring to freedom, not
23
+price.  Our General Public Licenses are designed to make sure that you
24
+have the freedom to distribute copies of free software (and charge for
25
+them if you wish), that you receive source code or can get it if you
26
+want it, that you can change the software or use pieces of it in new
27
+free programs, and that you know you can do these things.
28
+
29
+  To protect your rights, we need to prevent others from denying you
30
+these rights or asking you to surrender the rights.  Therefore, you have
31
+certain responsibilities if you distribute copies of the software, or if
32
+you modify it: responsibilities to respect the freedom of others.
33
+
34
+  For example, if you distribute copies of such a program, whether
35
+gratis or for a fee, you must pass on to the recipients the same
36
+freedoms that you received.  You must make sure that they, too, receive
37
+or can get the source code.  And you must show them these terms so they
38
+know their rights.
39
+
40
+  Developers that use the GNU GPL protect your rights with two steps:
41
+(1) assert copyright on the software, and (2) offer you this License
42
+giving you legal permission to copy, distribute and/or modify it.
43
+
44
+  For the developers' and authors' protection, the GPL clearly explains
45
+that there is no warranty for this free software.  For both users' and
46
+authors' sake, the GPL requires that modified versions be marked as
47
+changed, so that their problems will not be attributed erroneously to
48
+authors of previous versions.
49
+
50
+  Some devices are designed to deny users access to install or run
51
+modified versions of the software inside them, although the manufacturer
52
+can do so.  This is fundamentally incompatible with the aim of
53
+protecting users' freedom to change the software.  The systematic
54
+pattern of such abuse occurs in the area of products for individuals to
55
+use, which is precisely where it is most unacceptable.  Therefore, we
56
+have designed this version of the GPL to prohibit the practice for those
57
+products.  If such problems arise substantially in other domains, we
58
+stand ready to extend this provision to those domains in future versions
59
+of the GPL, as needed to protect the freedom of users.
60
+
61
+  Finally, every program is threatened constantly by software patents.
62
+States should not allow patents to restrict development and use of
63
+software on general-purpose computers, but in those that do, we wish to
64
+avoid the special danger that patents applied to a free program could
65
+make it effectively proprietary.  To prevent this, the GPL assures that
66
+patents cannot be used to render the program non-free.
67
+
68
+  The precise terms and conditions for copying, distribution and
69
+modification follow.
70
+
71
+                       TERMS AND CONDITIONS
72
+
73
+  0. Definitions.
74
+
75
+  "This License" refers to version 3 of the GNU General Public License.
76
+
77
+  "Copyright" also means copyright-like laws that apply to other kinds of
78
+works, such as semiconductor masks.
79
+
80
+  "The Program" refers to any copyrightable work licensed under this
81
+License.  Each licensee is addressed as "you".  "Licensees" and
82
+"recipients" may be individuals or organizations.
83
+
84
+  To "modify" a work means to copy from or adapt all or part of the work
85
+in a fashion requiring copyright permission, other than the making of an
86
+exact copy.  The resulting work is called a "modified version" of the
87
+earlier work or a work "based on" the earlier work.
88
+
89
+  A "covered work" means either the unmodified Program or a work based
90
+on the Program.
91
+
92
+  To "propagate" a work means to do anything with it that, without
93
+permission, would make you directly or secondarily liable for
94
+infringement under applicable copyright law, except executing it on a
95
+computer or modifying a private copy.  Propagation includes copying,
96
+distribution (with or without modification), making available to the
97
+public, and in some countries other activities as well.
98
+
99
+  To "convey" a work means any kind of propagation that enables other
100
+parties to make or receive copies.  Mere interaction with a user through
101
+a computer network, with no transfer of a copy, is not conveying.
102
+
103
+  An interactive user interface displays "Appropriate Legal Notices"
104
+to the extent that it includes a convenient and prominently visible
105
+feature that (1) displays an appropriate copyright notice, and (2)
106
+tells the user that there is no warranty for the work (except to the
107
+extent that warranties are provided), that licensees may convey the
108
+work under this License, and how to view a copy of this License.  If
109
+the interface presents a list of user commands or options, such as a
110
+menu, a prominent item in the list meets this criterion.
111
+
112
+  1. Source Code.
113
+
114
+  The "source code" for a work means the preferred form of the work
115
+for making modifications to it.  "Object code" means any non-source
116
+form of a work.
117
+
118
+  A "Standard Interface" means an interface that either is an official
119
+standard defined by a recognized standards body, or, in the case of
120
+interfaces specified for a particular programming language, one that
121
+is widely used among developers working in that language.
122
+
123
+  The "System Libraries" of an executable work include anything, other
124
+than the work as a whole, that (a) is included in the normal form of
125
+packaging a Major Component, but which is not part of that Major
126
+Component, and (b) serves only to enable use of the work with that
127
+Major Component, or to implement a Standard Interface for which an
128
+implementation is available to the public in source code form.  A
129
+"Major Component", in this context, means a major essential component
130
+(kernel, window system, and so on) of the specific operating system
131
+(if any) on which the executable work runs, or a compiler used to
132
+produce the work, or an object code interpreter used to run it.
133
+
134
+  The "Corresponding Source" for a work in object code form means all
135
+the source code needed to generate, install, and (for an executable
136
+work) run the object code and to modify the work, including scripts to
137
+control those activities.  However, it does not include the work's
138
+System Libraries, or general-purpose tools or generally available free
139
+programs which are used unmodified in performing those activities but
140
+which are not part of the work.  For example, Corresponding Source
141
+includes interface definition files associated with source files for
142
+the work, and the source code for shared libraries and dynamically
143
+linked subprograms that the work is specifically designed to require,
144
+such as by intimate data communication or control flow between those
145
+subprograms and other parts of the work.
146
+
147
+  The Corresponding Source need not include anything that users
148
+can regenerate automatically from other parts of the Corresponding
149
+Source.
150
+
151
+  The Corresponding Source for a work in source code form is that
152
+same work.
153
+
154
+  2. Basic Permissions.
155
+
156
+  All rights granted under this License are granted for the term of
157
+copyright on the Program, and are irrevocable provided the stated
158
+conditions are met.  This License explicitly affirms your unlimited
159
+permission to run the unmodified Program.  The output from running a
160
+covered work is covered by this License only if the output, given its
161
+content, constitutes a covered work.  This License acknowledges your
162
+rights of fair use or other equivalent, as provided by copyright law.
163
+
164
+  You may make, run and propagate covered works that you do not
165
+convey, without conditions so long as your license otherwise remains
166
+in force.  You may convey covered works to others for the sole purpose
167
+of having them make modifications exclusively for you, or provide you
168
+with facilities for running those works, provided that you comply with
169
+the terms of this License in conveying all material for which you do
170
+not control copyright.  Those thus making or running the covered works
171
+for you must do so exclusively on your behalf, under your direction
172
+and control, on terms that prohibit them from making any copies of
173
+your copyrighted material outside their relationship with you.
174
+
175
+  Conveying under any other circumstances is permitted solely under
176
+the conditions stated below.  Sublicensing is not allowed; section 10
177
+makes it unnecessary.
178
+
179
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180
+
181
+  No covered work shall be deemed part of an effective technological
182
+measure under any applicable law fulfilling obligations under article
183
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
184
+similar laws prohibiting or restricting circumvention of such
185
+measures.
186
+
187
+  When you convey a covered work, you waive any legal power to forbid
188
+circumvention of technological measures to the extent such circumvention
189
+is effected by exercising rights under this License with respect to
190
+the covered work, and you disclaim any intention to limit operation or
191
+modification of the work as a means of enforcing, against the work's
192
+users, your or third parties' legal rights to forbid circumvention of
193
+technological measures.
194
+
195
+  4. Conveying Verbatim Copies.
196
+
197
+  You may convey verbatim copies of the Program's source code as you
198
+receive it, in any medium, provided that you conspicuously and
199
+appropriately publish on each copy an appropriate copyright notice;
200
+keep intact all notices stating that this License and any
201
+non-permissive terms added in accord with section 7 apply to the code;
202
+keep intact all notices of the absence of any warranty; and give all
203
+recipients a copy of this License along with the Program.
204
+
205
+  You may charge any price or no price for each copy that you convey,
206
+and you may offer support or warranty protection for a fee.
207
+
208
+  5. Conveying Modified Source Versions.
209
+
210
+  You may convey a work based on the Program, or the modifications to
211
+produce it from the Program, in the form of source code under the
212
+terms of section 4, provided that you also meet all of these conditions:
213
+
214
+    a) The work must carry prominent notices stating that you modified
215
+    it, and giving a relevant date.
216
+
217
+    b) The work must carry prominent notices stating that it is
218
+    released under this License and any conditions added under section
219
+    7.  This requirement modifies the requirement in section 4 to
220
+    "keep intact all notices".
221
+
222
+    c) You must license the entire work, as a whole, under this
223
+    License to anyone who comes into possession of a copy.  This
224
+    License will therefore apply, along with any applicable section 7
225
+    additional terms, to the whole of the work, and all its parts,
226
+    regardless of how they are packaged.  This License gives no
227
+    permission to license the work in any other way, but it does not
228
+    invalidate such permission if you have separately received it.
229
+
230
+    d) If the work has interactive user interfaces, each must display
231
+    Appropriate Legal Notices; however, if the Program has interactive
232
+    interfaces that do not display Appropriate Legal Notices, your
233
+    work need not make them do so.
234
+
235
+  A compilation of a covered work with other separate and independent
236
+works, which are not by their nature extensions of the covered work,
237
+and which are not combined with it such as to form a larger program,
238
+in or on a volume of a storage or distribution medium, is called an
239
+"aggregate" if the compilation and its resulting copyright are not
240
+used to limit the access or legal rights of the compilation's users
241
+beyond what the individual works permit.  Inclusion of a covered work
242
+in an aggregate does not cause this License to apply to the other
243
+parts of the aggregate.
244
+
245
+  6. Conveying Non-Source Forms.
246
+
247
+  You may convey a covered work in object code form under the terms
248
+of sections 4 and 5, provided that you also convey the
249
+machine-readable Corresponding Source under the terms of this License,
250
+in one of these ways:
251
+
252
+    a) Convey the object code in, or embodied in, a physical product
253
+    (including a physical distribution medium), accompanied by the
254
+    Corresponding Source fixed on a durable physical medium
255
+    customarily used for software interchange.
256
+
257
+    b) Convey the object code in, or embodied in, a physical product
258
+    (including a physical distribution medium), accompanied by a
259
+    written offer, valid for at least three years and valid for as
260
+    long as you offer spare parts or customer support for that product
261
+    model, to give anyone who possesses the object code either (1) a
262
+    copy of the Corresponding Source for all the software in the
263
+    product that is covered by this License, on a durable physical
264
+    medium customarily used for software interchange, for a price no
265
+    more than your reasonable cost of physically performing this
266
+    conveying of source, or (2) access to copy the
267
+    Corresponding Source from a network server at no charge.
268
+
269
+    c) Convey individual copies of the object code with a copy of the
270
+    written offer to provide the Corresponding Source.  This
271
+    alternative is allowed only occasionally and noncommercially, and
272
+    only if you received the object code with such an offer, in accord
273
+    with subsection 6b.
274
+
275
+    d) Convey the object code by offering access from a designated
276
+    place (gratis or for a charge), and offer equivalent access to the
277
+    Corresponding Source in the same way through the same place at no
278
+    further charge.  You need not require recipients to copy the
279
+    Corresponding Source along with the object code.  If the place to
280
+    copy the object code is a network server, the Corresponding Source
281
+    may be on a different server (operated by you or a third party)
282
+    that supports equivalent copying facilities, provided you maintain
283
+    clear directions next to the object code saying where to find the
284
+    Corresponding Source.  Regardless of what server hosts the
285
+    Corresponding Source, you remain obligated to ensure that it is
286
+    available for as long as needed to satisfy these requirements.
287
+
288
+    e) Convey the object code using peer-to-peer transmission, provided
289
+    you inform other peers where the object code and Corresponding
290
+    Source of the work are being offered to the general public at no
291
+    charge under subsection 6d.
292
+
293
+  A separable portion of the object code, whose source code is excluded
294
+from the Corresponding Source as a System Library, need not be
295
+included in conveying the object code work.
296
+
297
+  A "User Product" is either (1) a "consumer product", which means any
298
+tangible personal property which is normally used for personal, family,
299
+or household purposes, or (2) anything designed or sold for incorporation
300
+into a dwelling.  In determining whether a product is a consumer product,
301
+doubtful cases shall be resolved in favor of coverage.  For a particular
302
+product received by a particular user, "normally used" refers to a
303
+typical or common use of that class of product, regardless of the status
304
+of the particular user or of the way in which the particular user
305
+actually uses, or expects or is expected to use, the product.  A product
306
+is a consumer product regardless of whether the product has substantial
307
+commercial, industrial or non-consumer uses, unless such uses represent
308
+the only significant mode of use of the product.
309
+
310
+  "Installation Information" for a User Product means any methods,
311
+procedures, authorization keys, or other information required to install
312
+and execute modified versions of a covered work in that User Product from
313
+a modified version of its Corresponding Source.  The information must
314
+suffice to ensure that the continued functioning of the modified object
315
+code is in no case prevented or interfered with solely because
316
+modification has been made.
317
+
318
+  If you convey an object code work under this section in, or with, or
319
+specifically for use in, a User Product, and the conveying occurs as
320
+part of a transaction in which the right of possession and use of the
321
+User Product is transferred to the recipient in perpetuity or for a
322
+fixed term (regardless of how the transaction is characterized), the
323
+Corresponding Source conveyed under this section must be accompanied
324
+by the Installation Information.  But this requirement does not apply
325
+if neither you nor any third party retains the ability to install
326
+modified object code on the User Product (for example, the work has
327
+been installed in ROM).
328
+
329
+  The requirement to provide Installation Information does not include a
330
+requirement to continue to provide support service, warranty, or updates
331
+for a work that has been modified or installed by the recipient, or for
332
+the User Product in which it has been modified or installed.  Access to a
333
+network may be denied when the modification itself materially and
334
+adversely affects the operation of the network or violates the rules and
335
+protocols for communication across the network.
336
+
337
+  Corresponding Source conveyed, and Installation Information provided,
338
+in accord with this section must be in a format that is publicly
339
+documented (and with an implementation available to the public in
340
+source code form), and must require no special password or key for
341
+unpacking, reading or copying.
342
+
343
+  7. Additional Terms.
344
+
345
+  "Additional permissions" are terms that supplement the terms of this
346
+License by making exceptions from one or more of its conditions.
347
+Additional permissions that are applicable to the entire Program shall
348
+be treated as though they were included in this License, to the extent
349
+that they are valid under applicable law.  If additional permissions
350
+apply only to part of the Program, that part may be used separately
351
+under those permissions, but the entire Program remains governed by
352
+this License without regard to the additional permissions.
353
+
354
+  When you convey a copy of a covered work, you may at your option
355
+remove any additional permissions from that copy, or from any part of
356
+it.  (Additional permissions may be written to require their own
357
+removal in certain cases when you modify the work.)  You may place
358
+additional permissions on material, added by you to a covered work,
359
+for which you have or can give appropriate copyright permission.
360
+
361
+  Notwithstanding any other provision of this License, for material you
362
+add to a covered work, you may (if authorized by the copyright holders of
363
+that material) supplement the terms of this License with terms:
364
+
365
+    a) Disclaiming warranty or limiting liability differently from the
366
+    terms of sections 15 and 16 of this License; or
367
+
368
+    b) Requiring preservation of specified reasonable legal notices or
369
+    author attributions in that material or in the Appropriate Legal
370
+    Notices displayed by works containing it; or
371
+
372
+    c) Prohibiting misrepresentation of the origin of that material, or
373
+    requiring that modified versions of such material be marked in
374
+    reasonable ways as different from the original version; or
375
+
376
+    d) Limiting the use for publicity purposes of names of licensors or
377
+    authors of the material; or
378
+
379
+    e) Declining to grant rights under trademark law for use of some
380
+    trade names, trademarks, or service marks; or
381
+
382
+    f) Requiring indemnification of licensors and authors of that
383
+    material by anyone who conveys the material (or modified versions of
384
+    it) with contractual assumptions of liability to the recipient, for
385
+    any liability that these contractual assumptions directly impose on
386
+    those licensors and authors.
387
+
388
+  All other non-permissive additional terms are considered "further
389
+restrictions" within the meaning of section 10.  If the Program as you
390
+received it, or any part of it, contains a notice stating that it is
391
+governed by this License along with a term that is a further
392
+restriction, you may remove that term.  If a license document contains
393
+a further restriction but permits relicensing or conveying under this
394
+License, you may add to a covered work material governed by the terms
395
+of that license document, provided that the further restriction does
396
+not survive such relicensing or conveying.
397
+
398
+  If you add terms to a covered work in accord with this section, you
399
+must place, in the relevant source files, a statement of the
400
+additional terms that apply to those files, or a notice indicating
401
+where to find the applicable terms.
402
+
403
+  Additional terms, permissive or non-permissive, may be stated in the
404
+form of a separately written license, or stated as exceptions;
405
+the above requirements apply either way.
406
+
407
+  8. Termination.
408
+
409
+  You may not propagate or modify a covered work except as expressly
410
+provided under this License.  Any attempt otherwise to propagate or
411
+modify it is void, and will automatically terminate your rights under
412
+this License (including any patent licenses granted under the third
413
+paragraph of section 11).
414
+
415
+  However, if you cease all violation of this License, then your
416
+license from a particular copyright holder is reinstated (a)
417
+provisionally, unless and until the copyright holder explicitly and
418
+finally terminates your license, and (b) permanently, if the copyright
419
+holder fails to notify you of the violation by some reasonable means
420
+prior to 60 days after the cessation.
421
+
422
+  Moreover, your license from a particular copyright holder is
423
+reinstated permanently if the copyright holder notifies you of the
424
+violation by some reasonable means, this is the first time you have
425
+received notice of violation of this License (for any work) from that
426
+copyright holder, and you cure the violation prior to 30 days after
427
+your receipt of the notice.
428
+
429
+  Termination of your rights under this section does not terminate the
430
+licenses of parties who have received copies or rights from you under
431
+this License.  If your rights have been terminated and not permanently
432
+reinstated, you do not qualify to receive new licenses for the same
433
+material under section 10.
434
+
435
+  9. Acceptance Not Required for Having Copies.
436
+
437
+  You are not required to accept this License in order to receive or
438
+run a copy of the Program.  Ancillary propagation of a covered work
439
+occurring solely as a consequence of using peer-to-peer transmission
440
+to receive a copy likewise does not require acceptance.  However,
441
+nothing other than this License grants you permission to propagate or
442
+modify any covered work.  These actions infringe copyright if you do
443
+not accept this License.  Therefore, by modifying or propagating a
444
+covered work, you indicate your acceptance of this License to do so.
445
+
446
+  10. Automatic Licensing of Downstream Recipients.
447
+
448
+  Each time you convey a covered work, the recipient automatically
449
+receives a license from the original licensors, to run, modify and
450
+propagate that work, subject to this License.  You are not responsible
451
+for enforcing compliance by third parties with this License.
452
+
453
+  An "entity transaction" is a transaction transferring control of an
454
+organization, or substantially all assets of one, or subdividing an
455
+organization, or merging organizations.  If propagation of a covered
456
+work results from an entity transaction, each party to that
457
+transaction who receives a copy of the work also receives whatever
458
+licenses to the work the party's predecessor in interest had or could
459
+give under the previous paragraph, plus a right to possession of the
460
+Corresponding Source of the work from the predecessor in interest, if
461
+the predecessor has it or can get it with reasonable efforts.
462
+
463
+  You may not impose any further restrictions on the exercise of the
464
+rights granted or affirmed under this License.  For example, you may
465
+not impose a license fee, royalty, or other charge for exercise of
466
+rights granted under this License, and you may not initiate litigation
467
+(including a cross-claim or counterclaim in a lawsuit) alleging that
468
+any patent claim is infringed by making, using, selling, offering for
469
+sale, or importing the Program or any portion of it.
470
+
471
+  11. Patents.
472
+
473
+  A "contributor" is a copyright holder who authorizes use under this
474
+License of the Program or a work on which the Program is based.  The
475
+work thus licensed is called the contributor's "contributor version".
476
+
477
+  A contributor's "essential patent claims" are all patent claims
478
+owned or controlled by the contributor, whether already acquired or
479
+hereafter acquired, that would be infringed by some manner, permitted
480
+by this License, of making, using, or selling its contributor version,
481
+but do not include claims that would be infringed only as a
482
+consequence of further modification of the contributor version.  For
483
+purposes of this definition, "control" includes the right to grant
484
+patent sublicenses in a manner consistent with the requirements of
485
+this License.
486
+
487
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
488
+patent license under the contributor's essential patent claims, to
489
+make, use, sell, offer for sale, import and otherwise run, modify and
490
+propagate the contents of its contributor version.
491
+
492
+  In the following three paragraphs, a "patent license" is any express
493
+agreement or commitment, however denominated, not to enforce a patent
494
+(such as an express permission to practice a patent or covenant not to
495
+sue for patent infringement).  To "grant" such a patent license to a
496
+party means to make such an agreement or commitment not to enforce a
497
+patent against the party.
498
+
499
+  If you convey a covered work, knowingly relying on a patent license,
500
+and the Corresponding Source of the work is not available for anyone
501
+to copy, free of charge and under the terms of this License, through a
502
+publicly available network server or other readily accessible means,
503
+then you must either (1) cause the Corresponding Source to be so
504
+available, or (2) arrange to deprive yourself of the benefit of the
505
+patent license for this particular work, or (3) arrange, in a manner
506
+consistent with the requirements of this License, to extend the patent
507
+license to downstream recipients.  "Knowingly relying" means you have
508
+actual knowledge that, but for the patent license, your conveying the
509
+covered work in a country, or your recipient's use of the covered work
510
+in a country, would infringe one or more identifiable patents in that
511
+country that you have reason to believe are valid.
512
+
513
+  If, pursuant to or in connection with a single transaction or
514
+arrangement, you convey, or propagate by procuring conveyance of, a
515
+covered work, and grant a patent license to some of the parties
516
+receiving the covered work authorizing them to use, propagate, modify
517
+or convey a specific copy of the covered work, then the patent license
518
+you grant is automatically extended to all recipients of the covered
519
+work and works based on it.
520
+
521
+  A patent license is "discriminatory" if it does not include within
522
+the scope of its coverage, prohibits the exercise of, or is
523
+conditioned on the non-exercise of one or more of the rights that are
524
+specifically granted under this License.  You may not convey a covered
525
+work if you are a party to an arrangement with a third party that is
526
+in the business of distributing software, under which you make payment
527
+to the third party based on the extent of your activity of conveying
528
+the work, and under which the third party grants, to any of the
529
+parties who would receive the covered work from you, a discriminatory
530
+patent license (a) in connection with copies of the covered work
531
+conveyed by you (or copies made from those copies), or (b) primarily
532
+for and in connection with specific products or compilations that
533
+contain the covered work, unless you entered into that arrangement,
534
+or that patent license was granted, prior to 28 March 2007.
535
+
536
+  Nothing in this License shall be construed as excluding or limiting
537
+any implied license or other defenses to infringement that may
538
+otherwise be available to you under applicable patent law.
539
+
540
+  12. No Surrender of Others' Freedom.
541
+
542
+  If conditions are imposed on you (whether by court order, agreement or
543
+otherwise) that contradict the conditions of this License, they do not
544
+excuse you from the conditions of this License.  If you cannot convey a
545
+covered work so as to satisfy simultaneously your obligations under this
546
+License and any other pertinent obligations, then as a consequence you may
547
+not convey it at all.  For example, if you agree to terms that obligate you
548
+to collect a royalty for further conveying from those to whom you convey
549
+the Program, the only way you could satisfy both those terms and this
550
+License would be to refrain entirely from conveying the Program.
551
+
552
+  13. Use with the GNU Affero General Public License.
553
+
554
+  Notwithstanding any other provision of this License, you have
555
+permission to link or combine any covered work with a work licensed
556
+under version 3 of the GNU Affero General Public License into a single
557
+combined work, and to convey the resulting work.  The terms of this
558
+License will continue to apply to the part which is the covered work,
559
+but the special requirements of the GNU Affero General Public License,
560
+section 13, concerning interaction through a network will apply to the
561
+combination as such.
562
+
563
+  14. Revised Versions of this License.
564
+
565
+  The Free Software Foundation may publish revised and/or new versions of
566
+the GNU General Public License from time to time.  Such new versions will
567
+be similar in spirit to the present version, but may differ in detail to
568
+address new problems or concerns.
569
+
570
+  Each version is given a distinguishing version number.  If the
571
+Program specifies that a certain numbered version of the GNU General
572
+Public License "or any later version" applies to it, you have the
573
+option of following the terms and conditions either of that numbered
574
+version or of any later version published by the Free Software
575
+Foundation.  If the Program does not specify a version number of the
576
+GNU General Public License, you may choose any version ever published
577
+by the Free Software Foundation.
578
+
579
+  If the Program specifies that a proxy can decide which future
580
+versions of the GNU General Public License can be used, that proxy's
581
+public statement of acceptance of a version permanently authorizes you
582
+to choose that version for the Program.
583
+
584
+  Later license versions may give you additional or different
585
+permissions.  However, no additional obligations are imposed on any
586
+author or copyright holder as a result of your choosing to follow a
587
+later version.
588
+
589
+  15. Disclaimer of Warranty.
590
+
591
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599
+
600
+  16. Limitation of Liability.
601
+
602
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610
+SUCH DAMAGES.
611
+
612
+  17. Interpretation of Sections 15 and 16.
613
+
614
+  If the disclaimer of warranty and limitation of liability provided
615
+above cannot be given local legal effect according to their terms,
616
+reviewing courts shall apply local law that most closely approximates
617
+an absolute waiver of all civil liability in connection with the
618
+Program, unless a warranty or assumption of liability accompanies a
619
+copy of the Program in return for a fee.
620
+
621
+                     END OF TERMS AND CONDITIONS
622
+
623
+            How to Apply These Terms to Your New Programs
624
+
625
+  If you develop a new program, and you want it to be of the greatest
626
+possible use to the public, the best way to achieve this is to make it
627
+free software which everyone can redistribute and change under these terms.
628
+
629
+  To do so, attach the following notices to the program.  It is safest
630
+to attach them to the start of each source file to most effectively
631
+state the exclusion of warranty; and each file should have at least
632
+the "copyright" line and a pointer to where the full notice is found.
633
+
634
+    <one line to give the program's name and a brief idea of what it does.>
635
+    Copyright (C) <year>  <name of author>
636
+
637
+    This program is free software: you can redistribute it and/or modify
638
+    it under the terms of the GNU General Public License as published by
639
+    the Free Software Foundation, either version 3 of the License, or
640
+    (at your option) any later version.
641
+
642
+    This program is distributed in the hope that it will be useful,
643
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
644
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
645
+    GNU General Public License for more details.
646
+
647
+    You should have received a copy of the GNU General Public License
648
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
649
+
650
+Also add information on how to contact you by electronic and paper mail.
651
+
652
+  If the program does terminal interaction, make it output a short
653
+notice like this when it starts in an interactive mode:
654
+
655
+    <program>  Copyright (C) <year>  <name of author>
656
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657
+    This is free software, and you are welcome to redistribute it
658
+    under certain conditions; type `show c' for details.
659
+
660
+The hypothetical commands `show w' and `show c' should show the appropriate
661
+parts of the General Public License.  Of course, your program's commands
662
+might be different; for a GUI interface, you would use an "about box".
663
+
664
+  You should also get your employer (if you work as a programmer) or school,
665
+if any, to sign a "copyright disclaimer" for the program, if necessary.
666
+For more information on this, and how to apply and follow the GNU GPL, see
667
+<http://www.gnu.org/licenses/>.
668
+
669
+  The GNU General Public License does not permit incorporating your program
670
+into proprietary programs.  If your program is a subroutine library, you
671
+may consider it more useful to permit linking proprietary applications with
672
+the library.  If this is what you want to do, use the GNU Lesser General
673
+Public License instead of this License.  But first, please read
674
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.

+ 16
- 0
NOTICE View File

@@ -0,0 +1,16 @@
1
+Copyright (c) 2018 Adrian Siekierka
2
+
3
+This file is part of Zeta.
4
+
5
+Zeta is free software: you can redistribute it and/or modify
6
+it under the terms of the GNU General Public License as published by
7
+the Free Software Foundation, either version 3 of the License, or
8
+(at your option) any later version.
9
+
10
+Zeta is distributed in the hope that it will be useful,
11
+but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+GNU General Public License for more details.
14
+
15
+You should have received a copy of the GNU General Public License
16
+along with Zeta.  If not, see <http://www.gnu.org/licenses/>.

+ 38
- 0
README.md View File

@@ -0,0 +1,38 @@
1
+# Zeta
2
+
3
+Zeta consists of:
4
+
5
+* an 8086/80186 emulation core, based on lunatic86,
6
+* an emulation environment geared specifically towards running ZZT and Super ZZT.
7
+
8
+Currently, it has the following front-ends:
9
+
10
+* *curses* - incomplete, designed primarily for testing,
11
+* *web* - utilizes the WASM-compiled version of Zeta to allow using Zeta inside a web browser.
12
+
13
+## Directory structure
14
+
15
+* build/ - contains build output files,
16
+* src/ - contains the source code to the Zeta emulator, as well as the Curse 
17
+
18
+## Implementing your own front-end
19
+
20
+Refer to src/zzt.h. Functions marked USER_FUNCTION are accessible to you to interface with
21
+the emulator core, while functions marked IMPLEMENT_FUNCTION should be implemented.
22
+
23
+Certain methods can be dummied out:
24
+
25
+* vfs_write - if you don't need file writing,
26
+* speaker_on/speaker_off - if you don't emulate the PC Speaker,
27
+* vfs_findfirst/vfs_findnext - if you don't want file lookup to work.
28
+
29
+There is, unfortunately, little documentation at this time.
30
+
31
+## License
32
+
33
+The source code release of Zeta generally available under the terms of the GPLv3 license.
34
+For different licensing terms, please contact me directly.
35
+
36
+The binary copy available [here](https://github.com/asiekierka/zeta-z2) is for usage by
37
+the [Museum of ZZT](http://museumofzzt.com/). It may not be used by any other entity, however it is used
38
+by the Museum with explicit permission.

+ 37
- 0
src/config.h View File

@@ -0,0 +1,37 @@
1
+/**
2
+ * Copyright (c) 2018 Adrian Siekierka
3
+ *
4
+ * This file is part of Zeta.
5
+ *
6
+ * Zeta is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * Zeta is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with Zeta.  If not, see <http://www.gnu.org/licenses/>.
18
+ */
19
+
20
+#ifndef __CONFIG_H__
21
+#define __CONFIG_H__
22
+
23
+//#define BIG_ENDIAN
24
+#define UNALIGNED_OK
25
+#define MAX_INTQUEUE_SIZE 256
26
+
27
+// required for accurate Zeta joystick support
28
+#define CPU_CHECK_KEEP_GOING
29
+
30
+//#define USE_8086_PUSH_SP_BUG
31
+//#define USE_OPCODES_8086_ALIASED
32
+//#define USE_OPCODES_8086_UNDOCUMENTED
33
+//#define USE_OPCODES_80186
34
+//#define USE_OPCODES_DECIMAL
35
+//#define USE_OPCODES_SALC
36
+
37
+#endif /* __CONFIG_H__ */

+ 1620
- 0
src/cpu.c
File diff suppressed because it is too large
View File


+ 131
- 0
src/cpu.h View File

@@ -0,0 +1,131 @@
1
+/**
2
+ * Copyright (c) 2018 Adrian Siekierka
3
+ *
4
+ * This file is part of Zeta.
5
+ *
6
+ * Zeta is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * Zeta is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with Zeta.  If not, see <http://www.gnu.org/licenses/>.
18
+ */
19
+
20
+#ifndef __CPU_H__
21
+#define __CPU_H__
22
+#define MAX_INTQUEUE_SIZE 256
23
+
24
+
25
+#include "config.h"
26
+#include "types.h"
27
+
28
+#define FLAG_CARRY 1
29
+#define FLAG_PARITY 4
30
+#define FLAG_ADJUST 16
31
+#define FLAG_ZERO 64
32
+#define FLAG_SIGN 128
33
+#define FLAG_TRAP 256
34
+#define FLAG_INTERRUPT 512
35
+#define FLAG_DIRECTION 1024
36
+#define FLAG_OVERFLOW 2048
37
+
38
+#define SEG_ES 0
39
+#define SEG_CS 1
40
+#define SEG_SS 2
41
+#define SEG_DS 3
42
+
43
+struct s_cpu_state {
44
+	u8 ram[1048576];
45
+
46
+	struct {
47
+		union {
48
+			struct {
49
+				#ifdef BIG_ENDIAN
50
+					u8 ah, al;
51
+				#else
52
+					u8 al, ah;
53
+				#endif
54
+			};
55
+			u16 ax;
56
+		};
57
+	};
58
+	struct {
59
+		union {
60
+			struct {
61
+				#ifdef BIG_ENDIAN
62
+					u8 ch, cl;
63
+				#else
64
+					u8 cl, ch;
65
+				#endif
66
+			};
67
+			u16 cx;
68
+		};
69
+	};
70
+	struct {
71
+		union {
72
+			struct {
73
+				#ifdef BIG_ENDIAN
74
+					u8 dh, dl;
75
+				#else
76
+					u8 dl, dh;
77
+				#endif
78
+			};
79
+			u16 dx;
80
+		};
81
+	};
82
+	struct {
83
+		union {
84
+			struct {
85
+				#ifdef BIG_ENDIAN
86
+					u8 bh, bl;
87
+				#else
88
+					u8 bl, bh;
89
+				#endif
90
+			};
91
+			u16 bx;
92
+		};
93
+	};
94
+	u16 sp, bp, si, di;
95
+	u16 seg[4];
96
+	u16 ip, flags;
97
+	u8 segmod, halted, terminated;
98
+	u32 keep_going;
99
+
100
+	void* port_obj;
101
+	void* intr_obj;
102
+
103
+	u16 (*func_port_in)(struct s_cpu_state* cpu, u16 port);
104
+	void (*func_port_out)(struct s_cpu_state* cpu, u16 port, u16 val);
105
+	int /* state */ (*func_interrupt)(struct s_cpu_state* cpu, u8 intr);
106
+
107
+	u8 intq[MAX_INTQUEUE_SIZE];
108
+	int intq_pos;
109
+};
110
+
111
+typedef struct s_cpu_state cpu_state;
112
+
113
+#define STATE_END 0
114
+#define STATE_CONTINUE 1
115
+#define STATE_BLOCK 2
116
+
117
+void cpu_init_globals();
118
+void cpu_init(cpu_state* cpu);
119
+int cpu_execute(cpu_state* cpu, int cycles);
120
+
121
+void cpu_push16(cpu_state* cpu, u16 v);
122
+u16 cpu_pop16(cpu_state* cpu);
123
+
124
+void cpu_emit_interrupt(cpu_state* cpu, u8 intr);
125
+void cpu_set_ip(cpu_state* cpu, u16 cs, u16 ip);
126
+
127
+// external
128
+
129
+void cpu_ext_log(const char* msg);
130
+
131
+#endif /* __CPU_H__ */

+ 134
- 0
src/curses_glue.c View File

@@ -0,0 +1,134 @@
1
+/**
2
+ * Copyright (c) 2018 Adrian Siekierka
3
+ *
4
+ * This file is part of Zeta.
5
+ *
6
+ * Zeta is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * Zeta is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with Zeta.  If not, see <http://www.gnu.org/licenses/>.
18
+ */
19
+
20
+#include <stdio.h>
21
+#include <stdlib.h>
22
+#include <string.h>
23
+#include <time.h>
24
+#include <ncurses.h>
25
+#include "zzt.h"
26
+
27
+void init_posix_glue();
28
+
29
+void speaker_on(double freq) {}
30
+void speaker_off() {}
31
+
32
+static int map_char_to_key[512];
33
+static WINDOW* window;
34
+
35
+int vfs_has_feature(int feature) {
36
+	return 1;
37
+}
38
+
39
+static void platform_kbd_tick() {
40
+	int c = getch();
41
+	if (c == ERR) return;
42
+	if (c == 263) c = 8;
43
+	if (c == 0 || map_char_to_key[c] != 0) {
44
+		int k = map_char_to_key[c];
45
+		zzt_key(c, k);
46
+	}
47
+}
48
+
49
+static void init_map_char_to_key() {
50
+	map_char_to_key[258] = 0x50; // down
51
+	map_char_to_key[260] = 0x4B; // left
52
+	map_char_to_key[259] = 0x48; // up
53
+	map_char_to_key[261] = 0x4D; // right
54
+	map_char_to_key[13] = 0x1C; // enter
55
+	map_char_to_key[0] = 0;
56
+	map_char_to_key[0x1C] = 1; // esc
57
+	for (int i = 1; i <= 9; i++) map_char_to_key[i + 48] = i + 1;
58
+	char* chrs = "!@#$%^&*()";
59
+	for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = i + 1;
60
+	map_char_to_key[48] = 11; // numbers
61
+	map_char_to_key[45] = 12; // -
62
+	map_char_to_key[95] = 12; // _
63
+	map_char_to_key[61] = 13; // =
64
+	map_char_to_key[43] = 12; // +
65
+	map_char_to_key[8] = 14; // backspace
66
+	map_char_to_key[9] = 15; // tab
67
+	chrs = "qwertyuiop[]";
68
+	for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = 15 + i;
69
+	chrs = "QWERTYUIOP{}";
70
+	for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = 15 + i;
71
+	map_char_to_key[13] = 28; // enter
72
+	// 29?
73
+	chrs = "asdfghjkl;'";
74
+	for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = 29 + i;
75
+	chrs = "ASDFGHJKL:\"";
76
+	for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = 29 + i;
77
+	map_char_to_key[96] = 41; // `
78
+	map_char_to_key[126] = 41; // ~
79
+	// 42?
80
+	map_char_to_key[92] = 43;
81
+	map_char_to_key[124] = 43; // |
82
+	chrs = "zxcvbnm,./";
83
+	for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = 43 + i;
84
+	chrs = "ZXCVBNM<>?";
85
+	for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = 43 + i;
86
+	// 54?
87
+	map_char_to_key[42] = 55; // *
88
+	// 56?
89
+	map_char_to_key[32] = 57; // space
90
+}
91
+
92
+int main() {
93
+	init_posix_glue();
94
+	init_map_char_to_key();
95
+	zzt_init();
96
+
97
+	window = initscr();
98
+	cbreak();
99
+	noecho();
100
+	nonl();
101
+	wclear(window);
102
+	nodelay(window, 1);
103
+	scrollok(window, 1);
104
+	idlok(window, 1);
105
+	keypad(window, 1);
106
+
107
+	clock_t last = clock();
108
+	clock_t curr = last;
109
+
110
+	while (zzt_execute(1600000)) {
111
+		// refresh screen
112
+		u8* ram = zzt_get_ram();
113
+		for (int y = 0; y < 25; y++) {
114
+			for (int x = 0; x < 80; x++) {
115
+				u8 chr = ram[TEXT_ADDR(x,y)];
116
+				if (chr == 2) chr = '@';
117
+				else if (chr == 0) chr = 32;
118
+				else if (chr < 32 || chr >= 128)
119
+					chr = '0' + (chr % 10);
120
+				mvwaddch(window, y, x, chr);
121
+			}
122
+		}
123
+		wrefresh(window);
124
+		zzt_mark_frame();
125
+
126
+		curr = clock();
127
+		float secs = (float) (curr - last) / CLOCKS_PER_SEC;
128
+		fprintf(stderr, "%.2f opc/sec\n", 1600000.0f / secs);
129
+		platform_kbd_tick();
130
+		last = curr;
131
+
132
+		zzt_mark_timer();
133
+	}
134
+}

+ 39
- 0
src/emscripten_glue.js View File

@@ -0,0 +1,39 @@
1
+mergeInto(LibraryManager.library, {
2
+	cpu_ext_log: function(s) {
3
+		console.log(Pointer_stringify(s));
4
+	},
5
+	vfs_time_ms: function() {
6
+		return vfsg_time_ms();
7
+	},
8
+	vfs_open: function(fn, mode) {
9
+		return vfsg_open(fn, mode);
10
+	},
11
+	vfs_seek: function(h, pos, type) {
12
+		return vfsg_seek(h, pos, type);
13
+	},
14
+	vfs_read: function(h, ptr, amount) {
15
+		return vfsg_read(h, ptr, amount);
16
+	},
17
+	vfs_write: function(h, ptr, amount) {
18
+		return vfsg_write(h, ptr, amount);
19
+	},
20
+	vfs_close: function(h) {
21
+		return vfsg_close(h);
22
+	},
23
+	vfs_findfirst: function(ptr, mask, spec) {
24
+		return vfsg_findfirst(ptr, mask, spec);
25
+	},
26
+	vfs_findnext: function(ptr) {
27
+		return vfsg_findnext(ptr);
28
+	},
29
+	vfs_has_feature: function(id) {
30
+		return vfsg_has_feature(id);
31
+	},
32
+	speaker_on: function(freq) {
33
+		speakerg_on(freq);
34
+	},
35
+	speaker_off: function() {
36
+		speakerg_off();
37
+	}
38
+});
39
+

+ 105
- 0
src/posix_glue.c View File

@@ -0,0 +1,105 @@
1
+/**
2
+ * Copyright (c) 2018 Adrian Siekierka
3
+ *
4
+ * This file is part of Zeta.
5
+ *
6
+ * Zeta is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * Zeta is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with Zeta.  If not, see <http://www.gnu.org/licenses/>.
18
+ */
19
+
20
+#include <stdio.h>
21
+#include <stdlib.h>
22
+#include <string.h>
23
+#include <time.h>
24
+#include <ncurses.h>
25
+#include "zzt.h"
26
+
27
+long vfs_time_ms() {
28
+	clock_t c = clock();
29
+	return c / 1000;
30
+}
31
+
32
+#define MAX_FNLEN 259
33
+
34
+static FILE* file_pointers[MAX_FILES];
35
+static char vfs_fnbuf[MAX_FNLEN+1];
36
+static int vfs_fnprefsize;
37
+
38
+int vfs_findfirst(u8* ptr, u16 mask, char* spec) { return -1; }
39
+int vfs_findnext(u8* ptr) { return -1; }
40
+
41
+void init_posix_glue() {
42
+	vfs_fnbuf[0] = 'v';
43
+	vfs_fnbuf[1] = 'f';
44
+	vfs_fnbuf[2] = 's';
45
+	vfs_fnbuf[3] = '/';
46
+	vfs_fnprefsize = 4;
47
+	for (int i = 0; i < MAX_FILES; i++)
48
+		file_pointers[i] = NULL;
49
+}
50
+
51
+int vfs_open(const char* filename, int mode) {
52
+	int len = strlen(filename);
53
+	if (len > (MAX_FNLEN - vfs_fnprefsize)) {
54
+		return -1;
55
+	}
56
+
57
+	int pos = 0;
58
+	while (pos < MAX_FILES && file_pointers[pos] != NULL) pos++;
59
+	if (pos == MAX_FILES) return -1;
60
+
61
+	for (int i = 0; i < strlen(filename); i++) {
62
+		char c = filename[i];
63
+		if (c >= 'a' && c <= 'z') c -= 'a' - 'A';
64
+		vfs_fnbuf[i+vfs_fnprefsize] = c;
65
+	}
66
+	vfs_fnbuf[len+vfs_fnprefsize] = 0;
67
+
68
+	FILE* file = fopen(vfs_fnbuf, (mode & 0x10000) ? "w+b" : (((mode & 0x03) == 0) ? "rb" : "r+b"));
69
+	if (file == NULL) return -1;
70
+	file_pointers[pos] = file;
71
+	return pos+1;
72
+}
73
+
74
+int vfs_read(int handle, u8* ptr, int amount) {
75
+	if (handle <= 0 || handle > MAX_FILES) return -1;
76
+	FILE* fptr = file_pointers[handle-1];
77
+	return fread(ptr, 1, amount, fptr);
78
+}
79
+
80
+int vfs_write(int handle, u8* ptr, int amount) {
81
+	if (handle <= 0 || handle > MAX_FILES) return -1;
82
+	FILE* fptr = file_pointers[handle-1];
83
+	return fwrite(ptr, 1, amount, fptr);
84
+}
85
+
86
+int vfs_seek(int handle, int amount, int type) {
87
+	if (handle <= 0 || handle > MAX_FILES) return -1;
88
+	FILE* fptr = file_pointers[handle-1];
89
+	switch (type) {
90
+		default:
91
+		case VFS_SEEK_SET: return fseek(fptr, amount, SEEK_SET);
92
+		case VFS_SEEK_CUR: return fseek(fptr, amount, SEEK_CUR);
93
+		case VFS_SEEK_END: return fseek(fptr, amount, SEEK_END);
94
+	}
95
+}
96
+
97
+int vfs_close(int handle) {
98
+	if (handle <= 0 || handle > MAX_FILES) return -1;
99
+	FILE* fptr = file_pointers[handle-1];
100
+	return fclose(fptr);
101
+}
102
+
103
+void cpu_ext_log(const char* s) {
104
+	fprintf(stderr, "%s\n", s);
105
+}

+ 30
- 0
src/types.h View File

@@ -0,0 +1,30 @@
1
+/**
2
+ * Copyright (c) 2018 Adrian Siekierka
3
+ *
4
+ * This file is part of Zeta.
5
+ *
6
+ * Zeta is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * Zeta is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with Zeta.  If not, see <http://www.gnu.org/licenses/>.
18
+ */
19
+
20
+#ifndef __TYPES_H__
21
+#define __TYPES_H__
22
+
23
+typedef char s8;
24
+typedef short s16;
25
+typedef int s32;
26
+typedef unsigned char u8;
27
+typedef unsigned short u16;
28
+typedef unsigned int u32;
29
+
30
+#endif /* __TYPES_H__ */

+ 697
- 0
src/zzt.c View File

@@ -0,0 +1,697 @@
1
+/**
2
+ * Copyright (c) 2018 Adrian Siekierka
3
+ *
4
+ * This file is part of Zeta.
5
+ *
6
+ * Zeta is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * Zeta is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with Zeta.  If not, see <http://www.gnu.org/licenses/>.
18
+ */
19
+
20
+#include "zzt.h"
21
+
22
+#ifdef EMSCRIPTEN
23
+#define fprintf(...)
24
+#else
25
+#include <stdio.h>
26
+#endif
27
+
28
+typedef struct {
29
+	cpu_state cpu;
30
+
31
+	// keyboard
32
+	int qch, qke, kmod;
33
+
34
+	// joystick
35
+	u8 joy_xstrobe_val, joy_ystrobe_val;
36
+	u8 joy_xstrobes, joy_ystrobes;
37
+
38
+	// mouse
39
+	u16 mouse_buttons;
40
+	u16 mouse_x, mouse_y;
41
+	s16 mouse_xd, mouse_yd;
42
+
43
+	// I/O
44
+	u8 cga_status;
45
+	u8 port_42_latch;
46
+	u16 port_42;
47
+	// u8 port_43[3]; (not actually used)
48
+	u8 port_61;
49
+	u8 port_201;
50
+
51
+	// DOS
52
+	u32 dos_dta;
53
+} zzt_state;
54
+
55
+zzt_state zzt;
56
+
57
+void zzt_kmod_set(int mod) {
58
+	zzt.kmod |= mod;
59
+}
60
+
61
+void zzt_kmod_clear(int mod) {
62
+	zzt.kmod &= ~mod;
63
+}
64
+
65
+void zzt_key(int c, int k) {
66
+	zzt.qch = c >= 0 && c < 128 ? c : 0;
67
+	zzt.qke = k;
68
+	fprintf(stderr, "kbget %d %d\n", zzt.qch, zzt.qke);
69
+}
70
+
71
+static void cpu_func_intr_0x10(cpu_state* cpu);
72
+static void cpu_func_intr_0x13(cpu_state* cpu);
73
+static void cpu_func_intr_0x16(cpu_state* cpu);
74
+static void cpu_func_intr_0x21(cpu_state* cpu);
75
+
76
+void zzt_mark_frame(void) {
77
+	zzt.cga_status |= 0x8;
78
+}
79
+
80
+#define JOY_MIN 3
81
+#define JOY_MAX 51
82
+#define JOY_MID (JOY_MIN+JOY_MAX/2)
83
+#define JOY_RANGE (JOY_MAX-JOY_MIN)
84
+
85
+void zzt_joy_set(int button) {
86
+	if (button < 2) zzt.port_201 &= ~(1 << (button + 4));
87
+}
88
+
89
+void zzt_joy_clear(int button) {
90
+	if (button < 2) zzt.port_201 |= (1 << (button + 4));
91
+}
92
+
93
+void zzt_joy_axis(int axis, int value) {
94
+	if (axis >= 2) return;
95
+
96
+	value = ((value + 127) * JOY_RANGE / 254) + JOY_MIN;
97
+	switch (axis) {
98
+		case 0: zzt.joy_xstrobe_val = value; break;
99
+		case 1: zzt.joy_ystrobe_val = value; break;
100
+	}
101
+}
102
+
103
+static void zzt_joy_strobe(zzt_state* zzt) {
104
+	if (zzt->joy_xstrobes == 0) zzt->cpu.keep_going++;
105
+	if (zzt->joy_ystrobes == 0) zzt->cpu.keep_going++;
106
+	zzt->joy_xstrobes = zzt->joy_xstrobe_val;
107
+	zzt->joy_ystrobes = zzt->joy_ystrobe_val;
108
+}
109
+
110
+void zzt_mouse_set(int button) {
111
+	zzt.mouse_buttons |= 1 << button;
112
+}
113
+
114
+void zzt_mouse_clear(int button) {
115
+	zzt.mouse_buttons &= ~(1 << button);
116
+}
117
+
118
+static inline int m_clamp(int v, int min, int max) {
119
+	return (v > min) ? ((v < max) ? v : max) : min;
120
+}
121
+
122
+void zzt_mouse_axis(int axis, int value) {
123
+	switch (axis) {
124
+		case 0:
125
+			zzt.mouse_xd += value;
126
+			zzt.mouse_x = m_clamp(zzt.mouse_x + value, 0, 639);
127
+			break;
128
+		case 1:
129
+			zzt.mouse_yd += value;
130
+			zzt.mouse_y = m_clamp(zzt.mouse_y + value, 0, 349);
131
+			break;
132
+	}
133
+}
134
+
135
+static u16 cpu_func_port_in_main(cpu_state* cpu, u16 addr) {
136
+	zzt_state* zzt = (zzt_state*) cpu;
137
+
138
+	switch (addr) {
139
+		case 0x61:
140
+			return zzt->port_61;
141
+		case 0x201:
142
+			if (!vfs_has_feature(FEATURE_JOY_CONNECTED))
143
+				return 0xF0;
144
+			zzt->port_201 &= 0xF0;
145
+			if (zzt->joy_xstrobes > 0) {
146
+				zzt->joy_xstrobes--;
147
+				if (zzt->joy_xstrobes == 0) cpu->keep_going--;
148
+				zzt->port_201 |= 1;
149
+			}
150
+			if (zzt->joy_ystrobes > 0) {
151
+				zzt->joy_ystrobes--;
152
+				if (zzt->joy_ystrobes == 0) cpu->keep_going--;
153
+				zzt->port_201 |= 2;
154
+			}
155
+			return zzt->port_201;
156
+		case 0x3DA: {
157
+			int old_status = zzt->cga_status;
158
+			zzt->cga_status = (old_status & (~0x8)) ^ 0x1;
159
+			return old_status;
160
+		}
161
+		default:
162
+			fprintf(stderr, "port in %04X\n", addr);
163
+			return 0;
164
+	}
165
+}
166
+
167
+static void cpu_func_port_out_main(cpu_state* cpu, u16 addr, u16 val) {
168
+	zzt_state* zzt = (zzt_state*) cpu;
169
+
170
+	switch (addr) {
171
+		case 0x42:
172
+			if (zzt->port_42_latch) zzt->port_42 = (zzt->port_42 & 0xFF) | ((val << 8) & 0xFF00);
173
+			else zzt->port_42 = (zzt->port_42 & 0xFF00) | (val & 0xFF);
174
+			zzt->port_42_latch ^= 1;
175
+//			if (!port_42_latch && (port_43[2] & 0x04) == 0x04 && (port_61 & 3) == 3) {
176
+			if (!(zzt->port_42_latch) && (zzt->port_61 & 3) == 3) {
177
+				speaker_on(1193182.0 / zzt->port_42);
178
+			}
179
+			return;
180
+		case 0x43: {
181
+/*			int addr = (val >> 6) & 0x3;
182
+			if (addr == 3) return;
183
+			if ((val & 0x30) == 0) {
184
+				zzt->port_43[addr] = val;
185
+			} */
186
+		} return;
187
+		case 0x61:
188
+			zzt->port_61 = val;
189
+			if ((val & 3) != 3) {
190
+				speaker_off();
191
+			}
192
+			return;
193
+		case 0x201:
194
+			zzt_joy_strobe(zzt);
195
+			return;
196
+		default:
197
+			fprintf(stderr, "port out %04X = %04X\n", addr, val);
198
+	}
199
+}
200
+
201
+static void cpu_func_intr_0x33(cpu_state* cpu) {
202
+	zzt_state* zzt = (zzt_state*) cpu;
203
+
204
+	switch (cpu->ax) {
205
+		case 0:
206
+			if (vfs_has_feature(FEATURE_MOUSE_CONNECTED)) {
207
+				cpu->ax = 0xFFFF;
208
+				cpu->bx = 0xFFFF;
209
+			}
210
+			break;
211
+		case 3:
212
+			cpu->bx = zzt->mouse_buttons;
213
+			cpu->cx = zzt->mouse_x / 8;
214
+			cpu->dx = zzt->mouse_y / 14;
215
+			break;
216
+		case 0xB:
217
+			cpu->cx = zzt->mouse_xd;
218
+			cpu->dx = zzt->mouse_yd;
219
+			zzt->mouse_xd = 0;
220
+			zzt->mouse_yd = 0;
221
+			break;
222
+		default:
223
+			fprintf(stderr, "mouse %04X\n", cpu->ax);
224
+			break;
225
+	}
226
+}
227
+
228
+static int cpu_func_interrupt_main(cpu_state* cpu, u8 intr) {
229
+	switch (intr) {
230
+		case 0x11:
231
+			cpu->al = cpu->ram[0x410];
232
+			cpu->ah = cpu->ram[0x411];
233
+			break;
234
+		case 0x12:
235
+			cpu->al = cpu->ram[0x413];
236
+			cpu->ah = cpu->ram[0x414];
237
+			break;
238
+		case 0x08: {
239
+			u32 time = cpu->ram[0x46c] | (cpu->ram[0x46d] << 8)
240
+				| (cpu->ram[0x46e] << 16) | (cpu->ram[0x46f] << 24);
241
+			time++;
242
+			cpu->ram[0x46c] = time & 0xFF;
243
+			cpu->ram[0x46d] = (time>>8) & 0xFF;
244
+			cpu->ram[0x46e] = (time>>16) & 0xFF;
245
+			cpu->ram[0x46f] = (time>>24) & 0xFF;
246
+			cpu_emit_interrupt(cpu, 0x1C);
247
+		} break;
248
+		case 0x1C: break;
249
+		case 0x10: cpu_func_intr_0x10(cpu); break;
250
+		case 0x13: cpu_func_intr_0x13(cpu); break;
251
+		case 0x16: cpu_func_intr_0x16(cpu); break;
252
+		case 0x21: cpu_func_intr_0x21(cpu); break;
253
+		case 0x33: cpu_func_intr_0x33(cpu); break;
254
+		case 0x15:
255
+			fprintf(stderr, "sysconf %04X\n", cpu->ax);
256
+			cpu->ah = 0x86;
257
+			cpu->flags |= FLAG_CARRY;
258
+			break;
259
+		default:
260
+			fprintf(stderr, "interrupt %02X\n", intr);
261
+			break;
262
+	}
263
+	return STATE_CONTINUE;
264
+}
265
+
266
+static void video_scroll_up(cpu_state* cpu, int lines, u8 empty_attr, int y1, int x1, int y2, int x2) {
267
+	if (lines <= 0) {
268
+		for (int y = y1; y <= y2; y++)
269
+		for (int x = x1; x <= x2; x++) {
270
+			cpu->ram[TEXT_ADDR(x,y)] = 0;
271
+			cpu->ram[TEXT_ADDR(x,y)+1] = empty_attr;
272
+		}
273
+	} else {
274
+		for (int y = y1+lines; y <= y2; y++)
275
+		for (int x = x1; x <= x2; x++) {
276
+			cpu->ram[TEXT_ADDR(x,y-lines)] = cpu->ram[TEXT_ADDR(x,y)];
277
+			cpu->ram[TEXT_ADDR(x,y-lines)+1] = cpu->ram[TEXT_ADDR(x,y)+1];
278
+		}
279
+
280
+		for (int y = y2-lines+1; y <= y2; y++)
281
+		for (int x = x1; x <= x2; x++) {
282
+			cpu->ram[TEXT_ADDR(x,y)] = 0;
283
+			cpu->ram[TEXT_ADDR(x,y)+1] = empty_attr;
284
+		}
285
+	}
286
+}
287
+
288
+static void cpu_0x10_output(cpu_state* cpu, u8 chr) {
289
+	u8 cursor_width = cpu->ram[0x44A];
290
+	u8 cursor_height = 25;
291
+
292
+	switch (chr) {
293
+		case 0x0D:
294
+			cpu->ram[0x450] = 0;
295
+			break;
296
+		case 0x0A:
297
+			if (cpu->ram[0x451] < (cursor_height - 1)) {
298
+				cpu->ram[0x451]++;
299
+			} else {
300
+				video_scroll_up(cpu, 1, 0x07, 0, 0, cursor_height - 1, cursor_width - 1);
301
+			}
302
+			break;
303
+		case 0x08:
304
+			if (cpu->ram[0x450] > 0)
305
+				cpu->ram[0x450]--;
306
+			cpu->ram[TEXT_ADDR(cpu->ram[0x450], cpu->ram[0x451])] = 0;
307
+			break;
308
+		case 0x07:
309
+			break;
310
+		default:
311
+			cpu->ram[TEXT_ADDR(cpu->ram[0x450], cpu->ram[0x451])] = chr;
312
+			cpu->ram[0x450]++;
313
+			if (cpu->ram[0x450] >= cursor_width) {
314
+				cpu->ram[0x450] = 0;
315
+				if (cpu->ram[0x451] < (cursor_height - 1)) {
316
+					cpu->ram[0x451]++;
317
+				} else {
318
+					video_scroll_up(cpu, 1, 0x07, 0, 0, cursor_height - 1, cursor_width - 1);
319
+				}
320
+			}
321
+			break;
322
+	}
323
+}
324
+
325
+static int video_mode = 3;
326
+int zzt_video_mode(void) {
327
+	return video_mode;
328
+}
329
+
330
+static void cpu_func_intr_0x10(cpu_state* cpu) {
331
+	if (cpu->ah == 0x02) {
332
+		cpu->ram[0x451] = cpu->dh;
333
+		cpu->ram[0x450] = cpu->dl;
334
+	} else if (cpu->ah == 0x03) {
335
+		cpu->dh = cpu->ram[0x451];
336
+		cpu->dl = cpu->ram[0x450];
337
+	} else if (cpu->ah == 0x04) {
338
+		cpu->ah = 0;
339
+	} else if (cpu->ah == 0x06) {
340
+		video_scroll_up(cpu, cpu->al, cpu->bh, cpu->ch, cpu->cl, cpu->dh, cpu->dl);
341
+	} else if (cpu->ah == 0x08) {
342
+		u32 addr = TEXT_ADDR(cpu->bl, cpu->bh);
343
+		cpu->ah = 0x08;
344
+		cpu->al = cpu->ram[addr];
345
+		cpu->bh = cpu->ram[addr+1];
346
+	} else if (cpu->ah == 0x09 || cpu->ah == 0x0A) {
347
+		u32 addr = TEXT_ADDR(cpu->bl, cpu->bh);
348
+		for (int i = 0; i < cpu->cx && addr < 160*25; i++, addr+=2) {
349
+			cpu->ram[addr] = cpu->al;
350
+			if (cpu->ah == 0x09) cpu->ram[addr + 1] = cpu->bl;
351
+		}
352
+	} else if (cpu->ah == 0x0E) {
353
+		cpu_0x10_output(cpu, cpu->al);
354
+	} else if (cpu->ah == 0x00) {
355
+		video_mode = cpu->al & 0x7F;
356
+		fprintf(stderr, "set video mode to %d\n", cpu->al);
357
+	} else if (cpu->ah == 0x0F) {
358
+		cpu->ah = cpu->ram[0x44A];
359
+		cpu->al = video_mode;
360
+		cpu->bh = 0;
361
+	} else {
362
+		fprintf(stderr, "int 0x10 AX=%04X AH=%02X AL=%02X BL=%02X\n",
363
+			cpu->ax, cpu->ah, cpu->al, cpu->bl);
364
+		cpu->flags |= FLAG_CARRY;
365
+	}
366
+}
367
+
368
+static void cpu_func_intr_0x13(cpu_state* cpu) {
369
+	fprintf(stderr, "int 0x13 AX=%04X\n", cpu->ax);
370
+}
371
+
372
+static void cpu_func_intr_0x16(cpu_state* cpu) {
373
+	zzt_state* zzt = (zzt_state*) cpu;
374
+
375
+	if (cpu->ah == 0x00) {
376
+		if (zzt->qke >= 0) {
377
+			cpu->flags &= ~FLAG_ZERO;
378
+			cpu->ah = zzt->qke;
379
+			cpu->al = zzt->qch;
380
+			zzt->qch = -1;
381
+			zzt->qke = -1;
382
+		} else {
383
+			cpu->flags |= FLAG_ZERO;
384
+		}
385
+		return;
386
+	} else if (cpu->ah == 0x01) {
387
+		if (zzt->qke >= 0) {
388
+			cpu->flags &= ~FLAG_ZERO;
389
+			cpu->ah = zzt->qke;
390
+			cpu->al = zzt->qch;
391
+		} else {
392
+			cpu->flags |= FLAG_ZERO;
393
+		}
394
+		return;
395
+	} else if (cpu->ah == 0x02) {
396
+		cpu->al = zzt->kmod;
397
+		return;
398
+	}
399
+	fprintf(stderr, "int 0x16 AX=%04X\n", cpu->ax);
400
+}
401
+
402
+#define STR_DS_DX (char*)(&cpu->ram[cpu->seg[SEG_DS]*16 + cpu->dx])
403
+
404
+static void cpu_func_intr_0x21(cpu_state* cpu) {
405
+	zzt_state* zzt = (zzt_state*) cpu;
406
+
407
+	switch (cpu->ah) {
408
+		case 0x30: // DOS version
409
+			cpu->al = 3;
410
+			cpu->ah = 0;
411
+			cpu->bh = 0;
412
+			return;
413
+		case 0x06: // d.c.output
414
+			cpu_0x10_output(cpu, cpu->dl);
415
+			cpu->al = cpu->dl;
416
+			return;
417
+		case 0x1A: // set dta
418
+			zzt->dos_dta = (cpu->seg[SEG_DS]*16 + cpu->dx);
419
+			return;
420
+		case 0x25: // set ivt
421
+			cpu->ram[cpu->al * 4] = cpu->dl;
422
+			cpu->ram[cpu->al * 4 + 1] = cpu->dh;
423
+			cpu->ram[cpu->al * 4 + 2] = cpu->seg[SEG_DS] & 0xFF;
424
+			cpu->ram[cpu->al * 4 + 3] = cpu->seg[SEG_DS] >> 8;
425
+			return;
426
+		case 0x2C: { // systime
427
+			long ms = vfs_time_ms();
428
+			cpu->ch = (ms / 3600000) % 24;
429
+			cpu->cl = (ms / 60000) % 60;
430
+			cpu->dh = (ms / 1000) % 60;
431
+			cpu->dl = (ms / 10) % 100;
432
+		} return;
433
+		case 0x35: // get ivt
434
+			cpu->bl = cpu->ram[cpu->al * 4];
435
+			cpu->bh = cpu->ram[cpu->al * 4 + 1];
436
+			cpu->seg[SEG_ES] = cpu->ram[cpu->al * 4 + 2]
437
+				| (cpu->ram[cpu->al * 4 + 3] << 8);
438
+			return;
439
+		case 0x3C: { // creat
440
+			int handle = vfs_open(STR_DS_DX, 0x10001);
441
+			if (handle < 0) {
442
+				fprintf(stderr, "not found\n");
443
+				cpu->ax = 0x02;
444
+				cpu->flags |= FLAG_CARRY;
445
+			} else {
446
+				cpu->ax = handle;
447
+				cpu->flags &= ~FLAG_CARRY;
448
+			}
449
+		} return;
450
+		case 0x3D: { // open
451
+			fprintf(stderr, "open %02X %s\n", cpu->al, STR_DS_DX);
452
+			int handle = vfs_open(STR_DS_DX, cpu->al);
453
+			if (handle < 0) {
454
+				fprintf(stderr, "not found\n");
455
+				cpu->ax = 0x02;
456
+				cpu->flags |= FLAG_CARRY;
457
+			} else {
458
+				cpu->ax = handle;
459
+				cpu->flags &= ~FLAG_CARRY;
460
+			}
461
+		} return;
462
+		case 0x3E: { // close
463
+			int res = vfs_close(cpu->bx);
464
+			if (res < 0) {
465
+				cpu->ax = 0x06;
466
+				cpu->flags |= FLAG_CARRY;
467
+			} else {
468
+				cpu->flags &= ~FLAG_CARRY;
469
+			}
470
+		} return;
471
+		case 0x3F: { // read
472
+			fprintf(stderr, "read %04X\n", cpu->cx);
473
+			int res = vfs_read(cpu->bx, (u8*)STR_DS_DX, cpu->cx);
474
+			if (res < 0) {
475
+				cpu->ax = 0x05;
476
+				cpu->flags |= FLAG_CARRY;
477
+			} else {
478
+				cpu->ax = res;
479
+				cpu->flags &= ~FLAG_CARRY;
480
+			}
481
+		} return;
482
+		case 0x40: { // write
483
+			fprintf(stderr, "write %04X\n", cpu->cx);
484
+			if (cpu->cx == 0) {
485
+				// we don't implement the special case
486
+				cpu->ax = 0x05;
487
+				cpu->flags |= FLAG_CARRY;
488
+				return;
489
+			}
490
+
491
+			int res = vfs_write(cpu->bx, (u8*)STR_DS_DX, cpu->cx);
492
+			if (res < 0) {
493
+				cpu->ax = 0x05;
494
+				cpu->flags |= FLAG_CARRY;
495
+			} else {
496
+				cpu->ax = res;
497
+				cpu->flags &= ~FLAG_CARRY;
498
+			}
499
+		} return;
500
+		case 0x42: { // lseek
501
+			int res = vfs_seek(cpu->bx, (cpu->cx << 16) | cpu->dx, cpu->al);
502
+			if (res < 0) {
503
+				cpu->ax = 0x05;
504
+				cpu->flags |= FLAG_CARRY;
505
+			} else {
506
+				cpu->ax = res;
507
+				cpu->flags &= ~FLAG_CARRY;
508
+			}
509
+		} return;
510
+		case 0x44: // 0x4400
511
+			if (cpu->ax == 0x4400) {
512
+				cpu->ax = 0x01;
513
+				cpu->flags |= FLAG_CARRY;
514
+				return;
515
+			}
516
+			break;
517
+		case 0x4C:
518
+			cpu->terminated = 1;
519
+			break;
520
+		case 0x4E: { // findfirst
521
+			int res = vfs_findfirst(cpu->ram + zzt->dos_dta, cpu->cx, STR_DS_DX);
522
+			if (res < 0) {
523
+				cpu->ax = 0x12;
524
+				cpu->flags |= FLAG_CARRY;
525
+			} else {
526
+				cpu->flags &= ~FLAG_CARRY;
527
+			}
528
+			break;
529
+		};
530
+		case 0x4F: { // findnext
531
+			int res = vfs_findnext(cpu->ram + zzt->dos_dta);
532
+			if (res < 0) {
533
+				cpu->ax = 0x12;
534
+				cpu->flags |= FLAG_CARRY;
535
+			} else {
536
+				cpu->flags &= ~FLAG_CARRY;
537
+			}
538
+		};
539
+		default:
540
+			fprintf(stderr, "int 0x21 AX=%04X\n", cpu->ax);
541
+			break;
542
+	}
543
+}
544
+
545
+/* #define MAX_ALLOC (639*64)
546
+static u32 seg_allocs[MAX_ALLOC];
547
+
548
+static int mem_alloc(u32 paragraphs, u8 simulate) {
549
+	int offset = 0;
550
+	while (offset < MAX_ALLOC) {
551
+		fprintf(stderr, "offset = %d\n", offset);
552
+		if (seg_allocs[offset] > 0) {
553
+			offset += seg_allocs[offset];
554
+		} else {
555
+			int size = 0;
556
+			while (seg_allocs[offset+size] == 0 && size < paragraphs) {
557
+				size++;
558
+			}
559
+			fprintf(stderr, "size = %d/%d\n", size, paragraphs);
560
+			if (size == paragraphs) {
561
+				if (!simulate) {
562
+					for (int i = 0; i < size; i++) {
563
+						seg_allocs[offset+i] = (size-i);
564
+					}
565
+				}
566
+				fprintf(stderr, "offset >= %d\n", offset);
567
+				return offset;
568
+			} else {
569
+				offset += size;
570
+			}
571
+		}
572
+	}
573
+
574
+	return -1;
575
+}
576
+
577
+static int mem_free(u32 addr) {
578
+	int v = seg_allocs[addr];
579
+	if (v <= 0) return 0;
580
+	if (addr > 0 && seg_allocs[addr - 1] > v) return 0;
581
+
582
+	for (int i = 0; i < v; i++) {
583
+		seg_allocs[addr+i] = 0;
584
+	}
585
+	return 1;
586
+} */
587
+
588
+static u8 vfs_read8(int handle, int pos) {
589
+	u8 v;
590
+	vfs_seek(handle, pos, VFS_SEEK_SET);
591
+	vfs_read(handle, &v, 1);
592
+	return v;
593
+}
594
+
595
+static u16 vfs_read16(int handle, int pos) {
596
+	u8 v1, v2;
597
+	vfs_seek(handle, pos, VFS_SEEK_SET);
598
+	vfs_read(handle, &v1, 1);
599
+	vfs_read(handle, &v2, 1);
600
+	return v1 | (v2 << 8);
601
+}
602
+
603
+u32 zzt_init(void) {
604
+/*	for (int i = 0; i < MAX_ALLOC; i++)
605
+		seg_allocs[i] = (i < 256) ? (256-i) : 0; */
606
+
607
+	zzt.qch = -1;
608
+	zzt.qke = -1;
609
+	zzt.joy_xstrobe_val = -1;
610
+	zzt.joy_ystrobe_val = -1;
611
+	zzt.joy_xstrobes = 0;
612
+	zzt.joy_ystrobes = 0;
613
+	zzt.mouse_buttons = 0;
614
+	zzt.mouse_x = 640 / 2;
615
+	zzt.mouse_y = 350 / 2;
616
+	zzt.port_201 = 0xF0;
617
+
618
+	cpu_init_globals();
619
+	cpu_init(&(zzt.cpu));
620
+
621
+	// sysconf constants
622
+
623
+	zzt.cpu.ram[0x410] = 0x61;
624
+	zzt.cpu.ram[0x411] = 0x00;
625
+	zzt.cpu.ram[0x413] = (640) & 255;
626
+	zzt.cpu.ram[0x414] = (640) >> 8;
627
+	zzt.cpu.ram[0xFFFFE] = 0xFB;
628
+
629
+	// video constants
630
+
631
+	zzt.cpu.ram[0x44A] = 80;
632
+	zzt.cpu.ram[0x463] = 0xD4;
633
+	zzt.cpu.ram[0x464] = 0x03;
634
+
635
+	zzt.cpu.func_port_in = cpu_func_port_in_main;
636
+	zzt.cpu.func_port_out = cpu_func_port_out_main;
637
+	zzt.cpu.func_interrupt = cpu_func_interrupt_main;
638
+
639
+	// load exe
640
+	// NOTE: relocation items are not handled, as the ZZT
641
+	// .EXE does not need them
642
+
643
+	int handle = vfs_open("zzt.exe", 0);
644
+	if (handle < 0)
645
+		handle = vfs_open("superz.exe", 0);
646
+
647
+	int last_page_size = vfs_read16(handle, 2);
648
+	int pages = vfs_read16(handle, 4);
649
+	int hdr_offset = vfs_read16(handle, 8);
650
+//	int minalloc = vfs_read16(handle, 0xA);
651
+//	int maxalloc = vfs_read16(handle, 0xC);
652
+
653
+	int filesize = (pages * 512) - ((last_page_size > 0) ? (512 - last_page_size) : 0) - (hdr_offset * 16);
654
+/*	int size_pars = (filesize + 15) / 16;
655
+	size_pars += 16; // PSP */
656
+//	int size_pars = 40400;
657
+//	int offset_pars = mem_alloc(size_pars, 0);
658
+	int offset_pars = 0x100;
659
+	int size_pars = 0xA000 - 0x100;
660
+
661
+	// location
662
+	zzt.cpu.seg[SEG_CS] = vfs_read16(handle, 0x16) + offset_pars + 0x10;
663
+	zzt.cpu.seg[SEG_SS] = vfs_read16(handle, 0xE) + offset_pars + 0x10;
664
+	zzt.cpu.seg[SEG_DS] = offset_pars;
665
+	zzt.cpu.seg[SEG_ES] = offset_pars;
666
+	zzt.cpu.ip = vfs_read16(handle, 0x14);
667
+	zzt.cpu.sp = vfs_read16(handle, 0x10);
668
+
669
+	// build faux psp
670
+	int psp = offset_pars * 16;
671
+	int seg_first = offset_pars + size_pars;
672
+	fprintf(stderr, "seg_first %04X\n", seg_first);
673
+	zzt.cpu.ram[psp + 0x02] = seg_first & 0xFF;
674
+	zzt.cpu.ram[psp + 0x03] = seg_first >> 8;
675
+	zzt.cpu.ram[psp + 0x80] = 1;
676
+	zzt.cpu.ram[psp + 0x81] = 0x0D;
677
+
678
+	// load file into memory
679
+	vfs_seek(handle, hdr_offset * 16, VFS_SEEK_SET);
680
+	vfs_read(handle, &(zzt.cpu.ram[(offset_pars * 16) + 256]), filesize);
681
+	fprintf(stderr, "wrote %d bytes to %d\n", filesize, (offset_pars * 16 + 256));
682
+
683
+	vfs_close(handle);
684
+	return psp;
685
+}
686
+
687
+int zzt_execute(int opcodes) {
688
+	return cpu_execute(&(zzt.cpu), opcodes);
689
+}
690
+
691
+void zzt_mark_timer(void) {
692
+	cpu_emit_interrupt(&(zzt.cpu), 0x08);
693
+}
694
+
695
+u8* zzt_get_ram(void) {
696
+	return zzt.cpu.ram;
697
+}

+ 104
- 0
src/zzt.h View File

@@ -0,0 +1,104 @@
1
+/**
2
+ * Copyright (c) 2018 Adrian Siekierka
3
+ *
4
+ * This file is part of Zeta.
5
+ *
6
+ * Zeta is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * Zeta is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with Zeta.  If not, see <http://www.gnu.org/licenses/>.
18
+ */
19
+
20
+#ifndef __ZZT_H__
21
+#define __ZZT_H__
22
+
23
+#ifdef EMSCRIPTEN
24
+#define USER_FUNCTION EMSCRIPTEN_KEEPALIVE
25
+#define IMPLEMENT_FUNCTION
26
+#include <emscripten.h>
27
+#else
28
+#define USER_FUNCTION
29
+#define IMPLEMENT_FUNCTION
30
+#endif
31
+
32
+#include "cpu.h"
33
+
34
+#define MAX_FILES 16
35
+#define TEXT_ADDR(x,y) (0xB8000 + ((y)*160) + ((x)*2))
36
+
37
+USER_FUNCTION
38
+int zzt_video_mode(void);
39
+USER_FUNCTION
40
+void zzt_key(int ch, int key);
41
+USER_FUNCTION
42
+void zzt_kmod_set(int mod);
43
+USER_FUNCTION
44
+void zzt_kmod_clear(int mod);
45
+USER_FUNCTION
46
+void zzt_joy_set(int button);
47
+USER_FUNCTION
48
+void zzt_joy_axis(int axis, int value /* -127..127 */);
49
+USER_FUNCTION
50
+void zzt_joy_clear(int button);
51
+USER_FUNCTION
52
+void zzt_mouse_set(int button);
53
+USER_FUNCTION
54
+void zzt_mouse_axis(int axis, int value /* 0..639, 0..349 */);
55
+USER_FUNCTION
56
+void zzt_mouse_clear(int button);
57
+USER_FUNCTION
58
+u32 zzt_init(void);
59
+USER_FUNCTION
60
+int zzt_execute(int opcodes);
61
+USER_FUNCTION
62
+u8* zzt_get_ram(void);
63
+USER_FUNCTION
64
+void zzt_mark_frame(void);
65
+USER_FUNCTION
66
+void zzt_mark_timer(void);
67
+
68
+IMPLEMENT_FUNCTION
69
+long vfs_time_ms(void);
70
+
71
+#define VFS_SEEK_SET 0
72
+#define VFS_SEEK_CUR 1
73
+#define VFS_SEEK_END 2
74
+#define VFS_OPEN_READ 0
75
+#define VFS_OPEN_WRITE 1
76
+#define VFS_OPEN_RW 2
77
+#define VFS_OPEN_TRUNCATE 0x10000
78
+
79
+IMPLEMENT_FUNCTION
80
+int vfs_open(const char* filename, int mode);
81
+IMPLEMENT_FUNCTION
82
+int vfs_seek(int handle, int pos, int type);
83
+IMPLEMENT_FUNCTION
84
+int vfs_read(int handle, u8* ptr, int amount);
85
+IMPLEMENT_FUNCTION
86
+int vfs_write(int handle, u8* ptr, int amount);
87
+IMPLEMENT_FUNCTION
88
+int vfs_close(int handle);
89
+IMPLEMENT_FUNCTION
90
+int vfs_findfirst(u8* ptr, u16 mask, char* spec);
91
+IMPLEMENT_FUNCTION
92
+int vfs_findnext(u8* ptr);
93
+
94
+#define FEATURE_JOY_CONNECTED 1
95
+#define FEATURE_MOUSE_CONNECTED 2
96
+IMPLEMENT_FUNCTION
97
+int vfs_has_feature(int feature);
98
+
99
+IMPLEMENT_FUNCTION
100
+void speaker_on(double freq);
101
+IMPLEMENT_FUNCTION
102
+void speaker_off(void);
103
+
104
+#endif /* __ZZT_H__ */

+ 9
- 0
web/ZipLoader.min.js
File diff suppressed because it is too large
View File


BIN
web/ascii.png View File


BIN
web/loading.png View File


+ 566
- 0
web/zzt.js View File

@@ -0,0 +1,566 @@
1
+/*!
2
+ * Copyright (c) 2018 Adrian Siekierka
3
+ *
4
+ * This file is part of Zeta.
5
+ *
6
+ * Zeta is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * Zeta is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with Zeta.  If not, see <http://www.gnu.org/licenses/>.
18
+ */
19
+
20
+var canvas = document.getElementById('zzt_canvas');
21
+var ctx = canvas.getContext('2d', {alpha: false});
22
+ctx.imageSmoothingEnabled = false;
23
+
24
+var asciiImg = new Image();
25
+var asciiFg = [];
26
+var emu = undefined;
27
+
28
+var palette = [
29
+	"#000000", "#0000AA", "#00AA00", "#00AAAA",
30
+	"#AA0000", "#AA00AA", "#AA5500", "#AAAAAA",
31
+	"#555555", "#5555FF", "#55FF55", "#55FFFF",
32
+	"#FF5555", "#FF55FF", "#FFFF55", "#FFFFFF"
33
+];
34
+
35
+var asciiFg = [];
36
+var chrBuf = [];
37
+
38
+function time_ms() { return new Date().getTime(); }
39
+
40
+var video_blink = false;
41
+var video_mode = 3;
42
+var last_video_mode = 3;
43
+
44
+function drawChar(x, y, chr, col) {
45
+	if (video_mode != last_video_mode) {
46
+		chrBuf = [];
47
+		last_video_mode = video_mode;
48
+	}
49
+
50
+	var width = 16;
51
+	if ((video_mode & 0x02) == 2) {
52
+		width = 8;
53
+	}
54
+
55
+	x = x * width;
56
+	y = y * 14;
57
+
58
+	var buffered = chrBuf[y * 80 + x];
59
+	if (video_blink && col >= 0x80) {
60
+		col = col & 0x7F;
61
+
62
+		var t = vfsg_time_ms();
63
+		var blinkcount = (t % 466);
64
+		if (blinkcount >= 233) {
65
+			col = (col >> 4) * 0x11;
66
+		}
67
+	}
68
+
69
+	var bufcmp = (chr << 8) | col;
70
+/*	if (chr == 0 || chr == 32) {
71
+		bufcmp &= 0xF0;
72
+	} */
73
+
74
+	if (buffered == bufcmp) {
75
+		return;
76
+	} else {
77
+		chrBuf[y * 80 + x] = bufcmp;
78
+	}
79
+
80
+	var bg = (col >> 4) & 0x0F;
81
+	var fg = (col & 15);
82
+
83
+	ctx.fillStyle = palette[bg];
84
+	ctx.fillRect(x, y, width, 14);
85
+
86
+	if (bg != fg && chr != 0 && chr != 32) {
87
+		ctx.drawImage(asciiFg[fg], (chr & 15) * 8, ((chr & 240) >> 4) * 14, 8, 14, x, y, width, 14);
88
+	}
89
+}
90
+
91
+var vfs_progress = {};
92
+var vfs = {};
93
+
94
+function vfs_append(fn, then) {
95
+	var loader = new ZipLoader(fn);
96
+	loader.on("progress", function(event) {
97
+		vfs_progress[fn] = (event.loaded / event.total);
98
+		draw_progress(get_vfs_prog_total() / vfs_files.length);
99
+	});
100
+
101
+	loader.load().then(function() {
102
+		vfs_progress[fn] = 0;
103
+		for (let key in loader.files) {
104
+			vfs[key.toUpperCase()] = loader.files[key];
105
+			vfs[key.toUpperCase()].readonly = true;
106
+		}
107
+
108
+		then();
109
+	});
110
+}
111
+
112
+var handles = {};
113
+
114
+function vfsg_has_feature(id) {
115
+	if (id == 1 /* joy connected */) return true;
116
+	else if (id == 2 /* mouse connected */) return true;
117
+	else return false;
118
+}
119
+
120
+function vfsg_open(fn, mode) {
121
+	fn = emu.Pointer_stringify(fn).toUpperCase();
122
+	var is_write = (mode & 0x3) == 1;
123
+	if (is_write) {
124
+		if (fn in vfs && vfs[fn].readonly) return -1;
125
+		if (!(fn in vfs) || ((mode & 0x10000) != 0)) {
126
+			vfs[fn] = {readonly: false, buffer: new Uint8Array(0)};
127
+		}
128
+	} else {
129
+		if (!(fn in vfs)) return -1;
130
+	}
131
+
132
+	console.log("opening " + fn);
133
+	var i = 1;
134
+	while (i in handles) i++;
135
+	handles[i] = {name: fn, pos: 0, mode: mode, array: vfs[fn].buffer, obj: vfs[fn]};
136
+
137
+	return i;
138
+}
139
+
140
+function vfsg_close(h) {
141
+	if (h in handles) {
142
+		delete handles[h];
143
+		return 0;
144
+	} else return -1;
145
+}
146
+
147
+function vfsg_seek(h, pos, type) {
148
+	if (!(h in handles)) return -1;
149
+	var newpos = pos;
150
+	if (type == 1) {
151
+		newpos += handles[h].pos;
152
+	} else if (type == 2) {
153
+		newpos += handles[h].array.length;
154
+	}
155
+	console.log("seek to " + newpos);
156
+	if (newpos > handles[h].array.length)
157
+		newpos = handles[h].array.length;
158
+	else if (newpos < 0)
159
+		newpos = 0;
160
+	handles[h].pos = newpos;
161
+	return 0;
162
+}
163
+
164
+function vfsg_read(h, ptr, amount) {
165
+	if (!(h in handles)) return -1;
166
+	h = handles[h];
167
+	var maxlen = Math.min(amount, h.array.length - h.pos);
168
+	console.log("reading " + maxlen + " bytes from " + h.pos + " to " + ptr);
169
+	for (var pos = 0; pos < maxlen; pos++) {
170
+		emu.setValue(ptr+pos, h.array[h.pos+pos], "i8");
171
+	}
172
+	console.log("read " + maxlen + " bytes");
173
+	h.pos += maxlen;
174
+	return maxlen;
175
+}
176
+
177
+function vfsg_write(h, ptr, amount) {
178
+	if (!(h in handles)) return -1;
179
+	h = handles[h];
180
+	var len = h.array.length;
181
+	var newlen = h.pos + amount;
182
+	if (newlen > len) {
183
+		var newA = new Uint8Array(newlen);
184
+		newA.set(h.array, 0);
185
+		h.obj.buffer = newA;
186
+		h.array = newA;
187
+		len = newlen;
188
+	}
189
+	for (var pos = 0; pos < amount; pos++) {
190
+		h.array[h.pos + pos] = emu.getValue(ptr+pos, "i8");
191
+	}
192
+	console.log("wrote " + amount + " bytes");
193
+	h.pos += amount;
194
+	return amount;
195
+}
196
+
197
+var ff_list = [];
198
+var ff_pos = 0;
199
+
200
+function vfs_list(spec) {
201
+	spec = spec.toUpperCase();
202
+	var list = [];
203
+	if (spec.startsWith("*.")) {
204
+		var suffix = spec.substring(1);
205
+		for (let key in vfs) {
206
+			if (key.endsWith(suffix)) {
207
+				list.push(key);
208
+			}
209
+		}
210
+		list.sort(function(a, b) {
211
+			var lenDiff = a.length - b.length;
212
+			if (lenDiff != 0) return lenDiff;
213
+			else return a.localeCompare(b);
214
+		});
215
+		return list;
216
+	} else {
217
+		console.log("unknown findfirst spec: " + spec);
218
+		return null;
219
+	}
220
+}
221
+
222
+function vfsg_findfirst(ptr, mask, spec) {
223
+	spec = emu.Pointer_stringify(spec);
224
+	ff_list = [];
225
+	var l = vfs_list(spec);
226
+	if (l == null) return -1;
227
+	ff_list = l;
228
+	ff_pos = 0;
229
+	return vfsg_findnext(ptr);
230
+}
231
+
232
+function vfsg_findnext(ptr) {
233
+	if (ff_pos >= ff_list.length) return -1;
234
+
235
+	// write documented fields
236
+	emu.setValue(ptr + 0x15, 0, "i8");
237
+	emu.setValue(ptr + 0x16, 0, "i8");
238
+	emu.setValue(ptr + 0x17, 0, "i8");
239
+	emu.setValue(ptr + 0x18, 0, "i8");
240
+	emu.setValue(ptr + 0x19, 0, "i8");
241
+
242
+	var size = vfs[ff_list[ff_pos]].buffer.length;
243
+	emu.setValue(ptr + 0x1A, size & 0xFF, "i8");
244
+	emu.setValue(ptr + 0x1B, (size >> 8) & 0xFF, "i8");
245
+	emu.setValue(ptr + 0x1C, (size >> 16) & 0xFF, "i8");
246
+	emu.setValue(ptr + 0x1D, (size >> 24) & 0xFF, "i8");
247
+
248
+	var fn = ff_list[ff_pos];
249
+	for (var i = 0; i < fn.length; i++)
250
+		emu.setValue(ptr + 0x1E + i, fn.charCodeAt(i), "i8");
251
+	emu.setValue(ptr + 0x1E + fn.length, 0, "i8");
252
+
253
+	ff_pos = ff_pos + 1;
254
+	return 0;
255
+}
256
+
257
+var queuedFrame = false;
258
+
259
+function zzt_frame() {
260
+	poll_gamepads();
261
+
262
+	video_mode = emu._zzt_video_mode();
263
+	var ptr = emu._zzt_get_ram();
264
+	var width = 40;
265
+	if ((video_mode & 0x02) == 2) width = 80;
266
+
267
+	for (var y = 0; y < 25; y++) {
268
+		for (var x = 0; x < width; x+=2) {
269
+			var chc = emu.getValue(ptr + 0xB8000 + (y*width+x)*2, "i32");
270
+			var chr1 = chc & 0xFF;
271
+			var col1 = (chc >> 8) & 0xFF;
272
+			var chr2 = (chc >> 16) & 0xFF;
273
+			var col2 = (chc >> 24) & 0xFF;
274
+			drawChar(x, y, chr1, col1);
275
+			drawChar(x+1, y, chr2, col2);
276
+		}
277
+	}
278
+
279
+	emu._zzt_mark_frame();
280
+	queuedFrame = false;
281
+}
282
+
283
+var last_timer_time = 0;
284
+var timer_dur = 1000 / 18.2;
285
+
286
+var vfsg_time_ms_val = 0;
287
+
288
+function vfsg_time_ms() {
289
+	return vfsg_time_ms_val;
290
+}
291
+
292
+function zzt_tick() {
293
+	vfsg_time_ms_val = time_ms();
294
+	if (emu._zzt_execute(40000)) {
295
+		if (!queuedFrame) {
296
+			queuedFrame = true;
297
+			window.requestAnimationFrame(zzt_frame);
298
+		}
299
+
300
+		var tms = time_ms();
301
+		while ((tms - last_timer_time) >= timer_dur) {
302
+			last_timer_time += timer_dur;
303
+			emu._zzt_mark_timer();
304
+		}
305
+		if (document.hasFocus())
306
+			window.postMessage("zzt_tick", "*");
307
+		else
308
+			setTimeout(zzt_tick, 20);
309
+	}
310
+}
311
+
312
+window.addEventListener("message", function(event) {
313
+	if (event.data == "zzt_tick") {
314
+		event.stopPropagation();
315
+		zzt_tick();
316
+	}
317
+}, true);
318
+
319
+var vfs_arg = null;
320
+
321
+function vfs_done() {
322
+	if (vfs_arg == null && ("ZZT.EXE" in vfs)) {
323
+		if ("TOWN.ZZT" in vfs) {
324
+			vfs_arg = "";
325
+		} else {
326
+			var zlist = vfs_list("*.ZZT");
327
+			if (zlist.length > 0) {
328
+				vfs_arg = zlist[0];
329
+			}
330
+		}
331
+	}
332
+
333
+	if (vfs_arg == null && ("SUPERZ.EXE" in vfs)) {
334
+		if ("MONSTER.SZT" in vfs) {
335
+			vfs_arg = "";
336
+		} else {
337
+			var zlist = vfs_list("*.SZT");
338
+			if (zlist.length > 0) {
339
+				vfs_arg = zlist[0];
340
+			}
341
+		}
342
+	}
343
+
344
+	video_blink = !("BLINKX.COM" in vfs);
345
+
346
+	vfs_arg = (vfs_arg || "").toUpperCase();
347
+
348
+	draw_progress(1.0);
349
+	Zeta().then(function(c) {
350
+		emu = c;
351
+		var psp_loc = emu._zzt_init();
352
+		var ram = emu._zzt_get_ram();
353
+		var arg = vfs_arg + '\r';
354
+		emu.setValue(ram + psp_loc + 0x80, vfs_arg.length, "i8");
355
+		for (var i = 0; i < vfs_arg.length; i++) {
356
+			emu.setValue(ram + psp_loc + 0x81 + i, vfs_arg.charCodeAt(i), "i8");
357
+		}
358
+
359
+		last_timer_time = time_ms();
360
+		zzt_tick();
361
+	});
362
+}
363
+
364
+var audioCtx = undefined;
365
+var audioGain = undefined;
366
+var pc_speaker = undefined;
367
+
368
+document.addEventListener('mousedown', function(event) {
369
+	if (audioCtx == undefined) {
370
+		audioCtx = new (window.AudioContext || window.webkitAudioContext) ();
371
+		audioGain = audioCtx.createGain();
372
+	}
373
+});
374
+
375
+// var minDuration = 1;
376
+var lastCurrTime = 0;
377
+var lastTimeMs = 0;
378
+var timeSpeakerOn = 0;
379
+
380
+function speakerg_on(freq) {
381
+	if (!document.hasFocus()) {
382
+		speakerg_off();
383
+		return;
384
+	}
385
+
386
+	if (audioCtx == undefined)
387
+		return;
388
+
389
+	var cTime = audioCtx.currentTime;
390
+	if (cTime != lastCurrTime) {
391
+		lastCurrTime = cTime;
392
+		lastTimeMs = time_ms();
393
+	}
394
+
395
+	var lastADelay = (time_ms() - lastTimeMs) / 1000.0;
396
+
397
+//	console.log("pc speaker " + freq + " " + (audioCtx.currentTime + lastADelay));
398
+	if (pc_speaker == undefined) {
399
+		pc_speaker = audioCtx.createOscillator();
400
+		pc_speaker.type = 'square';
401
+		pc_speaker.frequency.setValueAtTime(freq, audioCtx.currentTime + lastADelay);
402
+		pc_speaker.connect(audioGain);
403
+		audioGain.connect(audioCtx.destination);
404
+		audioGain.gain.setValueAtTime(0.2, audioCtx.currentTime);
405
+		pc_speaker.start(0);
406
+	} else {
407
+		pc_speaker.frequency.setValueAtTime(freq, audioCtx.currentTime + lastADelay);
408
+	}
409
+	timeSpeakerOn = time_ms();
410
+}
411
+
412
+function speakerg_off() {
413
+	if (pc_speaker == undefined)
414
+		return;
415
+
416
+	var cTime = audioCtx.currentTime;
417
+	if (cTime != lastCurrTime) {
418
+		lastCurrTime = cTime;
419
+		lastTimeMs = time_ms();
420
+	}
421
+
422
+	var lastADelay = (time_ms() - lastTimeMs) / 1000.0;
423
+//	console.log("pc speaker off " + (audioCtx.currentTime + lastADelay));
424
+	pc_speaker.frequency.setValueAtTime(0, audioCtx.currentTime + lastADelay);
425
+}
426
+
427
+canvas.contentEditable = true;
428
+
429
+document.addEventListener('keydown', function(event) {
430
+	if (event.target != canvas) return false;
431
+	var ret = true;
432
+
433
+	if (audioCtx == undefined)
434
+		audioCtx = new (window.AudioContext || window.webkitAudioContext) ();
435
+
436
+	if (event.key == "Shift") emu._zzt_kmod_set(0x01);
437
+	else if (event.key == "Control") emu._zzt_kmod_set(0x04);
438
+	else if (event.key == "Alt" || event.key == "AltGraph") emu._zzt_kmod_set(0x08);
439
+	else ret = false;
440
+
441
+	var chr = (event.key.length == 1) ? event.key.charCodeAt(0) : event.keyCode;
442
+	var key = zzt_kbdmap[event.key] || 0;
443
+	if (key >= 0x46 && key <= 0x53) chr = 0;
444
+	if (chr > 0 || key > 0) {
445
+		emu._zzt_key(chr, key);
446
+		ret = true;
447
+	}
448
+
449
+	if (ret) {
450
+		event.preventDefault();
451
+	}
452
+	return false;
453
+}, false);
454
+
455
+document.addEventListener('keyup', function(event) {
456
+	if (event.target != canvas) return false;
457
+
458
+	if (event.key == "Shift") emu._zzt_kmod_clear(0x01);
459
+	else if (event.key == "Control") emu._zzt_kmod_clear(0x04);
460
+	else if (event.key == "Alt" || event.key == "AltGraph") emu._zzt_kmod_clear(0x08);
461
+	else return false;
462
+
463
+	event.preventDefault();
464
+	return false;
465
+}, false);
466
+
467
+var vfs_files = [];
468
+var vfs_files_pos = 0;
469
+
470
+function draw_progress(p) {
471
+	ctx.fillStyle = "#ff0000";
472
+	ctx.fillRect(14*2, 112*2, p * 292*2, 20);
473
+}
474
+
475
+function get_vfs_prog_total() {
476
+	var i = vfs_files_pos;
477
+	for (var k in vfs_progress) {
478
+		i += vfs_progress[k];
479
+	}
480
+	return i;
481
+}
482
+
483
+function vfs_on_loaded() {
484
+	vfs_files_pos = vfs_files_pos + 1;
485
+	draw_progress(get_vfs_prog_total() / vfs_files.length);
486
+	if (vfs_files_pos == vfs_files.length) {
487
+		vfs_done();
488
+	}
489
+}
490
+
491
+/* gamepad logic */
492
+function poll_gamepads() {
493
+	var gamepads = navigator.getGamepads();
494
+	for (var i = 0; i < gamepads.length; i++) {
495
+		var gamepad = gamepads[i];
496
+		if (gamepad == null) continue;
497
+		if (gamepad.axes.length >= 2 && gamepad.buttons.length >= 1) {
498
+			var ax0 = gamepad.axes[0];
499
+			var ax1 = gamepad.axes[1];
500
+			ax0 = Math.round(ax0 * 127);
501
+			ax1 = Math.round(ax1 * 127);
502
+			emu._zzt_joy_axis(0, ax0);
503
+			emu._zzt_joy_axis(1, ax1);
504
+			emu._zzt_joy_clear(0);
505
+			for (var j = 0; j < gamepad.buttons.length; j++) {
506
+				if (gamepad.buttons[j].pressed) {
507
+					emu._zzt_joy_set(0);
508
+					break;
509
+				}
510
+			}
511
+		}
512
+	}
513
+}
514
+
515
+var mouseSensitivity = 4;
516
+
517
+function attach_mouse_handler(o) {
518
+	o.addEventListener("mousemove", function(e) {
519
+		var mx = e.movementX * mouseSensitivity;
520
+		var my = e.movementY * mouseSensitivity;
521
+		emu._zzt_mouse_axis(0, mx);
522
+		emu._zzt_mouse_axis(1, my);
523
+/*		var mouseX = e.clientX - o.offsetLeft;
524
+		var mouseY = e.clientY - o.offsetTop;
525
+		if (mouseX < 0) mouseX = 0;
526
+		else if (mouseX >= 640) mouseX = 639;
527
+		if (mouseY < 0) mouseY = 0;
528
+		else if (mouseY >= 350) mouseY = 349; */
529
+	});
530
+
531
+	o.addEventListener("mousedown", function(e) {
532
+		o.requestPointerLock();
533
+		emu._zzt_mouse_set(e.button);
534
+	});
535
+
536
+	o.addEventListener("mouseup", function(e) {
537
+		emu._zzt_mouse_clear(e.button);
538
+	});
539
+}
540
+
541
+function zzt_emu_create(options) {
542
+	asciiImg.src = options.charset_png || (options.path + "ascii.png");
543
+	asciiImg.onload = function() {
544
+		asciiFg[15] = asciiImg;
545
+		for (var i = 0; i < 15; i++) {
546
+			var charCanvas = document.createElement('canvas');
547
+			charCanvas.width = 128;
548
+			charCanvas.height = 224;
549
+			var charCtx = charCanvas.getContext('2d');
550
+			charCtx.globalCompositeOperation = 'copy';
551
+			charCtx.drawImage(asciiImg, 0, 0);
552
+			charCtx.globalCompositeOperation = 'source-in';
553
+			charCtx.fillStyle = palette[i];
554
+			charCtx.fillRect(0, 0, 128, 224);
555
+			asciiFg[i] = charCanvas;
556
+		}
557
+
558
+		attach_mouse_handler(canvas);
559
+
560
+		vfs_files = options.files;
561
+		vfs_arg = options.arg;
562
+		for (var s in vfs_files) {
563
+			vfs_append(vfs_files[s], vfs_on_loaded);
564
+		}
565
+	};
566
+}

+ 62
- 0
web/zzt_kbdmap.js View File

@@ -0,0 +1,62 @@
1
+/*!
2
+ * Copyright (c) 2018 Adrian Siekierka
3
+ *
4
+ * This file is part of Zeta.
5
+ *
6
+ * Zeta is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * Zeta is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with Zeta.  If not, see <http://www.gnu.org/licenses/>.
18
+ */
19
+
20
+zzt_kbdmap = {};
21
+zzt_kbdmap["ArrowUp"] = 0x48;
22
+zzt_kbdmap["ArrowLeft"] = 0x4B;
23
+zzt_kbdmap["ArrowRight"] = 0x4D;
24
+zzt_kbdmap["ArrowDown"] = 0x50;
25
+
26
+zzt_kbdmap["Home"] = 0x47;
27
+zzt_kbdmap["End"] = 0x4F;
28
+zzt_kbdmap["Insert"] = 0x52;
29
+zzt_kbdmap["Delete"] = 0x53;
30