Browse Source

initial working-ish code

vampirefrog 1 year ago
parent
commit
452210b741
35 changed files with 12481 additions and 0 deletions
  1. 51
    0
      Makefile
  2. 279
    0
      README.md
  3. 393
    0
      ansidecl.h
  4. 158
    0
      main.c
  5. 64
    0
      mamedef.h
  6. 440
    0
      md5.c
  7. 154
    0
      md5.h
  8. 396
    0
      okim6258.c
  9. 66
    0
      okim6258.h
  10. 259
    0
      sjis.c
  11. 19
    0
      sjis.h
  12. 4110
    0
      sjis_unicode.c
  13. 96
    0
      sjisranges.php
  14. 45
    0
      test-mem.c
  15. 24
    0
      test-path.c
  16. 108
    0
      tools.c
  17. 20
    0
      tools.h
  18. 204
    0
      v68.c
  19. 113
    0
      v68.h
  20. 648
    0
      v68doscall.c
  21. 524
    0
      v68fecall.c
  22. 282
    0
      v68human.c
  23. 79
    0
      v68human.h
  24. 429
    0
      v68io.c
  25. 36
    0
      v68io.h
  26. 507
    0
      v68iocscall.c
  27. 219
    0
      v68mem.c
  28. 28
    0
      v68mem.h
  29. 287
    0
      v68periph.c
  30. 15
    0
      v68periph.h
  31. 103
    0
      vgm.c
  32. 18
    0
      vgm.h
  33. 285
    0
      xinfo.c
  34. 1792
    0
      ym2151.c
  35. 230
    0
      ym2151.h

+ 51
- 0
Makefile View File

