zemu 0.2.2 → 0.3.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/zemu.rb +1 -1
- data/lib/zemu/config.rb +80 -10
- data/lib/zemu/instance.rb +65 -8
- data/lib/zemu/interactive.rb +11 -3
- data/src/debug.c +13 -61
- data/src/debug.h +5 -17
- data/src/io.c.erb +22 -0
- data/src/io.h.erb +7 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3278a3fa602a14489f1bfe77bee8d51781be503fac50dba4334dd400f492b5ca
|
4
|
+
data.tar.gz: 0dc3644e09613e7449bbc2dd3167f4823fca647cd0b5df94b35a0d39768a8b26
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bb87eef723a62c64742f06ec85bf7f5c976103c6e5b8678b5efec665b49ea3242efe59238f1ea28808c7ef3e597471ec050cda5f0152f3c74fa900f88df294ea
|
7
|
+
data.tar.gz: 29de4f2e78acae5a24a443595e3b683acb3fd3a6d00ec84991c1126e3e7b07ce35078de8721347ec84926ee99fd2bd21912b1ef768fa868c0d1cc75ae966db02
|
data/lib/zemu.rb
CHANGED
@@ -128,7 +128,7 @@ module Zemu
|
|
128
128
|
|
129
129
|
includes_str += " -I" + autogen
|
130
130
|
|
131
|
-
command = "#{compiler} -Werror -Wno-unknown-warning-option -fPIC -shared -Wl,-undefined -Wl,dynamic_lookup #{includes_str} #{defines_str} -o #{output} #{inputs_str}"
|
131
|
+
command = "#{compiler} -O2 -Werror -Wno-unknown-warning-option -fPIC -shared -Wl,-undefined -Wl,dynamic_lookup #{includes_str} #{defines_str} -o #{output} #{inputs_str}"
|
132
132
|
|
133
133
|
# Run the compiler and generate a library.
|
134
134
|
return system(command)
|
data/lib/zemu/config.rb
CHANGED
@@ -228,6 +228,10 @@ module Zemu
|
|
228
228
|
end
|
229
229
|
|
230
230
|
@ports = []
|
231
|
+
@setup_block = nil
|
232
|
+
@read_block = nil
|
233
|
+
@write_block = nil
|
234
|
+
@clock_block = nil
|
231
235
|
|
232
236
|
super
|
233
237
|
end
|
@@ -269,28 +273,46 @@ module Zemu
|
|
269
273
|
@write_block = block
|
270
274
|
end
|
271
275
|
|
276
|
+
# Defines the per-cycle behaviour of this IO device.
|
277
|
+
#
|
278
|
+
# Expects a block, the return value of which is a string
|
279
|
+
# defining the behaviour of the IO device on each system clock cycle.
|
280
|
+
# Care must be taken to ensure that this functionality does not conflict with that of
|
281
|
+
# any other IO devices.
|
282
|
+
#
|
283
|
+
# The block will be instance-evaluated at build-time, so it is possible to use
|
284
|
+
# instance variables of the IO device.
|
285
|
+
def when_clock(&block)
|
286
|
+
@clock_block = block
|
287
|
+
end
|
288
|
+
|
272
289
|
# Evaluates the when_setup block of this IO device and returns the resulting string.
|
273
290
|
def setup
|
274
|
-
instance_eval(&@setup_block)
|
291
|
+
return instance_eval(&@setup_block) unless @setup_block.nil?
|
292
|
+
return ""
|
275
293
|
end
|
276
294
|
|
277
295
|
# Evaluates the when_read block of this IO device and returns the resulting string.
|
278
296
|
def read
|
279
|
-
instance_eval(&@read_block)
|
297
|
+
return instance_eval(&@read_block) unless @read_block.nil?
|
298
|
+
return ""
|
280
299
|
end
|
281
300
|
|
282
301
|
# Evaluates the when_write block of this IO device and returns the resulting string.
|
283
302
|
def write
|
284
|
-
instance_eval(&@write_block)
|
303
|
+
return instance_eval(&@write_block) unless @write_block.nil?
|
304
|
+
return ""
|
305
|
+
end
|
306
|
+
|
307
|
+
# Evaluates the when_clock block of this IO device and returns the resulting string.
|
308
|
+
def clock
|
309
|
+
return instance_eval(&@clock_block) unless @clock_block.nil?
|
310
|
+
return ""
|
285
311
|
end
|
286
312
|
|
287
313
|
# Defines FFI API which will be available to the instance wrapper if this IO device is used.
|
288
314
|
def functions
|
289
|
-
[
|
290
|
-
{"name" => "zemu_io_#{name}_master_puts".to_sym, "args" => [:uint8], "return" => :void},
|
291
|
-
{"name" => "zemu_io_#{name}_master_gets".to_sym, "args" => [], "return" => :uint8},
|
292
|
-
{"name" => "zemu_io_#{name}_buffer_size".to_sym, "args" => [], "return" => :uint64}
|
293
|
-
]
|
315
|
+
[]
|
294
316
|
end
|
295
317
|
|
296
318
|
# Valid parameters for this object.
|
@@ -401,6 +423,15 @@ module Zemu
|
|
401
423
|
end
|
402
424
|
end
|
403
425
|
|
426
|
+
# Defines FFI API which will be available to the instance wrapper if this IO device is used.
|
427
|
+
def functions
|
428
|
+
[
|
429
|
+
{"name" => "zemu_io_#{name}_master_puts".to_sym, "args" => [:uint8], "return" => :void},
|
430
|
+
{"name" => "zemu_io_#{name}_master_gets".to_sym, "args" => [], "return" => :uint8},
|
431
|
+
{"name" => "zemu_io_#{name}_buffer_size".to_sym, "args" => [], "return" => :uint64}
|
432
|
+
]
|
433
|
+
end
|
434
|
+
|
404
435
|
# Valid parameters for a SerialPort, along with those
|
405
436
|
# defined in [Zemu::Config::IOPort].
|
406
437
|
def params
|
@@ -408,6 +439,44 @@ module Zemu
|
|
408
439
|
end
|
409
440
|
end
|
410
441
|
|
442
|
+
# Non-Maskable Interrupt Timer
|
443
|
+
#
|
444
|
+
# Represents a timer device, the period of which can be controlled
|
445
|
+
# by the CPU through an IO port. The timer generates an NMI once this
|
446
|
+
# period has expired. The timer can be reset via a control port.
|
447
|
+
class Timer < IOPort
|
448
|
+
def initialize
|
449
|
+
super
|
450
|
+
|
451
|
+
when_setup do
|
452
|
+
"zuint8 io_#{name}_count;\n" +
|
453
|
+
"zuint8 io_#{name}_running = 0;\n"
|
454
|
+
end
|
455
|
+
|
456
|
+
when_read do
|
457
|
+
end
|
458
|
+
|
459
|
+
when_write do
|
460
|
+
"if (port == #{count_port}) io_#{name}_count = value;\n" +
|
461
|
+
"else if (port == #{control_port}) io_#{name}_running = value;\n"
|
462
|
+
end
|
463
|
+
|
464
|
+
when_clock do
|
465
|
+
"if (io_#{name}_running)\n" +
|
466
|
+
"{\n" +
|
467
|
+
" if (io_#{name}_count > 0) io_#{name}_count--;\n" +
|
468
|
+
" else zemu_io_nmi(instance);\n" +
|
469
|
+
"}\n"
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
# Valid parameters for a Timer, along with those defined in
|
474
|
+
# [Zemu::Config::IOPort].
|
475
|
+
def params
|
476
|
+
super + %w(count_port control_port)
|
477
|
+
end
|
478
|
+
end
|
479
|
+
|
411
480
|
# Gets a binding for this object.
|
412
481
|
def get_binding
|
413
482
|
return binding
|
@@ -421,7 +490,7 @@ module Zemu
|
|
421
490
|
|
422
491
|
# Parameters accessible by this configuration object.
|
423
492
|
def params
|
424
|
-
return %w(name compiler output_directory clock_speed)
|
493
|
+
return %w(name compiler output_directory clock_speed serial_delay)
|
425
494
|
end
|
426
495
|
|
427
496
|
# Initial value for parameters of this configuration object.
|
@@ -429,7 +498,8 @@ module Zemu
|
|
429
498
|
return {
|
430
499
|
"compiler" => "clang",
|
431
500
|
"output_directory" => "bin",
|
432
|
-
"clock_speed" => 0
|
501
|
+
"clock_speed" => 0,
|
502
|
+
"serial_delay" => 0
|
433
503
|
}
|
434
504
|
end
|
435
505
|
|
data/lib/zemu/instance.rb
CHANGED
@@ -37,8 +37,24 @@ module Zemu
|
|
37
37
|
"L'" => 19
|
38
38
|
}
|
39
39
|
|
40
|
+
# States that the emulated machine can be in.
|
41
|
+
class RunState
|
42
|
+
# Currently executing an instruction.
|
43
|
+
RUNNING = 0
|
44
|
+
|
45
|
+
# Executed a HALT instruction in the previous cycle.
|
46
|
+
HALTED = 1
|
47
|
+
|
48
|
+
# Hit a breakpoint in the previous cycle.
|
49
|
+
BREAK = 2
|
50
|
+
|
51
|
+
# Undefined. Emulated machine has not yet reached a well-defined state.
|
52
|
+
UNDEFINED = -1
|
53
|
+
end
|
54
|
+
|
40
55
|
def initialize(configuration)
|
41
56
|
@clock = configuration.clock_speed
|
57
|
+
@serial_delay = configuration.serial_delay
|
42
58
|
|
43
59
|
@wrapper = make_wrapper(configuration)
|
44
60
|
|
@@ -47,6 +63,10 @@ module Zemu
|
|
47
63
|
@instance = @wrapper.zemu_init
|
48
64
|
@wrapper.zemu_power_on(@instance)
|
49
65
|
@wrapper.zemu_reset(@instance)
|
66
|
+
|
67
|
+
@state = RunState::UNDEFINED
|
68
|
+
|
69
|
+
@breakpoints = {}
|
50
70
|
end
|
51
71
|
|
52
72
|
# Returns the clock speed of this instance in Hz.
|
@@ -54,6 +74,11 @@ module Zemu
|
|
54
74
|
return @clock
|
55
75
|
end
|
56
76
|
|
77
|
+
# Returns the delay between characters on the serial port for this instance in seconds.
|
78
|
+
def serial_delay
|
79
|
+
return @serial_delay
|
80
|
+
end
|
81
|
+
|
57
82
|
# Returns a hash containing current values of the emulated
|
58
83
|
# machine's registers. All names are as those given in the Z80
|
59
84
|
# reference manual.
|
@@ -124,7 +149,32 @@ module Zemu
|
|
124
149
|
#
|
125
150
|
# Returns the number of cycles executed.
|
126
151
|
def continue(run_cycles=-1)
|
127
|
-
|
152
|
+
# Return immediately if we're HALTED.
|
153
|
+
return if @state == RunState::HALTED
|
154
|
+
|
155
|
+
cycles_executed = 0
|
156
|
+
|
157
|
+
@state = RunState::RUNNING
|
158
|
+
|
159
|
+
# Run as long as:
|
160
|
+
# We haven't hit a breakpoint
|
161
|
+
# We haven't halted
|
162
|
+
# We haven't hit the number of cycles we've been told to execute for.
|
163
|
+
while (run_cycles == -1 || cycles_executed < run_cycles) && (@state == RunState::RUNNING)
|
164
|
+
cycles_executed += @wrapper.zemu_debug_step(@instance)
|
165
|
+
|
166
|
+
pc = @wrapper.zemu_debug_pc(@instance)
|
167
|
+
|
168
|
+
# If the PC is now pointing to one of our breakpoints,
|
169
|
+
# we're in the BREAK state.
|
170
|
+
if @breakpoints[pc]
|
171
|
+
@state = RunState::BREAK
|
172
|
+
elsif @wrapper.zemu_debug_halted()
|
173
|
+
@state = RunState::HALTED
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
return cycles_executed
|
128
178
|
end
|
129
179
|
|
130
180
|
# Set a breakpoint of the given type at the given address.
|
@@ -133,17 +183,26 @@ module Zemu
|
|
133
183
|
# @param type The type of breakpoint:
|
134
184
|
# * :program => Break when the program counter hits the address given.
|
135
185
|
def break(address, type)
|
136
|
-
@
|
186
|
+
@breakpoints[address] = true
|
187
|
+
end
|
188
|
+
|
189
|
+
# Remove a breakpoint of the given type at the given address.
|
190
|
+
# Does nothing if no breakpoint previously existed at that address.
|
191
|
+
#
|
192
|
+
# @param address The address of the breakpoint to be removed.
|
193
|
+
# @param type The type of breakpoint. See Instance#break.
|
194
|
+
def remove_break(address, type)
|
195
|
+
@breakpoints[address] = false
|
137
196
|
end
|
138
197
|
|
139
198
|
# Returns true if the CPU has halted, false otherwise.
|
140
199
|
def halted?
|
141
|
-
return @
|
200
|
+
return @state == RunState::HALTED
|
142
201
|
end
|
143
202
|
|
144
203
|
# Returns true if a breakpoint has been hit, false otherwise.
|
145
204
|
def break?
|
146
|
-
return @
|
205
|
+
return @state == RunState::BREAK
|
147
206
|
end
|
148
207
|
|
149
208
|
# Powers off the emulated CPU and destroys this instance.
|
@@ -168,14 +227,12 @@ module Zemu
|
|
168
227
|
|
169
228
|
wrapper.attach_function :zemu_reset, [:pointer], :void
|
170
229
|
|
171
|
-
wrapper.attach_function :
|
230
|
+
wrapper.attach_function :zemu_debug_step, [:pointer], :uint64
|
172
231
|
|
173
232
|
wrapper.attach_function :zemu_debug_halted, [], :bool
|
174
|
-
wrapper.attach_function :zemu_debug_break, [], :bool
|
175
|
-
|
176
|
-
wrapper.attach_function :zemu_debug_set_breakpoint, [:uint16], :void
|
177
233
|
|
178
234
|
wrapper.attach_function :zemu_debug_register, [:pointer, :uint16], :uint16
|
235
|
+
wrapper.attach_function :zemu_debug_pc, [:pointer], :uint16
|
179
236
|
|
180
237
|
wrapper.attach_function :zemu_debug_get_memory, [:uint16], :uint8
|
181
238
|
|
data/lib/zemu/interactive.rb
CHANGED
@@ -114,13 +114,19 @@ module Zemu
|
|
114
114
|
cycles_left = cycles
|
115
115
|
actual_cycles = 0
|
116
116
|
|
117
|
+
serial_count = @instance.serial_delay
|
118
|
+
|
117
119
|
while ((cycles == -1) || (cycles_left > 0))
|
118
120
|
# Get time before execution.
|
119
121
|
start = Time.now
|
120
122
|
|
121
123
|
old_pc = r16("PC")
|
122
124
|
|
123
|
-
|
125
|
+
if (serial_count >= @instance.serial_delay)
|
126
|
+
process_serial
|
127
|
+
serial_count = 0
|
128
|
+
end
|
129
|
+
|
124
130
|
cycles_done = @instance.continue(1)
|
125
131
|
cycles_left -= cycles_done
|
126
132
|
actual_cycles += cycles_done
|
@@ -132,7 +138,9 @@ module Zemu
|
|
132
138
|
if @instance.clock_speed > 0
|
133
139
|
elapsed = ending - start
|
134
140
|
|
135
|
-
execution_time =
|
141
|
+
execution_time = cycles_done * (1.0/@instance.clock_speed)
|
142
|
+
serial_count += execution_time
|
143
|
+
|
136
144
|
padding = execution_time - elapsed
|
137
145
|
sleep(padding) unless padding < 0
|
138
146
|
end
|
@@ -169,7 +177,7 @@ module Zemu
|
|
169
177
|
|
170
178
|
(address.to_i(16)...address.to_i(16) + size.to_i(16)).each do |a|
|
171
179
|
m = @instance.memory(a)
|
172
|
-
if (m < 32)
|
180
|
+
if (m < 32 || m > 126)
|
173
181
|
log "%04x: %02x ." % [a, m]
|
174
182
|
else
|
175
183
|
log ("%04x: %02x " % [a, m]) + m.chr("UTF-8")
|
data/src/debug.c
CHANGED
@@ -1,69 +1,16 @@
|
|
1
1
|
#include "debug.h"
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
/* Currently, the number of breakpoints is defined statically.
|
6
|
-
* Perhaps in future there will be an unlimited number.
|
7
|
-
*/
|
8
|
-
zuint16 breakpoints[ZEMU_DEBUG_MAX_BREAKPOINTS];
|
9
|
-
unsigned int breakpoint_count = 0;
|
10
|
-
|
11
|
-
zusize zemu_debug_continue(Z80 * instance, zinteger run_cycles)
|
12
|
-
{
|
13
|
-
/* Return if we've halted. */
|
14
|
-
if (zemu_debug_state == HALTED) return 0;
|
15
|
-
|
16
|
-
zusize cycles = 0;
|
17
|
-
|
18
|
-
zemu_debug_state = RUNNING;
|
19
|
-
|
20
|
-
/* Run as long as:
|
21
|
-
* We don't hit a breakpoint
|
22
|
-
* We haven't run for more than the number of cycles given
|
23
|
-
*/
|
24
|
-
while (zemu_debug_state == RUNNING && (run_cycles < 0 || cycles < run_cycles))
|
25
|
-
{
|
26
|
-
cycles += zemu_debug_step(instance);
|
27
|
-
|
28
|
-
/* See if the Program Counter now matches any address
|
29
|
-
* in the breakpoint array.
|
30
|
-
*/
|
31
|
-
for (unsigned int b = 0; b < breakpoint_count; b++)
|
32
|
-
{
|
33
|
-
if (instance->state.pc == breakpoints[b])
|
34
|
-
{
|
35
|
-
zemu_debug_state = BREAK;
|
36
|
-
}
|
37
|
-
}
|
38
|
-
}
|
39
|
-
|
40
|
-
return cycles;
|
41
|
-
}
|
3
|
+
zboolean halted = FALSE;
|
42
4
|
|
43
5
|
zusize zemu_debug_step(Z80 * instance)
|
44
6
|
{
|
45
7
|
/* Will run for at least one cycle. */
|
46
8
|
zusize cycles = z80_run(instance, 1);
|
47
9
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
void zemu_debug_halt(void * context, zboolean state)
|
52
|
-
{
|
53
|
-
if (state)
|
54
|
-
{
|
55
|
-
zemu_debug_state = HALTED;
|
56
|
-
}
|
57
|
-
else
|
58
|
-
{
|
59
|
-
zemu_debug_state = RUNNING;
|
60
|
-
}
|
61
|
-
}
|
10
|
+
/* Execute the per-cycle behaviour of the peripheral devices. */
|
11
|
+
for (zusize i = 0; i < cycles; i++) zemu_io_clock(instance);
|
62
12
|
|
63
|
-
|
64
|
-
{
|
65
|
-
breakpoints[breakpoint_count] = address;
|
66
|
-
breakpoint_count++;
|
13
|
+
return cycles;
|
67
14
|
}
|
68
15
|
|
69
16
|
zuint16 zemu_debug_register(Z80 * instance, zuint16 r)
|
@@ -106,14 +53,19 @@ zuint16 zemu_debug_register(Z80 * instance, zuint16 r)
|
|
106
53
|
}
|
107
54
|
}
|
108
55
|
|
109
|
-
|
56
|
+
zuint16 zemu_debug_pc(Z80 * instance)
|
57
|
+
{
|
58
|
+
return instance->state.pc;
|
59
|
+
}
|
60
|
+
|
61
|
+
void zemu_debug_halt(void * context, zboolean state)
|
110
62
|
{
|
111
|
-
|
63
|
+
halted = state;
|
112
64
|
}
|
113
65
|
|
114
|
-
zboolean
|
66
|
+
zboolean zemu_debug_halted(void)
|
115
67
|
{
|
116
|
-
return (
|
68
|
+
return (halted);
|
117
69
|
}
|
118
70
|
|
119
71
|
zuint8 zemu_debug_get_memory(zuint16 address)
|
data/src/debug.h
CHANGED
@@ -3,28 +3,16 @@
|
|
3
3
|
#include <stdio.h>
|
4
4
|
|
5
5
|
#include "memory.h"
|
6
|
-
|
7
|
-
/* Define number of breakpoints, if not done so already. */
|
8
|
-
#ifndef ZEMU_DEBUG_MAX_BREAKPOINTS
|
9
|
-
#define ZEMU_DEBUG_MAX_BREAKPOINTS 256
|
10
|
-
#endif
|
11
|
-
|
12
|
-
typedef enum RunState
|
13
|
-
{
|
14
|
-
RUNNING,
|
15
|
-
HALTED,
|
16
|
-
BREAK,
|
17
|
-
UNDEFINED
|
18
|
-
} RunState;
|
19
|
-
|
20
|
-
zusize zemu_debug_continue(Z80 * instance, zinteger run_cycles);
|
6
|
+
#include "io.h"
|
21
7
|
|
22
8
|
zusize zemu_debug_step(Z80 * instance);
|
23
9
|
|
24
10
|
void zemu_debug_halt(void * context, zboolean state);
|
25
11
|
|
26
12
|
zboolean zemu_debug_halted(void);
|
27
|
-
|
28
|
-
|
13
|
+
zboolean zemu_debug_break(void);
|
14
|
+
zboolean zemu_debug_running(void);
|
29
15
|
|
30
16
|
zuint16 zemu_debug_register(Z80 * instance, zuint16 r);
|
17
|
+
|
18
|
+
zuint16 zemu_debug_pc(Z80 * instance);
|
data/src/io.c.erb
CHANGED
@@ -4,6 +4,21 @@
|
|
4
4
|
<%= device.setup %>
|
5
5
|
<% end %>
|
6
6
|
|
7
|
+
void zemu_io_nmi(Z80 * instance)
|
8
|
+
{
|
9
|
+
z80_nmi(instance);
|
10
|
+
}
|
11
|
+
|
12
|
+
void zemu_io_int_on(Z80 * instance)
|
13
|
+
{
|
14
|
+
z80_int(instance, TRUE);
|
15
|
+
}
|
16
|
+
|
17
|
+
void zemu_io_int_off(Z80 * instance)
|
18
|
+
{
|
19
|
+
z80_int(instance, FALSE);
|
20
|
+
}
|
21
|
+
|
7
22
|
zuint8 zemu_io_in(void * context, zuint16 port)
|
8
23
|
{
|
9
24
|
/* Z80 IO ports occupy the lower half of the address bus.
|
@@ -28,3 +43,10 @@ void zemu_io_out(void * context, zuint16 port, zuint8 value)
|
|
28
43
|
<%= device.write %>
|
29
44
|
<% end %>
|
30
45
|
}
|
46
|
+
|
47
|
+
void zemu_io_clock(Z80 * instance)
|
48
|
+
{
|
49
|
+
<% io.each do |device| %>
|
50
|
+
<%= device.clock %>
|
51
|
+
<% end %>
|
52
|
+
}
|
data/src/io.h.erb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
#ifndef _ZEMU_IO_H
|
2
|
+
#define _ZEMU_IO_H
|
3
|
+
|
1
4
|
#include "emulation/CPU/Z80.h"
|
2
5
|
|
3
6
|
#ifndef ZEMU_IO_SERIAL_BUFFER_SIZE
|
@@ -16,3 +19,7 @@ zusize zemu_io_serial_buffer_size(void);
|
|
16
19
|
|
17
20
|
zuint8 zemu_io_in(void * context, zuint16 port);
|
18
21
|
void zemu_io_out(void * context, zuint16 port, zuint8 value);
|
22
|
+
void zemu_io_nmi(Z80 * instance);
|
23
|
+
void zemu_io_clock(Z80 * instance);
|
24
|
+
|
25
|
+
#endif
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zemu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jay Valentine
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-08-26 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |2
|
14
14
|
Zemu is a gem which allows the user to configure a Z80-based system
|