z80 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a5289868d57c23014c7ebf04e4a895cfb66743a55bd158f33802f99b8da91ca8
4
+ data.tar.gz: 3d33827c3ea92ef3e6194a9b1f60eb6311763aa421ec0e6e459766f6242ee04b
5
+ SHA512:
6
+ metadata.gz: efffd69b66de491f606dec0271479dad51bd1d8a698582e65c3f566da4448bd0e7c5e5ff8bd04c3fa3ef0f1d8bb9d9434abc820c9b71fc916d5eb842d97834d4
7
+ data.tar.gz: 6909aa3c155aa3f957ee71e160efdef14984232042f9f1f918e171598a5bf24958d15a62d4f482c7d44317d850aac58abc153042aa70f7c968439c85b334706b
data/.editorconfig ADDED
@@ -0,0 +1,15 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ indent_size = 8
7
+ indent_style = tab
8
+ trim_trailing_whitespace = true
9
+
10
+ [*.md]
11
+ trim_trailing_whitespace = false
12
+
13
+ [*.{cff,yml}]
14
+ indent_size = 2
15
+ indent_style = space
@@ -0,0 +1,4 @@
1
+ github: redcode
2
+ ko_fi: redcode
3
+ liberapay: redcode
4
+ patreon: redcode
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ .DS_Store
2
+ .directory
3
+ Thumbs.db
4
+ *.a
5
+ *.bundle
6
+ *.o
7
+ *.so
8
+ /.bundle/
9
+ /_yardoc/
10
+ /coverage/
11
+ /doc/
12
+ /pkg/
13
+ /spec/reports/
14
+ /tmp/
15
+ /.ruby-version
16
+ /.yardoc
17
+ /Gemfile.lock
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # Z80-Ruby ChangeLog
2
+
3
+ ## 0.1.0 / 2023-12-24
4
+
5
+ Initial public release.
data/LICENSE-0BSD ADDED
@@ -0,0 +1,14 @@
1
+ BSD Zero Clause License
2
+
3
+ Copyright (C) 2023 Manuel Sainz de Baranda y Goñi.
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted.
7
+
8
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14
+ PERFORMANCE OF THIS SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,164 @@
1
+ # Z80-Ruby
2
+
3
+ Ruby binding for the [Z80](https://github.com/redcode/Z80) library.
4
+
5
+ ## Installation
6
+
7
+ First make sure that you have the Z80 library [installed](https://github.com/redcode/Z80#installation) on your system.
8
+
9
+ Then add `z80` to the `Gemfile` of your project and run `bundle`:
10
+
11
+ ```ruby
12
+ gem 'z80'
13
+ ```
14
+
15
+ Or install the gem directly with `gem`:
16
+
17
+ ```shell
18
+ gem install z80
19
+ ```
20
+
21
+ ## Examples
22
+
23
+ This small script demonstrates how to run the [CP/M version of ZEXALL](https://github.com/redcode/Z80/wiki/Z80-Instruction-Set-Exerciser) with a few lines of code:
24
+
25
+ ```ruby
26
+ require 'z80'
27
+
28
+ quit = false
29
+ memory = Array.new(65536, 0)
30
+ cpu = Z80.new
31
+
32
+ cpu.fetch_opcode = cpu.fetch = cpu.read do |context, address|
33
+ memory[address]
34
+ end
35
+
36
+ cpu.write do |context, address, value|
37
+ memory[address] = value
38
+ end
39
+
40
+ cpu.hook do |context, address|
41
+ case address
42
+ when 0 # END
43
+ cpu.terminate
44
+ quit = true
45
+ 0 # NOP
46
+ when 5 # PRINT
47
+ i = cpu.de
48
+ while (c = memory[i]) != 0x24
49
+ putc(c == 0xA ? "\n" : c) if c != 0xD
50
+ i = (i + 1) & 0xFFFF
51
+ end
52
+ 0xC9 # RET
53
+ else
54
+ 0 # NOP
55
+ end
56
+ end
57
+
58
+ program = File.read(ARGV[0])
59
+ memory[0x0100, program.size] = program.bytes
60
+ memory[0] = memory[5] = Z80::HOOK
61
+ cpu.power true
62
+ cpu.pc = 0x0100
63
+ cpu.run(Z80::MAXIMUM_CYCLES) until quit
64
+ puts
65
+ ```
66
+
67
+ <sup>**[<sub><img src="https://zxe.io/software/Z80/assets/images/ruby-icon.svg" height="14"></sub> run-yaze-zexall.rb](https://zxe.io/software/Z80/scripts/run-yaze-zexall.rb)**</sup>
68
+
69
+ This runs any tape from Patrik Rak's [Zilog Z80 CPU Test Suite](https://github.com/raxoft/z80test) (except `z80ccfscr.tap`):
70
+
71
+ ```ruby
72
+ require 'z80'
73
+
74
+ module Opcode
75
+ RET = 0xC9
76
+ NOP = 0x00
77
+ CALL = 0xCD
78
+ end
79
+
80
+ quit = false
81
+ tab = 0
82
+ cursor_x = 0
83
+ memory = Array.new(65536, 0)
84
+ cpu = Z80.new
85
+
86
+ cpu.fetch_opcode = cpu.fetch = cpu.read do |context, address|
87
+ memory[address]
88
+ end
89
+
90
+ cpu.write do |context, address, value|
91
+ memory[address] = value if address > 0x3FFF
92
+ end
93
+
94
+ cpu.in do |context, port|
95
+ port.odd? ? 255 : 191
96
+ end
97
+
98
+ cpu.hook do |context, address|
99
+ case address
100
+ when 0x0010 # PRINT
101
+ if tab == 0
102
+ case (c = cpu.a)
103
+ when 0x0D # CR
104
+ putc "\n"
105
+ cursor_x = 0
106
+ when 0x17 # TAB
107
+ tab = 2
108
+ when 0x7F # ©
109
+ printf "©"
110
+ cursor_x += 1
111
+ else
112
+ if c >= 32 && c < 127
113
+ putc c
114
+ cursor_x += 1
115
+ end
116
+ end
117
+ elsif (tab -= 1) != 0
118
+ c = 0x1F & cpu.a
119
+ x = 0x1F & cursor_x
120
+ if c < x
121
+ putc "\n"
122
+ cursor_x = 0
123
+ else
124
+ cursor_x += (c -= x)
125
+ end
126
+ print ' ' * c
127
+ end
128
+ Opcode::RET
129
+ when 0x7003 # Exit
130
+ cpu.terminate
131
+ quit = true
132
+ Opcode::NOP
133
+ else
134
+ Opcode::NOP
135
+ end
136
+ end
137
+
138
+ program = File.read(ARGV[0])
139
+ memory[0x8000, program.size - 91] = program.bytes[91..-1]
140
+ memory[0x0010] = Z80::HOOK # THE 'PRINT A CHARACTER' RESTART
141
+ memory[0x0D6B] = Opcode::RET # THE 'CLS' COMMAND ROUTINE
142
+ memory[0x1601] = Opcode::RET # THE 'CHAN_OPEN' SUBROUTINE
143
+ memory[0x7000] = Opcode::CALL # -.
144
+ memory[0x7001] = 0x00 # |- call 8000h
145
+ memory[0x7002] = 0x80 # -'
146
+ memory[0x7003] = Z80::HOOK
147
+ cpu.power true
148
+ cpu.im = 1
149
+ cpu.i = 0x3F
150
+ cpu.pc = 0x7000
151
+ cpu.run(Z80::MAXIMUM_CYCLES) until quit
152
+ ```
153
+
154
+ <sup>**[<sub><img src="https://zxe.io/software/Z80/assets/images/ruby-icon.svg" height="14"></sub> run-raxoft-z80test.rb](https://zxe.io/software/Z80/scripts/run-raxoft-z80test.rb)**</sup>
155
+
156
+ ## License
157
+
158
+ <img src="https://zxe.io/software/Z80/assets/images/0bsd.svg" width="160" align="right">
159
+
160
+ Copyright © 2023 Manuel Sainz de Baranda y Goñi.
161
+
162
+ Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
163
+
164
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require 'rake/extensiontask'
2
+
3
+ Rake::ExtensionTask.new('z80') do |ext|
4
+ ext.lib_dir = 'lib/z80'
5
+ end
@@ -0,0 +1,97 @@
1
+ require 'mkmf'
2
+ dir_config 'Z80'
3
+
4
+ abort "missing header Z80.h" unless have_header 'Z80.h'
5
+ abort "missing library Z80" unless have_library 'Z80'
6
+
7
+ %w(
8
+ z80_power
9
+ z80_instant_reset
10
+ z80_int
11
+ z80_nmi
12
+ z80_execute
13
+ z80_run
14
+ ).each do |function|
15
+ abort "missing #{function}()" unless have_func function
16
+ end
17
+
18
+ have_func 'z80_special_reset'
19
+
20
+ %w(
21
+ z80_break
22
+ z80_r
23
+ z80_refresh_address
24
+ z80_in_cycle
25
+ z80_out_cycle
26
+ ).each do |function|
27
+ abort "missing #{function}()" unless have_func(function, 'Z80.h')
28
+ end
29
+
30
+ %w(
31
+ Z80_MAXIMUM_CYCLES
32
+ Z80_MAXIMUM_CYCLES_PER_STEP
33
+ Z80_MINIMUM_CYCLES_PER_STEP
34
+ Z80_HOOK
35
+ Z80_OPTION_OUT_VC_255
36
+ Z80_OPTION_LD_A_IR_BUG
37
+ Z80_OPTION_HALT_SKIP
38
+ Z80_OPTION_XQ
39
+ Z80_OPTION_IM0_RETX_NOTIFICATIONS
40
+ Z80_OPTION_YQ
41
+ Z80_MODEL_ZILOG_NMOS
42
+ Z80_MODEL_ZILOG_CMOS
43
+ Z80_MODEL_NEC_NMOS
44
+ Z80_MODEL_ST_CMOS
45
+ Z80_REQUEST_REJECT_NMI
46
+ Z80_REQUEST_NMI
47
+ Z80_REQUEST_INT
48
+ Z80_RESUME_HALT
49
+ Z80_RESUME_XY
50
+ Z80_RESUME_IM0_XY
51
+ Z80_MEMPTR
52
+ Z80_PC
53
+ Z80_SP
54
+ Z80_XY
55
+ Z80_IX
56
+ Z80_IY
57
+ Z80_AF
58
+ Z80_BC
59
+ Z80_DE
60
+ Z80_HL
61
+ Z80_AF_
62
+ Z80_BC_
63
+ Z80_DE_
64
+ Z80_HL_
65
+ Z80_MEMPTRH
66
+ Z80_MEMPTRL
67
+ Z80_PCH
68
+ Z80_PCL
69
+ Z80_SPH
70
+ Z80_SPL
71
+ Z80_XYH
72
+ Z80_XYL
73
+ Z80_IXH
74
+ Z80_IXL
75
+ Z80_IYH
76
+ Z80_IYL
77
+ Z80_A
78
+ Z80_F
79
+ Z80_B
80
+ Z80_C
81
+ Z80_D
82
+ Z80_E
83
+ Z80_H
84
+ Z80_L
85
+ Z80_A_
86
+ Z80_F_
87
+ Z80_B_
88
+ Z80_C_
89
+ Z80_D_
90
+ Z80_E_
91
+ Z80_H_
92
+ Z80_L_
93
+ ).each do |macro|
94
+ abort "missing #{macro}" unless have_macro(macro, 'Z80.h')
95
+ end
96
+
97
+ create_makefile "z80/z80"
data/ext/z80/z80.c ADDED
@@ -0,0 +1,791 @@
1
+ /* ______ ______ ______
2
+ /\___ \/\ __ \\ __ \
3
+ ____ \/__/ /\_\ __ \\ \/\ \ ______________________________________
4
+ | /\_____\\_____\\_____\ |
5
+ | Zilog \/_____//_____//_____/ CPU Emulator - Ruby Binding |
6
+ | Copyright (C) 2023 Manuel Sainz de Baranda y Goñi. |
7
+ | |
8
+ | Permission to use, copy, modify, and/or distribute this software |
9
+ | for any purpose with or without fee is hereby granted. |
10
+ | |
11
+ | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL |
12
+ | WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED |
13
+ | WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL |
14
+ | THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR |
15
+ | CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM |
16
+ | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, |
17
+ | NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
18
+ | CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
19
+ | |
20
+ '===================================================================*/
21
+
22
+ #include <ruby.h>
23
+ #include <Z80.h>
24
+ #include <Z/macros/array.h>
25
+ #include <inttypes.h>
26
+ #include <stdio.h>
27
+
28
+ static rb_data_type_t const z80_data_type;
29
+
30
+ #define GET_Z80 \
31
+ Z80 *z80; \
32
+ TypedData_Get_Struct(self, Z80, &z80_data_type, z80);
33
+
34
+ enum { FetchOpcode, Fetch, Read, Write, In, Out,
35
+ Halt, Nop,
36
+ NMIA, INTA, INTFetch,
37
+ ld_i_a, ld_r_a, reti, retn,
38
+ Hook, Illegal,
39
+ Context
40
+ };
41
+
42
+
43
+ /* Callbacks: Dummy Bridges */
44
+
45
+ static zuint8 dummy_read(void *context, zuint16 address)
46
+ {
47
+ Z_UNUSED(context) Z_UNUSED(address)
48
+ return 0; /* nop */
49
+ }
50
+
51
+
52
+ static void dummy_write(void *context, zuint16 address, zuint8 value)
53
+ {Z_UNUSED(context) Z_UNUSED(address)}
54
+
55
+
56
+ static zuint8 dummy_in(void *context, zuint16 port)
57
+ {
58
+ Z_UNUSED(context) Z_UNUSED(port)
59
+ return 255;
60
+ }
61
+
62
+
63
+ /* Callbacks: Bridges */
64
+
65
+ #define PROC_CALL(index, arity, ...) \
66
+ rb_funcall( \
67
+ external[index], rb_intern("call"), arity + 1, \
68
+ external[Context] Z_IF(arity)(Z_COMMA) __VA_ARGS__)
69
+
70
+ #define METHOD_CALL(index, arity, ...) \
71
+ rb_funcall( \
72
+ external[index], rb_intern("call"), arity \
73
+ Z_IF(arity)(Z_COMMA) __VA_ARGS__)
74
+
75
+
76
+ #define CALLBACK_BRIDGES(receiver, call) \
77
+ \
78
+ static zuint8 receiver##_fetch_opcode(VALUE *external, zuint16 address) \
79
+ {return (zuint8)NUM2UINT(call(FetchOpcode, 1, UINT2NUM(address)));} \
80
+ \
81
+ \
82
+ static zuint8 receiver##_fetch(VALUE *external, zuint16 address) \
83
+ {return (zuint8)NUM2UINT(call(Fetch, 1, UINT2NUM(address)));} \
84
+ \
85
+ \
86
+ static zuint8 receiver##_read(VALUE *external, zuint16 address) \
87
+ {return (zuint8)NUM2UINT(call(Read, 1, UINT2NUM(address)));} \
88
+ \
89
+ \
90
+ static void receiver##_write(VALUE *external, zuint16 address, zuint8 value) \
91
+ {call(Write, 2, UINT2NUM(address), UINT2NUM(value));} \
92
+ \
93
+ \
94
+ static zuint8 receiver##_in(VALUE *external, zuint16 port) \
95
+ {return (zuint8)NUM2UINT(call(In, 1, UINT2NUM(port)));} \
96
+ \
97
+ \
98
+ static void receiver##_out(VALUE *external, zuint16 port, zuint8 value) \
99
+ {call(Out, 2, UINT2NUM(port), UINT2NUM(value));} \
100
+ \
101
+ \
102
+ static void receiver##_halt(VALUE *external, zuint8 state) \
103
+ {call(Halt, 1, UINT2NUM(state));} \
104
+ \
105
+ \
106
+ static zuint8 receiver##_nop(VALUE *external, zuint16 address) \
107
+ {return (zuint8)NUM2UINT(call(Nop, 1, UINT2NUM(address)));} \
108
+ \
109
+ \
110
+ static zuint8 receiver##_nmia(VALUE *external, zuint16 address) \
111
+ {return (zuint8)NUM2UINT(call(NMIA, 1, UINT2NUM(address)));} \
112
+ \
113
+ \
114
+ static zuint8 receiver##_inta(VALUE *external, zuint16 address) \
115
+ {return (zuint8)NUM2UINT(call(INTA, 1, UINT2NUM(address)));} \
116
+ \
117
+ \
118
+ static zuint8 receiver##_int_fetch(VALUE *external, zuint16 address) \
119
+ {return (zuint8)NUM2UINT(call(INTFetch, 1, UINT2NUM(address)));} \
120
+ \
121
+ \
122
+ static void receiver##_ld_i_a(VALUE *external) {call(ld_i_a, 0);} \
123
+ static void receiver##_ld_r_a(VALUE *external) {call(ld_r_a, 0);} \
124
+ static void receiver##_reti (VALUE *external) {call(reti, 0);} \
125
+ static void receiver##_retn (VALUE *external) {call(reti, 0);} \
126
+ \
127
+ \
128
+ static zuint8 receiver##_hook(VALUE *external, zuint16 address) \
129
+ {return (zuint8)NUM2UINT(call(Hook, 1, UINT2NUM(address)));} \
130
+ \
131
+ \
132
+ static zuint8 receiver##_illegal(VALUE *external, zuint8 opcode) \
133
+ {return (zuint8)NUM2UINT(call(Illegal, 1, UINT2NUM(opcode)));}
134
+
135
+
136
+ CALLBACK_BRIDGES(proc, PROC_CALL )
137
+ CALLBACK_BRIDGES(method, METHOD_CALL)
138
+
139
+ #undef PROC_CALL
140
+ #undef METHOD_CALL
141
+ #undef CALLBACK_BRIDGES
142
+
143
+
144
+ /* MARK: - Callbacks: Accessors */
145
+
146
+ typedef struct {
147
+ zusize offset;
148
+ void* dummy;
149
+ void* proc_bridge;
150
+ void* method_bridge;
151
+ } CallbackInfo;
152
+
153
+ static CallbackInfo const callback_info_table[] = {
154
+ {Z_MEMBER_OFFSET(Z80, fetch_opcode), dummy_read, proc_fetch_opcode, method_fetch_opcode},
155
+ {Z_MEMBER_OFFSET(Z80, fetch ), dummy_read, proc_fetch, method_fetch, },
156
+ {Z_MEMBER_OFFSET(Z80, read ), dummy_read, proc_read, method_read, },
157
+ {Z_MEMBER_OFFSET(Z80, write ), dummy_write, proc_write, method_write, },
158
+ {Z_MEMBER_OFFSET(Z80, in ), dummy_read, proc_in, method_in, },
159
+ {Z_MEMBER_OFFSET(Z80, out ), dummy_write, proc_out, method_out, },
160
+ {Z_MEMBER_OFFSET(Z80, halt ), NULL, proc_halt, method_halt, },
161
+ {Z_MEMBER_OFFSET(Z80, nop ), NULL, proc_nop, method_nop, },
162
+ {Z_MEMBER_OFFSET(Z80, nmia ), NULL, proc_nmia, method_nmia, },
163
+ {Z_MEMBER_OFFSET(Z80, inta ), NULL, proc_inta, method_inta, },
164
+ {Z_MEMBER_OFFSET(Z80, int_fetch ), NULL, proc_int_fetch, method_int_fetch, },
165
+ {Z_MEMBER_OFFSET(Z80, ld_i_a ), NULL, proc_ld_i_a, method_ld_i_a, },
166
+ {Z_MEMBER_OFFSET(Z80, ld_r_a ), NULL, proc_ld_r_a, method_ld_r_a, },
167
+ {Z_MEMBER_OFFSET(Z80, reti ), NULL, proc_reti, method_reti, },
168
+ {Z_MEMBER_OFFSET(Z80, retn ), NULL, proc_retn, method_retn, },
169
+ {Z_MEMBER_OFFSET(Z80, hook ), NULL, proc_hook, method_hook, },
170
+ {Z_MEMBER_OFFSET(Z80, illegal ), NULL, proc_illegal, method_illegal, }
171
+ };
172
+
173
+
174
+ static void set_callback(VALUE self, VALUE object, zuint index)
175
+ {
176
+ CallbackInfo const *callback_info;
177
+ VALUE *external;
178
+ GET_Z80;
179
+
180
+ external = (VALUE *)z80->context + index;
181
+ *external = object;
182
+ callback_info = callback_info_table + index;
183
+
184
+ *(void **)((char *)z80 + callback_info->offset) = object != Qnil
185
+ ? *(void **)((char *)z80 + callback_info->offset) = callback_info->proc_bridge
186
+ : callback_info->dummy;
187
+ }
188
+
189
+
190
+ #define CALLBACK_ACCESSOR(member, index) \
191
+ \
192
+ static VALUE Z80__set_##member(VALUE self, VALUE callback) \
193
+ { \
194
+ set_callback(self, callback, index); \
195
+ return Qnil; \
196
+ } \
197
+ \
198
+ \
199
+ static VALUE Z80__##member(VALUE self) \
200
+ { \
201
+ GET_Z80; \
202
+ if (rb_block_given_p()) set_callback(self, rb_block_proc(), index); \
203
+ return *((VALUE *)z80->context + index); \
204
+ }
205
+
206
+
207
+ CALLBACK_ACCESSOR(fetch_opcode, FetchOpcode)
208
+ CALLBACK_ACCESSOR(fetch, Fetch )
209
+ CALLBACK_ACCESSOR(read, Read )
210
+ CALLBACK_ACCESSOR(write, Write )
211
+ CALLBACK_ACCESSOR(in, In )
212
+ CALLBACK_ACCESSOR(out, Out )
213
+ CALLBACK_ACCESSOR(halt, Halt )
214
+ CALLBACK_ACCESSOR(nop, Nop )
215
+ CALLBACK_ACCESSOR(nmia, NMIA )
216
+ CALLBACK_ACCESSOR(inta, INTA )
217
+ CALLBACK_ACCESSOR(int_fetch, INTFetch )
218
+ CALLBACK_ACCESSOR(ld_i_a, ld_i_a )
219
+ CALLBACK_ACCESSOR(ld_r_a, ld_r_a )
220
+ CALLBACK_ACCESSOR(reti, reti )
221
+ CALLBACK_ACCESSOR(retn, retn )
222
+ CALLBACK_ACCESSOR(hook, Hook )
223
+ CALLBACK_ACCESSOR(illegal, Illegal )
224
+
225
+ #undef CALLBACK_ACCESSOR
226
+
227
+
228
+ /* MARK: - Other Accessors */
229
+
230
+ static VALUE Z80__set_context(VALUE self, VALUE context)
231
+ {
232
+ GET_Z80;
233
+ *((VALUE *)z80->context + Context) = context;
234
+ return Qnil;
235
+ }
236
+
237
+
238
+ static VALUE Z80__context(VALUE self)
239
+ {
240
+ GET_Z80;
241
+ return *((VALUE *)z80->context + Context);
242
+ }
243
+
244
+
245
+ #define MACRO( member, macro) macro(*z80)
246
+ #define DIRECT(member, macro) z80->member
247
+ #define UINT_TO_BOOL(value) value ? Qtrue : Qfalse
248
+
249
+ #define BOOL_NUM_TO_UINT(value) \
250
+ (value == Qfalse ? 0 : (value == Qtrue ? 1 : !!NUM2UINT(value)))
251
+
252
+
253
+ #define ACCESSOR(type, member, access, with, c_to_ruby, ruby_to_c) \
254
+ \
255
+ static VALUE Z80__##member(VALUE self) \
256
+ { \
257
+ GET_Z80; \
258
+ return c_to_ruby(access(member, with)); \
259
+ } \
260
+ \
261
+ \
262
+ static VALUE Z80__set_##member(VALUE self, VALUE value) \
263
+ { \
264
+ GET_Z80; \
265
+ access(member, with) = (type)ruby_to_c(value); \
266
+ return value; \
267
+ }
268
+
269
+
270
+ ACCESSOR(zusize, cycles, DIRECT, Z_EMPTY, SIZET2NUM, NUM2SIZET )
271
+ ACCESSOR(zusize, cycle_limit, DIRECT, Z_EMPTY, SIZET2NUM, NUM2SIZET )
272
+ ACCESSOR(zuint16, memptr, MACRO, Z80_MEMPTR, UINT2NUM, NUM2UINT )
273
+ ACCESSOR(zuint16, pc, MACRO, Z80_PC, UINT2NUM, NUM2UINT )
274
+ ACCESSOR(zuint16, sp, MACRO, Z80_SP, UINT2NUM, NUM2UINT )
275
+ ACCESSOR(zuint16, xy, MACRO, Z80_XY, UINT2NUM, NUM2UINT )
276
+ ACCESSOR(zuint16, ix, MACRO, Z80_IX, UINT2NUM, NUM2UINT )
277
+ ACCESSOR(zuint16, iy, MACRO, Z80_IY, UINT2NUM, NUM2UINT )
278
+ ACCESSOR(zuint16, af, MACRO, Z80_AF, UINT2NUM, NUM2UINT )
279
+ ACCESSOR(zuint16, bc, MACRO, Z80_BC, UINT2NUM, NUM2UINT )
280
+ ACCESSOR(zuint16, de, MACRO, Z80_DE, UINT2NUM, NUM2UINT )
281
+ ACCESSOR(zuint16, hl, MACRO, Z80_HL, UINT2NUM, NUM2UINT )
282
+ ACCESSOR(zuint16, af_, MACRO, Z80_AF_, UINT2NUM, NUM2UINT )
283
+ ACCESSOR(zuint16, bc_, MACRO, Z80_BC_, UINT2NUM, NUM2UINT )
284
+ ACCESSOR(zuint16, de_, MACRO, Z80_DE_, UINT2NUM, NUM2UINT )
285
+ ACCESSOR(zuint16, hl_, MACRO, Z80_HL_, UINT2NUM, NUM2UINT )
286
+ ACCESSOR(zuint8, memptrh, MACRO, Z80_MEMPTRH, UINT2NUM, NUM2UINT )
287
+ ACCESSOR(zuint8, memptrl, MACRO, Z80_MEMPTRL, UINT2NUM, NUM2UINT )
288
+ ACCESSOR(zuint8, pch, MACRO, Z80_PCH, UINT2NUM, NUM2UINT )
289
+ ACCESSOR(zuint8, pcl, MACRO, Z80_PCL, UINT2NUM, NUM2UINT )
290
+ ACCESSOR(zuint8, sph, MACRO, Z80_SPH, UINT2NUM, NUM2UINT )
291
+ ACCESSOR(zuint8, spl, MACRO, Z80_SPL, UINT2NUM, NUM2UINT )
292
+ ACCESSOR(zuint8, xyh, MACRO, Z80_XYH, UINT2NUM, NUM2UINT )
293
+ ACCESSOR(zuint8, yl, MACRO, Z80_XYL, UINT2NUM, NUM2UINT )
294
+ ACCESSOR(zuint8, ixh, MACRO, Z80_IXH, UINT2NUM, NUM2UINT )
295
+ ACCESSOR(zuint8, ixl, MACRO, Z80_IXL, UINT2NUM, NUM2UINT )
296
+ ACCESSOR(zuint8, iyh, MACRO, Z80_IYH, UINT2NUM, NUM2UINT )
297
+ ACCESSOR(zuint8, iyl, MACRO, Z80_IYL, UINT2NUM, NUM2UINT )
298
+ ACCESSOR(zuint8, a, MACRO, Z80_A, UINT2NUM, NUM2UINT )
299
+ ACCESSOR(zuint8, f, MACRO, Z80_F, UINT2NUM, NUM2UINT )
300
+ ACCESSOR(zuint8, b, MACRO, Z80_B, UINT2NUM, NUM2UINT )
301
+ ACCESSOR(zuint8, c, MACRO, Z80_C, UINT2NUM, NUM2UINT )
302
+ ACCESSOR(zuint8, d, MACRO, Z80_D, UINT2NUM, NUM2UINT )
303
+ ACCESSOR(zuint8, e, MACRO, Z80_E, UINT2NUM, NUM2UINT )
304
+ ACCESSOR(zuint8, h, MACRO, Z80_H, UINT2NUM, NUM2UINT )
305
+ ACCESSOR(zuint8, l, MACRO, Z80_L, UINT2NUM, NUM2UINT )
306
+ ACCESSOR(zuint8, a_, MACRO, Z80_A_, UINT2NUM, NUM2UINT )
307
+ ACCESSOR(zuint8, f_, MACRO, Z80_F_, UINT2NUM, NUM2UINT )
308
+ ACCESSOR(zuint8, b_, MACRO, Z80_B_, UINT2NUM, NUM2UINT )
309
+ ACCESSOR(zuint8, c_, MACRO, Z80_C_, UINT2NUM, NUM2UINT )
310
+ ACCESSOR(zuint8, d_, MACRO, Z80_D_, UINT2NUM, NUM2UINT )
311
+ ACCESSOR(zuint8, e_, MACRO, Z80_E_, UINT2NUM, NUM2UINT )
312
+ ACCESSOR(zuint8, h_, MACRO, Z80_H_, UINT2NUM, NUM2UINT )
313
+ ACCESSOR(zuint8, l_, MACRO, Z80_L_, UINT2NUM, NUM2UINT )
314
+ ACCESSOR(zuint8, r, DIRECT, Z_EMPTY, UINT2NUM, NUM2UINT )
315
+ ACCESSOR(zuint8, i, DIRECT, Z_EMPTY, UINT2NUM, NUM2UINT )
316
+ ACCESSOR(zuint8, r7, DIRECT, Z_EMPTY, UINT2NUM, NUM2UINT )
317
+ ACCESSOR(zuint8, im, DIRECT, Z_EMPTY, UINT2NUM, NUM2UINT )
318
+ ACCESSOR(zuint8, request, DIRECT, Z_EMPTY, UINT2NUM, NUM2UINT )
319
+ ACCESSOR(zuint8, resume, DIRECT, Z_EMPTY, UINT2NUM, NUM2UINT )
320
+ ACCESSOR(zuint8, iff1, DIRECT, Z_EMPTY, UINT_TO_BOOL, BOOL_NUM_TO_UINT)
321
+ ACCESSOR(zuint8, iff2, DIRECT, Z_EMPTY, UINT_TO_BOOL, BOOL_NUM_TO_UINT)
322
+ ACCESSOR(zuint8, q, DIRECT, Z_EMPTY, UINT2NUM, NUM2UINT )
323
+ ACCESSOR(zuint8, options, DIRECT, Z_EMPTY, UINT2NUM, NUM2UINT )
324
+ ACCESSOR(zuint8, int_line, DIRECT, Z_EMPTY, UINT_TO_BOOL, BOOL_NUM_TO_UINT)
325
+ ACCESSOR(zuint8, halt_line, DIRECT, Z_EMPTY, UINT_TO_BOOL, BOOL_NUM_TO_UINT)
326
+
327
+ #undef UINT_TO_BOOL
328
+ #undef MACRO
329
+ #undef DIRECT
330
+ #undef ACCESSOR
331
+
332
+
333
+ #define FLAG_ACCESSOR(flag, shift) \
334
+ \
335
+ static VALUE Z80__##flag(VALUE self) \
336
+ { \
337
+ GET_Z80; \
338
+ return UINT2NUM((Z80_F(*z80) >> shift) & 1); \
339
+ } \
340
+ \
341
+ static VALUE Z80__set_##flag(VALUE self, VALUE value) \
342
+ { \
343
+ zuint8 bit = (zuint8)(NUM2UINT(value) & 1); \
344
+ GET_Z80; \
345
+ Z80_F(*z80) = (Z80_F(*z80) & ~(1U << shift)) | (bit << shift); \
346
+ return UINT2NUM(bit); \
347
+ }
348
+
349
+
350
+ FLAG_ACCESSOR(sf, 7)
351
+ FLAG_ACCESSOR(zf, 6)
352
+ FLAG_ACCESSOR(yf, 5)
353
+ FLAG_ACCESSOR(hf, 4)
354
+ FLAG_ACCESSOR(xf, 3)
355
+ FLAG_ACCESSOR(pf, 2)
356
+ FLAG_ACCESSOR(nf, 1)
357
+ FLAG_ACCESSOR(cf, 0)
358
+
359
+ #undef FLAG_ACCESSOR
360
+
361
+
362
+ /* MARK: - Methods */
363
+
364
+ static VALUE Z80__power(VALUE self, VALUE state)
365
+ {
366
+ GET_Z80;
367
+ z80_power(z80, RB_TEST(state));
368
+ return self;
369
+ }
370
+
371
+
372
+ static VALUE Z80__instant_reset(VALUE self)
373
+ {
374
+ GET_Z80;
375
+ z80_instant_reset(z80);
376
+ return self;
377
+ }
378
+
379
+
380
+ static VALUE Z80__int(VALUE self, VALUE state)
381
+ {
382
+ GET_Z80;
383
+ z80_int(z80, RB_TEST(state));
384
+ return self;
385
+ }
386
+
387
+
388
+ static VALUE Z80__nmi(VALUE self)
389
+ {
390
+ GET_Z80;
391
+ z80_nmi(z80);
392
+ return self;
393
+ }
394
+
395
+
396
+ static VALUE Z80__execute(VALUE self, VALUE cycles)
397
+ {
398
+ GET_Z80;
399
+ return SIZET2NUM(z80_execute(z80, NUM2SIZET(cycles)));
400
+ }
401
+
402
+
403
+ static VALUE Z80__run(VALUE self, VALUE cycles)
404
+ {
405
+ GET_Z80;
406
+ return SIZET2NUM(z80_run(z80, NUM2SIZET(cycles)));
407
+ }
408
+
409
+
410
+ static VALUE Z80__terminate(VALUE self)
411
+ {
412
+ GET_Z80;
413
+ z80_break(z80);
414
+ return self;
415
+ }
416
+
417
+
418
+ static VALUE Z80__full_r(VALUE self)
419
+ {
420
+ GET_Z80;
421
+ return UINT2NUM(z80_r(z80));
422
+ }
423
+
424
+
425
+ static VALUE Z80__refresh_address(VALUE self)
426
+ {
427
+ GET_Z80;
428
+ return UINT2NUM(z80_refresh_address(z80));
429
+ }
430
+
431
+
432
+ static VALUE Z80__in_cycle(VALUE self)
433
+ {
434
+ GET_Z80;
435
+ return UINT2NUM(z80_in_cycle(z80));
436
+ }
437
+
438
+
439
+ static VALUE Z80__out_cycle(VALUE self)
440
+ {
441
+ GET_Z80;
442
+ return UINT2NUM(z80_out_cycle(z80));
443
+ }
444
+
445
+
446
+ static struct {char const* name; zuint offset;} const
447
+
448
+ members_16[] = {
449
+ {"memptr", Z_MEMBER_OFFSET(Z80, memptr )},
450
+ {"pc", Z_MEMBER_OFFSET(Z80, pc )},
451
+ {"sp", Z_MEMBER_OFFSET(Z80, sp )},
452
+ {"xy", Z_MEMBER_OFFSET(Z80, xy )},
453
+ {"ix", Z_MEMBER_OFFSET(Z80, ix_iy[0])},
454
+ {"iy", Z_MEMBER_OFFSET(Z80, ix_iy[1])},
455
+ {"af", Z_MEMBER_OFFSET(Z80, af )},
456
+ {"bc", Z_MEMBER_OFFSET(Z80, bc )},
457
+ {"de", Z_MEMBER_OFFSET(Z80, de )},
458
+ {"hl", Z_MEMBER_OFFSET(Z80, hl )},
459
+ {"af_", Z_MEMBER_OFFSET(Z80, af_ )},
460
+ {"bc_", Z_MEMBER_OFFSET(Z80, bc_ )},
461
+ {"de_", Z_MEMBER_OFFSET(Z80, de_ )},
462
+ {"hl_", Z_MEMBER_OFFSET(Z80, hl_ )}
463
+ },
464
+
465
+ members_8[] = {
466
+ {"r", Z_MEMBER_OFFSET(Z80, r )},
467
+ {"i", Z_MEMBER_OFFSET(Z80, i )},
468
+ {"r7", Z_MEMBER_OFFSET(Z80, r7 )},
469
+ {"im", Z_MEMBER_OFFSET(Z80, im )},
470
+ {"request", Z_MEMBER_OFFSET(Z80, request )},
471
+ {"resume", Z_MEMBER_OFFSET(Z80, resume )},
472
+ {"iff1", Z_MEMBER_OFFSET(Z80, iff1 )},
473
+ {"iff2", Z_MEMBER_OFFSET(Z80, iff2 )},
474
+ {"q", Z_MEMBER_OFFSET(Z80, q )},
475
+ {"options", Z_MEMBER_OFFSET(Z80, options )},
476
+ {"int_line", Z_MEMBER_OFFSET(Z80, int_line )},
477
+ {"halt_line", Z_MEMBER_OFFSET(Z80, halt_line)}
478
+ };
479
+
480
+
481
+ static VALUE Z80__to_h(VALUE self)
482
+ {
483
+ VALUE hash = rb_hash_new();
484
+ VALUE kv[(Z_ARRAY_SIZE(members_16) + Z_ARRAY_SIZE(members_8)) * 2];
485
+ int i = 0, j;
486
+ GET_Z80;
487
+
488
+ for (j = 0; j < Z_ARRAY_SIZE(members_16);)
489
+ {
490
+ kv[i++] = rb_id2sym(rb_intern(members_16[j].name));
491
+ kv[i++] = UINT2NUM(*(zuint16 *)(void *)((char *)z80 + members_16[j++].offset));
492
+ }
493
+
494
+ for (j = 0; j < Z_ARRAY_SIZE(members_8);)
495
+ {
496
+ kv[i++] = rb_id2sym(rb_intern(members_8[j].name));
497
+ kv[i++] = UINT2NUM(*((zuint8 *)z80 + members_8[j++].offset));
498
+ }
499
+
500
+ rb_hash_bulk_insert_into_st_table(Z_ARRAY_SIZE(kv), kv, hash);
501
+ return hash;
502
+ }
503
+
504
+
505
+ static char const one_hyphen[2] = "1-";
506
+
507
+
508
+ static VALUE Z80__print(VALUE self)
509
+ {
510
+ zuint8 f;
511
+ GET_Z80;
512
+ f = Z80_F(*z80);
513
+
514
+ /*
515
+ PC 0000 AF 0000 AF' 0000 IX 0000
516
+ SP 0000 BC 0000 BC' 0000 IY 0000
517
+ IR 0000 DE 0000 DE' 0000 XY 0000
518
+ WZ 0000 HL 0000 HL' 0000 Q 00
519
+ S Z Y H X P N C IFF1 0 IM 0 EI 1
520
+ - - 1 - - 1 - - IFF2 0 R7 0 RI 1
521
+ /INT high RS 00 data 00 00 00 00
522
+ /HALT high RQ 00 data 00 00 00 00*/
523
+
524
+ printf( "PC %04" PRIX16 " AF %04" PRIX16 " AF' %04" PRIX16 " IX %04" PRIX16 "\n"
525
+ "SP %04" PRIX16 " BC %04" PRIX16 " BC' %04" PRIX16 " IY %04" PRIX16 "\n"
526
+ "IR %02" PRIX8 "%02" PRIX8 " DE %04" PRIX16 " DE' %04" PRIX16 " XY %04" PRIX16 "\n"
527
+ "WZ %04" PRIX16 " HL %04" PRIX16 " HL' %04" PRIX16 " Q %02" PRIX8 "\n"
528
+ "S Z Y H X P N C" " IFF1 %" PRIu8 " IM %" PRIu8 " EI %" PRIu8 "\n"
529
+ "%c %c %c %c %c %c %c %c IFF2 %" PRIu8 " R7 %" PRIu8 " RI %" PRIu8 "\n",
530
+ Z80_PC(*z80), Z80_AF(*z80), Z80_AF_(*z80), Z80_IX(*z80),
531
+ Z80_SP(*z80), Z80_BC(*z80), Z80_BC_(*z80), Z80_IY(*z80),
532
+ z80->i, z80->r, Z80_DE(*z80), Z80_DE_(*z80), Z80_IX(*z80),
533
+ Z80_MEMPTR(*z80), Z80_HL(*z80), Z80_HL_(*z80), z80->q,
534
+ z80->iff1, z80->im, '\0',
535
+ one_hyphen[!(f & Z80_SF)],
536
+ one_hyphen[!(f & Z80_ZF)],
537
+ one_hyphen[!(f & Z80_YF)],
538
+ one_hyphen[!(f & Z80_HF)],
539
+ one_hyphen[!(f & Z80_XF)],
540
+ one_hyphen[!(f & Z80_PF)],
541
+ one_hyphen[!(f & Z80_NF)],
542
+ one_hyphen[!(f & Z80_CF)],
543
+ z80->iff2, z80->r7 >> 7, '\0');
544
+
545
+ return Qnil;
546
+ }
547
+
548
+
549
+ /* MARK: - Object Lifecycle */
550
+
551
+ static void Z80__mark(Z80 *z80)
552
+ {
553
+ VALUE *externals = z80->context;
554
+
555
+ for (int i = 18; i;) if (externals[--i] != Qnil)
556
+ rb_gc_mark_movable(externals[i]);
557
+ }
558
+
559
+
560
+ static void Z80__free(Z80 *z80)
561
+ {
562
+ free(z80->context);
563
+ xfree(z80);
564
+ }
565
+
566
+
567
+ static size_t Z80__memsize(const void *z80)
568
+ {return sizeof(Z80) + sizeof(VALUE[18]);}
569
+
570
+
571
+ static void Z80__compact(Z80 *z80)
572
+ {
573
+ VALUE *externals = z80->context;
574
+
575
+ for (int i = 18; i;) if (externals[--i] != Qnil)
576
+ externals[i] = rb_gc_location(externals[i]);
577
+ }
578
+
579
+
580
+ static rb_data_type_t const z80_data_type = {
581
+ .wrap_struct_name = "z80",
582
+ .function = {
583
+ .dmark = (void (*)(void *))Z80__mark,
584
+ .dfree = (void (*)(void *))Z80__free,
585
+ .dsize = NULL,
586
+ .dcompact = (void (*)(void *))Z80__compact
587
+ },
588
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY
589
+ };
590
+
591
+
592
+ static VALUE Z80__alloc(VALUE klass)
593
+ {
594
+ Z80 *z80;
595
+ VALUE object = TypedData_Make_Struct(klass, Z80, &z80_data_type, z80);
596
+ VALUE *externals = z80->context = malloc(sizeof(VALUE[18]));
597
+
598
+ for (int i = 18; i;) externals[--i] = Qnil;
599
+
600
+ z80->options = Z80_MODEL_ZILOG_NMOS;
601
+ z80->fetch_opcode =
602
+ z80->fetch =
603
+ z80->read = dummy_read;
604
+ z80->write =
605
+ z80->out = dummy_write;
606
+ z80->in = dummy_in;
607
+ z80->halt = NULL;
608
+ z80->nop =
609
+ z80->nmia =
610
+ z80->inta =
611
+ z80->int_fetch =
612
+ z80->hook = NULL;
613
+ z80->ld_i_a =
614
+ z80->ld_r_a =
615
+ z80->reti =
616
+ z80->retn = NULL;
617
+ z80->illegal = NULL;
618
+
619
+ return object;
620
+ }
621
+
622
+
623
+ /* Library Initialization */
624
+
625
+ void Init_z80(void)
626
+ {
627
+ VALUE module, klass = rb_const_get(rb_cObject, rb_intern("Z80"));
628
+
629
+ rb_define_alloc_func(klass, Z80__alloc);
630
+
631
+ rb_define_const(klass, "MAXIMUM_CYCLES", ULL2NUM(Z80_MAXIMUM_CYCLES ));
632
+ rb_define_const(klass, "MAXIMUM_CYCLES_PER_STEP", UINT2NUM(Z80_MAXIMUM_CYCLES_PER_STEP));
633
+ rb_define_const(klass, "HOOK", UINT2NUM(Z80_HOOK ));
634
+
635
+ rb_define_const(klass, "SF", UINT2NUM(Z80_SF));
636
+ rb_define_const(klass, "ZF", UINT2NUM(Z80_ZF));
637
+ rb_define_const(klass, "YF", UINT2NUM(Z80_YF));
638
+ rb_define_const(klass, "HF", UINT2NUM(Z80_HF));
639
+ rb_define_const(klass, "XF", UINT2NUM(Z80_XF));
640
+ rb_define_const(klass, "PF", UINT2NUM(Z80_PF));
641
+ rb_define_const(klass, "NF", UINT2NUM(Z80_NF));
642
+ rb_define_const(klass, "CF", UINT2NUM(Z80_CF));
643
+
644
+ module = rb_define_module_under(klass, "Option");
645
+
646
+ rb_define_const(module, "OUT_VC_255", UINT2NUM(Z80_OPTION_OUT_VC_255 ));
647
+ rb_define_const(module, "LD_A_IR_BUG", UINT2NUM(Z80_OPTION_LD_A_IR_BUG ));
648
+ rb_define_const(module, "HALT_SKIP", UINT2NUM(Z80_OPTION_HALT_SKIP ));
649
+ rb_define_const(module, "XQ", UINT2NUM(Z80_OPTION_XQ ));
650
+ rb_define_const(module, "IM0_RETX_NOTIFICATIONS", UINT2NUM(Z80_OPTION_IM0_RETX_NOTIFICATIONS));
651
+ rb_define_const(module, "YQ", UINT2NUM(Z80_OPTION_YQ ));
652
+
653
+ module = rb_define_module_under(module, "Model");
654
+
655
+ rb_define_const(module, "ZILOG_NMOS", UINT2NUM(Z80_MODEL_ZILOG_NMOS));
656
+ rb_define_const(module, "ZILOG_CMOS", UINT2NUM(Z80_MODEL_ZILOG_CMOS));
657
+ rb_define_const(module, "NEC_NMOS", UINT2NUM(Z80_MODEL_NEC_NMOS ));
658
+ rb_define_const(module, "ST_CMOS", UINT2NUM(Z80_MODEL_ST_CMOS ));
659
+
660
+ module = rb_define_module_under(klass, "Request");
661
+
662
+ rb_define_const(module, "REJECT_NMI", UINT2NUM(Z80_REQUEST_REJECT_NMI ));
663
+ rb_define_const(module, "NMI", UINT2NUM(Z80_REQUEST_NMI ));
664
+ rb_define_const(module, "INT", UINT2NUM(Z80_REQUEST_INT ));
665
+ /* rb_define_const(module, "SPECIAL_RESET", UINT2NUM(Z80_REQUEST_SPECIAL_RESET));*/
666
+
667
+ module = rb_define_module_under(klass, "Resume");
668
+
669
+ rb_define_const(module, "HALT", UINT2NUM(Z80_RESUME_HALT ));
670
+ rb_define_const(module, "XY", UINT2NUM(Z80_RESUME_XY ));
671
+ rb_define_const(module, "IM0_XY", UINT2NUM(Z80_RESUME_IM0_XY));
672
+
673
+ # define DEFINE_ACCESSOR(name, getter_arity) \
674
+ rb_define_method(klass, #name, Z80__##name, getter_arity); \
675
+ rb_define_method(klass, #name "=", Z80__set_##name, 1);
676
+
677
+ DEFINE_ACCESSOR(fetch_opcode, 0)
678
+ DEFINE_ACCESSOR(fetch, 0)
679
+ DEFINE_ACCESSOR(read, 0)
680
+ DEFINE_ACCESSOR(write, 0)
681
+ DEFINE_ACCESSOR(in, 0)
682
+ DEFINE_ACCESSOR(out, 0)
683
+ DEFINE_ACCESSOR(halt, 0)
684
+ DEFINE_ACCESSOR(nop, 0)
685
+ DEFINE_ACCESSOR(nmia, 0)
686
+ DEFINE_ACCESSOR(inta, 0)
687
+ DEFINE_ACCESSOR(int_fetch, 0)
688
+ DEFINE_ACCESSOR(ld_i_a, 0)
689
+ DEFINE_ACCESSOR(ld_r_a, 0)
690
+ DEFINE_ACCESSOR(reti, 0)
691
+ DEFINE_ACCESSOR(retn, 0)
692
+ DEFINE_ACCESSOR(hook, 0)
693
+ DEFINE_ACCESSOR(illegal, 0)
694
+ DEFINE_ACCESSOR(context, 0)
695
+ DEFINE_ACCESSOR(cycles, 0)
696
+ DEFINE_ACCESSOR(cycle_limit, 0)
697
+ DEFINE_ACCESSOR(memptr, 0)
698
+ DEFINE_ACCESSOR(pc, 0)
699
+ DEFINE_ACCESSOR(sp, 0)
700
+ DEFINE_ACCESSOR(xy, 0)
701
+ DEFINE_ACCESSOR(ix, 0)
702
+ DEFINE_ACCESSOR(iy, 0)
703
+ DEFINE_ACCESSOR(af, 0)
704
+ DEFINE_ACCESSOR(bc, 0)
705
+ DEFINE_ACCESSOR(de, 0)
706
+ DEFINE_ACCESSOR(hl, 0)
707
+ DEFINE_ACCESSOR(af_, 0)
708
+ DEFINE_ACCESSOR(bc_, 0)
709
+ DEFINE_ACCESSOR(de_, 0)
710
+ DEFINE_ACCESSOR(hl_, 0)
711
+ DEFINE_ACCESSOR(memptrh, 0)
712
+ DEFINE_ACCESSOR(memptrl, 0)
713
+ DEFINE_ACCESSOR(pch, 0)
714
+ DEFINE_ACCESSOR(pcl, 0)
715
+ DEFINE_ACCESSOR(sph, 0)
716
+ DEFINE_ACCESSOR(spl, 0)
717
+ DEFINE_ACCESSOR(xyh, 0)
718
+ DEFINE_ACCESSOR(yl, 0)
719
+ DEFINE_ACCESSOR(ixh, 0)
720
+ DEFINE_ACCESSOR(ixl, 0)
721
+ DEFINE_ACCESSOR(iyh, 0)
722
+ DEFINE_ACCESSOR(iyl, 0)
723
+ DEFINE_ACCESSOR(a, 0)
724
+ DEFINE_ACCESSOR(f, 0)
725
+ DEFINE_ACCESSOR(b, 0)
726
+ DEFINE_ACCESSOR(c, 0)
727
+ DEFINE_ACCESSOR(d, 0)
728
+ DEFINE_ACCESSOR(e, 0)
729
+ DEFINE_ACCESSOR(h, 0)
730
+ DEFINE_ACCESSOR(l, 0)
731
+ DEFINE_ACCESSOR(a_, 0)
732
+ DEFINE_ACCESSOR(f_, 0)
733
+ DEFINE_ACCESSOR(b_, 0)
734
+ DEFINE_ACCESSOR(c_, 0)
735
+ DEFINE_ACCESSOR(d_, 0)
736
+ DEFINE_ACCESSOR(e_, 0)
737
+ DEFINE_ACCESSOR(h_, 0)
738
+ DEFINE_ACCESSOR(l_, 0)
739
+ DEFINE_ACCESSOR(r, 0)
740
+ DEFINE_ACCESSOR(i, 0)
741
+ DEFINE_ACCESSOR(r7, 0)
742
+ DEFINE_ACCESSOR(im, 0)
743
+ DEFINE_ACCESSOR(request, 0)
744
+ DEFINE_ACCESSOR(resume, 0)
745
+ DEFINE_ACCESSOR(iff1, 0)
746
+ DEFINE_ACCESSOR(iff2, 0)
747
+ DEFINE_ACCESSOR(q, 0)
748
+ DEFINE_ACCESSOR(options, 0)
749
+ DEFINE_ACCESSOR(int_line, 0)
750
+ DEFINE_ACCESSOR(halt_line, 0)
751
+ DEFINE_ACCESSOR(sf, 0)
752
+ DEFINE_ACCESSOR(zf, 0)
753
+ DEFINE_ACCESSOR(yf, 0)
754
+ DEFINE_ACCESSOR(hf, 0)
755
+ DEFINE_ACCESSOR(xf, 0)
756
+ DEFINE_ACCESSOR(pf, 0)
757
+ DEFINE_ACCESSOR(nf, 0)
758
+ DEFINE_ACCESSOR(cf, 0)
759
+
760
+ # undef DEFINE_ACCESSOR
761
+
762
+ rb_define_method(klass, "power", Z80__power, 1);
763
+ rb_define_method(klass, "instant_reset", Z80__instant_reset, 0);
764
+ rb_define_method(klass, "int", Z80__int, 1);
765
+ rb_define_method(klass, "nmi", Z80__nmi, 0);
766
+ rb_define_method(klass, "execute", Z80__execute, 1);
767
+ rb_define_method(klass, "run", Z80__run, 1);
768
+ rb_define_method(klass, "terminate", Z80__terminate, 0);
769
+ rb_define_method(klass, "full_r", Z80__refresh_address, 0);
770
+ rb_define_method(klass, "refresh_address", Z80__refresh_address, 0);
771
+ rb_define_method(klass, "in_cycle", Z80__in_cycle, 0);
772
+ rb_define_method(klass, "out_cycle", Z80__out_cycle, 0);
773
+ rb_define_method(klass, "to_h", Z80__to_h, 0);
774
+ rb_define_method(klass, "print", Z80__print, 0);
775
+ /* rb_define_method(klass, "to_s", Z80__to_s, 0);*/
776
+
777
+ rb_define_alias(klass, "t", "cycles" );
778
+ rb_define_alias(klass, "t=", "cycles=" );
779
+ rb_define_alias(klass, "wz", "memptr" );
780
+ rb_define_alias(klass, "wz=", "memptr=" );
781
+ rb_define_alias(klass, "w", "memptrh" );
782
+ rb_define_alias(klass, "w=", "memptrh=");
783
+ rb_define_alias(klass, "z", "memptrl" );
784
+ rb_define_alias(klass, "z=", "memptrl=");
785
+ rb_define_alias(klass, "vf", "pf" );
786
+ rb_define_alias(klass, "vf=", "pf=" );
787
+ rb_define_alias(klass, "state", "to_h" );
788
+ }
789
+
790
+
791
+ /* z80.c EOF */
@@ -0,0 +1,3 @@
1
+ class Z80
2
+ VERSION = '0.1.0'
3
+ end
data/lib/z80.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'z80/version'
2
+ require 'z80/z80'
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: z80
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Manuel Sainz de Baranda y Goñi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-12-24 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: 'Z80-Ruby is a Ruby binding for the Zilog Z80 CPU emulator (https://github.com/redcode/Z80).
14
+ It is ideal for analysis, hacking, testing and debugging. All from the comfort of
15
+ Ruby.
16
+
17
+ '
18
+ email: manuel@zxe.io
19
+ executables: []
20
+ extensions:
21
+ - ext/z80/extconf.rb
22
+ extra_rdoc_files: []
23
+ files:
24
+ - ".editorconfig"
25
+ - ".github/FUNDING.yml"
26
+ - ".gitignore"
27
+ - CHANGELOG.md
28
+ - LICENSE-0BSD
29
+ - README.md
30
+ - Rakefile
31
+ - ext/z80/extconf.rb
32
+ - ext/z80/z80.c
33
+ - lib/z80.rb
34
+ - lib/z80/version.rb
35
+ homepage: https://zxe.io/software/Z80
36
+ licenses:
37
+ - 0BSD
38
+ metadata:
39
+ bug_tracker_uri: https://github.com/redcode/Z80-Ruby/issues
40
+ changelog_uri: https://github.com/redcode/Z80-Ruby/blob/master/CHANGELOG.md
41
+ homepage_uri: https://zxe.io/software/Z80
42
+ source_code_uri: https://github.com/redcode/Z80-Ruby
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubygems_version: 3.5.0.dev
59
+ signing_key:
60
+ specification_version: 4
61
+ summary: Ruby binding for the Z80 library.
62
+ test_files: []