@@ -0,0 +1,51 @@
1
+MUSASHIFILES=m68kcpu.c m68kdasm.c
2
+MUSASHIGENCFILES=m68kops.c m68kopac.c m68kopdm.c m68kopnz.c
3
+
4
+MUSASHIOBJS=$(patsubst %.c,musashi/%.o,$(MUSASHIFILES))
5
+MUSASHIGENOBJS=$(patsubst %.c,musashi/%.o,$(MUSASHIGENCFILES))
6
+
7
+all: v68 xinfo sjis2utf8
8
+
9
+$(patsubst %.c,musashi/%.c,$(MUSASHIGENCFILES)): musashi/m68kmake musashi/m68k_in.c
10
+	(cd musashi && ./m68kmake)
11
+
12
+musashi/m68kmake: musashi/m68kmake.o
13
+	gcc $^ -o $@
14
+
15
+v68: main.o tools.o v68.o v68mem.o v68io.o v68periph.o v68human.o v68doscall.o v68iocscall.o v68fecall.o sjis.o sjis_unicode.o ym2151.o okim6258.o vgm.o $(MUSASHIOBJS) $(MUSASHIGENOBJS)
16
+	gcc $^ -lao -lm -o $@
17
+
18
+xinfo: xinfo.o md5.o cmdline.o
19
+	gcc $^ -o $@
20
+
21
+sjis2utf8: sjis2utf8.o sjis.o sjis_unicode.o
22
+	gcc $^ -o $@
23
+
24
+test-mem: test-mem.o v68.o v68mem.o v68human.o v68opm.o v68io.o v68doscall.o v68fecall.o v68iocscall.o okim6258.o ym2151.o vgm.o sjis.o sjis_unicode.o $(MUSASHIOBJS) $(MUSASHIGENOBJS)
25
+	gcc $^ -lao -lm -o $@
26
+
27
+%.o: %.c
28
+	gcc -g -Wall -c $< -o $@
29
+
30
+clean:
31
+	rm -f *.o musashi/*.o $(patsubst %.c,musashi/%.c,$(MUSASHIGENCFILES)) ay.js *.wasm *.map test
32
+
33
+main.o: main.c v68.h okim6258.h mamedef.h ym2151.h v68io.h cmdline.h \
34
+ tools.h
35
+tools.o: tools.c tools.h
36
+v68.o: v68.c v68.h okim6258.h mamedef.h ym2151.h v68io.h \
37
+ musashi/m68kcpu.h musashi/m68k.h musashi/m68kconf.h
38
+v68io.o: v68io.c v68io.h v68.h okim6258.h mamedef.h ym2151.h
39
+ym2151.o: ym2151.c mamedef.h ym2151.h
40
+okim6258.o: okim6258.c mamedef.h okim6258.h
41
+vgm.o: vgm.c vgm.h
42
+m68kcpu.o: musashi/m68kcpu.c musashi/m68kops.h musashi/m68kcpu.h \
43
+ musashi/m68k.h musashi/m68kconf.h
44
+m68kdasm.o: musashi/m68kdasm.c musashi/m68k.h musashi/m68kconf.h
45
+m68kops.o: musashi/m68kops.c musashi/m68kops.h
46
+m68kopac.o: musashi/m68kopac.c musashi/m68kcpu.h musashi/m68k.h \
47
+ musashi/m68kconf.h
48
+m68kopdm.o: musashi/m68kopdm.c musashi/m68kcpu.h musashi/m68k.h \
49
+ musashi/m68kconf.h
50
+m68kopnz.o: musashi/m68kopnz.c musashi/m68kcpu.h musashi/m68k.h \
51
+ musashi/m68kconf.h

+ 279
- 0
README.md View File

@@ -0,0 +1,279 @@
1
+PSP = Program Segment Prefix, similar to DOS PSP
2
+
3
+USP = User Stack Pointer
4
+SSP = Supervisor Stack Pointer
5
+BSS = space for global vars, initialized to zero at load
6
+
7
+https://nfggames.com/X68000/index.php/Mirrors/Groundzero%20Organization/x68tools/develop/docs/puni/
8
+
9
+puni7_2/oswork.man:320, メモリ管理ポインタ:
10
+```
11
+
12
+· Memory management pointer
13
+
14
+offset   size
15
+$00 (0)   1.l   Previous memory management pointer (leading with 0)
16
+$04 (4)   1.l   Parent process memory management pointer (0 with no parent)
17
+$08 (8)   1.l   Last address of this memory block + 1
18
+$0c (12)  1.l   Next memory management pointer (end with 0)
19
+
20
+It is a structure of 16 bytes created at the head of each memory block. The first memory block exists in the supervisor area inside Human 68k.
21
+
22
+The most significant byte of the 4th byte (the process that secured memory) represents the attribute of that memory block.
23
+
24
+$ff Resident process (KEEP)
25
+$fe unknown (MEMDRV)
26
+$fd Sub memory block
27
+
28
+· Process management pointer
29
+
30
+A 256-byte   structure (including a memory management pointer) for holding process information, which is created at the beginning of the memory block for each process.
31
+
32
+offset   size
33
+$00(0)    4.l   (memory management pointer)
34
+$10(16)   1.l   Environment's address (not secured if -1)
35
+$14(20)   1.l   Return address at the end
36
+$18(24)   1.l   Return address when interrupted by CTRL + C
37
+$1c(28)   1.l   Return address when interrupt due to error
38
+$20(32)   1.l   command line address
39
+$24(36)   12.b  File handler usage of process
40
+                (In use = 1 in the order of bits 0 to 7 of $24 to $2f)
41
+$30(48)   1.l   Start address of BSS
42
+$34(52)   1.l   Start address of heap (same as BSS)
43
+$38(56)   1.l   Initial stack address (end of heap + 1)
44
+$3c(60)   1.l   USP of the parent process
45
+$40(64)   1.l   parent process SSP
46
+$44(68)   1.w   parent process SR
47
+$46(70)   1.w   SR at abort
48
+$48(72)   1.l   SSP at abort
49
+$4c(76)   1.l   trap # 10 vector
50
+$50(80)   1.l   vector of trap # 11
51
+$54(84)   1.l   trap #12 vector
52
+$58(88)   1.l   trap #13 vector
53
+$5c(92)   1.l   trap #14 vector
54
+$60(96)   1.l   shell activation flag (0: normal startup - 1: started as shell)
55
+$64(100)  1.b   Module number
56
+$65(101)  3.b   (unused)
57
+$68(104)  1.l   Process management pointer of loaded child process
58
+$6a(108)  5.l   (unused)
59
+$80(128)  2. b  Drive name of executable file
60
+$82(130)  66.b  Path name of executable file
61
+$c4(196)  24.b  File name of executable file
62
+$dc(220)  9.l   (unused)
63
+
64
+$ff4b	_EXEC		Loading / executing programs
65
+
66
+Arg	MD.w		Module number and mode (MODULE.b × 256 + MODE.w)
67
+	FILE.l		Pointer to file name
68
+	CMDLINE.l	Command line pointer
69
+	LOADADR.l	Load address
70
+	EXECADR.l	Execution address
71
+	FILE2.l		Filename in overlay X file
72
+	ENVPTR.l	Environment pointer
73
+	LIMIT.l		Limit address
74
+	TYPE.b		File type (upper 8 bits of FILE)
75
+
76
+Return values
77
+	MODE = 0,4
78
+		Process end code (error code if negative number)
79
+		When the process ends, d1-d7 / a1-a6 is undefined.
80
+	MODE = 1
81
+		d0.l	Execution address of the program (error code if negative number)
82
+		a0.l	Memory management pointer
83
+		a1.l	End of program
84
+		a2.l	Command line
85
+		a3.l	Environment pointer
86
+		a4.l	Execution address
87
+	MODE = 2
88
+		Error code
89
+	MODE = 3
90
+		Program length (error code if negative number)
91
+	MODE = 5
92
+		Module number * 256 (error code if negative number)
93
+
94
+	Load / execute the file specified by FILE according to the value of mode MODE.
95
+
96
+	MODE = 0
97
+		Specify the command line with CMDLINE, the environment with ENVPTR, load and execute the file specified by FILE.
98
+	MODE = 1
99
+		CMDLINE でコマンドラインを、ENVPTR で環境を指定して、FILE で指定したファイルをロードする. 正常終了した場合は必ず MODE = 4 を実行すること.
100
+	MODE = 2
101
+		ENVPTR で指定した環境から path を検索して、FILE で指定したコマンド行をフルパスのファイル名とコマンドラインに分け、FILE とCMDLINE の各ポインタに設定する.
102
+		ファイル名バッファ FILE は 90 バイト以上、コマンドラインバッファ CMDLINE は 256 バイト以上必要.
103
+	MODE = 3
104
+		LOADADR でロードアドレスを、LIMIT でリミットアドレスを指定して、FILE で指定したファイルをロードする.
105
+	MODE = 4
106
+		EXECADR で指定したアドレスからプログラムを実行する.
107
+		MD = 1 でロードした後、実行する時に使用する.
108
+	MODE = 5
109
+		FILE で指定したオーバーレイ X ファイル中の、FILE2 で指定したファイルのモジュール番号を調べる.
110
+		バインドリスト先頭からのオフセットが $fffff00 より大きいファイルは、オフセット値をビット反転した数をモジュール番号として返す.
111
+		ただし、このようなオフセット値が負数のファイルはロード出来ない.
112
+		Human68k version 3.02 では正常に動作しない(FILE2 で指定したファイル名の拡張子 1 バイト目を X に変更したファイル名で検索される).
113
+
114
+	WHen MODE = 0 to 2, when 0 is specified as ENVPTR, use your own environment.
115
+	MODE = 0,1,3 の時、MODULE でオーバーレイ X ファイル中の各ファイルのモジュール番号(0〜255)を指定することが可能.
116
+	また、実行ファイル名の拡張子が .X .Z .R のいずれでもない場合は、FILE の上位 8bitでファイルタイプ TYPE を指定し、それによってファイルの形式を指定する.
117
+
118
+	TYPE = 1	.R
119
+	TYPE = 2	.Z
120
+	TYPE = 3	.X
121
+
122
+MD = 0,1
123
+	pea	(ENVPTR)
124
+	pea	(CMDLINE)
125
+	pea	(FILE)
126
+	move.b	TYPE,(sp)
127
+	move	MD,-(sp)
128
+	DOS	_EXEC
129
+	lea	(14,sp),sp
130
+
131
+MD = 2
132
+	pea	(ENVPTR)
133
+	pea	(CMDLINE)
134
+	pea	(FILE)
135
+	move	MD,-(sp)
136
+	DOS	_EXEC
137
+	lea	(14,sp),sp
138
+
139
+MD = 3
140
+	pea	(LIMIT)
141
+	pea	(LOADADR)
142
+	pea	(FILE)
143
+	move.b	TYPE,(sp)
144
+	move	MD,-(sp)
145
+	DOS	_EXEC
146
+	lea	(14,sp),sp
147
+
148
+MD = 4
149
+	pea	(EXECADR)
150
+	move	MD,-(sp)
151
+	DOS	_EXEC
152
+	addq.l	#6,sp
153
+
154
+MD = 5
155
+	pea	(FILE2)
156
+	pea	(FILE)
157
+	move	MD,-(sp)
158
+	DOS	_EXEC
159
+	lea	(10,sp),sp
160
+
161
+```
162
+
163
+
164
+```
165
+・Structure of .X file header
166
+
167
+offset	size
168
+$00	2.b	Identifier 'HU'(0x48 0x55)
169
+$02	1.b	Reserved (0)
170
+$03	1.b	Load mode (0:Normal 1:Minimum block 2:High address)
171
+$04	1.l	Base address
172
+$08	1.l	Entry point address
173
+$0c	1.l	Text section size
174
+$10	1.l	Data section size
175
+$14	1.l	Block storage section size (including .comm, .stack)
176
+$18	1.l	Relocation table size
177
+$1c	1.l	Symbol table size
178
+$20	1.l	SCD line number table size
179
+$24	1.l	SCD symbol table size
180
+$28	1.l	SCD string table size
181
+$2c	4.l	Reserved (0)
182
+$3c	1.l	Position of the bound module list from the top of the file
183
+
184
+Size: 64 ($40) bytes
185
+
186
+  実行ファイルは、ベースアドレスにロードして再配置処理が行われた状態で格納されている.
187
+  よって、実際のロードアドレスがベースアドレスと等しければ再配置は行わなくて良い.
188
+  また両者が等しくない場合は、その差を足す.
189
+  実行開始アドレスもベースアドレスが加算された値が格納されているので、こちらも差を足す.
190
+
191
+・Relocation
192
+
193
+  再配置は以下の手続きを再配置テーブルのサイズ分繰り返す事によって行われる.
194
+
195
+1) プログラム先頭アドレスを A、ベースアドレスを B とする.
196
+2) A から B を引き、これを C とする.
197
+3) 再配置テーブルから 1 ワード収得し、D とする.
198
+4) D が 1 の場合、再配置テーブルから 1 ロングワード収得し、新しい D とする.
199
+5) D の最下位ビットが 0(偶数)の場合は、A に D を加算し、A のアドレスからの
200
+   1 ロングワードに C を足す.
201
+6) D の最下位ビットが 1(奇数)の場合は、A に D-1 を加算し、A のアドレスからの
202
+   1 ワードに C を足す(ワードサイズの再配置は通常使われる事はない).
203
+
204
+・Sections
205
+
206
+1. Header($40 bytes)
207
+2. Text section
208
+3. Data section
209
+3-1. Section information ($40 byte)
210
+    SX モードで作成された実行ファイルには、データセクションの先頭に仮想オブジェクト *SYSTEM* がリンクされ、セクション情報が出力される.
211
+3-2.".data"
212
+3-3.".rdata" の実体
213
+3-4.".rldata" の実体
214
+3-5.相対オフセットテーブル(n*4 バイト)
215
+    SX モード作成された実行ファイルにおいて、".rdata" 及び ".rldata" 内で相対
216
+    セクション内へのポインタを使用した場合に出力される.
217
+4.Block storage section
218
+  実体は出力されない.
219
+4-1.".bss"
220
+4-2.".common"
221
+4-3.".stack"
222
+5.Relocation table
223
+6.Symbol table
224
+7.SCD table
225
+8.If bound, repeat 1-7
226
+9.Bind list
227
+
228
+  相対セクションは一種のオフセット定義であり、".rdata" と ".rldata" の実体を除きその領域は実行ファイルに出力されないが、以下の順で定義される.
229
+
230
+1.".rdata"
231
+2.".rbss"
232
+3.".rcommon"
233
+4.".rstack"
234
+5.".rldata"
235
+6.".rlbss"
236
+7.".rlcommon"
237
+8.".rlstack"
238
+
239
+・Bound list
240
+
241
+offset	size
242
+$00	8.b	ファイル名($e5 で始まるファイル名は $05 とする. 残りはスペース
243
+		で埋める.)
244
+$08	3.b	拡張子(残りはスペースで埋める)
245
+$0b	1.b	属性(%XLAD_VSHR. ただし ASHR 以外を指定しても当然エラーになる)
246
+$0c	10.b	8 バイト以上のファイル名の残り(残りは $00 で埋める)
247
+$16	1.w	Last modified time
248
+		%mmmS_SSSS_HHHH_HMMM(H:時 Mm:分 S:秒)
249
+$18	1.w	Last modified date
250
+		%mmmD_DDDD_YYYY_YYYM(Y:年 Mm:月 D:日)
251
+$1a	1.b	特殊属性の変更禁止フラグ┐BIND.X で使用
252
+$1b	1.b	特殊属性(%00A0_0SHR)	┘
253
+$1c	1.l	バインドファイル先頭からのオフセット
254
+
255
+Size: 32($20) bytes
256
+
257
+  ディレクトリエントリとほぼ同じ構造である.
258
+  年月日及び時刻の上下バイトがディレクトリエントリ同様逆転しているので注意すること.
259
+  ファイルの残りが 0 バイトでリストが終わり、32 バイト以上の時はまだ続きがあり、それ以外(1〜31 バイト)ならば異常な構造となる.
260
+```
261
+
262
+
263
+```
264
+
265
+$ff47	_CURDIR		Get the current directory
266
+
267
+Arg DRIVE.w		Drive number (0: Current, 1: A, 2: B ... 26: Z)
268
+	BUFFER.l	Buffer pointer
269
+
270
+Ret Error Code
271
+
272
+	Writes the current directory of the drive specified by DRIVE into the buffer of 65 bytes specified by BUFFER.
273
+	Drive name · Do not add '\' to root directory and '\' to terminate.
274
+
275
+	pea	(BUFFER)
276
+	move	DRIVE,-(sp)
277
+	DOS	_CURDIR
278
+	addq.l	#6,sp
279
+```

+ 393
- 0
ansidecl.h View File

@@ -0,0 +1,393 @@
1
+/* ANSI and traditional C compatability macros
2
+   Copyright (C) 1991-2017 Free Software Foundation, Inc.
3
+   This file is part of the GNU C Library.
4
+
5
+This program 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 2 of the License, or
8
+(at your option) any later version.
9
+
10
+This program 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 this program; if not, write to the Free Software
17
+Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
18
+
19
+/* ANSI and traditional C compatibility macros
20
+
21
+   ANSI C is assumed if __STDC__ is #defined.
22
+
23
+   Macro		ANSI C definition	Traditional C definition
24
+   -----		---- - ----------	----------- - ----------
25
+   PTR			`void *'		`char *'
26
+   const		not defined		`'
27
+   volatile		not defined		`'
28
+   signed		not defined		`'
29
+
30
+   For ease of writing code which uses GCC extensions but needs to be
31
+   portable to other compilers, we provide the GCC_VERSION macro that
32
+   simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various
33
+   wrappers around __attribute__.  Also, __extension__ will be #defined
34
+   to nothing if it doesn't work.  See below.  */
35
+
36
+#ifndef	_ANSIDECL_H
37
+#define _ANSIDECL_H	1
38
+
39
+#ifdef __cplusplus
40
+extern "C" {
41
+#endif
42
+
43
+/* Every source file includes this file,
44
+   so they will all get the switch for lint.  */
45
+/* LINTLIBRARY */
46
+
47
+/* Using MACRO(x,y) in cpp #if conditionals does not work with some
48
+   older preprocessors.  Thus we can't define something like this:
49
+
50
+#define HAVE_GCC_VERSION(MAJOR, MINOR) \
51
+  (__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR)))
52
+
53
+and then test "#if HAVE_GCC_VERSION(2,7)".
54
+
55
+So instead we use the macro below and test it against specific values.  */
56
+
57
+/* This macro simplifies testing whether we are using gcc, and if it
58
+   is of a particular minimum version. (Both major & minor numbers are
59
+   significant.)  This macro will evaluate to 0 if we are not using
60
+   gcc at all.  */
61
+#ifndef GCC_VERSION
62
+#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
63
+#endif /* GCC_VERSION */
64
+
65
+#if defined (__STDC__) || defined(__cplusplus) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32)
66
+/* All known AIX compilers implement these things (but don't always
67
+   define __STDC__).  The RISC/OS MIPS compiler defines these things
68
+   in SVR4 mode, but does not define __STDC__.  */
69
+/* eraxxon@alumni.rice.edu: The Compaq C++ compiler, unlike many other
70
+   C++ compilers, does not define __STDC__, though it acts as if this
71
+   was so. (Verified versions: 5.7, 6.2, 6.3, 6.5) */
72
+
73
+#define PTR		void *
74
+
75
+#undef const
76
+#undef volatile
77
+#undef signed
78
+
79
+/* inline requires special treatment; it's in C99, and GCC >=2.7 supports
80
+   it too, but it's not in C89.  */
81
+#undef inline
82
+#if __STDC_VERSION__ >= 199901L || defined(__cplusplus) || (defined(__SUNPRO_C) && defined(__C99FEATURES__))
83
+/* it's a keyword */
84
+#else
85
+# if GCC_VERSION >= 2007
86
+#  define inline __inline__   /* __inline__ prevents -pedantic warnings */
87
+# else
88
+#  define inline  /* nothing */
89
+# endif
90
+#endif
91
+
92
+#else	/* Not ANSI C.  */
93
+
94
+#define PTR		char *
95
+
96
+/* some systems define these in header files for non-ansi mode */
97
+#undef const
98
+#undef volatile
99
+#undef signed
100
+#undef inline
101
+#define const
102
+#define volatile
103
+#define signed
104
+#define inline
105
+
106
+#endif	/* ANSI C.  */
107
+
108
+/* Define macros for some gcc attributes.  This permits us to use the
109
+   macros freely, and know that they will come into play for the
110
+   version of gcc in which they are supported.  */
111
+
112
+#if (GCC_VERSION < 2007)
113
+# define __attribute__(x)
114
+#endif
115
+
116
+/* Attribute __malloc__ on functions was valid as of gcc 2.96. */
117
+#ifndef ATTRIBUTE_MALLOC
118
+# if (GCC_VERSION >= 2096)
119
+#  define ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
120
+# else
121
+#  define ATTRIBUTE_MALLOC
122
+# endif /* GNUC >= 2.96 */
123
+#endif /* ATTRIBUTE_MALLOC */
124
+
125
+/* Attributes on labels were valid as of gcc 2.93 and g++ 4.5.  For
126
+   g++ an attribute on a label must be followed by a semicolon.  */
127
+#ifndef ATTRIBUTE_UNUSED_LABEL
128
+# ifndef __cplusplus
129
+#  if GCC_VERSION >= 2093
130
+#   define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED
131
+#  else
132
+#   define ATTRIBUTE_UNUSED_LABEL
133
+#  endif
134
+# else
135
+#  if GCC_VERSION >= 4005
136
+#   define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED ;
137
+#  else
138
+#   define ATTRIBUTE_UNUSED_LABEL
139
+#  endif
140
+# endif
141
+#endif
142
+
143
+/* Similarly to ARG_UNUSED below.  Prior to GCC 3.4, the C++ frontend
144
+   couldn't parse attributes placed after the identifier name, and now
145
+   the entire compiler is built with C++.  */
146
+#ifndef ATTRIBUTE_UNUSED
147
+#if GCC_VERSION >= 3004
148
+#  define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
149
+#else
150
+#define ATTRIBUTE_UNUSED
151
+#endif
152
+#endif /* ATTRIBUTE_UNUSED */
153
+
154
+/* Before GCC 3.4, the C++ frontend couldn't parse attributes placed after the
155
+   identifier name.  */
156
+#if ! defined(__cplusplus) || (GCC_VERSION >= 3004)
157
+# define ARG_UNUSED(NAME) NAME ATTRIBUTE_UNUSED
158
+#else /* !__cplusplus || GNUC >= 3.4 */
159
+# define ARG_UNUSED(NAME) NAME
160
+#endif /* !__cplusplus || GNUC >= 3.4 */
161
+
162
+#ifndef ATTRIBUTE_NORETURN
163
+#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
164
+#endif /* ATTRIBUTE_NORETURN */
165
+
166
+/* Attribute `nonnull' was valid as of gcc 3.3.  */
167
+#ifndef ATTRIBUTE_NONNULL
168
+# if (GCC_VERSION >= 3003)
169
+#  define ATTRIBUTE_NONNULL(m) __attribute__ ((__nonnull__ (m)))
170
+# else
171
+#  define ATTRIBUTE_NONNULL(m)
172
+# endif /* GNUC >= 3.3 */
173
+#endif /* ATTRIBUTE_NONNULL */
174
+
175
+/* Attribute `returns_nonnull' was valid as of gcc 4.9.  */
176
+#ifndef ATTRIBUTE_RETURNS_NONNULL
177
+# if (GCC_VERSION >= 4009)
178
+#  define ATTRIBUTE_RETURNS_NONNULL __attribute__ ((__returns_nonnull__))
179
+# else
180
+#  define ATTRIBUTE_RETURNS_NONNULL
181
+# endif /* GNUC >= 4.9 */
182
+#endif /* ATTRIBUTE_RETURNS_NONNULL */
183
+
184
+/* Attribute `pure' was valid as of gcc 3.0.  */
185
+#ifndef ATTRIBUTE_PURE
186
+# if (GCC_VERSION >= 3000)
187
+#  define ATTRIBUTE_PURE __attribute__ ((__pure__))
188
+# else
189
+#  define ATTRIBUTE_PURE
190
+# endif /* GNUC >= 3.0 */
191
+#endif /* ATTRIBUTE_PURE */
192
+
193
+/* Use ATTRIBUTE_PRINTF when the format specifier must not be NULL.
194
+   This was the case for the `printf' format attribute by itself
195
+   before GCC 3.3, but as of 3.3 we need to add the `nonnull'
196
+   attribute to retain this behavior.  */
197
+#ifndef ATTRIBUTE_PRINTF
198
+#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ATTRIBUTE_NONNULL(m)
199
+#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2)
200
+#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3)
201
+#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4)
202
+#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5)
203
+#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6)
204
+#endif /* ATTRIBUTE_PRINTF */
205
+
206
+/* Use ATTRIBUTE_FPTR_PRINTF when the format attribute is to be set on
207
+   a function pointer.  Format attributes were allowed on function
208
+   pointers as of gcc 3.1.  */
209
+#ifndef ATTRIBUTE_FPTR_PRINTF
210
+# if (GCC_VERSION >= 3001)
211
+#  define ATTRIBUTE_FPTR_PRINTF(m, n) ATTRIBUTE_PRINTF(m, n)
212
+# else
213
+#  define ATTRIBUTE_FPTR_PRINTF(m, n)
214
+# endif /* GNUC >= 3.1 */
215
+# define ATTRIBUTE_FPTR_PRINTF_1 ATTRIBUTE_FPTR_PRINTF(1, 2)
216
+# define ATTRIBUTE_FPTR_PRINTF_2 ATTRIBUTE_FPTR_PRINTF(2, 3)
217
+# define ATTRIBUTE_FPTR_PRINTF_3 ATTRIBUTE_FPTR_PRINTF(3, 4)
218
+# define ATTRIBUTE_FPTR_PRINTF_4 ATTRIBUTE_FPTR_PRINTF(4, 5)
219
+# define ATTRIBUTE_FPTR_PRINTF_5 ATTRIBUTE_FPTR_PRINTF(5, 6)
220
+#endif /* ATTRIBUTE_FPTR_PRINTF */
221
+
222
+/* Use ATTRIBUTE_NULL_PRINTF when the format specifier may be NULL.  A
223
+   NULL format specifier was allowed as of gcc 3.3.  */
224
+#ifndef ATTRIBUTE_NULL_PRINTF
225
+# if (GCC_VERSION >= 3003)
226
+#  define ATTRIBUTE_NULL_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n)))
227
+# else
228
+#  define ATTRIBUTE_NULL_PRINTF(m, n)
229
+# endif /* GNUC >= 3.3 */
230
+# define ATTRIBUTE_NULL_PRINTF_1 ATTRIBUTE_NULL_PRINTF(1, 2)
231
+# define ATTRIBUTE_NULL_PRINTF_2 ATTRIBUTE_NULL_PRINTF(2, 3)
232
+# define ATTRIBUTE_NULL_PRINTF_3 ATTRIBUTE_NULL_PRINTF(3, 4)
233
+# define ATTRIBUTE_NULL_PRINTF_4 ATTRIBUTE_NULL_PRINTF(4, 5)
234
+# define ATTRIBUTE_NULL_PRINTF_5 ATTRIBUTE_NULL_PRINTF(5, 6)
235
+#endif /* ATTRIBUTE_NULL_PRINTF */
236
+
237
+/* Attribute `sentinel' was valid as of gcc 3.5.  */
238
+#ifndef ATTRIBUTE_SENTINEL
239
+# if (GCC_VERSION >= 3005)
240
+#  define ATTRIBUTE_SENTINEL __attribute__ ((__sentinel__))
241
+# else
242
+#  define ATTRIBUTE_SENTINEL
243
+# endif /* GNUC >= 3.5 */
244
+#endif /* ATTRIBUTE_SENTINEL */
245
+
246
+
247
+#ifndef ATTRIBUTE_ALIGNED_ALIGNOF
248
+# if (GCC_VERSION >= 3000)
249
+#  define ATTRIBUTE_ALIGNED_ALIGNOF(m) __attribute__ ((__aligned__ (__alignof__ (m))))
250
+# else
251
+#  define ATTRIBUTE_ALIGNED_ALIGNOF(m)
252
+# endif /* GNUC >= 3.0 */
253
+#endif /* ATTRIBUTE_ALIGNED_ALIGNOF */
254
+
255
+/* Useful for structures whose layout must match some binary specification
256
+   regardless of the alignment and padding qualities of the compiler.  */
257
+#ifndef ATTRIBUTE_PACKED
258
+# define ATTRIBUTE_PACKED __attribute__ ((packed))
259
+#endif
260
+
261
+/* Attribute `hot' and `cold' was valid as of gcc 4.3.  */
262
+#ifndef ATTRIBUTE_COLD
263
+# if (GCC_VERSION >= 4003)
264
+#  define ATTRIBUTE_COLD __attribute__ ((__cold__))
265
+# else
266
+#  define ATTRIBUTE_COLD
267
+# endif /* GNUC >= 4.3 */
268
+#endif /* ATTRIBUTE_COLD */
269
+#ifndef ATTRIBUTE_HOT
270
+# if (GCC_VERSION >= 4003)
271
+#  define ATTRIBUTE_HOT __attribute__ ((__hot__))
272
+# else
273
+#  define ATTRIBUTE_HOT
274
+# endif /* GNUC >= 4.3 */
275
+#endif /* ATTRIBUTE_HOT */
276
+
277
+/* Attribute 'no_sanitize_undefined' was valid as of gcc 4.9.  */
278
+#ifndef ATTRIBUTE_NO_SANITIZE_UNDEFINED
279
+# if (GCC_VERSION >= 4009)
280
+#  define ATTRIBUTE_NO_SANITIZE_UNDEFINED __attribute__ ((no_sanitize_undefined))
281
+# else
282
+#  define ATTRIBUTE_NO_SANITIZE_UNDEFINED
283
+# endif /* GNUC >= 4.9 */
284
+#endif /* ATTRIBUTE_NO_SANITIZE_UNDEFINED */
285
+
286
+/* We use __extension__ in some places to suppress -pedantic warnings
287
+   about GCC extensions.  This feature didn't work properly before
288
+   gcc 2.8.  */
289
+#if GCC_VERSION < 2008
290
+#define __extension__
291
+#endif
292
+
293
+/* This is used to declare a const variable which should be visible
294
+   outside of the current compilation unit.  Use it as
295
+     EXPORTED_CONST int i = 1;
296
+   This is because the semantics of const are different in C and C++.
297
+   "extern const" is permitted in C but it looks strange, and gcc
298
+   warns about it when -Wc++-compat is not used.  */
299
+#ifdef __cplusplus
300
+#define EXPORTED_CONST extern const
301
+#else
302
+#define EXPORTED_CONST const
303
+#endif
304
+
305
+/* Be conservative and only use enum bitfields with C++ or GCC.
306
+   FIXME: provide a complete autoconf test for buggy enum bitfields.  */
307
+
308
+#ifdef __cplusplus
309
+#define ENUM_BITFIELD(TYPE) enum TYPE
310
+#elif (GCC_VERSION > 2000)
311
+#define ENUM_BITFIELD(TYPE) __extension__ enum TYPE
312
+#else
313
+#define ENUM_BITFIELD(TYPE) unsigned int
314
+#endif
315
+
316
+#if __cpp_constexpr >= 200704
317
+#define CONSTEXPR constexpr
318
+#else
319
+#define CONSTEXPR
320
+#endif
321
+
322
+/* C++11 adds the ability to add "override" after an implementation of a
323
+   virtual function in a subclass, to:
324
+     (A) document that this is an override of a virtual function
325
+     (B) allow the compiler to issue a warning if it isn't (e.g. a mismatch
326
+         of the type signature).
327
+
328
+   Similarly, it allows us to add a "final" to indicate that no subclass
329
+   may subsequently override the vfunc.
330
+
331
+   Provide OVERRIDE and FINAL as macros, allowing us to get these benefits
332
+   when compiling with C++11 support, but without requiring C++11.
333
+
334
+   For gcc, use "-std=c++11" to enable C++11 support; gcc 6 onwards enables
335
+   this by default (actually GNU++14).  */
336
+
337
+#if defined __cplusplus
338
+# if __cplusplus >= 201103
339
+   /* C++11 claims to be available: use it.  Final/override were only
340
+      implemented in 4.7, though.  */
341
+#  if GCC_VERSION < 4007
342
+#   define OVERRIDE
343
+#   define FINAL
344
+#  else
345
+#   define OVERRIDE override
346
+#   define FINAL final
347
+#  endif
348
+# elif GCC_VERSION >= 4007
349
+   /* G++ 4.7 supports __final in C++98.  */
350
+#  define OVERRIDE
351
+#  define FINAL __final
352
+# else
353
+   /* No C++11 support; leave the macros empty.  */
354
+#  define OVERRIDE
355
+#  define FINAL
356
+# endif
357
+#else
358
+  /* No C++11 support; leave the macros empty.  */
359
+# define OVERRIDE
360
+# define FINAL
361
+#endif
362
+
363
+/* A macro to disable the copy constructor and assignment operator.
364
+   When building with C++11 and above, the methods are explicitly
365
+   deleted, causing a compile-time error if something tries to copy.
366
+   For C++03, this just declares the methods, causing a link-time
367
+   error if the methods end up called (assuming you don't
368
+   define them).  For C++03, for best results, place the macro
369
+   under the private: access specifier, like this,
370
+
371
+   class name_lookup
372
+   {
373
+     private:
374
+       DISABLE_COPY_AND_ASSIGN (name_lookup);
375
+   };
376
+
377
+   so that most attempts at copy are caught at compile-time.  */
378
+
379
+#if __cplusplus >= 201103
380
+#define DISABLE_COPY_AND_ASSIGN(TYPE)		\
381
+  TYPE (const TYPE&) = delete;			\
382
+  void operator= (const TYPE &) = delete
383
+  #else
384
+#define DISABLE_COPY_AND_ASSIGN(TYPE)		\
385
+  TYPE (const TYPE&);				\
386
+  void operator= (const TYPE &)
387
+#endif /* __cplusplus >= 201103 */
388
+
389
+#ifdef __cplusplus
390
+}
391
+#endif
392
+
393
+#endif	/* ansidecl.h	*/

