zemu 0.3.9 → 0.4.0
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/config.rb +209 -0
- data/lib/zemu/debug.rb +68 -0
- data/lib/zemu/instance.rb +11 -1
- data/lib/zemu/interactive.rb +85 -9
- data/lib/zemu.rb +1 -0
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: caa59294431c1faadda8328bc7fbefa504526ae43a5531e2cf1d6c2bc7dd5c87
|
|
4
|
+
data.tar.gz: 72ced5e284f94e586862e80e97f5d95f55a9a3dbc931dc889fdc73352cef3a82
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dbb449fa4a076320a3073391f98687098e4e0f8b484099a7ca2c67325f857e8923397267dc01c5bee521cf66e9457149a8845e15f4a8b74ae7962e1f84623ae1
|
|
7
|
+
data.tar.gz: 846f7d09837e09fdb5711ba7d3ee09ca734cf0454c10efaff77a2d92de742e88332cc2c3e008db7026c528460368e410c9c9ebaacf29694e513880255085d579
|
data/lib/zemu/config.rb
CHANGED
|
@@ -439,6 +439,215 @@ module Zemu
|
|
|
439
439
|
end
|
|
440
440
|
end
|
|
441
441
|
|
|
442
|
+
# Block drive object
|
|
443
|
+
#
|
|
444
|
+
# Represents a device with a sequence of sectors of a fixed size,
|
|
445
|
+
# which can be accessed via IO instructions as an IDE drive.
|
|
446
|
+
class BlockDrive < IOPort
|
|
447
|
+
# Constructor.
|
|
448
|
+
#
|
|
449
|
+
# Takes a block in which the parameters of the block drive
|
|
450
|
+
# can be initialized.
|
|
451
|
+
#
|
|
452
|
+
# All parameters can be set within this block.
|
|
453
|
+
# They become readonly as soon as the block completes.
|
|
454
|
+
#
|
|
455
|
+
# Constructor raises RangeError if a file is provided for initialization
|
|
456
|
+
# and it is of the wrong size.
|
|
457
|
+
#
|
|
458
|
+
# @example
|
|
459
|
+
#
|
|
460
|
+
# Zemu::Config::BlockDrive.new do
|
|
461
|
+
# name "drive"
|
|
462
|
+
# base_port 0x0c
|
|
463
|
+
# sector_size 512
|
|
464
|
+
# num_sectors 64
|
|
465
|
+
# end
|
|
466
|
+
#
|
|
467
|
+
#
|
|
468
|
+
def initialize
|
|
469
|
+
@blocks = []
|
|
470
|
+
@initialize_from = nil
|
|
471
|
+
|
|
472
|
+
super
|
|
473
|
+
|
|
474
|
+
num_sectors.times do
|
|
475
|
+
sector = []
|
|
476
|
+
sector_size.times do
|
|
477
|
+
sector << 0
|
|
478
|
+
end
|
|
479
|
+
@blocks << sector
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
# Initialize from provided file if applicable.
|
|
483
|
+
unless @initialize_from.nil?
|
|
484
|
+
# Check file size.
|
|
485
|
+
file_size = File.size(@initialize_from)
|
|
486
|
+
if (file_size != num_sectors * sector_size)
|
|
487
|
+
raise RangeError, "Initialization file for Zemu::Config::BlockDrive '#{name}' is of wrong size."
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
File.open(@initialize_from, "rb") do |f|
|
|
491
|
+
num_sectors.times do |s|
|
|
492
|
+
sector_size.times do |b|
|
|
493
|
+
@blocks[s][b] = f.getbyte()
|
|
494
|
+
end
|
|
495
|
+
end
|
|
496
|
+
end
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
when_setup do
|
|
500
|
+
<<-eos
|
|
501
|
+
#include <stdio.h>
|
|
502
|
+
|
|
503
|
+
zuint8 sector_data_#{name}[#{sector_size}];
|
|
504
|
+
zuint32 sector_data_#{name}_offset;
|
|
505
|
+
zuint32 loaded_sector_#{name} = Z_UINT32_MAXIMUM;
|
|
506
|
+
zuint8 drive_mode_#{name};
|
|
507
|
+
zuint8 drive_status_#{name} = 0b01000000;
|
|
508
|
+
|
|
509
|
+
zuint8 lba_#{name}_0;
|
|
510
|
+
zuint8 lba_#{name}_1;
|
|
511
|
+
zuint8 lba_#{name}_2;
|
|
512
|
+
zuint8 lba_#{name}_3;
|
|
513
|
+
|
|
514
|
+
void internal_#{name}_load_sector(zuint32 sector)
|
|
515
|
+
{
|
|
516
|
+
if (loaded_sector_#{name} == sector) return;
|
|
517
|
+
|
|
518
|
+
FILE * fptr = fopen("#{@initialize_from}", "rb");
|
|
519
|
+
fseek(fptr, sector * #{sector_size}, SEEK_SET);
|
|
520
|
+
fread(sector_data_#{name}, #{sector_size}, 1, fptr);
|
|
521
|
+
fclose(fptr);
|
|
522
|
+
|
|
523
|
+
loaded_sector_#{name} = sector;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
void internal_#{name}_write_current_sector()
|
|
527
|
+
{
|
|
528
|
+
FILE * fptr = fopen("#{@initialize_from}", "r+b");
|
|
529
|
+
fseek(fptr, loaded_sector_#{name} * #{sector_size}, SEEK_SET);
|
|
530
|
+
fwrite(sector_data_#{name}, 1, #{sector_size}, fptr);
|
|
531
|
+
fclose(fptr);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
zuint8 zemu_io_#{name}_readbyte(zuint32 sector, zuint32 offset)
|
|
535
|
+
{
|
|
536
|
+
internal_#{name}_load_sector(sector);
|
|
537
|
+
return sector_data_#{name}[offset];
|
|
538
|
+
}
|
|
539
|
+
eos
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
when_read do
|
|
543
|
+
<<-eos
|
|
544
|
+
if (port == #{base_port})
|
|
545
|
+
{
|
|
546
|
+
zuint8 b = sector_data_#{name}[sector_data_#{name}_offset];
|
|
547
|
+
sector_data_#{name}_offset++;
|
|
548
|
+
if (sector_data_#{name}_offset >= #{sector_size})
|
|
549
|
+
{
|
|
550
|
+
drive_status_#{name} = 0b01000000;
|
|
551
|
+
}
|
|
552
|
+
return b;
|
|
553
|
+
}
|
|
554
|
+
else if (port == #{base_port+7})
|
|
555
|
+
{
|
|
556
|
+
return drive_status_#{name};
|
|
557
|
+
}
|
|
558
|
+
eos
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
when_write do
|
|
562
|
+
<<-eos
|
|
563
|
+
if (port == #{base_port})
|
|
564
|
+
{
|
|
565
|
+
if (drive_mode_#{name} == 0x01)
|
|
566
|
+
{
|
|
567
|
+
sector_data_#{name}[sector_data_#{name}_offset] = value;
|
|
568
|
+
sector_data_#{name}_offset++;
|
|
569
|
+
if (sector_data_#{name}_offset >= #{sector_size})
|
|
570
|
+
{
|
|
571
|
+
internal_#{name}_write_current_sector();
|
|
572
|
+
drive_status_#{name} = 0b01000000;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
else if (port == #{base_port+3})
|
|
577
|
+
{
|
|
578
|
+
lba_#{name}_0 = value;
|
|
579
|
+
}
|
|
580
|
+
else if (port == #{base_port+4})
|
|
581
|
+
{
|
|
582
|
+
lba_#{name}_1 = value;
|
|
583
|
+
}
|
|
584
|
+
else if (port == #{base_port+5})
|
|
585
|
+
{
|
|
586
|
+
lba_#{name}_2 = value;
|
|
587
|
+
}
|
|
588
|
+
else if (port == #{base_port+6})
|
|
589
|
+
{
|
|
590
|
+
lba_#{name}_3 = value & 0b00011111;
|
|
591
|
+
}
|
|
592
|
+
else if (port == #{base_port+7})
|
|
593
|
+
{
|
|
594
|
+
if (value == 0x20)
|
|
595
|
+
{
|
|
596
|
+
zuint32 sector = 0;
|
|
597
|
+
sector |= (zuint32)lba_#{name}_3 << 24;
|
|
598
|
+
sector |= (zuint32)lba_#{name}_2 << 16;
|
|
599
|
+
sector |= (zuint32)lba_#{name}_1 << 8;
|
|
600
|
+
sector |= (zuint32)lba_#{name}_0;
|
|
601
|
+
|
|
602
|
+
internal_#{name}_load_sector(sector);
|
|
603
|
+
sector_data_#{name}_offset = 0;
|
|
604
|
+
|
|
605
|
+
drive_mode_#{name} = 0x00;
|
|
606
|
+
drive_status_#{name} = 0b00001000;
|
|
607
|
+
}
|
|
608
|
+
else if (value == 0x30)
|
|
609
|
+
{
|
|
610
|
+
zuint32 sector = 0;
|
|
611
|
+
sector |= (zuint32)lba_#{name}_3 << 24;
|
|
612
|
+
sector |= (zuint32)lba_#{name}_2 << 16;
|
|
613
|
+
sector |= (zuint32)lba_#{name}_1 << 8;
|
|
614
|
+
sector |= (zuint32)lba_#{name}_0;
|
|
615
|
+
|
|
616
|
+
internal_#{name}_load_sector(sector);
|
|
617
|
+
sector_data_#{name}_offset = 0;
|
|
618
|
+
|
|
619
|
+
drive_mode_#{name} = 0x01;
|
|
620
|
+
drive_status_#{name} = 0b00001000;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
eos
|
|
624
|
+
end
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
# Array of sectors of this drive.
|
|
628
|
+
def blocks
|
|
629
|
+
@blocks
|
|
630
|
+
end
|
|
631
|
+
|
|
632
|
+
# Set file to initialize from.
|
|
633
|
+
def initialize_from(file)
|
|
634
|
+
@initialize_from = file
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
# Defines FFI API which will be available to the instance wrapper if this IO device is used.
|
|
638
|
+
def functions
|
|
639
|
+
[
|
|
640
|
+
{"name" => "zemu_io_#{name}_readbyte", "args" => [:uint32, :uint32], "return" => :uint8},
|
|
641
|
+
]
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
# Valid parameters for a BlockDrive, along with those
|
|
645
|
+
# defined in [Zemu::Config::IOPort].
|
|
646
|
+
def params
|
|
647
|
+
super + %w(base_port sector_size num_sectors)
|
|
648
|
+
end
|
|
649
|
+
end
|
|
650
|
+
|
|
442
651
|
# Non-Maskable Interrupt Timer
|
|
443
652
|
#
|
|
444
653
|
# Represents a timer device, the period of which can be controlled
|
data/lib/zemu/debug.rb
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
module Zemu
|
|
2
|
+
# Handles debugging functionality, like mapping of symbols to addresses,
|
|
3
|
+
# disassembling of instructions, etc.
|
|
4
|
+
module Debug
|
|
5
|
+
# Loads a map file at the given path, and returns a hash of address => Symbol
|
|
6
|
+
# for the symbols defined within.
|
|
7
|
+
def self.load_map(path)
|
|
8
|
+
symbols = {}
|
|
9
|
+
|
|
10
|
+
File.open(path, "r") do |f|
|
|
11
|
+
f.each_line do |l|
|
|
12
|
+
s = Symbol.parse(l)
|
|
13
|
+
|
|
14
|
+
if symbols[s.address].nil?
|
|
15
|
+
symbols[s.address] = []
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
symbols[s.address] << s
|
|
19
|
+
symbols[s.address].sort_by!(&:label)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
return symbols
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Represents a symbol definition, of the form `label = address`.
|
|
27
|
+
class Symbol
|
|
28
|
+
# Parse a symbol definition, returning a Symbol instance.
|
|
29
|
+
def self.parse(s)
|
|
30
|
+
# Split on whitespace.
|
|
31
|
+
tokens = s.to_s.split(' ')
|
|
32
|
+
|
|
33
|
+
if tokens.size < 3
|
|
34
|
+
raise ArgumentError, "Invalid symbol definition: '#{s}'"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
label = tokens[0]
|
|
38
|
+
|
|
39
|
+
address = nil
|
|
40
|
+
|
|
41
|
+
if /0x[0-9a-fA-F]+/ =~ tokens[2]
|
|
42
|
+
address = tokens[2][2..-1].to_i(16)
|
|
43
|
+
elsif /\$[0-9a-fA-F]+/ =~ tokens[2]
|
|
44
|
+
address = tokens[2][1..-1].to_i(16)
|
|
45
|
+
elsif /\d+/ =~ tokens[2]
|
|
46
|
+
address = tokens[2].to_i
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
if address.nil?
|
|
50
|
+
raise ArgumentError, "Invalid symbol address: '#{tokens[2]}'"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
return self.new(label, address)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Textual label for this symbol.
|
|
57
|
+
attr_reader :label
|
|
58
|
+
|
|
59
|
+
# Address of this symbol in the binary.
|
|
60
|
+
attr_reader :address
|
|
61
|
+
|
|
62
|
+
def initialize(label, address)
|
|
63
|
+
@label = label
|
|
64
|
+
@address = address
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
data/lib/zemu/instance.rb
CHANGED
|
@@ -142,6 +142,16 @@ module Zemu
|
|
|
142
142
|
return return_string
|
|
143
143
|
end
|
|
144
144
|
|
|
145
|
+
# Get a byte from the attached disk drive.
|
|
146
|
+
#
|
|
147
|
+
# @param sector The sector to read
|
|
148
|
+
# @param offset The offset in sector to read
|
|
149
|
+
#
|
|
150
|
+
# Gets a byte at the given offset in the given sector.
|
|
151
|
+
def drive_readbyte(sector, offset)
|
|
152
|
+
return @wrapper.zemu_io_block_drive_readbyte(sector, offset)
|
|
153
|
+
end
|
|
154
|
+
|
|
145
155
|
# Continue running this instance until either:
|
|
146
156
|
# * A HALT instruction is executed
|
|
147
157
|
# * A breakpoint is hit
|
|
@@ -238,7 +248,7 @@ module Zemu
|
|
|
238
248
|
|
|
239
249
|
configuration.io.each do |device|
|
|
240
250
|
device.functions.each do |f|
|
|
241
|
-
wrapper.attach_function(f["name"], f["args"], f["return"])
|
|
251
|
+
wrapper.attach_function(f["name"].to_sym, f["args"], f["return"])
|
|
242
252
|
end
|
|
243
253
|
end
|
|
244
254
|
|
data/lib/zemu/interactive.rb
CHANGED
|
@@ -8,6 +8,8 @@ module Zemu
|
|
|
8
8
|
def initialize(instance)
|
|
9
9
|
@instance = instance
|
|
10
10
|
|
|
11
|
+
@symbol_table = {}
|
|
12
|
+
|
|
11
13
|
@master, @slave = PTY.open
|
|
12
14
|
log "Opened PTY at #{@slave.path}"
|
|
13
15
|
end
|
|
@@ -59,6 +61,9 @@ module Zemu
|
|
|
59
61
|
memory(cmd[1], cmd[2])
|
|
60
62
|
end
|
|
61
63
|
|
|
64
|
+
elsif cmd[0] == "map"
|
|
65
|
+
load_map(cmd[1])
|
|
66
|
+
|
|
62
67
|
elsif cmd[0] == "help"
|
|
63
68
|
log "Available commands:"
|
|
64
69
|
log " continue [<n>] - Continue execution for <n> cycles"
|
|
@@ -66,6 +71,7 @@ module Zemu
|
|
|
66
71
|
log " registers - View register contents"
|
|
67
72
|
log " memory <a> [<n>] - View <n> bytes of memory, starting at address <a>."
|
|
68
73
|
log " <n> defaults to 1 if omitted."
|
|
74
|
+
log " map <path> - Load symbols from map file at <path>"
|
|
69
75
|
log " break <a> - Set a breakpoint at the given address <a>."
|
|
70
76
|
log " quit - End this emulator instance."
|
|
71
77
|
|
|
@@ -79,16 +85,53 @@ module Zemu
|
|
|
79
85
|
end
|
|
80
86
|
|
|
81
87
|
# Outputs a table giving the current values of the instance's registers.
|
|
88
|
+
# For the 16-bit registers (BC, DE, HL, IX, IY, SP, PC), attempts to identify the symbol
|
|
89
|
+
# to which they point.
|
|
82
90
|
def registers
|
|
83
91
|
log "A: #{r("A")} F: #{r("F")}"
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
92
|
+
|
|
93
|
+
registers_gp('B', 'C')
|
|
94
|
+
registers_gp('D', 'E')
|
|
95
|
+
registers_gp('H', 'L')
|
|
96
|
+
|
|
87
97
|
log ""
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
98
|
+
|
|
99
|
+
register_16("IX")
|
|
100
|
+
register_16("IY")
|
|
101
|
+
register_16("SP")
|
|
102
|
+
register_16("PC")
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Displays the value of a 16-bit register.
|
|
106
|
+
def register_16(r)
|
|
107
|
+
value = @instance.registers[r]
|
|
108
|
+
|
|
109
|
+
log "#{r}: #{r16(r)} (#{get_symbol(value)})"
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Displays the value of a general-purpose 16-bit register pair.
|
|
113
|
+
def registers_gp(hi, lo)
|
|
114
|
+
value = hilo(@instance.registers[hi], @instance.registers[lo])
|
|
115
|
+
|
|
116
|
+
log "#{hi}: #{r(hi)} #{lo}: #{r(lo)} (#{get_symbol(value)})"
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Gets the symbol associated with the given value.
|
|
120
|
+
# If no matching symbol, gives offset from previous symbol.
|
|
121
|
+
def get_symbol(value)
|
|
122
|
+
syms = nil
|
|
123
|
+
addr = value
|
|
124
|
+
while addr > 0 do
|
|
125
|
+
syms = @symbol_table[addr]
|
|
126
|
+
break unless syms.nil?
|
|
127
|
+
addr -= 1
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
sym = if syms.nil? then nil else syms[0] end
|
|
131
|
+
|
|
132
|
+
sym_str = "<#{if sym.nil? then 'undefined' else sym.label end}#{if addr == value then '' else "+#{value-addr}" end}>"
|
|
133
|
+
|
|
134
|
+
return sym_str
|
|
92
135
|
end
|
|
93
136
|
|
|
94
137
|
# Returns a particular 8-bit register value.
|
|
@@ -101,6 +144,11 @@ module Zemu
|
|
|
101
144
|
return "0x%04x" % @instance.registers[reg]
|
|
102
145
|
end
|
|
103
146
|
|
|
147
|
+
# Concatenates two 8-bit values, in big-endian format.
|
|
148
|
+
def hilo(hi, lo)
|
|
149
|
+
return (hi << 8) | lo
|
|
150
|
+
end
|
|
151
|
+
|
|
104
152
|
# Continue for *up to* the given number of cycles.
|
|
105
153
|
# Fewer cycles may be executed, depending on the behaviour of the processor.
|
|
106
154
|
def continue(cycles=-1)
|
|
@@ -114,7 +162,7 @@ module Zemu
|
|
|
114
162
|
cycles_left = cycles
|
|
115
163
|
actual_cycles = 0
|
|
116
164
|
|
|
117
|
-
serial_count = @instance.serial_delay
|
|
165
|
+
serial_count = @instance.serial_delay.to_f
|
|
118
166
|
|
|
119
167
|
while ((cycles == -1) || (cycles_left > 0))
|
|
120
168
|
# Get time before execution.
|
|
@@ -124,7 +172,7 @@ module Zemu
|
|
|
124
172
|
|
|
125
173
|
if (serial_count >= @instance.serial_delay)
|
|
126
174
|
process_serial
|
|
127
|
-
serial_count = 0
|
|
175
|
+
serial_count = 0.0
|
|
128
176
|
end
|
|
129
177
|
|
|
130
178
|
cycles_done = @instance.continue(1)
|
|
@@ -185,6 +233,34 @@ module Zemu
|
|
|
185
233
|
end
|
|
186
234
|
end
|
|
187
235
|
|
|
236
|
+
# Loads a MAP file from the given path.
|
|
237
|
+
def load_map(path)
|
|
238
|
+
if path.nil?
|
|
239
|
+
log "No path specified."
|
|
240
|
+
return
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
unless File.exist?(path.to_s)
|
|
244
|
+
log "Map file '#{path}' does not exist."
|
|
245
|
+
return
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
if File.directory?(path.to_s)
|
|
249
|
+
log "Cannot open '#{path}': it is a directory."
|
|
250
|
+
return
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
syms = {}
|
|
254
|
+
begin
|
|
255
|
+
syms.merge! Debug.load_map(path.to_s)
|
|
256
|
+
rescue ArgumentError => e
|
|
257
|
+
log "Error loading map file: #{e.message}"
|
|
258
|
+
syms.clear
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
@symbol_table.merge! syms
|
|
262
|
+
end
|
|
263
|
+
|
|
188
264
|
# Process serial input/output via the TTY.
|
|
189
265
|
def process_serial
|
|
190
266
|
# Read/write serial.
|
data/lib/zemu.rb
CHANGED
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.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jay Valentine
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-10-23 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
|
|
@@ -29,6 +29,7 @@ extra_rdoc_files: []
|
|
|
29
29
|
files:
|
|
30
30
|
- lib/zemu.rb
|
|
31
31
|
- lib/zemu/config.rb
|
|
32
|
+
- lib/zemu/debug.rb
|
|
32
33
|
- lib/zemu/instance.rb
|
|
33
34
|
- lib/zemu/interactive.rb
|
|
34
35
|
- src/debug.c
|
|
@@ -333,8 +334,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
333
334
|
- !ruby/object:Gem::Version
|
|
334
335
|
version: '0'
|
|
335
336
|
requirements: []
|
|
336
|
-
|
|
337
|
-
rubygems_version: 2.7.6
|
|
337
|
+
rubygems_version: 3.1.2
|
|
338
338
|
signing_key:
|
|
339
339
|
specification_version: 4
|
|
340
340
|
summary: A configurable Z80 emulator.
|