zemu 0.4.2 → 1.1.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 +424 -384
- data/lib/zemu/debug.rb +39 -6
- data/lib/zemu/instance.rb +145 -8
- data/lib/zemu/interactive.rb +13 -12
- data/lib/zemu.rb +8 -27
- data/src/bus.c.erb +119 -0
- data/src/bus.h.erb +53 -0
- data/src/debug.c +1 -1
- data/src/debug.h +1 -2
- data/src/main.c +1 -2
- metadata +4 -6
- data/src/io.c.erb +0 -52
- data/src/io.h.erb +0 -25
- data/src/memory.c.erb +0 -59
- data/src/memory.h.erb +0 -11
data/lib/zemu/debug.rb
CHANGED
@@ -5,22 +5,55 @@ module Zemu
|
|
5
5
|
# Loads a map file at the given path, and returns a hash of address => Symbol
|
6
6
|
# for the symbols defined within.
|
7
7
|
def self.load_map(path)
|
8
|
-
symbols =
|
8
|
+
symbols = []
|
9
9
|
|
10
10
|
File.open(path, "r") do |f|
|
11
11
|
f.each_line do |l|
|
12
12
|
s = Symbol.parse(l)
|
13
13
|
|
14
|
-
|
15
|
-
|
14
|
+
symbols << s
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
return Symbols.new(symbols)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Contains a set of symbols.
|
22
|
+
# Allows for various lookup operations.
|
23
|
+
class Symbols
|
24
|
+
# Constructor.
|
25
|
+
def initialize(syms)
|
26
|
+
@syms = []
|
27
|
+
syms.each do |s|
|
28
|
+
@syms << s
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Access all symbols with a given address.
|
33
|
+
def [](address)
|
34
|
+
at_address = []
|
35
|
+
@syms.each do |s|
|
36
|
+
if s.address == address
|
37
|
+
at_address << s
|
16
38
|
end
|
39
|
+
end
|
40
|
+
|
41
|
+
return at_address.sort_by(&:label)
|
42
|
+
end
|
17
43
|
|
18
|
-
|
19
|
-
|
44
|
+
# Find a symbol with a given name.
|
45
|
+
def find_by_name(name)
|
46
|
+
@syms.each do |s|
|
47
|
+
return s if s.label == name
|
20
48
|
end
|
49
|
+
|
50
|
+
return nil
|
21
51
|
end
|
22
52
|
|
23
|
-
|
53
|
+
# Get symbols as a hash.
|
54
|
+
def hash
|
55
|
+
return @syms
|
56
|
+
end
|
24
57
|
end
|
25
58
|
|
26
59
|
# Represents a symbol definition, of the form `label = address`.
|
data/lib/zemu/instance.rb
CHANGED
@@ -2,6 +2,17 @@ require 'ffi'
|
|
2
2
|
require 'ostruct'
|
3
3
|
|
4
4
|
module Zemu
|
5
|
+
# Exception raised when an error occurs in a Zemu::Instance.
|
6
|
+
class InstanceError < StandardError
|
7
|
+
# Constructor.
|
8
|
+
#
|
9
|
+
# @param msg The exception message
|
10
|
+
#
|
11
|
+
def initialize(msg="An error occurred with the Zemu::Instance")
|
12
|
+
super
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
5
16
|
# Represents an instance of a Zemu emulator.
|
6
17
|
#
|
7
18
|
# Provides methods by which the state of the emulator can be observed
|
@@ -61,9 +72,11 @@ module Zemu
|
|
61
72
|
end
|
62
73
|
|
63
74
|
def initialize(configuration)
|
64
|
-
|
75
|
+
@devices = configuration.devices
|
76
|
+
|
77
|
+
# Methods defined by bus devices that we make
|
65
78
|
# accessible to the user.
|
66
|
-
@
|
79
|
+
@device_methods = []
|
67
80
|
|
68
81
|
@clock = configuration.clock_speed
|
69
82
|
@serial_delay = configuration.serial_delay
|
@@ -73,12 +86,95 @@ module Zemu
|
|
73
86
|
@serial = []
|
74
87
|
|
75
88
|
@instance = @wrapper.zemu_init
|
89
|
+
|
90
|
+
# Declare handlers.
|
91
|
+
# Memory write handler.
|
92
|
+
@mem_write = Proc.new do |addr, value|
|
93
|
+
@devices.each do |d|
|
94
|
+
d.mem_write(addr, value)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Memory read handler.
|
99
|
+
@mem_read = Proc.new do |addr|
|
100
|
+
r = 0
|
101
|
+
@devices.each do |d|
|
102
|
+
v = d.mem_read(addr)
|
103
|
+
unless v.nil?
|
104
|
+
r = v
|
105
|
+
break
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
r
|
110
|
+
end
|
111
|
+
|
112
|
+
# IO write handler.
|
113
|
+
@io_write = Proc.new do |port, value|
|
114
|
+
@devices.each do |d|
|
115
|
+
d.io_write(port, value)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# IO read handler.
|
120
|
+
@io_read = Proc.new do |port|
|
121
|
+
r = 0
|
122
|
+
@devices.each do |d|
|
123
|
+
v = d.io_read(port)
|
124
|
+
unless v.nil?
|
125
|
+
r = v
|
126
|
+
break
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
r
|
131
|
+
end
|
132
|
+
|
133
|
+
# IO read handler.
|
134
|
+
@io_clock = Proc.new do |cycles|
|
135
|
+
@devices.each do |d|
|
136
|
+
d.clock(cycles)
|
137
|
+
end
|
138
|
+
|
139
|
+
bus_state = 0
|
140
|
+
|
141
|
+
if @devices.any? { |d| d.nmi? }
|
142
|
+
bus_state |= 1
|
143
|
+
end
|
144
|
+
|
145
|
+
if @devices.any? { |d| d.interrupt? }
|
146
|
+
bus_state |= 2
|
147
|
+
end
|
148
|
+
|
149
|
+
bus_state
|
150
|
+
end
|
151
|
+
|
152
|
+
# Attach handlers.
|
153
|
+
@wrapper.zemu_set_mem_write_handler(@mem_write)
|
154
|
+
@wrapper.zemu_set_mem_read_handler(@mem_read)
|
155
|
+
@wrapper.zemu_set_io_write_handler(@io_write)
|
156
|
+
@wrapper.zemu_set_io_read_handler(@io_read)
|
157
|
+
@wrapper.zemu_set_io_clock_handler(@io_clock)
|
158
|
+
|
76
159
|
@wrapper.zemu_power_on(@instance)
|
77
160
|
@wrapper.zemu_reset(@instance)
|
78
161
|
|
79
162
|
@state = RunState::UNDEFINED
|
80
163
|
|
81
164
|
@breakpoints = {}
|
165
|
+
@tracepoints = {}
|
166
|
+
end
|
167
|
+
|
168
|
+
# Returns the device with the given name, or nil
|
169
|
+
# if no such device exists.
|
170
|
+
def device(name)
|
171
|
+
@devices.each do |d|
|
172
|
+
if d.name == name
|
173
|
+
return d
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
nil
|
82
178
|
end
|
83
179
|
|
84
180
|
# Returns the clock speed of this instance in Hz.
|
@@ -141,7 +237,7 @@ module Zemu
|
|
141
237
|
# emulated machine.
|
142
238
|
def serial_puts(string)
|
143
239
|
string.each_char do |c|
|
144
|
-
|
240
|
+
device('serial').put_byte(c.ord)
|
145
241
|
end
|
146
242
|
end
|
147
243
|
|
@@ -157,14 +253,14 @@ module Zemu
|
|
157
253
|
def serial_gets(count=nil)
|
158
254
|
return_string = ""
|
159
255
|
|
160
|
-
actual_count =
|
256
|
+
actual_count = device('serial').transmitted_count()
|
161
257
|
|
162
258
|
if count.nil? || actual_count < count
|
163
259
|
count = actual_count
|
164
260
|
end
|
165
261
|
|
166
262
|
count.to_i.times do
|
167
|
-
return_string +=
|
263
|
+
return_string += device('serial').get_byte().chr
|
168
264
|
end
|
169
265
|
|
170
266
|
return return_string
|
@@ -203,6 +299,12 @@ module Zemu
|
|
203
299
|
|
204
300
|
pc = @wrapper.zemu_debug_pc(@instance)
|
205
301
|
|
302
|
+
# If there's a tracepoint at this address,
|
303
|
+
# execute the associated proc.
|
304
|
+
unless @tracepoints[pc].nil?
|
305
|
+
@tracepoints[pc].call(self)
|
306
|
+
end
|
307
|
+
|
206
308
|
# If the PC is now pointing to one of our breakpoints,
|
207
309
|
# we're in the BREAK state.
|
208
310
|
if @breakpoints[pc]
|
@@ -224,6 +326,26 @@ module Zemu
|
|
224
326
|
@breakpoints[address] = true
|
225
327
|
end
|
226
328
|
|
329
|
+
# Set a tracepoint to execute the given block at an address.
|
330
|
+
#
|
331
|
+
# @param address The address of the tracepoint
|
332
|
+
# @param block The block to execute at the tracepoint.
|
333
|
+
# The block takes the instance as a parameter.
|
334
|
+
#
|
335
|
+
# @example
|
336
|
+
# instance.trace(0x1234) do |i|
|
337
|
+
# puts "HL value: 04x" % i.registers["HL"]
|
338
|
+
# end
|
339
|
+
#
|
340
|
+
def trace(address, &block)
|
341
|
+
if block.arity != 1
|
342
|
+
raise InstanceError,
|
343
|
+
"Wrong arity for tracepoint - expected 1, got #{block.arity}"
|
344
|
+
end
|
345
|
+
|
346
|
+
@tracepoints[address] = block
|
347
|
+
end
|
348
|
+
|
227
349
|
# Remove a breakpoint of the given type at the given address.
|
228
350
|
# Does nothing if no breakpoint previously existed at that address.
|
229
351
|
#
|
@@ -257,6 +379,21 @@ module Zemu
|
|
257
379
|
|
258
380
|
wrapper.ffi_lib [File.join(configuration.output_directory, "#{configuration.name}.so")]
|
259
381
|
|
382
|
+
# Handler types for handling bus accesses.
|
383
|
+
wrapper.callback :mem_write_handler, [:uint32, :uint8], :void
|
384
|
+
wrapper.callback :mem_read_handler, [:uint32], :uint8
|
385
|
+
|
386
|
+
wrapper.callback :io_write_handler, [:uint8, :uint8], :void
|
387
|
+
wrapper.callback :io_read_handler, [:uint8], :uint8
|
388
|
+
wrapper.callback :io_clock_handler, [:uint64], :uint8
|
389
|
+
|
390
|
+
wrapper.attach_function :zemu_set_mem_write_handler, [:mem_write_handler], :void
|
391
|
+
wrapper.attach_function :zemu_set_mem_read_handler, [:mem_read_handler], :void
|
392
|
+
|
393
|
+
wrapper.attach_function :zemu_set_io_write_handler, [:io_write_handler], :void
|
394
|
+
wrapper.attach_function :zemu_set_io_read_handler, [:io_read_handler], :void
|
395
|
+
wrapper.attach_function :zemu_set_io_clock_handler, [:io_clock_handler], :void
|
396
|
+
|
260
397
|
wrapper.attach_function :zemu_init, [], :pointer
|
261
398
|
wrapper.attach_function :zemu_free, [:pointer], :void
|
262
399
|
|
@@ -275,10 +412,10 @@ module Zemu
|
|
275
412
|
wrapper.attach_function :zemu_debug_get_memory, [:uint16], :uint8
|
276
413
|
wrapper.attach_function :zemu_debug_set_memory, [:uint16, :uint8], :void
|
277
414
|
|
278
|
-
configuration.
|
415
|
+
configuration.devices.each do |device|
|
279
416
|
device.functions.each do |f|
|
280
417
|
wrapper.attach_function(f["name"].to_sym, f["args"], f["return"])
|
281
|
-
@
|
418
|
+
@device_methods << f["name"].to_sym
|
282
419
|
end
|
283
420
|
end
|
284
421
|
|
@@ -287,7 +424,7 @@ module Zemu
|
|
287
424
|
|
288
425
|
# Redirects calls to I/O FFI functions.
|
289
426
|
def method_missing(method, *args)
|
290
|
-
if @
|
427
|
+
if @device_methods.include? method
|
291
428
|
return @wrapper.send(method)
|
292
429
|
end
|
293
430
|
|
data/lib/zemu/interactive.rb
CHANGED
@@ -11,6 +11,7 @@ module Zemu
|
|
11
11
|
# to the emulator window.
|
12
12
|
def initialize(instance, options = {})
|
13
13
|
@print_serial = options[:print_serial]
|
14
|
+
@trace = []
|
14
15
|
|
15
16
|
@instance = instance
|
16
17
|
|
@@ -70,6 +71,9 @@ module Zemu
|
|
70
71
|
elsif cmd[0] == "map"
|
71
72
|
load_map(cmd[1])
|
72
73
|
|
74
|
+
elsif cmd[0] == "trace"
|
75
|
+
trace()
|
76
|
+
|
73
77
|
elsif cmd[0] == "help"
|
74
78
|
log "Available commands:"
|
75
79
|
log " continue [<n>] - Continue execution for <n> cycles"
|
@@ -90,6 +94,14 @@ module Zemu
|
|
90
94
|
close
|
91
95
|
end
|
92
96
|
|
97
|
+
# Print trace for the emulator instance
|
98
|
+
# (last 200 addresses visited).
|
99
|
+
def trace
|
100
|
+
@trace.each do |t|
|
101
|
+
puts "%04x" % t
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
93
105
|
# Outputs a table giving the current values of the instance's registers.
|
94
106
|
# For the 16-bit registers (BC, DE, HL, IX, IY, SP, PC), attempts to identify the symbol
|
95
107
|
# to which they point.
|
@@ -171,9 +183,6 @@ module Zemu
|
|
171
183
|
serial_count = @instance.serial_delay.to_f
|
172
184
|
|
173
185
|
while ((cycles == -1) || (cycles_left > 0))
|
174
|
-
# Get time before execution.
|
175
|
-
start = Time.now
|
176
|
-
|
177
186
|
old_pc = r16("PC")
|
178
187
|
|
179
188
|
if (serial_count >= @instance.serial_delay)
|
@@ -185,18 +194,10 @@ module Zemu
|
|
185
194
|
cycles_left -= cycles_done
|
186
195
|
actual_cycles += cycles_done
|
187
196
|
|
188
|
-
# Get time after execution.
|
189
|
-
ending = Time.now
|
190
|
-
|
191
197
|
# Get elapsed time and calculate padding time to match clock speed.
|
192
198
|
if @instance.clock_speed > 0
|
193
|
-
elapsed = ending - start
|
194
|
-
|
195
199
|
execution_time = cycles_done * (1.0/@instance.clock_speed)
|
196
200
|
serial_count += execution_time
|
197
|
-
|
198
|
-
padding = execution_time - elapsed
|
199
|
-
sleep(padding) unless padding < 0
|
200
201
|
end
|
201
202
|
|
202
203
|
# Have we hit a breakpoint or HALT instruction?
|
@@ -258,7 +259,7 @@ module Zemu
|
|
258
259
|
|
259
260
|
syms = {}
|
260
261
|
begin
|
261
|
-
syms.merge! Debug.load_map(path.to_s)
|
262
|
+
syms.merge! Debug.load_map(path.to_s).hash
|
262
263
|
rescue ArgumentError => e
|
263
264
|
log "Error loading map file: #{e.message}"
|
264
265
|
syms.clear
|
data/lib/zemu.rb
CHANGED
@@ -111,7 +111,7 @@ module Zemu
|
|
111
111
|
|
112
112
|
inputs_str = inputs.map { |i| File.join(SRC, i) }.join(" ")
|
113
113
|
|
114
|
-
inputs_str += " " + File.join(autogen, "
|
114
|
+
inputs_str += " " + File.join(autogen, "bus.c")
|
115
115
|
|
116
116
|
defines = {
|
117
117
|
"CPU_Z80_STATIC" => 1,
|
@@ -143,14 +143,13 @@ module Zemu
|
|
143
143
|
#
|
144
144
|
# @param [Zemu::Config] configuration The configuration for which an emulator will be generated.
|
145
145
|
def Zemu::generate(configuration)
|
146
|
-
|
147
|
-
generate_io(configuration)
|
146
|
+
generate_bus(configuration)
|
148
147
|
end
|
149
148
|
|
150
|
-
# Generates the
|
151
|
-
def Zemu::
|
152
|
-
header_template = ERB.new File.read(File.join(SRC, "
|
153
|
-
source_template = ERB.new File.read(File.join(SRC, "
|
149
|
+
# Generates the bus.c and bus.h files for a given configuration.
|
150
|
+
def Zemu::generate_bus(configuration)
|
151
|
+
header_template = ERB.new File.read(File.join(SRC, "bus.h.erb"))
|
152
|
+
source_template = ERB.new File.read(File.join(SRC, "bus.c.erb"))
|
154
153
|
|
155
154
|
autogen = File.join(configuration.output_directory, "autogen_#{configuration.name}")
|
156
155
|
|
@@ -158,28 +157,10 @@ module Zemu
|
|
158
157
|
Dir.mkdir autogen
|
159
158
|
end
|
160
159
|
|
161
|
-
File.write(File.join(autogen, "
|
160
|
+
File.write(File.join(autogen, "bus.h"),
|
162
161
|
header_template.result(configuration.get_binding))
|
163
162
|
|
164
|
-
File.write(File.join(autogen, "
|
165
|
-
source_template.result(configuration.get_binding))
|
166
|
-
end
|
167
|
-
|
168
|
-
# Generates the io.c and io.h files for a given configuration.
|
169
|
-
def Zemu::generate_io(configuration)
|
170
|
-
header_template = ERB.new File.read(File.join(SRC, "io.h.erb"))
|
171
|
-
source_template = ERB.new File.read(File.join(SRC, "io.c.erb"))
|
172
|
-
|
173
|
-
autogen = File.join(configuration.output_directory, "autogen_#{configuration.name}")
|
174
|
-
|
175
|
-
unless Dir.exist? autogen
|
176
|
-
Dir.mkdir autogen
|
177
|
-
end
|
178
|
-
|
179
|
-
File.write(File.join(autogen, "io.h"),
|
180
|
-
header_template.result(configuration.get_binding))
|
181
|
-
|
182
|
-
File.write(File.join(autogen, "io.c"),
|
163
|
+
File.write(File.join(autogen, "bus.c"),
|
183
164
|
source_template.result(configuration.get_binding))
|
184
165
|
end
|
185
166
|
end
|
data/src/bus.c.erb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
#include "bus.h"
|
2
|
+
|
3
|
+
mem_write_handler_t * mem_write_handler;
|
4
|
+
mem_read_handler_t * mem_read_handler;
|
5
|
+
|
6
|
+
io_write_handler_t * io_write_handler;
|
7
|
+
io_read_handler_t * io_read_handler;
|
8
|
+
io_clock_handler_t * io_clock_handler;
|
9
|
+
|
10
|
+
<% devices.each do |d| %>
|
11
|
+
<% next if d.memory.nil? %>
|
12
|
+
<%= d.memory.setup %>
|
13
|
+
<% end %>
|
14
|
+
|
15
|
+
void zemu_set_mem_write_handler(mem_write_handler_t * h)
|
16
|
+
{
|
17
|
+
mem_write_handler = h;
|
18
|
+
}
|
19
|
+
|
20
|
+
void zemu_set_mem_read_handler(mem_read_handler_t * h)
|
21
|
+
{
|
22
|
+
mem_read_handler = h;
|
23
|
+
}
|
24
|
+
|
25
|
+
void zemu_set_io_write_handler(io_write_handler_t * h)
|
26
|
+
{
|
27
|
+
io_write_handler = h;
|
28
|
+
}
|
29
|
+
|
30
|
+
void zemu_set_io_read_handler(io_read_handler_t * h)
|
31
|
+
{
|
32
|
+
io_read_handler = h;
|
33
|
+
}
|
34
|
+
|
35
|
+
void zemu_set_io_clock_handler(io_clock_handler_t * h)
|
36
|
+
{
|
37
|
+
io_clock_handler = h;
|
38
|
+
}
|
39
|
+
|
40
|
+
zuint8 zemu_memory_read(void * context, zuint16 address)
|
41
|
+
{
|
42
|
+
return zemu_memory_peek(address);
|
43
|
+
}
|
44
|
+
|
45
|
+
void zemu_memory_write(void * context, zuint16 address, zuint8 value)
|
46
|
+
{
|
47
|
+
zemu_memory_poke(address, value);
|
48
|
+
}
|
49
|
+
|
50
|
+
zuint8 zemu_memory_peek(zuint16 address)
|
51
|
+
{
|
52
|
+
zuint32 address_32 = address;
|
53
|
+
|
54
|
+
<% devices.each do |d| %>
|
55
|
+
<% next if d.memory.nil? %>
|
56
|
+
if ((address_32 >= <%= d.memory.address %>) && (address_32 < <%= d.memory.address + d.memory.size%>))
|
57
|
+
return <%= d.memory.access_read %>[address_32 - <%= d.memory.address %>];
|
58
|
+
<% end %>
|
59
|
+
|
60
|
+
return mem_read_handler(address_32);
|
61
|
+
}
|
62
|
+
|
63
|
+
void zemu_memory_poke(zuint16 address, zuint8 value)
|
64
|
+
{
|
65
|
+
zuint32 address_32 = address;
|
66
|
+
|
67
|
+
<% devices.each do |d| %>
|
68
|
+
<% next if d.memory.nil? %>
|
69
|
+
if ((address_32 >= <%= d.memory.address %>) && (address_32 < <%= d.memory.address + d.memory.size%>))
|
70
|
+
<%= d.memory.access_write %>[address_32 - <%= d.memory.address %>] = value;
|
71
|
+
<% end %>
|
72
|
+
|
73
|
+
mem_write_handler(address_32, value);
|
74
|
+
}
|
75
|
+
|
76
|
+
void zemu_io_nmi(Z80 * instance)
|
77
|
+
{
|
78
|
+
z80_nmi(instance);
|
79
|
+
}
|
80
|
+
|
81
|
+
void zemu_io_int_on(Z80 * instance)
|
82
|
+
{
|
83
|
+
z80_int(instance, TRUE);
|
84
|
+
}
|
85
|
+
|
86
|
+
void zemu_io_int_off(Z80 * instance)
|
87
|
+
{
|
88
|
+
z80_int(instance, FALSE);
|
89
|
+
}
|
90
|
+
|
91
|
+
zuint8 zemu_io_in(void * context, zuint16 port)
|
92
|
+
{
|
93
|
+
/* Z80 IO ports occupy the lower half of the address bus.
|
94
|
+
* We cannot assume that the top half is valid.
|
95
|
+
*/
|
96
|
+
port &= 0x00FF;
|
97
|
+
|
98
|
+
return io_read_handler((zuint8)port);
|
99
|
+
}
|
100
|
+
|
101
|
+
void zemu_io_out(void * context, zuint16 port, zuint8 value)
|
102
|
+
{
|
103
|
+
/* Z80 IO ports occupy the lower half of the address bus.
|
104
|
+
* We cannot assume that the top half is valid.
|
105
|
+
*/
|
106
|
+
port &= 0x00FF;
|
107
|
+
|
108
|
+
io_write_handler((zuint8)port, value);
|
109
|
+
}
|
110
|
+
|
111
|
+
void zemu_io_clock(Z80 * instance, zusize cycles)
|
112
|
+
{
|
113
|
+
zuint8 bus_state = io_clock_handler(cycles);
|
114
|
+
|
115
|
+
if (bus_state & 0x01) zemu_io_nmi(instance);
|
116
|
+
|
117
|
+
if (bus_state & 0x02) zemu_io_int_on(instance);
|
118
|
+
else zemu_io_int_off(instance);
|
119
|
+
}
|
data/src/bus.h.erb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
#ifndef _ZEMU_IO_H
|
2
|
+
#define _ZEMU_IO_H
|
3
|
+
|
4
|
+
#include "emulation/CPU/Z80.h"
|
5
|
+
|
6
|
+
#ifndef ZEMU_IO_SERIAL_BUFFER_SIZE
|
7
|
+
#define ZEMU_IO_SERIAL_BUFFER_SIZE 256
|
8
|
+
#endif
|
9
|
+
|
10
|
+
typedef struct {
|
11
|
+
zuint8 buffer[ZEMU_IO_SERIAL_BUFFER_SIZE];
|
12
|
+
unsigned int head;
|
13
|
+
unsigned int tail;
|
14
|
+
} SerialBuffer;
|
15
|
+
|
16
|
+
/* Type of a function writing to a memory address. */
|
17
|
+
typedef void mem_write_handler_t(zuint32, zuint8);
|
18
|
+
|
19
|
+
/* Type of a function reading from a memory address. */
|
20
|
+
typedef zuint8 mem_read_handler_t(zuint32);
|
21
|
+
|
22
|
+
/* Type of a function writing to an IO port. */
|
23
|
+
typedef void io_write_handler_t(zuint8, zuint8);
|
24
|
+
|
25
|
+
/* Type of a function reading from an IO port. */
|
26
|
+
typedef zuint8 io_read_handler_t(zuint8);
|
27
|
+
|
28
|
+
/* Type of a function to handle a clock cycle for a peripheral. */
|
29
|
+
typedef zuint8 io_clock_handler_t(zusize);
|
30
|
+
|
31
|
+
void zemu_set_mem_write_handler(mem_write_handler_t * h);
|
32
|
+
void zemu_set_mem_read_handler(mem_read_handler_t * h);
|
33
|
+
|
34
|
+
void zemu_set_io_write_handler(io_write_handler_t * h);
|
35
|
+
void zemu_set_io_read_handler(io_read_handler_t * h);
|
36
|
+
void zemu_set_io_clock_handler(io_clock_handler_t * h);
|
37
|
+
|
38
|
+
zuint8 zemu_memory_read(void * context, zuint16 address);
|
39
|
+
void zemu_memory_write(void * context, zuint16 address, zuint8 value);
|
40
|
+
|
41
|
+
zuint8 zemu_memory_peek(zuint16 address);
|
42
|
+
void zemu_memory_poke(zuint16 address, zuint8 value);
|
43
|
+
|
44
|
+
void zemu_io_serial_master_puts(zuint8 val);
|
45
|
+
zuint8 zemu_io_serial_master_gets(void);
|
46
|
+
zusize zemu_io_serial_buffer_size(void);
|
47
|
+
|
48
|
+
zuint8 zemu_io_in(void * context, zuint16 port);
|
49
|
+
void zemu_io_out(void * context, zuint16 port, zuint8 value);
|
50
|
+
void zemu_io_nmi(Z80 * instance);
|
51
|
+
void zemu_io_clock(Z80 * instance, zusize cycles);
|
52
|
+
|
53
|
+
#endif
|
data/src/debug.c
CHANGED
@@ -8,7 +8,7 @@ zusize zemu_debug_step(Z80 * instance)
|
|
8
8
|
zusize cycles = z80_run(instance, 1);
|
9
9
|
|
10
10
|
/* Execute the per-cycle behaviour of the peripheral devices. */
|
11
|
-
|
11
|
+
zemu_io_clock(instance, cycles);
|
12
12
|
|
13
13
|
return cycles;
|
14
14
|
}
|
data/src/debug.h
CHANGED
data/src/main.c
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:
|
4
|
+
version: 1.1.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: 2022-01-30 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
|
@@ -32,6 +32,8 @@ files:
|
|
32
32
|
- lib/zemu/debug.rb
|
33
33
|
- lib/zemu/instance.rb
|
34
34
|
- lib/zemu/interactive.rb
|
35
|
+
- src/bus.c.erb
|
36
|
+
- src/bus.h.erb
|
35
37
|
- src/debug.c
|
36
38
|
- src/debug.h
|
37
39
|
- src/external/Z/API/Z/ABIs/generic/allocator.h
|
@@ -310,11 +312,7 @@ files:
|
|
310
312
|
- src/external/z80/sources/Z80.c
|
311
313
|
- src/interrupt.c
|
312
314
|
- src/interrupt.h
|
313
|
-
- src/io.c.erb
|
314
|
-
- src/io.h.erb
|
315
315
|
- src/main.c
|
316
|
-
- src/memory.c.erb
|
317
|
-
- src/memory.h.erb
|
318
316
|
homepage: https://github.com/jayvalentine/zemu
|
319
317
|
licenses:
|
320
318
|
- GPL-3.0
|