+ 158
- 0
main.c View File

@@ -0,0 +1,158 @@
1
+#include <stdio.h>
2
+#include <signal.h>
3
+#include <string.h>
4
+#include <sys/types.h>
5
+#include <sys/stat.h>
6
+#include <fcntl.h>
7
+#include <unistd.h>
8
+#include <limits.h>
9
+#include <ao/ao.h>
10
+
11
+#include "v68.h"
12
+#include "v68io.h"
13
+#include "cmdline.h"
14
+#include "tools.h"
15
+
16
+#define BUF_SIZE 4096
17
+#define SAMPLE_RATE 44100
18
+#define V68_CLOCK 16000000
19
+#define V68_RAM 2*1024*1024
20
+
21
+int opt_utf8 = 0;
22
+int opt_verbosity = 1;
23
+int opt_log_calls = 0;
24
+int opt_dasm = 0;
25
+
26
+int running = 1;
27
+
28
+void sighandler(int signum) {
29
+	signal(signum, NULL);
30
+	printf("Caught signal %d, coming out...\n", signum);
31
+	running = 0;
32
+}
33
+
34
+void print_help(char *argv0) {
35
+	printf("Usage: %s [options] command [args]\n", argv0);
36
+	printf("Options:\n");
37
+	printf("\t-c \"<command>\"  Execute this command before main command. Example: -c mxdrv.x.\n");
38
+	printf("\t-u                Convert output to utf-8.\n");
39
+	printf("\t-v                Increase verbosity by 1.\n");
40
+	printf("\t-t                Trace system calls (DOS, FE and IOCS).\n");
41
+	printf("\t-d                Disassemble instructions as they are executed.\n");
42
+}
43
+
44
+int parse_cmdline(int argc, char **argv) {
45
+	int first_nonarg_reached = 0;
46
+
47
+	char cmdbuf[1024];
48
+	cmdbuf[0] = 0;
49
+
50
+	for(int i = 1; i < argc; i++) {
51
+		if(!first_nonarg_reached) {
52
+			if(!strcmp(argv[i], "-c")) {
53
+				if(argc > i+1) {
54
+					i++;
55
+					v68_queue_command(argv[i]);
56
+				} else {
57
+					fprintf(stderr, "-c requires an argument\n");
58
+				}
59
+			} else if (!strcmp(argv[i], "-u")) {
60
+				opt_utf8 = 1;
61
+			} else if (!strcmp(argv[i], "-v")) {
62
+				opt_verbosity++;
63
+			} else if (!strcmp(argv[i], "-t")) {
64
+				opt_log_calls = 1;
65
+			} else if (!strcmp(argv[i], "-d")) {
66
+				opt_dasm = 1;
67
+			} else if(argv[i][0] == '-') {
68
+				print_help(argv[0]);
69
+				return 1;
70
+			} else {
71
+				first_nonarg_reached = 1;
72
+			}
73
+		}
74
+
75
+		if(first_nonarg_reached) {
76
+			strncat(cmdbuf, argv[i], sizeof(cmdbuf) - strlen(cmdbuf));
77
+			strncat(cmdbuf, " ", sizeof(cmdbuf) - strlen(cmdbuf));
78
+		}
79
+	}
80
+	if(cmdbuf[0]) {
81
+		v68_queue_command(cmdbuf);
82
+		return 0;
83
+	}
84
+
85
+	print_help(argv[0]);
86
+	return 1;
87
+}
88
+
89
+int main(int argc, char **argv, char **envp) {
90
+	int er = v68_init(V68_CLOCK, V68_RAM, SAMPLE_RATE);
91
+	if(er) {
92
+		fprintf(stderr, "Could not init VM! (%x)\n", er);
93
+		return -1;
94
+	}
95
+
96
+	if(parse_cmdline(argc, argv)) {
97
+		fprintf(stderr, "Could not parse command line\n");
98
+		return -1;
99
+	}
100
+
101
+	v68.log_calls = opt_log_calls;
102
+	v68.log_dasm = opt_dasm;
103
+	v68.verbosity = opt_verbosity;
104
+	v68_io_autodetect_drives();
105
+	v68_dump_drives();
106
+	struct vgm_logger l;
107
+	vgm_logger_begin(&l, "v68.vgm");
108
+	v68.logger = &l;
109
+
110
+	char *v68_path = getenv("V68_PATH");
111
+	v68_env_set("PATH", v68_path ? v68_path : getenv("PATH"));
112
+	for(char **e = envp; *e; e++) {
113
+		v68_env_append(*e);
114
+	}
115
+
116
+	// AO
117
+	ao_initialize();
118
+
119
+	int default_driver = ao_default_driver_id();
120
+
121
+	ao_sample_format format;
122
+	memset(&format, 0, sizeof(format));
123
+	format.bits = 16;
124
+	format.channels = 2;
125
+	format.rate = SAMPLE_RATE;
126
+	format.byte_format = AO_FMT_LITTLE;
127
+
128
+	ao_device *device = ao_open_live(default_driver, &format, NULL /* no options */);
129
+	if (device == NULL) {
130
+		fprintf(stderr, "Error opening device.\n");
131
+		return 1;
132
+	}
133
+
134
+	signal(SIGINT, sighandler);
135
+
136
+	/* -- Play some stuff -- */
137
+	while(running) {
138
+		int32_t bufL[BUF_SIZE], bufR[BUF_SIZE];
139
+		int16_t buf[BUF_SIZE * 2];
140
+		v68_fill_buffer(bufL, bufR, BUF_SIZE);
141
+		for(int i = 0; i < BUF_SIZE; i++) {
142
+			buf[i * 2] = bufL[i];
143
+			buf[i * 2 + 1] = bufR[i];
144
+		}
145
+		ao_play(device, (char *)buf, BUF_SIZE * format.channels * format.bits / 8);
146
+	}
147
+
148
+	/* -- Close and shutdown -- */
149
+	ao_close(device);
150
+
151
+	ao_shutdown();
152
+
153
+	vgm_logger_end(&l);
154
+
155
+	v68_shutdown();
156
+
157
+	return 0;
158
+}

+ 64
- 0
mamedef.h View File

@@ -0,0 +1,64 @@
1
+#ifndef __MAMEDEF_H__
2
+#define __MAMEDEF_H__
3
+
4
+// typedefs to use MAME's (U)INTxx types (copied from MAME\src\ods\odscomm.h)
5
+/* 8-bit values */
6
+typedef unsigned char						UINT8;
7
+typedef signed char 						INT8;
8
+
9
+/* 16-bit values */
10
+typedef unsigned short						UINT16;
11
+typedef signed short						INT16;
12
+
13
+/* 32-bit values */
14
+#ifndef _WINDOWS_H
15
+typedef unsigned int						UINT32;
16
+typedef signed int							INT32;
17
+#endif
18
+
19
+/* 64-bit values */
20
+#ifndef _WINDOWS_H
21
+#ifdef _MSC_VER
22
+typedef signed __int64						INT64;
23
+typedef unsigned __int64					UINT64;
24
+#else
25
+__extension__ typedef unsigned long long	UINT64;
26
+__extension__ typedef signed long long		INT64;
27
+#endif
28
+#endif
29
+
30
+/* offsets and addresses are 32-bit (for now...) */
31
+typedef UINT32	offs_t;
32
+
33
+/* stream_sample_t is used to represent a single sample in a sound stream */
34
+typedef INT32 stream_sample_t;
35
+
36
+#if defined(VGM_BIG_ENDIAN)
37
+#define BYTE_XOR_BE(x)	 (x)
38
+#elif defined(VGM_LITTLE_ENDIAN)
39
+#define BYTE_XOR_BE(x)	((x) ^ 0x01)
40
+#else
41
+// don't define BYTE_XOR_BE so that it throws an error when compiling
42
+#endif
43
+
44
+#if defined(_MSC_VER)
45
+//#define INLINE	static __forceinline
46
+#define INLINE	static __inline
47
+#elif defined(__GNUC__)
48
+#define INLINE	static __inline__
49
+#else
50
+#define INLINE	static inline
51
+#endif
52
+#define M_PI	3.14159265358979323846
53
+
54
+#ifdef _DEBUG
55
+#define logerror	printf
56
+#else
57
+#define logerror
58
+#endif
59
+
60
+extern stream_sample_t* DUMMYBUF[];
61
+
62
+typedef void (*SRATE_CALLBACK)(void*, UINT32);
63
+
64
+#endif	// __MAMEDEF_H__

+ 440
- 0
md5.c View File

@@ -0,0 +1,440 @@
1
+/* md5.c - Functions to compute MD5 message digest of files or memory blocks
2
+   according to the definition of MD5 in RFC 1321 from April 1992.
3
+   Copyright (C) 1995-2017 Free Software Foundation, Inc.
4
+
5
+   NOTE: This source is derived from an old version taken from the GNU C
6
+   Library (glibc).
7
+
8
+   This program is free software; you can redistribute it and/or modify it
9
+   under the terms of the GNU General Public License as published by the
10
+   Free Software Foundation; either version 2, or (at your option) any
11
+   later version.
12
+
13
+   This program is distributed in the hope that it will be useful,
14
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+   GNU General Public License for more details.
17
+
18
+   You should have received a copy of the GNU General Public License
19
+   along with this program; if not, write to the Free Software Foundation,
20
+   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
21
+
22
+/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.  */
23
+
24
+#ifdef HAVE_CONFIG_H
25
+# include <config.h>
26
+#endif
27
+
28
+#include <sys/types.h>
29
+
30
+# include <string.h>
31
+#if STDC_HEADERS || defined _LIBC
32
+# include <stdlib.h>
33
+#else
34
+# ifndef HAVE_MEMCPY
35
+#  define memcpy(d, s, n) bcopy ((s), (d), (n))
36
+# endif
37
+#endif
38
+
39
+#include "ansidecl.h"
40
+#include "md5.h"
41
+
42
+#ifdef _LIBC
43
+# include <endian.h>
44
+# if __BYTE_ORDER == __BIG_ENDIAN
45
+#  define WORDS_BIGENDIAN 1
46
+# endif
47
+#endif
48
+
49
+#ifdef WORDS_BIGENDIAN
50
+# define SWAP(n)							\
51
+    (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
52
+#else
53
+# define SWAP(n) (n)
54
+#endif
55
+
56
+
57
+/* This array contains the bytes used to pad the buffer to the next
58
+   64-byte boundary.  (RFC 1321, 3.1: Step 1)  */
59
+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */ };
60
+
61
+
62
+/* Initialize structure containing state of computation.
63
+   (RFC 1321, 3.3: Step 3)  */
64
+void
65
+md5_init_ctx (struct md5_ctx *ctx)
66
+{
67
+  ctx->A = (md5_uint32) 0x67452301;
68
+  ctx->B = (md5_uint32) 0xefcdab89;
69
+  ctx->C = (md5_uint32) 0x98badcfe;
70
+  ctx->D = (md5_uint32) 0x10325476;
71
+
72
+  ctx->total[0] = ctx->total[1] = 0;
73
+  ctx->buflen = 0;
74
+}
75
+
76
+/* Put result from CTX in first 16 bytes following RESBUF.  The result
77
+   must be in little endian byte order.
78
+
79
+   IMPORTANT: RESBUF may not be aligned as strongly as MD5_UNIT32 so we
80
+   put things in a local (aligned) buffer first, then memcpy into RESBUF.  */
81
+void *
82
+md5_read_ctx (const struct md5_ctx *ctx, void *resbuf)
83
+{
84
+  md5_uint32 buffer[4];
85
+
86
+  buffer[0] = SWAP (ctx->A);
87
+  buffer[1] = SWAP (ctx->B);
88
+  buffer[2] = SWAP (ctx->C);
89
+  buffer[3] = SWAP (ctx->D);
90
+
91
+  memcpy (resbuf, buffer, 16);
92
+
93
+  return resbuf;
94
+}
95
+
96
+/* Process the remaining bytes in the internal buffer and the usual
97
+   prolog according to the standard and write the result to RESBUF.
98
+
99
+   IMPORTANT: On some systems it is required that RESBUF is correctly
100
+   aligned for a 32 bits value.  */
101
+void *
102
+md5_finish_ctx (struct md5_ctx *ctx, void *resbuf)
103
+{
104
+  /* Take yet unprocessed bytes into account.  */
105
+  md5_uint32 bytes = ctx->buflen;
106
+  md5_uint32 swap_bytes;
107
+  size_t pad;
108
+
109
+  /* Now count remaining bytes.  */
110
+  ctx->total[0] += bytes;
111
+  if (ctx->total[0] < bytes)
112
+    ++ctx->total[1];
113
+
114
+  pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
115
+  memcpy (&ctx->buffer[bytes], fillbuf, pad);
116
+
117
+  /* Put the 64-bit file length in *bits* at the end of the buffer.
118
+     Use memcpy to avoid aliasing problems.  On most systems, this
119
+     will be optimized away to the same code.  */
120
+  swap_bytes = SWAP (ctx->total[0] << 3);
121
+  memcpy (&ctx->buffer[bytes + pad], &swap_bytes, sizeof (swap_bytes));
122
+  swap_bytes = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29));
123
+  memcpy (&ctx->buffer[bytes + pad + 4], &swap_bytes, sizeof (swap_bytes));
124
+
125
+  /* Process last bytes.  */
126
+  md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
127
+
128
+  return md5_read_ctx (ctx, resbuf);
129
+}
130
+
131
+/* Compute MD5 message digest for bytes read from STREAM.  The
132
+   resulting message digest number will be written into the 16 bytes
133
+   beginning at RESBLOCK.  */
134
+int
135
+md5_stream (FILE *stream, void *resblock)
136
+{
137
+  /* Important: BLOCKSIZE must be a multiple of 64.  */
138
+#define BLOCKSIZE 4096
139
+  struct md5_ctx ctx;
140
+  char buffer[BLOCKSIZE + 72];
141
+  size_t sum;
142
+
143
+  /* Initialize the computation context.  */
144
+  md5_init_ctx (&ctx);
145
+
146
+  /* Iterate over full file contents.  */
147
+  while (1)
148
+    {
149
+      /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
150
+	 computation function processes the whole buffer so that with the
151
+	 next round of the loop another block can be read.  */
152
+      size_t n;
153
+      sum = 0;
154
+
155
+      /* Read block.  Take care for partial reads.  */
156
+      do
157
+	{
158
+	  n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
159
+
160
+	  sum += n;
161
+	}
162
+      while (sum < BLOCKSIZE && n != 0);
163
+      if (n == 0 && ferror (stream))
164
+        return 1;
165
+
166
+      /* If end of file is reached, end the loop.  */
167
+      if (n == 0)
168
+	break;
169
+
170
+      /* Process buffer with BLOCKSIZE bytes.  Note that
171
+			BLOCKSIZE % 64 == 0
172
+       */
173
+      md5_process_block (buffer, BLOCKSIZE, &ctx);
174
+    }
175
+
176
+  /* Add the last bytes if necessary.  */
177
+  if (sum > 0)
178
+    md5_process_bytes (buffer, sum, &ctx);
179
+
180
+  /* Construct result in desired memory.  */
181
+  md5_finish_ctx (&ctx, resblock);
182
+  return 0;
183
+}
184
+
185
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
186
+   result is always in little endian byte order, so that a byte-wise
187
+   output yields to the wanted ASCII representation of the message
188
+   digest.  */
189
+void *
190
+md5_buffer (const char *buffer, size_t len, void *resblock)
191
+{
192
+  struct md5_ctx ctx;
193
+
194
+  /* Initialize the computation context.  */
195
+  md5_init_ctx (&ctx);
196
+
197
+  /* Process whole buffer but last len % 64 bytes.  */
198
+  md5_process_bytes (buffer, len, &ctx);
199
+
200
+  /* Put result in desired memory area.  */
201
+  return md5_finish_ctx (&ctx, resblock);
202
+}
203
+
204
+
205
+void
206
+md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx)
207
+{
208
+  /* When we already have some bits in our internal buffer concatenate
209
+     both inputs first.  */
210
+  if (ctx->buflen != 0)
211
+    {
212
+      size_t left_over = ctx->buflen;
213
+      size_t add = 128 - left_over > len ? len : 128 - left_over;
214
+
215
+      memcpy (&ctx->buffer[left_over], buffer, add);
216
+      ctx->buflen += add;
217
+
218
+      if (left_over + add > 64)
219
+	{
220
+	  md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx);
221
+	  /* The regions in the following copy operation cannot overlap.  */
222
+	  memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
223
+		  (left_over + add) & 63);
224
+	  ctx->buflen = (left_over + add) & 63;
225
+	}
226
+
227
+      buffer = (const void *) ((const char *) buffer + add);
228
+      len -= add;
229
+    }
230
+
231
+  /* Process available complete blocks.  */
232
+  if (len > 64)
233
+    {
234
+#if !_STRING_ARCH_unaligned
235
+/* To check alignment gcc has an appropriate operator.  Other
236
+   compilers don't.  */
237
+# if __GNUC__ >= 2
238
+#  define UNALIGNED_P(p) (((md5_uintptr) p) % __alignof__ (md5_uint32) != 0)
239
+# else
240
+#  define UNALIGNED_P(p) (((md5_uintptr) p) % sizeof (md5_uint32) != 0)
241
+# endif
242
+      if (UNALIGNED_P (buffer))
243
+        while (len > 64)
244
+          {
245
+	    memcpy (ctx->buffer, buffer, 64);
246
+            md5_process_block (ctx->buffer, 64, ctx);
247
+            buffer = (const char *) buffer + 64;
248
+            len -= 64;
249
+          }
250
+      else
251
+#endif
252
+	{
253
+	  md5_process_block (buffer, len & ~63, ctx);
254
+	  buffer = (const void *) ((const char *) buffer + (len & ~63));
255
+	  len &= 63;
256
+	}
257
+    }
258
+
259
+  /* Move remaining bytes in internal buffer.  */
260
+  if (len > 0)
261
+    {
262
+      memcpy (ctx->buffer, buffer, len);
263
+      ctx->buflen = len;
264
+    }
265
+}
266
+
267
+
268
+/* These are the four functions used in the four steps of the MD5 algorithm
269
+   and defined in the RFC 1321.  The first function is a little bit optimized
270
+   (as found in Colin Plumbs public domain implementation).  */
271
+/* #define FF(b, c, d) ((b & c) | (~b & d)) */
272
+#define FF(b, c, d) (d ^ (b & (c ^ d)))
273
+#define FG(b, c, d) FF (d, b, c)
274
+#define FH(b, c, d) (b ^ c ^ d)
275
+#define FI(b, c, d) (c ^ (b | ~d))
276
+
277
+/* Process LEN bytes of BUFFER, accumulating context into CTX.
278
+   It is assumed that LEN % 64 == 0.  */
279
+
280
+void
281
+md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx)
282
+{
283
+  md5_uint32 correct_words[16];
284
+  const md5_uint32 *words = (const md5_uint32 *) buffer;
285
+  size_t nwords = len / sizeof (md5_uint32);
286
+  const md5_uint32 *endp = words + nwords;
287
+  md5_uint32 A = ctx->A;
288
+  md5_uint32 B = ctx->B;
289
+  md5_uint32 C = ctx->C;
290
+  md5_uint32 D = ctx->D;
291
+
292
+  /* First increment the byte count.  RFC 1321 specifies the possible
293
+     length of the file up to 2^64 bits.  Here we only compute the
294
+     number of bytes.  Do a double word increment.  */
295
+  ctx->total[0] += len;
296
+  ctx->total[1] += ((len >> 31) >> 1) + (ctx->total[0] < len);
297
+
298
+  /* Process all bytes in the buffer with 64 bytes in each round of
299
+     the loop.  */
300
+  while (words < endp)
301
+    {
302
+      md5_uint32 *cwp = correct_words;
303
+      md5_uint32 A_save = A;
304
+      md5_uint32 B_save = B;
305
+      md5_uint32 C_save = C;
306
+      md5_uint32 D_save = D;
307
+
308
+      /* First round: using the given function, the context and a constant
309
+	 the next context is computed.  Because the algorithms processing
310
+	 unit is a 32-bit word and it is determined to work on words in
311
+	 little endian byte order we perhaps have to change the byte order
312
+	 before the computation.  To reduce the work for the next steps
313
+	 we store the swapped words in the array CORRECT_WORDS.  */
314
+
315
+#define OP(a, b, c, d, s, T)						\
316
+      do								\
317
+        {								\
318
+	  a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T;		\
319
+	  ++words;							\
320
+	  CYCLIC (a, s);						\
321
+	  a += b;							\
322
+        }								\
323
+      while (0)
324
+
325
+      /* It is unfortunate that C does not provide an operator for
326
+	 cyclic rotation.  Hope the C compiler is smart enough.  */
327
+#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
328
+
329
+      /* Before we start, one word to the strange constants.
330
+	 They are defined in RFC 1321 as
331
+
332
+	 T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
333
+       */
334
+
335
+      /* Round 1.  */
336
+      OP (A, B, C, D,  7, (md5_uint32) 0xd76aa478);
337
+      OP (D, A, B, C, 12, (md5_uint32) 0xe8c7b756);
338
+      OP (C, D, A, B, 17, (md5_uint32) 0x242070db);
339
+      OP (B, C, D, A, 22, (md5_uint32) 0xc1bdceee);
340
+      OP (A, B, C, D,  7, (md5_uint32) 0xf57c0faf);
341
+      OP (D, A, B, C, 12, (md5_uint32) 0x4787c62a);
342
+      OP (C, D, A, B, 17, (md5_uint32) 0xa8304613);
343
+      OP (B, C, D, A, 22, (md5_uint32) 0xfd469501);
344
+      OP (A, B, C, D,  7, (md5_uint32) 0x698098d8);
345
+      OP (D, A, B, C, 12, (md5_uint32) 0x8b44f7af);
346
+      OP (C, D, A, B, 17, (md5_uint32) 0xffff5bb1);
347
+      OP (B, C, D, A, 22, (md5_uint32) 0x895cd7be);
348
+      OP (A, B, C, D,  7, (md5_uint32) 0x6b901122);
349
+      OP (D, A, B, C, 12, (md5_uint32) 0xfd987193);
350
+      OP (C, D, A, B, 17, (md5_uint32) 0xa679438e);
351
+      OP (B, C, D, A, 22, (md5_uint32) 0x49b40821);
352
+
353
+      /* For the second to fourth round we have the possibly swapped words
354
+	 in CORRECT_WORDS.  Redefine the macro to take an additional first
355
+	 argument specifying the function to use.  */
356
+#undef OP
357
+#define OP(a, b, c, d, k, s, T)						\
358
+      do 								\
359
+	{								\
360
+	  a += FX (b, c, d) + correct_words[k] + T;			\
361
+	  CYCLIC (a, s);						\
362
+	  a += b;							\
363
+	}								\
364
+      while (0)
365
+
366
+#define FX(b, c, d) FG (b, c, d)
367
+
368
+      /* Round 2.  */
369
+      OP (A, B, C, D,  1,  5, (md5_uint32) 0xf61e2562);
370
+      OP (D, A, B, C,  6,  9, (md5_uint32) 0xc040b340);
371
+      OP (C, D, A, B, 11, 14, (md5_uint32) 0x265e5a51);
372
+      OP (B, C, D, A,  0, 20, (md5_uint32) 0xe9b6c7aa);
373
+      OP (A, B, C, D,  5,  5, (md5_uint32) 0xd62f105d);
374
+      OP (D, A, B, C, 10,  9, (md5_uint32) 0x02441453);
375
+      OP (C, D, A, B, 15, 14, (md5_uint32) 0xd8a1e681);
376
+      OP (B, C, D, A,  4, 20, (md5_uint32) 0xe7d3fbc8);
377
+      OP (A, B, C, D,  9,  5, (md5_uint32) 0x21e1cde6);
378
+      OP (D, A, B, C, 14,  9, (md5_uint32) 0xc33707d6);
379
+      OP (C, D, A, B,  3, 14, (md5_uint32) 0xf4d50d87);
380
+      OP (B, C, D, A,  8, 20, (md5_uint32) 0x455a14ed);
381
+      OP (A, B, C, D, 13,  5, (md5_uint32) 0xa9e3e905);
382
+      OP (D, A, B, C,  2,  9, (md5_uint32) 0xfcefa3f8);
383
+      OP (C, D, A, B,  7, 14, (md5_uint32) 0x676f02d9);
384
+      OP (B, C, D, A, 12, 20, (md5_uint32) 0x8d2a4c8a);
385
+
386
+#undef FX
387
+#define FX(b, c, d) FH (b, c, d)
388
+
389
+      /* Round 3.  */
390
+      OP (A, B, C, D,  5,  4, (md5_uint32) 0xfffa3942);
391
+      OP (D, A, B, C,  8, 11, (md5_uint32) 0x8771f681);
392
+      OP (C, D, A, B, 11, 16, (md5_uint32) 0x6d9d6122);
393
+      OP (B, C, D, A, 14, 23, (md5_uint32) 0xfde5380c);
394
+      OP (A, B, C, D,  1,  4, (md5_uint32) 0xa4beea44);
395
+      OP (D, A, B, C,  4, 11, (md5_uint32) 0x4bdecfa9);
396
+      OP (C, D, A, B,  7, 16, (md5_uint32) 0xf6bb4b60);
397
+      OP (B, C, D, A, 10, 23, (md5_uint32) 0xbebfbc70);
398
+      OP (A, B, C, D, 13,  4, (md5_uint32) 0x289b7ec6);
399
+      OP (D, A, B, C,  0, 11, (md5_uint32) 0xeaa127fa);
400
+      OP (C, D, A, B,  3, 16, (md5_uint32) 0xd4ef3085);
401
+      OP (B, C, D, A,  6, 23, (md5_uint32) 0x04881d05);
402
+      OP (A, B, C, D,  9,  4, (md5_uint32) 0xd9d4d039);
403
+      OP (D, A, B, C, 12, 11, (md5_uint32) 0xe6db99e5);
404
+      OP (C, D, A, B, 15, 16, (md5_uint32) 0x1fa27cf8);
405
+      OP (B, C, D, A,  2, 23, (md5_uint32) 0xc4ac5665);
406
+
407
+#undef FX
408
+#define FX(b, c, d) FI (b, c, d)
409
+
410
+      /* Round 4.  */
411
+      OP (A, B, C, D,  0,  6, (md5_uint32) 0xf4292244);
412
+      OP (D, A, B, C,  7, 10, (md5_uint32) 0x432aff97);
413
+      OP (C, D, A, B, 14, 15, (md5_uint32) 0xab9423a7);
414
+      OP (B, C, D, A,  5, 21, (md5_uint32) 0xfc93a039);
415
+      OP (A, B, C, D, 12,  6, (md5_uint32) 0x655b59c3);
416
+      OP (D, A, B, C,  3, 10, (md5_uint32) 0x8f0ccc92);
417
+      OP (C, D, A, B, 10, 15, (md5_uint32) 0xffeff47d);
418
+      OP (B, C, D, A,  1, 21, (md5_uint32) 0x85845dd1);
419
+      OP (A, B, C, D,  8,  6, (md5_uint32) 0x6fa87e4f);
420
+      OP (D, A, B, C, 15, 10, (md5_uint32) 0xfe2ce6e0);
421
+      OP (C, D, A, B,  6, 15, (md5_uint32) 0xa3014314);
422
+      OP (B, C, D, A, 13, 21, (md5_uint32) 0x4e0811a1);
423
+      OP (A, B, C, D,  4,  6, (md5_uint32) 0xf7537e82);
424
+      OP (D, A, B, C, 11, 10, (md5_uint32) 0xbd3af235);
425
+      OP (C, D, A, B,  2, 15, (md5_uint32) 0x2ad7d2bb);
426
+      OP (B, C, D, A,  9, 21, (md5_uint32) 0xeb86d391);
427
+
428
+      /* Add the starting values of the context.  */
429
+      A += A_save;
430
+      B += B_save;
431
+      C += C_save;
432
+      D += D_save;
433
+    }
434
+
435
+  /* Put checksum in context given as argument.  */
436
+  ctx->A = A;
437
+  ctx->B = B;
438
+  ctx->C = C;
439
+  ctx->D = D;
440
+}

+ 154
- 0
md5.h View File

@@ -0,0 +1,154 @@
1
+/* md5.h - Declaration of functions and data types used for MD5 sum
2
+   computing library functions.
3
+   Copyright (C) 1995-2017 Free Software Foundation, Inc.
4
+   NOTE: The canonical source of this file is maintained with the GNU C
5
+   Library.  Bugs can be reported to bug-glibc@prep.ai.mit.edu.
6
+
7
+   This program is free software; you can redistribute it and/or modify it
8
+   under the terms of the GNU General Public License as published by the
9
+   Free Software Foundation; either version 2, or (at your option) any
10
+   later version.
11
+
12
+   This program is distributed in the hope that it will be useful,
13
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
+   GNU General Public License for more details.
16
+
17
+   You should have received a copy of the GNU General Public License
18
+   along with this program; if not, write to the Free Software Foundation,
19
+   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
20
+
21
+#ifndef _MD5_H
22
+#define _MD5_H 1
23
+
24
+#include <stdio.h>
25
+
26
+#if defined HAVE_LIMITS_H || _LIBC
27
+# include <limits.h>
28
+#endif
29
+
30
+#include "ansidecl.h"
31
+
32
+/* The following contortions are an attempt to use the C preprocessor
33
+   to determine an unsigned integral type that is 32 bits wide.  An
34
+   alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
35
+   doing that would require that the configure script compile and *run*
36
+   the resulting executable.  Locally running cross-compiled executables
37
+   is usually not possible.  */
38
+
39
+#ifdef _LIBC
40
+# include <sys/types.h>
41
+typedef u_int32_t md5_uint32;
42
+typedef uintptr_t md5_uintptr;
43
+#elif defined (HAVE_SYS_TYPES_H) && defined (HAVE_STDINT_H)
44
+#include <stdint.h>
45
+#include <sys/types.h>
46
+typedef uint32_t md5_uint32;
47
+typedef uintptr_t md5_uintptr;
48
+#else
49
+#  define INT_MAX_32_BITS 2147483647
50
+
51
+/* If UINT_MAX isn't defined, assume it's a 32-bit type.
52
+   This should be valid for all systems GNU cares about because
53
+   that doesn't include 16-bit systems, and only modern systems
54
+   (that certainly have <limits.h>) have 64+-bit integral types.  */
55
+
56
+# ifndef INT_MAX
57
+#  define INT_MAX INT_MAX_32_BITS
58
+# endif
59
+
60
+# if INT_MAX == INT_MAX_32_BITS
61
+   typedef unsigned int md5_uint32;
62
+# else
63
+#  if SHRT_MAX == INT_MAX_32_BITS
64
+    typedef unsigned short md5_uint32;
65
+#  else
66
+#   if LONG_MAX == INT_MAX_32_BITS
67
+     typedef unsigned long md5_uint32;
68
+#   else
69
+     /* The following line is intended to evoke an error.
70
+        Using #error is not portable enough.  */
71
+     "Cannot determine unsigned 32-bit data type."
72
+#   endif
73
+#  endif
74
+# endif
75
+/* We have to make a guess about the integer type equivalent in size
76
+   to pointers which should always be correct.  */
77
+typedef unsigned long int md5_uintptr;
78
+#endif
79
+
80
+#ifdef __cplusplus
81
+extern "C" {
82
+#endif
83
+
84
+/* Structure to save state of computation between the single steps.  */
85
+struct md5_ctx
86
+{
87
+  md5_uint32 A;
88
+  md5_uint32 B;
89
+  md5_uint32 C;
90
+  md5_uint32 D;
91
+
92
+  md5_uint32 total[2];
93
+  md5_uint32 buflen;
94
+  char buffer[128] ATTRIBUTE_ALIGNED_ALIGNOF(md5_uint32);
95
+};
96
+
97
+/*
98
+ * The following three functions are build up the low level used in
99
+ * the functions `md5_stream' and `md5_buffer'.
100
+ */
101
+
102
+/* Initialize structure containing state of computation.
103
+   (RFC 1321, 3.3: Step 3)  */
104
+extern void md5_init_ctx (struct md5_ctx *ctx);
105
+
106
+/* Starting with the result of former calls of this function (or the
107
+   initialization function update the context for the next LEN bytes
108
+   starting at BUFFER.
109
+   It is necessary that LEN is a multiple of 64!!! */
110
+extern void md5_process_block (const void *buffer, size_t len,
111
+                               struct md5_ctx *ctx);
112
+
113
+/* Starting with the result of former calls of this function (or the
114
+   initialization function update the context for the next LEN bytes
115
+   starting at BUFFER.
116
+   It is NOT required that LEN is a multiple of 64.  */
117
+extern void md5_process_bytes (const void *buffer, size_t len,
118
+                               struct md5_ctx *ctx);
119
+
120
+/* Process the remaining bytes in the buffer and put result from CTX
121
+   in first 16 bytes following RESBUF.  The result is always in little
122
+   endian byte order, so that a byte-wise output yields to the wanted
123
+   ASCII representation of the message digest.
124
+
125
+   IMPORTANT: On some systems it is required that RESBUF is correctly
126
+   aligned for a 32 bits value.  */
127
+extern void *md5_finish_ctx (struct md5_ctx *ctx, void *resbuf);
128
+
129
+
130
+/* Put result from CTX in first 16 bytes following RESBUF.  The result is
131
+   always in little endian byte order, so that a byte-wise output yields
132
+   to the wanted ASCII representation of the message digest.
133
+
134
+   IMPORTANT: On some systems it is required that RESBUF is correctly
135
+   aligned for a 32 bits value.  */
136
+extern void *md5_read_ctx (const struct md5_ctx *ctx, void *resbuf);
137
+
138
+
139
+/* Compute MD5 message digest for bytes read from STREAM.  The
140
+   resulting message digest number will be written into the 16 bytes
141
+   beginning at RESBLOCK.  */
142
+extern int md5_stream (FILE *stream, void *resblock);
143
+
144
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
145
+   result is always in little endian byte order, so that a byte-wise
146
+   output yields to the wanted ASCII representation of the message
147
+   digest.  */
148
+extern void *md5_buffer (const char *buffer, size_t len, void *resblock);
149
+
150
+#ifdef __cplusplus
151
+}
152
+#endif
153
+
154
+#endif

+ 396
- 0
okim6258.c View File

@@ -0,0 +1,396 @@
1
+/**********************************************************************************************
2
+ *
3
+ *   OKI MSM6258 ADPCM
4
+ *
5
+ *   TODO:
6
+ *   3-bit ADPCM support
7
+ *   Recording?
8
+ *
9
+ **********************************************************************************************/
10
+
11
+#include <stddef.h>	// for NULL
12
+#include "mamedef.h"
13
+
14
+#ifdef _DEBUG
15
+#include <stdio.h>
16
+#endif
17
+
18
+#include <math.h>
19
+#include "okim6258.h"
20
+
21
+#define COMMAND_STOP		(1 << 0)
22
+#define COMMAND_PLAY		(1 << 1)
23
+#define	COMMAND_RECORD		(1 << 2)
24
+
25
+#define STATUS_PLAYING		(1 << 1)
26
+#define STATUS_RECORDING	(1 << 2)
27
+
28
+static const int dividers[4] = { 1024, 768, 512, 512 };
29
+
30
+#define QUEUE_SIZE	(1 << 1)
31
+#define QUEUE_MASK	(QUEUE_SIZE - 1)
32
+
33
+/* step size index shift table */
34
+static const int index_shift[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
35
+
36
+/* lookup table for the precomputed difference */
37
+static int diff_lookup[49*16];
38
+
39
+/* tables computed? */
40
+static int tables_computed = 0;
41
+
42
+/**********************************************************************************************
43
+
44
+     compute_tables -- compute the difference tables
45
+
46
+***********************************************************************************************/
47
+
48
+static void compute_tables(void) {
49
+	if (tables_computed)
50
+		return;
51
+
52
+	/* nibble to bit map */
53
+	static const int nbl2bit[16][4] = {
54
+		{ 1, 0, 0, 0}, { 1, 0, 0, 1}, { 1, 0, 1, 0}, { 1, 0, 1, 1},
55
+		{ 1, 1, 0, 0}, { 1, 1, 0, 1}, { 1, 1, 1, 0}, { 1, 1, 1, 1},
56
+		{-1, 0, 0, 0}, {-1, 0, 0, 1}, {-1, 0, 1, 0}, {-1, 0, 1, 1},
57
+		{-1, 1, 0, 0}, {-1, 1, 0, 1}, {-1, 1, 1, 0}, {-1, 1, 1, 1}
58
+	};
59
+
60
+	int step, nib;
61
+
62
+	/* loop over all possible steps */
63
+	for (step = 0; step <= 48; step++) {
64
+		/* compute the step value */
65
+		int stepval = floor(16.0 * pow(11.0 / 10.0, (double)step));
66
+
67
+		/* loop over all nibbles and compute the difference */
68
+		for (nib = 0; nib < 16; nib++) {
69
+			diff_lookup[step*16 + nib] = nbl2bit[nib][0] *
70
+				(stepval   * nbl2bit[nib][1] +
71
+				 stepval/2 * nbl2bit[nib][2] +
72
+				 stepval/4 * nbl2bit[nib][3] +
73
+				 stepval/8);
74
+		}
75
+	}
76
+
77
+	tables_computed = 1;
78
+}
79
+
80
+
81
+static int16_t clock_adpcm(struct okim6258 *chip, uint8_t nibble) {
82
+	int32_t max = chip->output_mask - 1;
83
+	int32_t min = -chip->output_mask;
84
+
85
+	// original MAME algorithm (causes a DC offset over time)
86
+	//chip->signal += diff_lookup[chip->step * 16 + (nibble & 15)];
87
+
88
+	// awesome algorithm ported from XM6 - it works PERFECTLY
89
+	int sample = diff_lookup[chip->step * 16 + (nibble & 15)];
90
+	chip->signal = ((sample << 8) + (chip->signal * 245)) >> 8;
91
+
92
+	/* clamp to the maximum */
93
+	if (chip->signal > max)
94
+		chip->signal = max;
95
+	else if (chip->signal < min)
96
+		chip->signal = min;
97
+
98
+	/* adjust the step size and clamp */
99
+	chip->step += index_shift[nibble & 7];
100
+	if (chip->step > 48)
101
+		chip->step = 48;
102
+	else if (chip->step < 0)
103
+		chip->step = 0;
104
+
105
+	/* return the signal scaled up to 32767 */
106
+	return chip->signal << 4;
107
+}
108
+
109
+/**********************************************************************************************
110
+
111
+     okim6258_update -- update the sound chip so that it is in sync with CPU execution
112
+
113
+***********************************************************************************************/
114
+void okim6258_update(struct okim6258 *chip, stream_sample_t **outputs, int samples) {
115
+	stream_sample_t *bufL = outputs[0];
116
+	stream_sample_t *bufR = outputs[1];
117
+
118
+	if (chip->status & STATUS_PLAYING) {
119
+		int nibble_shift = chip->nibble_shift;
120
+
121
+		while (samples) {
122
+			/* Compute the new amplitude and update the current step */
123
+			//int nibble = (chip->data_in >> nibble_shift) & 0xf;
124
+			int nibble;
125
+			int16_t sample;
126
+
127
+			if (! nibble_shift) {
128
+				// 1st nibble - get data
129
+				if (! chip->data_empty) {
130
+					chip->data_in = chip->data_buf[chip->data_buf_pos >> 4];
131
+					chip->data_buf_pos += 0x10;
132
+					chip->data_buf_pos &= 0x7F;
133
+					if ((chip->data_buf_pos >> 4) == (chip->data_buf_pos & 0x0F))
134
+						chip->data_empty ++;
135
+				} else {
136
+					//chip->data_in = chip->data_in_last;
137
+					if (chip->data_empty < 0x80)
138
+						chip->data_empty ++;
139
+				}
140
+			}
141
+			nibble = (chip->data_in >> nibble_shift) & 0xf;
142
+
143
+			/* Output to the buffer */
144
+			//int16_t sample = clock_adpcm(chip, nibble);
145
+			if (chip->data_empty < 0x02) {
146
+				sample = clock_adpcm(chip, nibble);
147
+				chip->last_smpl = sample;
148
+			} else {
149
+				// Valley Bell: data_empty behaviour (loosely) ported from XM6
150
+				if (chip->data_empty >= 0x02 + 0x01) {
151
+					chip->data_empty -= 0x01;
152
+					chip->signal = chip->signal * 15 / 16;
153
+					chip->last_smpl = chip->signal << 4;
154
+				}
155
+				sample = chip->last_smpl;
156
+			}
157
+
158
+			nibble_shift ^= 4;
159
+
160
+			*bufL++ = (chip->pan & 0x02) ? 0x00 : sample;
161
+			*bufR++ = (chip->pan & 0x01) ? 0x00 : sample;
162
+			samples--;
163
+		}
164
+
165
+		/* Update the parameters */
166
+		chip->nibble_shift = nibble_shift;
167
+	} else {
168
+		/* Fill with 0 */
169
+		while (samples--) {
170
+			//*buffer++ = 0;
171
+			*bufL++ = 0;
172
+			*bufR++ = 0;
173
+		}
174
+	}
175
+}
176
+
177
+/**********************************************************************************************
178
+
179
+     OKIM6258_start -- start emulation of an OKIM6258-compatible chip
180
+
181
+***********************************************************************************************/
182
+static int get_vclk(struct okim6258 *chip) {
183
+	int clk_rnd;
184
+
185
+	clk_rnd = chip->master_clock;
186
+	clk_rnd += chip->divider / 2;	 // for better rounding - should help some of the streams
187
+
188
+	return clk_rnd / chip->divider;
189
+}
190
+
191
+int okim6258_init(struct okim6258 *chip, int clock, int divider, int adpcm_type, int output_12bits) {
192
+	compute_tables();
193
+
194
+	chip->initial_clock = clock;
195
+	chip->initial_div = divider;
196
+	chip->master_clock = clock;
197
+	chip->adpcm_type = /*intf->*/adpcm_type;
198
+	chip->clock_buffer[0x00] = (clock & 0x000000FF) >>  0;
199
+	chip->clock_buffer[0x01] = (clock & 0x0000FF00) >>  8;
200
+	chip->clock_buffer[0x02] = (clock & 0x00FF0000) >> 16;
201
+	chip->clock_buffer[0x03] = (clock & 0xFF000000) >> 24;
202
+	chip->SmpRateFunc = NULL;
203
+
204
+	/* D/A precision is 10-bits but 12-bit data can be output serially to an external DAC */
205
+	chip->output_bits = output_12bits ? 12 : 10;
206
+	chip->internal_10_bit = 0;
207
+	if (chip->internal_10_bit)
208
+		chip->output_mask = (1 << (chip->output_bits - 1));
209
+	else
210
+		chip->output_mask = (1 << (12 - 1));
211
+	chip->divider = dividers[divider];
212
+
213
+	chip->signal = -2;
214
+	chip->step = 0;
215
+
216
+	return get_vclk(chip);
217
+}
218
+
219
+
220
+/**********************************************************************************************
221
+
222
+     OKIM6258_stop -- stop emulation of an OKIM6258-compatible chip
223
+
224
+***********************************************************************************************/
225
+
226
+void okim6258_stop(struct okim6258 *chip) {
227
+}
228
+
229
+void okim6258_reset(struct okim6258 *chip) {
230
+	chip->master_clock = chip->initial_clock;
231
+	chip->clock_buffer[0x00] = (chip->initial_clock & 0x000000FF) >>  0;
232
+	chip->clock_buffer[0x01] = (chip->initial_clock & 0x0000FF00) >>  8;
233
+	chip->clock_buffer[0x02] = (chip->initial_clock & 0x00FF0000) >> 16;
234
+	chip->clock_buffer[0x03] = (chip->initial_clock & 0xFF000000) >> 24;
235
+	chip->divider = dividers[chip->initial_div];
236
+	if (chip->SmpRateFunc != NULL)
237
+		chip->SmpRateFunc(chip->SmpRateData, get_vclk(chip));
238
+
239
+	chip->signal = -2;
240
+	chip->step = 0;
241
+	chip->status = 0;
242
+
243
+	// Valley Bell: Added reset of the Data In register.
244
+	chip->data_in = 0x00;
245
+	chip->data_buf[0] = chip->data_buf[1] = 0x00;
246
+	chip->data_buf_pos = 0x00;
247
+	chip->data_empty = 0xFF;
248
+	chip->pan = 0x00;
249
+}
250
+
251
+/**********************************************************************************************
252
+
253
+     okim6258_set_divider -- set the master clock divider
254
+
255
+***********************************************************************************************/
256
+void okim6258_set_divider(struct okim6258 *chip, int val) {
257
+	chip->divider = dividers[val];
258
+
259
+	if (chip->SmpRateFunc != NULL)
260
+		chip->SmpRateFunc(chip->SmpRateData, get_vclk(chip));
261
+}
262
+
263
+
264
+/**********************************************************************************************
265
+
266
+     okim6258_set_clock -- set the master clock
267
+
268
+***********************************************************************************************/
269
+void okim6258_set_clock(struct okim6258 *chip, int val) {
270
+	if (val) {
271
+		chip->master_clock = val;
272
+	} else {
273
+		chip->master_clock =	(chip->clock_buffer[0x00] <<  0) |
274
+								(chip->clock_buffer[0x01] <<  8) |
275
+								(chip->clock_buffer[0x02] << 16) |
276
+								(chip->clock_buffer[0x03] << 24);
277
+	}
278
+
279
+	if (chip->SmpRateFunc != NULL)
280
+		chip->SmpRateFunc(chip->SmpRateData, get_vclk(chip));
281
+}
282
+
283
+
284
+/**********************************************************************************************
285
+
286
+     okim6258_get_vclk -- get the VCLK/sampling frequency
287
+
288
+***********************************************************************************************/
289
+int okim6258_get_vclk(struct okim6258 *chip) {
290
+	return get_vclk(chip);
291
+}
292
+
293
+
294
+/**********************************************************************************************
295
+
296
+     okim6258_data_w -- write to the control port of an OKIM6258-compatible chip
297
+
298
+***********************************************************************************************/
299
+static void okim6258_data_w(struct okim6258 *chip, uint8_t data) {
300
+	if (chip->data_empty >= 0x02)
301
+		chip->data_buf_pos = 0x00;
302
+	chip->data_in_last = data;
303
+	chip->data_buf[chip->data_buf_pos & 0x0F] = data;
304
+	chip->data_buf_pos += 0x01;
305
+	chip->data_buf_pos &= 0xF7;
306
+	if ((chip->data_buf_pos >> 4) == (chip->data_buf_pos & 0x0F)) {
307
+		//fprintf(stderr, "Warning: FIFO full!\n");
308
+		chip->data_buf_pos = (chip->data_buf_pos & 0xF0) | ((chip->data_buf_pos-1) & 0x07);
309
+	}
310
+	chip->data_empty = 0x00;
311
+}
312
+
313
+
314
+/**********************************************************************************************
315
+
316
+     okim6258_ctrl_w -- write to the control port of an OKIM6258-compatible chip
317
+
318
+***********************************************************************************************/
319
+static void okim6258_ctrl_w(struct okim6258 *chip, uint8_t data) {
320
+	if (data & COMMAND_STOP) {
321
+		chip->status &= ~(STATUS_PLAYING | STATUS_RECORDING);
322
+		return;
323
+	}
324
+
325
+	if (data & COMMAND_PLAY) {
326
+		if (!(chip->status & STATUS_PLAYING)) {
327
+			chip->status |= STATUS_PLAYING;
328
+
329
+			/* Also reset the ADPCM parameters */
330
+			chip->signal = -2;	// Note: XM6 lets this fade to 0 when nothing is going on
331
+			chip->step = 0;
332
+			chip->nibble_shift = 0;
333
+
334
+			chip->data_buf[0x00] = data;
335
+			chip->data_buf_pos = 0x01;	// write pos 01, read pos 00
336
+			chip->data_empty = 0x00;
337
+		}
338
+		chip->step = 0;	// this line was verified with the source of XM6
339
+		chip->nibble_shift = 0;
340
+	} else {
341
+		chip->status &= ~STATUS_PLAYING;
342
+	}
343
+
344
+	if(data & COMMAND_RECORD) {
345
+		// logerror("M6258: Record enabled\n");
346
+		chip->status |= STATUS_RECORDING;
347
+	} else {
348
+		chip->status &= ~STATUS_RECORDING;
349
+	}
350
+}
351
+
352
+static void okim6258_set_clock_byte(struct okim6258 *chip, uint8_t Byte, uint8_t val) {
353
+	chip->clock_buffer[Byte] = val;
354
+}
355
+
356
+static void okim6258_pan_w(struct okim6258 *chip, uint8_t data) {
357
+	chip->pan = data;
358
+}
359
+
360
+
361
+void okim6258_write(struct okim6258 *chip, uint8_t Port, uint8_t Data) {
362
+	switch(Port) {
363
+	case 0x00:
364
+		okim6258_ctrl_w(chip, /*0x00, */Data);
365
+		break;
366
+	case 0x01:
367
+		okim6258_data_w(chip, /*0x00, */Data);
368
+		break;
369
+	case 0x02:
370
+		okim6258_pan_w(chip, Data);
371
+		break;
372
+	case 0x08:
373
+	case 0x09:
374
+	case 0x0A:
375
+		okim6258_set_clock_byte(chip, Port & 0x03, Data);
376
+		break;
377
+	case 0x0B:
378
+		okim6258_set_clock_byte(chip, Port & 0x03, Data);
379
+		okim6258_set_clock(chip, 0);
380
+		break;
381
+	case 0x0C:
382
+		okim6258_set_divider(chip, Data);
383
+		break;
384
+	}
385
+}
386
+
387
+
388
+void okim6258_set_options(struct okim6258 *chip, uint16_t options) {
389
+	chip->internal_10_bit = (options >> 0) & 0x01;
390
+}
391
+
392
+void okim6258_set_srchg_cb(struct okim6258 *chip, SRATE_CALLBACK CallbackFunc, void* DataPtr) {
393
+	// set Sample Rate Change Callback routine
394
+	chip->SmpRateFunc = CallbackFunc;
395
+	chip->SmpRateData = DataPtr;
396
+}

+ 66
- 0
okim6258.h View File

@@ -0,0 +1,66 @@
1
+#pragma once
2
+
3
+#include <stdint.h>
4
+#include "mamedef.h"
5
+
6
+struct okim6258 {
7
+	uint8_t status;
8
+
9
+	uint32_t master_clock;      /* master clock frequency */
10
+	uint32_t divider;           /* master clock divider */
11
+	uint8_t adpcm_type;         /* 3/4 bit ADPCM select */
12
+	uint8_t data_in;            /* ADPCM data-in register */
13
+	uint8_t nibble_shift;       /* nibble select */
14
+
15
+	uint8_t output_bits, internal_10_bit;
16
+	int32_t output_mask;
17
+
18
+	// Valley Bell: Added a small queue to prevent race conditions.
19
+	uint8_t data_buf[8];
20
+	uint8_t data_in_last;
21
+	uint8_t data_buf_pos;
22
+	// Data Empty Values:
23
+	//  00 - data written, but not read yet
24
+	//  01 - read data, waiting for next write
25
+	//  02 - tried to read, but had no data
26
+	uint8_t data_empty;
27
+	// Valley Bell: Added pan
28
+	uint8_t pan;
29
+	int32_t last_smpl;
30
+
31
+	int32_t signal;
32
+	int32_t step;
33
+
34
+	uint8_t clock_buffer[0x04];
35
+	uint32_t initial_clock;
36
+	uint8_t initial_div;
37
+
38
+	SRATE_CALLBACK SmpRateFunc;
39
+	void* SmpRateData;
40
+};
41
+
42
+#define FOSC_DIV_BY_1024    0
43
+#define FOSC_DIV_BY_768     1
44
+#define FOSC_DIV_BY_512     2
45
+
46
+#define TYPE_3BITS          0
47
+#define TYPE_4BITS          1
48
+
49
+#define OUTPUT_10BITS       0
50
+#define OUTPUT_12BITS       1
51
+
52
+int okim6258_init(struct okim6258 *chip, int clock, int divider, int adpcm_type, int output_12bits);
53
+
54
+void okim6258_stop(struct okim6258 *chip);
55
+void okim6258_reset(struct okim6258 *chip);
56
+
57
+void okim6258_set_divider(struct okim6258 *chip, int val);
58
+void okim6258_set_clock(struct okim6258 *chip, int val);
59
+int okim6258_get_vclk(struct okim6258 *chip);
60
+
61
+void okim6258_update(struct okim6258 *chip, stream_sample_t **outputs, int samples);
62
+
63
+void okim6258_write(struct okim6258 *chip, uint8_t Port, uint8_t Data);
64
+
65
+void okim6258_set_options(struct okim6258 *chip, uint16_t options);
66
+void okim6258_set_srchg_cb(struct okim6258 *chip, SRATE_CALLBACK CallbackFunc, void* DataPtr);

+ 259
- 0
sjis.c View File

@@ -0,0 +1,259 @@
1
+#include <stdio.h>
2
+
3
+#include "sjis.h"
4
+
5
+int sjis_strlen(uint8_t *data, int len) {
6
+	int l = 0;
7
+	for(int i = 0; i < len; i++) {
8
+		l++;
9
+		if(data[i] >= 0x80) {
10
+			l++;
11
+			i++;
12
+		}
13
+	}
14
+	return l;
15
+}
16
+
17
+int sjis_to_utf8(uint8_t *sjis_data, int sjis_len, uint8_t *utf8_data, int utf8_len) {
18
+	if(sjis_len < 1) return 0;
19
+	if(utf8_len < 1) return -1;
20
+
21
+	int j = 0;
22
+	for(int i = 0; i < sjis_len; i++) {
23
+		uint32_t c;
24
+		if((sjis_data[i] >= 0x80 && sjis_data[i] <= 0xa0) || (sjis_data[i] >= 0xe0 && sjis_data[i] <= 0xff)) {
25
+			if(sjis_len - i < 2)
26
+				return -1;
27
+			c = sjis_char_to_unicode((sjis_data[i] << 8) | sjis_data[i+1]);
28
+			i++;
29
+		} else if(sjis_data[i] < 0x20) {
30
+			c = sjis_data[i];
31
+		} else {
32
+			c = sjis_char_to_unicode(sjis_data[i]);
33
+		}
34
+
35
+		if(c < 0x80) {
36
+			if(utf8_len - j < 1)
37
+				return j;
38
+			utf8_data[j++] = c;
39
+		} else if(c < 0x800) {
40
+			if(utf8_len - j < 2)
41
+				return j;
42
+			utf8_data[j++] = 192 + c / 64;
43
+			utf8_data[j++] = 128 + c % 64;
44
+		} else if(c - 0xd800u < 0x800) {
45
+			return j;
46
+		} else if(c < 0x10000) {
47
+			if(utf8_len - j < 3)
48
+				return j;
49
+			utf8_data[j++] = 224 + c / 4096;
50
+			utf8_data[j++] = 128 + c / 64 % 64;
51
+			utf8_data[j++] = 128 + c % 64;
52
+		} else if (c<0x110000) {
53
+			if(utf8_len - j < 4)
54
+				return j;
55
+			utf8_data[j++] = 240+c/262144;
56
+			utf8_data[j++] = 128+c/4096%64;
57
+			utf8_data[j++] = 128+c/64%64;
58
+			utf8_data[j++] = 128+c%64;
59
+		} else return j;
60
+	}
61
+	return j;
62
+}
63
+
64
+static void put_escaped(uint8_t c) {
65
+	switch(c) {
66
+		case 0:
67
+			putchar('\\');
68
+			putchar('0');
69
+			break;
70
+		case '\b':
71
+			putchar('\\');
72
+			putchar('b');
73
+			break;
74
+		// case '\r':
75
+		// 	putchar('\\');
76
+		// 	putchar('r');
77
+		// 	break;
78
+		// case '\n':
79
+		// 	putchar('\\');
80
+		// 	putchar('n');
81
+		// 	break;
82
+		case '\t':
83
+			putchar('\\');
84
+			putchar('\t');
85
+			break;
86
+		case '\\':
87
+			putchar('\\');
88
+			putchar('\\');
89
+			break;
90
+		default:
91
+			printf("\\0%02o", c);
92
+	}
93
+}
94
+
95
+int sjis_print_utf8(uint8_t *sjis_data, int sjis_len) {
96
+	return sjis_write_utf8(stdout, sjis_data, sjis_len);
97
+}
98
+
99
+int sjis_write_utf8(FILE *f, uint8_t *sjis_data, int sjis_len) {
100
+	if(sjis_len < 1) return 0;
101
+
102
+	int j = 0;
103
+	for(int i = 0; i < sjis_len; i++) {
104
+		uint32_t c;
105
+		if(sjis_data[i] >= 0xf0 && sjis_data[i] <= 0xf3) {
106
+			continue;
107
+		} else if((sjis_data[i] >= 0x80 && sjis_data[i] <= 0xa0) || (sjis_data[i] >= 0xe0 && sjis_data[i] <= 0xef)) {
108
+			if(sjis_len - i < 2)
109
+				return -1;
110
+			c = sjis_char_to_unicode((sjis_data[i] << 8) | sjis_data[i+1]);
111
+			i++;
112
+		} else {
113
+			c = sjis_char_to_unicode(sjis_data[i]);
114
+		}
115
+
116
+		char buf[4];
117
+		if(c < 0x80) {
118
+			buf[0] = c;
119
+			fwrite(buf, 1, 1, f);
120
+		} else if(c < 0x800) {
121
+			buf[0] = 192 + c / 64;
122
+			buf[1] = 128 + c % 64;
123
+			fwrite(buf, 2, 1, f);
124
+		} else if(c - 0xd800u < 0x800) {
125
+		} else if(c < 0x10000) {
126
+			buf[0] = 224 + c / 4096;
127
+			buf[1] = 128 + c / 64 % 64;
128
+			buf[2] = 128 + c % 64;
129
+			fwrite(buf, 3, 1, f);
130
+		} else if (c<0x110000) {
131
+			buf[0] = 240+c/262144;
132
+			buf[1] = 128+c/4096%64;
133
+			buf[2] = 128+c/64%64;
134
+			buf[3] = 128+c%64;
135
+			fwrite(buf, 4, 1, f);
136
+		}
137
+	}
138
+	return j;
139
+}
140
+
141
+int sjis_print_utf8_escaped(uint8_t *sjis_data, int sjis_len) {
142
+	if(sjis_len < 1) return 0;
143
+
144
+	int j = 0;
145
+	for(int i = 0; i < sjis_len; i++) {
146
+		uint32_t c;
147
+		if(sjis_data[i] >= 0xf0 && sjis_data[i] <= 0xf3) {
148
+			continue;
149
+		} else if((sjis_data[i] >= 0x80 && sjis_data[i] <= 0xa0) || (sjis_data[i] >= 0xe0 && sjis_data[i] <= 0xef)) {
150
+			if(sjis_len - i < 2)
151
+				return -1;
152
+			c = sjis_char_to_unicode((sjis_data[i] << 8) | sjis_data[i+1]);
153
+			i++;
154
+		} else if(sjis_data[i] == '"') {
155
+			putchar('\\');
156
+			putchar('"');
157
+		} else if(sjis_data[i] < 0x20) {
158
+			put_escaped(sjis_data[i]);
159
+			continue;
160
+		} else {
161
+			c = sjis_char_to_unicode(sjis_data[i]);
162
+		}
163
+
164
+		if(c < 0x80) {
165
+			putchar(c);
166
+		} else if(c < 0x800) {
167
+			putchar(192 + c / 64);
168
+			putchar(128 + c % 64);
169
+		} else if(c - 0xd800u < 0x800) {
170
+		} else if(c < 0x10000) {
171
+			putchar(224 + c / 4096);
172
+			putchar(128 + c / 64 % 64);
173
+			putchar(128 + c % 64);
174
+		} else if (c<0x110000) {
175
+			putchar(240+c/262144);
176
+			putchar(128+c/4096%64);
177
+			putchar(128+c/64%64);
178
+			putchar(128+c%64);
179
+		}
180
+	}
181
+	return j;
182
+}
183
+
184
+int sjis_print_escaped(uint8_t *sjis_data, int sjis_len) {
185
+	if(sjis_len < 1) return 0;
186
+
187
+	int j = 0;
188
+	for(int i = 0; i < sjis_len; i++) {
189
+		if(sjis_data[i] >= 0xf0 && sjis_data[i] <= 0xf3) {
190
+			putchar(sjis_data[i]);
191
+			continue;
192
+		} else if((sjis_data[i] >= 0x80 && sjis_data[i] <= 0xa0) || (sjis_data[i] >= 0xe0 && sjis_data[i] <= 0xef)) {
193
+			if(sjis_len - i < 2)
194
+				return -1;
195
+			putchar(sjis_data[i]);
196
+			putchar(sjis_data[i+1]);
197
+			i++;
198
+		} else if(sjis_data[i] < 0x20) {
199
+			put_escaped(sjis_data[i]);
200
+		} else {
201
+			if(sjis_data[i] == '"')
202
+				putchar('\\');
203
+			putchar(sjis_data[i]);
204
+		}
205
+	}
206
+	return j;
207
+}
208
+
209
+uint16_t jis_to_sjis(uint16_t val) {
210
+	uint8_t j2 = val & 0xff;
211
+	uint8_t j1 = val >> 8;
212
+	uint8_t s1, s2;
213
+	if(33 <= j1 && j1 <= 94)
214
+		s1 = (j1 + 1) / 2 + 112;
215
+	else
216
+		s1 = (j1 + 1) / 2 + 176;
217
+	if(j1 & 1)
218
+		s2 = j2 + 31 + (j2 / 96);
219
+	else
220
+		s2 = j2 + 126;
221
+
222
+	return (s1 << 8) | s2;
223
+}
224
+
225
+uint16_t jis_from_sjis(uint16_t val) {
226
+	int status = 0;
227
+	uint8_t j1 = 0;
228
+	uint8_t j2 = 0;
229
+	uint8_t b1 = val >> 8;
230
+	uint8_t b2 = val & 0xff;
231
+	if((b1 >= 0x81 && b1 <= 0x84) || (b1 >= 0x87 && b1 <= 0x9f)) {
232
+		j1 = 2 * (b1 - 0x70) - 1;
233
+		if (b2 >= 0x40 && b2 <= 0x9e) {
234
+			j2 = b2 - 31;
235
+			if (j2 > 95)
236
+				j2 -= 1;
237
+			status = 1;
238
+		} else if (b2 >= 0x9f && b2 <= 0xfc) {
239
+			j2 = b2 - 126;
240
+			j1 += 1;
241
+			status = 1;
242
+		}
243
+	} else if (b1 >= 0xe0 && b1 <= 0xef) {
244
+		j1 = 2 * (b1 - 0xb0) - 1;
245
+		if (b2 >= 0x40 && b2 <= 0x9e) {
246
+			j2 = b2 - 31;
247
+			if (j2 > 95)
248
+				j2 -= 1;
249
+			status = 1;
250
+		} else if (b2 >= 0x9f && b2 <= 0xfc) {
251
+			j2 = b2 - 126;
252
+			j1 += 1;
253
+			status = 1;
254
+		}
255
+	}
256
+
257
+	if(status == 0) return 0;
258
+	return (j1 << 8) | j2;
259
+}

+ 19
- 0
sjis.h View File

@@ -0,0 +1,19 @@
1
+#ifndef SJIS_H_
2
+#define SJIS_H_
3
+
4
+#include <stdio.h>
5
+#include <stdint.h>
6
+
7
+int sjis_strlen(uint8_t *data, int len);
8
+int sjis_to_utf8(uint8_t *sjis_data, int sjis_len, uint8_t *utf8_data, int utf8_len);
9
+int utf8_to_sjis(uint8_t *utf8_data, int utf8_len, uint8_t *sjis_data, int sjis_len);
10
+uint32_t sjis_char_to_unicode(uint16_t sjis);
11
+uint16_t unicode_char_to_sjis(uint32_t unicode);
12
+
13
+int sjis_print_utf8_escaped(uint8_t *sjis_data, int sjis_len);
14
+int sjis_write_utf8(FILE *f, uint8_t *sjis_data, int sjis_len);
15
+int sjis_print_utf8(uint8_t *sjis_data, int sjis_len);
16
+int sjis_print_escaped(uint8_t *sjis_data, int sjis_len);
17
+uint16_t jis_to_sjis(uint16_t val);
18
+
19
+#endif /* SJIS_H_ */

+ 4110
- 0
sjis_unicode.c
File diff suppressed because it is too large
View File


+ 96
- 0
sjisranges.php View File

@@ -0,0 +1,96 @@
1
+<?php
2
+
3
+$sjis = array();
4
+$unicode = array();
5
+
6
+$files = $argc < 2 ? array('sjis.txt') : array_slice($argv, 1);
7
+foreach($files as $file) {
8
+	$f = fopen($file, "r");
9
+	if(!$f) die("Could not open $sjisTxt");
10
+
11
+	while(!feof($f)) {
12
+		$line = fgets($f);
13
+		if(preg_match('#^0x(?<sjis>[0-9a-f]{2,4})\s+(0x|U\+)(?<unicode>[0-9a-f]{4,})#i', $line, $match)) {
14
+			$sjis[intval($match['sjis'], 16)] = intval($match['unicode'], 16);
15
+			$unicode[intval($match['unicode'], 16)] = intval($match['sjis'], 16);
16
+		}
17
+	}
18
+
19
+	fclose($f);
20
+}
21
+
22
+echo "#include <stdint.h>\n\n";
23
+
24
+generate_function($sjis, 'sjis', 'unicode');
25
+generate_function($unicode, 'unicode', 'sjis');
26
+
27
+function generate_function($data, $prefix, $to) {
28
+	ksort($data);
29
+
30
+	$ranges = array();
31
+
32
+	// fill small gaps
33
+	$prev = 0;
34
+	foreach($data as $code => $unicode) {
35
+		if($code - $prev > 1 && $code - $prev < 15) {
36
+			for($i = $prev+1; $i < $code; $i++)
37
+				$data[$i] = 0x55;
38
+		}
39
+		$prev = $code;
40
+	}
41
+
42
+	ksort($data);
43
+
44
+	$prev = 0;
45
+	$start = 0;
46
+	$data[99999999] = null; // force end condition for last range
47
+	$total = 0;
48
+	foreach($data as $code => $unicode) {
49
+		if($prev != $code-1) {
50
+			if($code > 0 && $prev > 0) {
51
+				$s = array_search(intval($start), array_keys($data));
52
+				$e = array_search(intval($prev), array_keys($data));
53
+				$l = $e - $s + 1;
54
+				$ranges[] = array(
55
+					'start' => $start,
56
+					'end' => $prev,
57
+					's' => $s,
58
+					'e' => $e,
59
+					'data' => array_slice($data, $s, $l),
60
+					'table_start' => $total,
61
+					'table_end' => $total + $l,
62
+				);
63
+				$total += $l;
64
+			}
65
+			$start = $code;
66
+		}
67
+		$prev = $code;
68
+	}
69
+
70
+	$src_width = $prefix == 'unicode' ? 32 : 16;
71
+	$dst_width = $prefix == 'unicode' ? 16 : 32;
72
+
73
+	echo "static uint{$dst_width}_t {$prefix}_table[] = {\n";
74
+
75
+	foreach($ranges as $range) {
76
+		printf("\t /* 0x%04x - 0x%04x */", $range['start'], $range['end']);
77
+		foreach($range['data'] as $k => $d) {
78
+			if($k % 8 == 0)
79
+				echo "\n\t";
80
+			else echo ' ';
81
+			printf('0x%04x,', $d);
82
+		}
83
+		echo "\n";
84
+	}
85
+	echo "};\n";
86
+
87
+	echo "uint{$dst_width}_t {$prefix}_char_to_$to(uint{$src_width}_t $prefix) {\n";
88
+	foreach($ranges as $k => $range) {
89
+		printf("\tif($prefix >= 0x%04x && $prefix <= 0x%04x)", $range['start'], $range['end']);
90
+		printf(" return {$prefix}_table[0x%04x + $prefix - 0x%04x];\n", $range['table_start'], $range['start']);
91
+	}
92
+	if($to == 'sjis')
93
+		echo "\treturn 0x81a6; // ※\n}\n";
94
+	else
95
+		echo "\treturn 0x203b; // ※\n}\n";
96
+}

+ 45
- 0
test-mem.c View File

@@ -0,0 +1,45 @@
1
+#include <stdio.h>
2
+#include "v68.h"
3
+#include "v68mem.h"
4
+
5
+int main(int argc, char **argv, char **envp) {
6
+
7
+	struct v68 v;
8
+	v68_init(16000000, 2 * 1024 * 1024, 44100);
9
+
10
+	v68_mem_dump();
11
+
12
+	uint32_t m1 = v68_mem_alloc(1024, 0);
13
+	printf("Allocated 1024B @0x%08x\n", m1);
14
+	v68_mem_dump();
15
+
16
+	uint32_t m2 = v68_mem_alloc(4096, 0);
17
+	printf("Allocated 4096B @0x%08x\n", m2);
18
+	v68_mem_dump();
19
+
20
+	uint32_t m3 = v68_mem_alloc(2048, 0);
21
+	printf("Allocated 2048B @0x%08x\n", m3);
22
+	v68_mem_dump();
23
+
24
+	uint32_t f = v68_mem_free(m2, 0);
25
+	printf("Freed 0x%06x %d\n", m2, f);
26
+	v68_mem_dump();
27
+
28
+	f = v68_mem_free(m1, 0);
29
+	printf("Freed 0x%06x %d\n", m1, f);
30
+	v68_mem_dump();
31
+
32
+	uint32_t m4 = v68_mem_alloc(1024, 0);
33
+	printf("Allocated 1024B @0x%08x\n", m4);
34
+	v68_mem_dump();
35
+
36
+	f = v68_mem_free(m1, 0);
37
+	printf("Freed 0x%06x %d\n", m1, f);
38
+	v68_mem_dump();
39
+
40
+	f = v68_mem_free(m3, 0);
41
+	printf("Freed 0x%06x %d\n", m3, f);
42
+	v68_mem_dump();
43
+
44
+	return 0;
45
+}

+ 24
- 0
test-path.c View File

@@ -0,0 +1,24 @@
1
+#include <limits.h>
2
+
3
+#include "v68io.h"
4
+
5
+int main(int argc, char **argv, char **envp) {
6
+	v68_io_init();
7
+	v68_io_autodetect_drives();
8
+	v68_dump_drives();
9
+
10
+	char buf[PATH_MAX];
11
+	char *c = v68_io_xlate_path("/media/tb/vgm/ProjectAY.zip", buf, PATH_MAX);
12
+	printf("%s\n", c);
13
+
14
+	c = v68_io_xlate_dos_path("h:\\foo.txt", buf, PATH_MAX);
15
+	printf("%s\n", c);
16
+
17
+	c = v68_io_xlate_dos_path("D:\\Program%20Files%20(x86)\\dbForGe%20Studio%20for%20MySQL\\dbForge%20Studio%20for%20MySQL.exe", buf, PATH_MAX);
18
+	printf("%s\n", c);
19
+
20
+	char buf2[PATH_MAX];
21
+	c = v68_io_resolve_path(buf, buf2, PATH_MAX);
22
+	printf("resolved %s -> %s\n", buf, c);
23
+	return 0;
24
+}

+ 108
- 0
tools.c View File

@@ -0,0 +1,108 @@
1
+#include <stdio.h>
2
+#include <stdlib.h>
3
+#include <stdint.h>
4
+#include <string.h>
5
+#include <errno.h>
6
+#include <libgen.h>
7
+#include <sys/types.h>
8
+#include <sys/stat.h>
9
+#include <unistd.h>
10
+#include <dirent.h>
11
+#ifndef __EMSCRIPTEN__
12
+#include <zlib.h>
13
+#endif /* __EMSCRIPTEN */
14
+#include "tools.h"
15
+
16
+uint8_t *load_file(const char *filename, size_t *size_out) {
17
+	FILE *f = fopen(filename, "rb");
18
+	if(!f) {
19
+		fprintf(
20
+			stderr,
21
+			"Could not open %s: %s (%d)\n",
22
+			filename,
23
+			strerror(errno),
24
+			errno
25
+		);
26
+		return NULL;
27
+	}
28
+	fseek(f, 0, SEEK_END);
29
+	size_t size = ftell(f);
30
+	uint8_t *data = malloc(size);
31
+	if(!data) {
32
+		fprintf(
33
+			stderr,
34
+			"Could not allocate %lu bytes for %s: %s (%d)\n",
35
+			size, filename, strerror(errno), errno
36
+		);
37
+		fclose(f);
38
+		return NULL;
39
+	}
40
+	rewind(f);
41
+	fread(data, 1, size, f);
42
+	fclose(f);
43
+
44
+	if(size_out) *size_out = size;
45
+	return data;
46
+}
47
+
48
+int gcd(int a, int b) {
49
+	int c = a % b;
50
+
51
+	while(c > 0) {
52
+		a = b;
53
+		b = c;
54
+		c = a % b;
55
+	}
56
+
57
+	return b;
58
+}
59
+
60
+void csv_quote(char *str, size_t len) {
61
+	if(len == 0) len = strlen(str);
62
+
63
+	if(str == 0) {
64
+		putchar('\\');
65
+		putchar('N');
66
+		return;
67
+	}
68
+
69
+	putchar('"');
70
+	for(int i = 0; i < len; i++) {
71
+		switch(str[i]) {
72
+			case 0:
73
+				putchar('\\');
74
+				putchar(0);
75
+				break;
76
+			case '\\':
77
+				putchar('\\');
78
+				putchar('\\');
79
+				break;
80
+			case '\b':
81
+				putchar('\\');
82
+				putchar('b');
83
+				break;
84
+			case '\n':
85
+				putchar('\\');
86
+				putchar('n');
87
+				break;
88
+			case '\r':
89
+				putchar('\\');
90
+				putchar('r');
91
+				break;
92
+			case '\t':
93
+				putchar('\\');
94
+				putchar('t');
95
+				break;
96
+			case 26:
97
+				putchar('\\');
98
+				putchar('Z');
99
+				break;
100
+			case '"':
101
+				putchar('"');
102
+				putchar('"');
103
+				break;
104
+			default: putchar(str[i]);
105
+		}
106
+	}
107
+	putchar('"');
108
+}

+ 20
- 0
tools.h View File

@@ -0,0 +1,20 @@
1
+#ifndef TOOLS_H_
2
+#define TOOLS_H_
3
+
4
+#include <stdlib.h>
5
+#include <stdint.h>
6
+
7
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
8
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
9
+
10
+uint8_t *load_file(const char *filename, size_t *size_out);
11
+uint8_t *load_gzfile(const char *filename, size_t *size_out);
12
+int gcd(int a, int b); /* Greatest Common Divisor */
13
+void csv_quote(char *str, size_t len);
14
+
15
+// Execute fn for every file or for each file in every folder
16
+// if recurse = 1, recurse subdirectories
17
+// names and num_names can come from argv and argc
18
+void each_file(const char **names, int num_names, void (*fn)(char *), int recurse);
19
+
20
+#endif /* TOOLS_H_ */

+ 204
- 0
v68.c View File

@@ -0,0 +1,204 @@
1
+#include <stdio.h>
2
+#include <stdlib.h>
3
+#include <errno.h>
4
+#include <string.h>
5
+#include <limits.h>
6
+
7
+#include "v68.h"
8
+#include "v68io.h"
9
+#include "v68mem.h"
10
+#include "v68periph.h"
11
+#include "musashi/m68kcpu.h"
12
+
13
+struct v68 v68;
14
+
15
+int v68_init(int clock, int ram_size, int sample_rate) {
16
+	memset(&v68, 0, sizeof(v68));
17
+
18
+	v68.log_dasm = 0;
19
+	v68.verbosity = 1;
20
+
21
+	v68.ram_size = ram_size;
22
+	v68.cpu_clock = clock;
23
+	v68.sample_rate = sample_rate;
24
+
25
+	v68.ram = malloc(v68.ram_size);
26
+	if(!v68.ram) return errno;
27
+
28
+	m68k_init();
29
+	m68k_set_cpu_type(M68K_CPU_TYPE_68000);
30
+	m68k_pulse_reset();
31
+
32
+	v68_mem_init();
33
+	v68_periph_init();
34
+	v68_io_init();
35
+	v68_human_init();
36
+
37
+	return 0;