zemu 0.4.0 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: caa59294431c1faadda8328bc7fbefa504526ae43a5531e2cf1d6c2bc7dd5c87
4
- data.tar.gz: 72ced5e284f94e586862e80e97f5d95f55a9a3dbc931dc889fdc73352cef3a82
3
+ metadata.gz: 62fdf5d376fa7ea32170f7f2ae62af17f3e96f8714313af513aabf86ef56fc71
4
+ data.tar.gz: 3adcc264bc22f519fff6bb0604051058b198ef3a200c3c5b118f1de1796d84ce
5
5
  SHA512:
6
- metadata.gz: dbb449fa4a076320a3073391f98687098e4e0f8b484099a7ca2c67325f857e8923397267dc01c5bee521cf66e9457149a8845e15f4a8b74ae7962e1f84623ae1
7
- data.tar.gz: 846f7d09837e09fdb5711ba7d3ee09ca734cf0454c10efaff77a2d92de742e88332cc2c3e008db7026c528460368e410c9c9ebaacf29694e513880255085d579
6
+ metadata.gz: 4bd2cbaf5099cd0874a5d59b519aaf7371e0c3b537fc7c57d70cb82f9003c751362dbed28aa1d5187736932f8d498746d95d1a404f1b43ff3cee571a1248c23a
7
+ data.tar.gz: 9a320b4fbaddf08a24ba5ef58452ab0750d9fec1476bc8b389d43fc2b623364ab82cd037e61560828740a3e01adfa7647093eefad14d72ee5f6ec0152beb11fe
data/lib/zemu/config.rb CHANGED
@@ -75,10 +75,83 @@ module Zemu
75
75
  # @param [String] compiler The path to the compiler to be used for compiling the emulator executable.
76
76
  #
77
77
  class Config < ConfigObject
78
+ # Bus Device.
79
+ #
80
+ # Represents a device connected to the I/O
81
+ # or memory buses, or both.
82
+ class BusDevice < ConfigObject
83
+ # Constructor.
84
+ #
85
+ # This object should not be constructed directly.
86
+ def initialize
87
+ if self.class == Zemu::Config::BusDevice
88
+ raise NotImplementedError, "Cannot construct an instance of the abstract class Zemu::Config::BusDevice."
89
+ end
90
+
91
+ super
92
+ end
93
+
94
+ # Setup to be performed on initialising the emulator
95
+ # instance.
96
+ def when_setup
97
+ ""
98
+ end
99
+
100
+ # Memory bus write handler.
101
+ #
102
+ # Defines C code generated for handling memory
103
+ # writes for this device.
104
+ def when_mem_write
105
+ ""
106
+ end
107
+
108
+ # Memory bus read handler.
109
+ #
110
+ # Defines C code generated for handling memory
111
+ # reads for this device.
112
+ def when_mem_read
113
+ ""
114
+ end
115
+
116
+ # IO bus write handler.
117
+ #
118
+ # Defines C code generated for handling IO
119
+ # writes for this device.
120
+ def when_io_write
121
+ ""
122
+ end
123
+
124
+ # IO bus read handler.
125
+ #
126
+ # Defines C code generated for handling IO
127
+ # reads for this device.
128
+ def when_io_read
129
+ ""
130
+ end
131
+
132
+ # Clock handler.
133
+ #
134
+ # Defines C code which executes for every
135
+ # clock cycle.
136
+ def when_clock
137
+ ""
138
+ end
139
+
140
+ # FFI functions provided by this device.
141
+ def functions
142
+ []
143
+ end
144
+
145
+ # Parameters for a bus device.
146
+ def params
147
+ %w(name)
148
+ end
149
+ end
150
+
78
151
  # Memory object.
79
152
  #
80
153
  # This is an abstract class from which all other memory objects inherit.
81
- class Memory < ConfigObject
154
+ class Memory < BusDevice
82
155
  # Constructor.
83
156
  #
84
157
  # Do not use, as this is an abstract class. Use one of the subclasses instead.
@@ -107,15 +180,50 @@ module Zemu
107
180
  end
108
181
  end
109
182
 
110
- # @return [Boolean] true if this memory section is readonly, false otherwise.
183
+ # Is this memory read-only?
111
184
  def readonly?
112
- return false
185
+ false
186
+ end
187
+
188
+ # Defines generated C to declare this memory block.
189
+ def when_setup
190
+ init_array = []
191
+ contents.each_with_index do |b, i|
192
+ init_array << ((i % 16 == 0) ? "\n " : "") + ("0x%02x, " % b)
193
+ end
194
+
195
+ <<-eos
196
+ /* Initialization memory block "#{name}" */
197
+ #{if self.readonly? then "const" else "" end} zuint8 zemu_memory_block_#{name}[0x#{size.to_s(16)}] =
198
+ {#{init_array.join("")}
199
+ };
200
+ eos
201
+ end
202
+
203
+ # Defines generated C to handle reading this memory block.
204
+ def when_mem_read
205
+ <<-eos
206
+ if (address_32 >= 0x#{address.to_s(16)} && address_32 < 0x#{(address + size).to_s(16)})
207
+ {
208
+ return zemu_memory_block_#{name}[address_32 - 0x#{address.to_s(16)}];
209
+ }
210
+ eos
211
+ end
212
+
213
+ # Defines generated C to handle writing to this memory block.
214
+ def when_mem_write
215
+ <<-eos
216
+ if (address_32 >= 0x#{address.to_s(16)} && address_32 < 0x#{(address + size).to_s(16)})
217
+ {
218
+ zemu_memory_block_#{name}[address_32 - 0x#{address.to_s(16)}] = value;
219
+ }
220
+ eos
113
221
  end
114
222
 
115
223
  # Valid parameters for this object.
116
224
  # Should be extended by subclasses but NOT REPLACED.
117
225
  def params
118
- return %w(name address size)
226
+ super + %w(address size)
119
227
  end
120
228
 
121
229
  # Reads the contents of a file in binary format and
@@ -155,8 +263,17 @@ module Zemu
155
263
  super
156
264
  end
157
265
 
266
+ # Is this memory block readonly?
158
267
  def readonly?
159
- return true
268
+ true
269
+ end
270
+
271
+ # Defines generated C to handle writing to this
272
+ # memory block. Because this block is read-only,
273
+ # no code is generated to handle writes.
274
+ def when_mem_write
275
+ # Cannot write to read-only memory.
276
+ ""
160
277
  end
161
278
  end
162
279
 
@@ -165,169 +282,13 @@ module Zemu
165
282
  # Represents a block of memory which can be read and written.
166
283
  class RAM < Memory
167
284
  end
168
-
169
- # Input/Output Port object
170
- #
171
- # Represents an input/output device assigned to one or more ports.
172
- #
173
- # This is an abstract class and cannot be instantiated directly.
174
- # The when_setup, when_read, and when_write methods can be used to define
175
- # the behaviour of a subclass.
176
- #
177
- # @example
178
- # class MyIODevice < IOPort
179
- # # Extend the parameters of the object so we can define a port.
180
- # def params
181
- # super + "port"
182
- # end
183
- #
184
- # def initialize
185
- # super
186
- #
187
- # # Define the setup for the IO device.
188
- # # This is some global C code that ends up in "io.c".
189
- # # Parameters can be used here, as the block is instance-evaluated.
190
- # when_setup do
191
- # %Q(zuint8 #{name}_value = 42;)
192
- # end
193
- #
194
- # # Define the logic when reading from an IO port.
195
- # # The C variable "port" takes the value of the 8-bit port
196
- # # address being read from, and should be used to identify
197
- # # if this IO device is the one being used.
198
- # when_read do
199
- # %Q(if (port == #{port}) return #{name}_value;)
200
- # end
201
- #
202
- # # Define the logic when writing to the IO port.
203
- # # Similar to #when_read, but we have access to an extra
204
- # # C variable, "value". This is the value being written
205
- # # to the IO port.
206
- # when_write do
207
- # %Q(if (port == #{port}) #{name}_value = value;)
208
- # end
209
- # end
210
- # end
211
- #
212
- # # The subclass can now be declared as below:
213
- # device = MyIODevice.new do
214
- # name "myDevice"
215
- # port 11
216
- # end
217
- #
218
- #
219
- class IOPort < ConfigObject
220
- attr_reader :io_type
221
-
222
- # Constructor.
223
- #
224
- # Do not use, as this is an abstract class. Use one of the subclasses instead.
225
- def initialize
226
- if self.class == Zemu::Config::IOPort
227
- raise NotImplementedError, "Cannot construct an instance of the abstract class Zemu::Config::IOPort."
228
- end
229
-
230
- @ports = []
231
- @setup_block = nil
232
- @read_block = nil
233
- @write_block = nil
234
- @clock_block = nil
235
-
236
- super
237
- end
238
-
239
- # Defines the setup behaviour of this IO device.
240
- #
241
- # Expects a block, the return value of which is a string
242
- # containing all data and function declarations required by this IO device.
243
- #
244
- # The block will be instance-evaluated at build-time, so it is possible to use
245
- # instance variables of the IO device.
246
- def when_setup(&block)
247
- @setup_block = block
248
- end
249
-
250
- # Defines the read behaviour of this IO device.
251
- #
252
- # Expects a block, the return value of which is a string
253
- # containing the behaviour of this IO device when a value is read from the IO bus.
254
- # Care must be taken to ensure that this functionality does not conflict with that of
255
- # any other IO devices.
256
- #
257
- # The block will be instance-evaluated at build-time, so it is possible to use
258
- # instance variables of the IO device.
259
- def when_read(&block)
260
- @read_block = block
261
- end
262
-
263
- # Defines the write behaviour of this IO device.
264
- #
265
- # Expects a block, the return value of which is a string
266
- # containing the behaviour of this IO device when a value is written to the IO bus.
267
- # Care must be taken to ensure that this functionality does not conflict with that of
268
- # any other IO devices.
269
- #
270
- # The block will be instance-evaluated at build-time, so it is possible to use
271
- # instance variables of the IO device.
272
- def when_write(&block)
273
- @write_block = block
274
- end
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
-
289
- # Evaluates the when_setup block of this IO device and returns the resulting string.
290
- def setup
291
- return instance_eval(&@setup_block) unless @setup_block.nil?
292
- return ""
293
- end
294
-
295
- # Evaluates the when_read block of this IO device and returns the resulting string.
296
- def read
297
- return instance_eval(&@read_block) unless @read_block.nil?
298
- return ""
299
- end
300
-
301
- # Evaluates the when_write block of this IO device and returns the resulting string.
302
- def write
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 ""
311
- end
312
-
313
- # Defines FFI API which will be available to the instance wrapper if this IO device is used.
314
- def functions
315
- []
316
- end
317
-
318
- # Valid parameters for this object.
319
- # Should be extended by subclasses but NOT REPLACED.
320
- def params
321
- %w(name)
322
- end
323
- end
324
285
 
325
286
  # Serial Input/Output object
326
287
  #
327
288
  # Represents a serial connection between the emulated CPU
328
289
  # and the host machine, with input and output mapped to Z80 I/O
329
290
  # ports.
330
- class SerialPort < IOPort
291
+ class SerialPort < BusDevice
331
292
  # Constructor.
332
293
  #
333
294
  # Takes a block in which the parameters of the serial port
@@ -347,80 +308,84 @@ module Zemu
347
308
  #
348
309
  def initialize
349
310
  super
311
+ end
350
312
 
351
- when_setup do
352
- "SerialBuffer io_#{name}_buffer_master = { .head = 0, .tail = 0 };\n" +
353
- "SerialBuffer io_#{name}_buffer_slave = { .head = 0, .tail = 0 };\n" +
354
- "\n" +
355
- "zusize zemu_io_#{name}_buffer_size(void)\n" +
356
- "{\n" +
357
- " zusize start = io_#{name}_buffer_slave.head;\n" +
358
- " zusize end = io_#{name}_buffer_slave.tail\n;" +
359
- " if (end < start) end += ZEMU_IO_SERIAL_BUFFER_SIZE;\n" +
360
- " return end - start;\n" +
361
- "}\n" +
362
- "\n" +
363
- "void zemu_io_#{name}_slave_puts(zuint8 val)\n" +
364
- "{\n" +
365
- " io_#{name}_buffer_slave.buffer[io_#{name}_buffer_slave.tail] = val;\n" +
366
- " io_#{name}_buffer_slave.tail++;\n" +
367
- " if (io_#{name}_buffer_slave.tail >= ZEMU_IO_SERIAL_BUFFER_SIZE)\n" +
368
- " io_#{name}_buffer_slave.tail = 0;\n" +
369
- "}\n" +
370
- "\n" +
371
- "zuint8 zemu_io_#{name}_slave_gets(void)\n" +
372
- "{\n" +
373
- " zuint8 val = io_#{name}_buffer_master.buffer[io_#{name}_buffer_master.head];\n" +
374
- " io_#{name}_buffer_master.head++;\n" +
375
- " if (io_#{name}_buffer_master.head >= ZEMU_IO_SERIAL_BUFFER_SIZE)\n" +
376
- " io_#{name}_buffer_master.head = 0;\n" +
377
- "\n" +
378
- " return val;\n" +
379
- "}\n" +
380
- "\n" +
381
- "void zemu_io_#{name}_master_puts(zuint8 val)\n" +
382
- "{\n" +
383
- " io_#{name}_buffer_master.buffer[io_#{name}_buffer_master.tail] = val;\n" +
384
- " io_#{name}_buffer_master.tail++;\n" +
385
- " if (io_#{name}_buffer_master.tail >= ZEMU_IO_SERIAL_BUFFER_SIZE)\n" +
386
- " io_#{name}_buffer_master.tail = 0;\n" +
387
- "}\n" +
388
- "\n" +
389
- "zuint8 zemu_io_#{name}_master_gets(void)\n" +
390
- "{\n" +
391
- " zuint8 val = io_#{name}_buffer_slave.buffer[io_#{name}_buffer_slave.head];\n" +
392
- " io_#{name}_buffer_slave.head++;\n" +
393
- " if (io_#{name}_buffer_slave.head >= ZEMU_IO_SERIAL_BUFFER_SIZE)\n" +
394
- " io_#{name}_buffer_slave.head = 0;\n" +
395
- "\n" +
396
- " return val;\n" +
397
- "}\n"
398
- end
399
-
400
- when_read do
401
- "if (port == #{in_port})\n" +
402
- "{\n" +
403
- " return zemu_io_#{name}_slave_gets();\n" +
404
- "}\n" +
405
- "else if (port == #{ready_port})\n" +
406
- "{\n" +
407
- " if (io_#{name}_buffer_master.head == io_#{name}_buffer_master.tail)\n" +
408
- " {\n" +
409
- " return 0;\n" +
410
- " }\n" +
411
- " else\n" +
412
- " {\n" +
413
- " return 1;\n" +
414
- " }\n" +
415
- "}\n"
416
- end
417
-
418
- when_write do
419
- "if (port == #{out_port})\n" +
420
- "{\n" +
421
- " zemu_io_#{name}_slave_puts(value);\n" +
422
- "}\n"
423
- end
313
+ # Defines generated C to declare the serial device.
314
+ def when_setup
315
+ "SerialBuffer io_#{name}_buffer_master = { .head = 0, .tail = 0 };\n" +
316
+ "SerialBuffer io_#{name}_buffer_slave = { .head = 0, .tail = 0 };\n" +
317
+ "\n" +
318
+ "zusize zemu_io_#{name}_buffer_size(void)\n" +
319
+ "{\n" +
320
+ " zusize start = io_#{name}_buffer_slave.head;\n" +
321
+ " zusize end = io_#{name}_buffer_slave.tail\n;" +
322
+ " if (end < start) end += ZEMU_IO_SERIAL_BUFFER_SIZE;\n" +
323
+ " return end - start;\n" +
324
+ "}\n" +
325
+ "\n" +
326
+ "void zemu_io_#{name}_slave_puts(zuint8 val)\n" +
327
+ "{\n" +
328
+ " io_#{name}_buffer_slave.buffer[io_#{name}_buffer_slave.tail] = val;\n" +
329
+ " io_#{name}_buffer_slave.tail++;\n" +
330
+ " if (io_#{name}_buffer_slave.tail >= ZEMU_IO_SERIAL_BUFFER_SIZE)\n" +
331
+ " io_#{name}_buffer_slave.tail = 0;\n" +
332
+ "}\n" +
333
+ "\n" +
334
+ "zuint8 zemu_io_#{name}_slave_gets(void)\n" +
335
+ "{\n" +
336
+ " zuint8 val = io_#{name}_buffer_master.buffer[io_#{name}_buffer_master.head];\n" +
337
+ " io_#{name}_buffer_master.head++;\n" +
338
+ " if (io_#{name}_buffer_master.head >= ZEMU_IO_SERIAL_BUFFER_SIZE)\n" +
339
+ " io_#{name}_buffer_master.head = 0;\n" +
340
+ "\n" +
341
+ " return val;\n" +
342
+ "}\n" +
343
+ "\n" +
344
+ "void zemu_io_#{name}_master_puts(zuint8 val)\n" +
345
+ "{\n" +
346
+ " io_#{name}_buffer_master.buffer[io_#{name}_buffer_master.tail] = val;\n" +
347
+ " io_#{name}_buffer_master.tail++;\n" +
348
+ " if (io_#{name}_buffer_master.tail >= ZEMU_IO_SERIAL_BUFFER_SIZE)\n" +
349
+ " io_#{name}_buffer_master.tail = 0;\n" +
350
+ "}\n" +
351
+ "\n" +
352
+ "zuint8 zemu_io_#{name}_master_gets(void)\n" +
353
+ "{\n" +
354
+ " zuint8 val = io_#{name}_buffer_slave.buffer[io_#{name}_buffer_slave.head];\n" +
355
+ " io_#{name}_buffer_slave.head++;\n" +
356
+ " if (io_#{name}_buffer_slave.head >= ZEMU_IO_SERIAL_BUFFER_SIZE)\n" +
357
+ " io_#{name}_buffer_slave.head = 0;\n" +
358
+ "\n" +
359
+ " return val;\n" +
360
+ "}\n"
361
+ end
362
+
363
+ # Defines generated C to handle reading from serial port's
364
+ # registers.
365
+ def when_io_read
366
+ "if (port == #{in_port})\n" +
367
+ "{\n" +
368
+ " return zemu_io_#{name}_slave_gets();\n" +
369
+ "}\n" +
370
+ "else if (port == #{ready_port})\n" +
371
+ "{\n" +
372
+ " if (io_#{name}_buffer_master.head == io_#{name}_buffer_master.tail)\n" +
373
+ " {\n" +
374
+ " return 0;\n" +
375
+ " }\n" +
376
+ " else\n" +
377
+ " {\n" +
378
+ " return 1;\n" +
379
+ " }\n" +
380
+ "}\n"
381
+ end
382
+
383
+ # Defines generated C to handle writing to the serial port's registers.
384
+ def when_io_write
385
+ "if (port == #{out_port})\n" +
386
+ "{\n" +
387
+ " zemu_io_#{name}_slave_puts(value);\n" +
388
+ "}\n"
424
389
  end
425
390
 
426
391
  # Defines FFI API which will be available to the instance wrapper if this IO device is used.
@@ -433,7 +398,7 @@ module Zemu
433
398
  end
434
399
 
435
400
  # Valid parameters for a SerialPort, along with those
436
- # defined in [Zemu::Config::IOPort].
401
+ # defined in [Zemu::Config::BusDevice].
437
402
  def params
438
403
  super + %w(in_port out_port ready_port)
439
404
  end
@@ -443,7 +408,7 @@ module Zemu
443
408
  #
444
409
  # Represents a device with a sequence of sectors of a fixed size,
445
410
  # which can be accessed via IO instructions as an IDE drive.
446
- class BlockDrive < IOPort
411
+ class BlockDrive < BusDevice
447
412
  # Constructor.
448
413
  #
449
414
  # Takes a block in which the parameters of the block drive
@@ -466,18 +431,9 @@ module Zemu
466
431
  #
467
432
  #
468
433
  def initialize
469
- @blocks = []
470
434
  @initialize_from = nil
471
435
 
472
436
  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
437
 
482
438
  # Initialize from provided file if applicable.
483
439
  unless @initialize_from.nil?
@@ -486,17 +442,11 @@ module Zemu
486
442
  if (file_size != num_sectors * sector_size)
487
443
  raise RangeError, "Initialization file for Zemu::Config::BlockDrive '#{name}' is of wrong size."
488
444
  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
445
  end
446
+ end
498
447
 
499
- when_setup do
448
+ # Defines generated C to declare the block device.
449
+ def when_setup
500
450
  <<-eos
501
451
  #include <stdio.h>
502
452
 
@@ -537,9 +487,11 @@ zuint8 zemu_io_#{name}_readbyte(zuint32 sector, zuint32 offset)
537
487
  return sector_data_#{name}[offset];
538
488
  }
539
489
  eos
540
- end
490
+ end
541
491
 
542
- when_read do
492
+ # Defines generated C to handle reading the block drive's
493
+ # registers.
494
+ def when_io_read
543
495
  <<-eos
544
496
  if (port == #{base_port})
545
497
  {
@@ -556,9 +508,11 @@ else if (port == #{base_port+7})
556
508
  return drive_status_#{name};
557
509
  }
558
510
  eos
559
- end
511
+ end
560
512
 
561
- when_write do
513
+ # Defines generated C to handle writing to the block drive's
514
+ # registers.
515
+ def when_io_write
562
516
  <<-eos
563
517
  if (port == #{base_port})
564
518
  {
@@ -621,12 +575,31 @@ else if (port == #{base_port+7})
621
575
  }
622
576
  }
623
577
  eos
624
- end
625
578
  end
626
579
 
627
580
  # Array of sectors of this drive.
628
581
  def blocks
629
- @blocks
582
+ b = []
583
+
584
+ if @initialize_from.nil?
585
+ num_sectors.times do
586
+ this_block = []
587
+ sector_size.times do
588
+ this_block << 0
589
+ end
590
+ b << this_block
591
+ end
592
+ return b
593
+ end
594
+
595
+ File.open(@initialize_from, "rb") do |f|
596
+ num_sectors.times do
597
+ this_block = f.read(sector_size)
598
+ b << this_block.unpack("C" * sector_size)
599
+ end
600
+ end
601
+
602
+ b
630
603
  end
631
604
 
632
605
  # Set file to initialize from.
@@ -642,7 +615,7 @@ eos
642
615
  end
643
616
 
644
617
  # Valid parameters for a BlockDrive, along with those
645
- # defined in [Zemu::Config::IOPort].
618
+ # defined in [Zemu::Config::BusDevice].
646
619
  def params
647
620
  super + %w(base_port sector_size num_sectors)
648
621
  end
@@ -653,30 +626,27 @@ eos
653
626
  # Represents a timer device, the period of which can be controlled
654
627
  # by the CPU through an IO port. The timer generates an NMI once this
655
628
  # period has expired. The timer can be reset via a control port.
656
- class Timer < IOPort
657
- def initialize
658
- super
659
-
660
- when_setup do
661
- "zuint8 io_#{name}_count;\n" +
662
- "zuint8 io_#{name}_running = 0;\n"
663
- end
664
-
665
- when_read do
666
- end
629
+ class Timer < BusDevice
630
+ # Defines generated C that sets up the timer.
631
+ def when_setup
632
+ "zuint8 io_#{name}_count;\n" +
633
+ "zuint8 io_#{name}_running = 0;\n"
634
+ end
667
635
 
668
- when_write do
669
- "if (port == #{count_port}) io_#{name}_count = value;\n" +
670
- "else if (port == #{control_port}) io_#{name}_running = value;\n"
671
- end
636
+ # Defines generated C that handles writing to the timer's
637
+ # registers.
638
+ def when_io_write
639
+ "if (port == #{count_port}) io_#{name}_count = value;\n" +
640
+ "else if (port == #{control_port}) io_#{name}_running = value;\n"
641
+ end
672
642
 
673
- when_clock do
674
- "if (io_#{name}_running)\n" +
675
- "{\n" +
676
- " if (io_#{name}_count > 0) io_#{name}_count--;\n" +
677
- " else zemu_io_nmi(instance);\n" +
678
- "}\n"
679
- end
643
+ # Defines generated C that handles a clock tick for the timer.
644
+ def when_clock
645
+ "if (io_#{name}_running)\n" +
646
+ "{\n" +
647
+ " if (io_#{name}_count > 0) io_#{name}_count--;\n" +
648
+ " else zemu_io_nmi(instance);\n" +
649
+ "}\n"
680
650
  end
681
651
 
682
652
  # Valid parameters for a Timer, along with those defined in
@@ -691,11 +661,8 @@ eos
691
661
  return binding
692
662
  end
693
663
 
694
- # The memory sections of this configuration object.
695
- attr_reader :memory
696
-
697
- # The IO devices of this configuration object.
698
- attr_reader :io
664
+ # The bus devices of this configuration object.
665
+ attr_reader :devices
699
666
 
700
667
  # Parameters accessible by this configuration object.
701
668
  def params
@@ -734,8 +701,7 @@ eos
734
701
  #
735
702
  # @raise [Zemu::ConfigError] Raised if the +name+ parameter is not set, or contains whitespace.
736
703
  def initialize
737
- @memory = []
738
- @io = []
704
+ @devices = []
739
705
 
740
706
  super
741
707
 
@@ -750,16 +716,29 @@ eos
750
716
 
751
717
  # Adds a new memory section to this configuration.
752
718
  #
719
+ # Deprecated - retained only for backwards compatibility.
720
+ # Use add_device instead.
721
+ #
753
722
  # @param [Zemu::Config::Memory] mem The memory object to add.
754
723
  def add_memory(mem)
755
- @memory << mem
724
+ @devices << mem
756
725
  end
757
726
 
758
727
  # Adds a new IO device to this configuration.
759
728
  #
760
- # @param [Zemu::Config::IOPort] io The IO device to add.
729
+ # Deprecated - retained only for backwards compatibility.
730
+ # Use add_device instead.
731
+ #
732
+ # @param [Zemu::Config::BusDevice] io The IO device to add.
761
733
  def add_io(io)
762
- @io << io
734
+ @devices << io
735
+ end
736
+
737
+ # Adds a new device to the bus for this configuration.
738
+ #
739
+ # @param [Zemu::Config::BusDevice] device The device to add.
740
+ def add_device(device)
741
+ @devices << device
763
742
  end
764
743
  end
765
744
 
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
- if symbols[s.address].nil?
15
- symbols[s.address] = []
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
- symbols[s.address] << s
19
- symbols[s.address].sort_by!(&:label)
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
- return symbols
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
@@ -37,6 +37,14 @@ module Zemu
37
37
  "L'" => 19
38
38
  }
39
39
 
40
+ # Mapping of extended registers
41
+ # to the registers that comprise them.
42
+ REGISTERS_EXTENDED = {
43
+ "HL" => ["H", "L"],
44
+ "BC" => ["B", "C"],
45
+ "DE" => ["D", "E"]
46
+ }
47
+
40
48
  # States that the emulated machine can be in.
41
49
  class RunState
42
50
  # Currently executing an instruction.
@@ -53,6 +61,10 @@ module Zemu
53
61
  end
54
62
 
55
63
  def initialize(configuration)
64
+ # Methods defined by bus devices that we make
65
+ # accessible to the user.
66
+ @device_methods = []
67
+
56
68
  @clock = configuration.clock_speed
57
69
  @serial_delay = configuration.serial_delay
58
70
 
@@ -91,6 +103,12 @@ module Zemu
91
103
  REGISTERS.each do |reg, num|
92
104
  r[reg] = @wrapper.zemu_debug_register(@instance, num)
93
105
  end
106
+
107
+ REGISTERS_EXTENDED.each do |reg, components|
108
+ hi = components[0]
109
+ lo = components[1]
110
+ r[reg] = (r[hi] << 8) | r[lo]
111
+ end
94
112
 
95
113
  return r
96
114
  end
@@ -105,6 +123,16 @@ module Zemu
105
123
  return @wrapper.zemu_debug_get_memory(address)
106
124
  end
107
125
 
126
+ # Set the value in memory at a given address.
127
+ #
128
+ # @param address The address in memory to be set.
129
+ # @param value The value to set to.
130
+ #
131
+ # Returns nothing.
132
+ def set_memory(address, value)
133
+ @wrapper.zemu_debug_set_memory(address, value)
134
+ end
135
+
108
136
  # Write a string to the serial line of the emulated CPU.
109
137
  #
110
138
  # @param string The string to be sent.
@@ -245,16 +273,27 @@ module Zemu
245
273
  wrapper.attach_function :zemu_debug_pc, [:pointer], :uint16
246
274
 
247
275
  wrapper.attach_function :zemu_debug_get_memory, [:uint16], :uint8
276
+ wrapper.attach_function :zemu_debug_set_memory, [:uint16, :uint8], :void
248
277
 
249
- configuration.io.each do |device|
278
+ configuration.devices.each do |device|
250
279
  device.functions.each do |f|
251
280
  wrapper.attach_function(f["name"].to_sym, f["args"], f["return"])
281
+ @device_methods << f["name"].to_sym
252
282
  end
253
283
  end
254
284
 
255
285
  return wrapper
256
286
  end
257
287
 
288
+ # Redirects calls to I/O FFI functions.
289
+ def method_missing(method, *args)
290
+ if @device_methods.include? method
291
+ return @wrapper.send(method)
292
+ end
293
+
294
+ super
295
+ end
296
+
258
297
  private :make_wrapper
259
298
  end
260
299
  end
@@ -5,7 +5,14 @@ module Zemu
5
5
  # Constructor.
6
6
  #
7
7
  # Create a new interactive wrapper for the given instance.
8
- def initialize(instance)
8
+ # The options hash allows the user to configure the behaviour
9
+ # of the interactive instance:
10
+ # :print_serial => true if serial input/output should be logged
11
+ # to the emulator window.
12
+ def initialize(instance, options = {})
13
+ @print_serial = options[:print_serial]
14
+ @trace = []
15
+
9
16
  @instance = instance
10
17
 
11
18
  @symbol_table = {}
@@ -64,6 +71,9 @@ module Zemu
64
71
  elsif cmd[0] == "map"
65
72
  load_map(cmd[1])
66
73
 
74
+ elsif cmd[0] == "trace"
75
+ trace()
76
+
67
77
  elsif cmd[0] == "help"
68
78
  log "Available commands:"
69
79
  log " continue [<n>] - Continue execution for <n> cycles"
@@ -84,6 +94,14 @@ module Zemu
84
94
  close
85
95
  end
86
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
+
87
105
  # Outputs a table giving the current values of the instance's registers.
88
106
  # For the 16-bit registers (BC, DE, HL, IX, IY, SP, PC), attempts to identify the symbol
89
107
  # to which they point.
@@ -179,6 +197,9 @@ module Zemu
179
197
  cycles_left -= cycles_done
180
198
  actual_cycles += cycles_done
181
199
 
200
+ @trace << r16("PC")
201
+ @trace = @trace[1..] if @trace.size > 200
202
+
182
203
  # Get time after execution.
183
204
  ending = Time.now
184
205
 
@@ -193,6 +214,11 @@ module Zemu
193
214
  sleep(padding) unless padding < 0
194
215
  end
195
216
 
217
+ if (@instance.memory(0x200) != 0xf3)
218
+ log "Buffer overflow at #{r16("PC")}"
219
+ break
220
+ end
221
+
196
222
  # Have we hit a breakpoint or HALT instruction?
197
223
  if @instance.break?
198
224
  log "Hit breakpoint at #{r16("PC")}."
@@ -252,7 +278,7 @@ module Zemu
252
278
 
253
279
  syms = {}
254
280
  begin
255
- syms.merge! Debug.load_map(path.to_s)
281
+ syms.merge! Debug.load_map(path.to_s).hash
256
282
  rescue ArgumentError => e
257
283
  log "Error loading map file: #{e.message}"
258
284
  syms.clear
@@ -275,12 +301,12 @@ module Zemu
275
301
 
276
302
  unless input.empty?
277
303
  @instance.serial_puts input
278
- log "Serial in: #{input}"
304
+ log "Serial in: #{input} ($#{input.ord.to_s(16)})" if @print_serial
279
305
  end
280
306
 
281
307
  unless output.empty?
282
308
  @master.write output
283
- log "Serial out: #{output}"
309
+ log "Serial out: #{output} ($#{output.ord.to_s(16)})" if @print_serial
284
310
  end
285
311
  end
286
312
  end
data/lib/zemu.rb CHANGED
@@ -62,10 +62,12 @@ module Zemu
62
62
  SRC = File.join(__dir__, "..", "src")
63
63
 
64
64
  # Build and start an emulator according to the given configuration.
65
+ # Returns the emulator instance.
65
66
  #
66
67
  # @param [Zemu::Config] configuration The configuration for which an emulator will be generated.
67
- def Zemu::start(configuration)
68
- build(configuration)
68
+ # @param user_defines Any user-defined preprocessor macros.
69
+ def Zemu::start(configuration, user_defines={})
70
+ build(configuration, user_defines)
69
71
 
70
72
  return Instance.new(configuration)
71
73
  end
@@ -73,19 +75,19 @@ module Zemu
73
75
  # Starts an interactive instance of an emulator, according to the given configuration.
74
76
  #
75
77
  # @param [Zemu::Config] configuration The configuration for which an emulator will be generated.
76
- def Zemu::start_interactive(configuration)
78
+ def Zemu::start_interactive(configuration, options = {})
77
79
  instance = start(configuration)
78
80
 
79
- interactive = InteractiveInstance.new(instance)
81
+ interactive = InteractiveInstance.new(instance, options)
80
82
  interactive.run
81
83
  end
82
84
 
83
85
  # Builds a library according to the given configuration.
86
+ # Returns true if the build is a success, false (build failed) or nil (compiler not found) otherwise.
84
87
  #
85
88
  # @param [Zemu::Config] configuration The configuration for which an emulator will be generated.
86
- #
87
- # @returns true if the build is a success, false (build failed) or nil (compiler not found) otherwise.
88
- def Zemu::build(configuration)
89
+ # @param user_defines Any user-defined preprocessor macros.
90
+ def Zemu::build(configuration, user_defines={})
89
91
  # Create the output directory unless it already exists.
90
92
  unless Dir.exist? configuration.output_directory
91
93
  Dir.mkdir configuration.output_directory
@@ -109,13 +111,15 @@ module Zemu
109
111
 
110
112
  inputs_str = inputs.map { |i| File.join(SRC, i) }.join(" ")
111
113
 
112
- inputs_str += " " + File.join(autogen, "memory.c") + " " + File.join(autogen, "io.c")
114
+ inputs_str += " " + File.join(autogen, "bus.c")
113
115
 
114
116
  defines = {
115
117
  "CPU_Z80_STATIC" => 1,
116
118
  "CPU_Z80_USE_LOCAL_HEADER" => 1
117
119
  }
118
120
 
121
+ defines.merge! user_defines
122
+
119
123
  defines_str = defines.map { |d, v| "-D#{d}=#{v}" }.join(" ")
120
124
 
121
125
  includes = [
@@ -139,32 +143,13 @@ module Zemu
139
143
  #
140
144
  # @param [Zemu::Config] configuration The configuration for which an emulator will be generated.
141
145
  def Zemu::generate(configuration)
142
- generate_memory(configuration)
143
- generate_io(configuration)
144
- end
145
-
146
- # Generates the memory.c and memory.h files for a given configuration.
147
- def Zemu::generate_memory(configuration)
148
- header_template = ERB.new File.read(File.join(SRC, "memory.h.erb"))
149
- source_template = ERB.new File.read(File.join(SRC, "memory.c.erb"))
150
-
151
- autogen = File.join(configuration.output_directory, "autogen_#{configuration.name}")
152
-
153
- unless Dir.exist? autogen
154
- Dir.mkdir autogen
155
- end
156
-
157
- File.write(File.join(autogen, "memory.h"),
158
- header_template.result(configuration.get_binding))
159
-
160
- File.write(File.join(autogen, "memory.c"),
161
- source_template.result(configuration.get_binding))
146
+ generate_bus(configuration)
162
147
  end
163
148
 
164
- # Generates the io.c and io.h files for a given configuration.
165
- def Zemu::generate_io(configuration)
166
- header_template = ERB.new File.read(File.join(SRC, "io.h.erb"))
167
- source_template = ERB.new File.read(File.join(SRC, "io.c.erb"))
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"))
168
153
 
169
154
  autogen = File.join(configuration.output_directory, "autogen_#{configuration.name}")
170
155
 
@@ -172,10 +157,10 @@ module Zemu
172
157
  Dir.mkdir autogen
173
158
  end
174
159
 
175
- File.write(File.join(autogen, "io.h"),
160
+ File.write(File.join(autogen, "bus.h"),
176
161
  header_template.result(configuration.get_binding))
177
162
 
178
- File.write(File.join(autogen, "io.c"),
163
+ File.write(File.join(autogen, "bus.c"),
179
164
  source_template.result(configuration.get_binding))
180
165
  end
181
166
  end
data/src/bus.c.erb ADDED
@@ -0,0 +1,88 @@
1
+ #include "bus.h"
2
+
3
+ <% devices.each do |device| %>
4
+ <%= device.when_setup %>
5
+ <% end %>
6
+
7
+ zuint8 zemu_memory_read(void * context, zuint16 address)
8
+ {
9
+ zuint32 address_32 = address;
10
+ <% devices.each do |mem| %>
11
+ <%= mem.when_mem_read %>
12
+ <% end %>
13
+ /* Unmapped memory has a value of 0. */
14
+ return 0;
15
+ }
16
+
17
+ void zemu_memory_write(void * context, zuint16 address, zuint8 value)
18
+ {
19
+ zuint32 address_32 = address;
20
+ <% devices.each do |mem| %>
21
+ <%= mem.when_mem_write %>
22
+ <% end %>
23
+ }
24
+
25
+ zuint8 zemu_memory_peek(zuint16 address)
26
+ {
27
+ zuint32 address_32 = address;
28
+ <% devices.each do |mem| %>
29
+ <%= mem.when_mem_read %>
30
+ <% end %>
31
+ /* Unmapped memory has a value of 0. */
32
+ return 0;
33
+ }
34
+
35
+ void zemu_memory_poke(zuint16 address, zuint8 value)
36
+ {
37
+ zuint32 address_32 = address;
38
+ <% devices.each do |mem| %>
39
+ <%= mem.when_mem_write %>
40
+ <% end %>
41
+ }
42
+
43
+ void zemu_io_nmi(Z80 * instance)
44
+ {
45
+ z80_nmi(instance);
46
+ }
47
+
48
+ void zemu_io_int_on(Z80 * instance)
49
+ {
50
+ z80_int(instance, TRUE);
51
+ }
52
+
53
+ void zemu_io_int_off(Z80 * instance)
54
+ {
55
+ z80_int(instance, FALSE);
56
+ }
57
+
58
+ zuint8 zemu_io_in(void * context, zuint16 port)
59
+ {
60
+ /* Z80 IO ports occupy the lower half of the address bus.
61
+ * We cannot assume that the top half is valid.
62
+ */
63
+ port &= 0x00FF;
64
+
65
+ <% devices.each do |device| %>
66
+ <%= device.when_io_read %>
67
+ <% end %>
68
+ return 0;
69
+ }
70
+
71
+ void zemu_io_out(void * context, zuint16 port, zuint8 value)
72
+ {
73
+ /* Z80 IO ports occupy the lower half of the address bus.
74
+ * We cannot assume that the top half is valid.
75
+ */
76
+ port &= 0x00FF;
77
+
78
+ <% devices.each do |device| %>
79
+ <%= device.when_io_write %>
80
+ <% end %>
81
+ }
82
+
83
+ void zemu_io_clock(Z80 * instance)
84
+ {
85
+ <% devices.each do |device| %>
86
+ <%= device.when_clock %>
87
+ <% end %>
88
+ }
@@ -13,6 +13,13 @@ typedef struct {
13
13
  unsigned int tail;
14
14
  } SerialBuffer;
15
15
 
16
+
17
+ zuint8 zemu_memory_read(void * context, zuint16 address);
18
+ void zemu_memory_write(void * context, zuint16 address, zuint8 value);
19
+
20
+ zuint8 zemu_memory_peek(zuint16 address);
21
+ void zemu_memory_poke(zuint16 address, zuint8 value);
22
+
16
23
  void zemu_io_serial_master_puts(zuint8 val);
17
24
  zuint8 zemu_io_serial_master_gets(void);
18
25
  zusize zemu_io_serial_buffer_size(void);
data/src/debug.c CHANGED
@@ -72,3 +72,8 @@ zuint8 zemu_debug_get_memory(zuint16 address)
72
72
  {
73
73
  return zemu_memory_peek(address);
74
74
  }
75
+
76
+ void zemu_debug_set_memory(zuint16 address, zuint8 value)
77
+ {
78
+ zemu_memory_poke(address, value);
79
+ }
data/src/debug.h CHANGED
@@ -2,8 +2,7 @@
2
2
 
3
3
  #include <stdio.h>
4
4
 
5
- #include "memory.h"
6
- #include "io.h"
5
+ #include "bus.h"
7
6
 
8
7
  zusize zemu_debug_step(Z80 * instance);
9
8
 
data/src/main.c CHANGED
@@ -4,8 +4,7 @@
4
4
 
5
5
  #include "debug.h"
6
6
 
7
- #include "memory.h"
8
- #include "io.h"
7
+ #include "bus.h"
9
8
  #include "interrupt.h"
10
9
 
11
10
  /* Allocate and initialize a Z80 instance.
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.0
4
+ version: 0.6.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: 2021-10-23 00:00:00.000000000 Z
11
+ date: 2021-12-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
data/src/io.c.erb DELETED
@@ -1,52 +0,0 @@
1
- #include "io.h"
2
-
3
- <% io.each do |device| %>
4
- <%= device.setup %>
5
- <% end %>
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
-
22
- zuint8 zemu_io_in(void * context, zuint16 port)
23
- {
24
- /* Z80 IO ports occupy the lower half of the address bus.
25
- * We cannot assume that the top half is valid.
26
- */
27
- port &= 0x00FF;
28
-
29
- <% io.each do |device| %>
30
- <%= device.read %>
31
- <% end %>
32
- return 0;
33
- }
34
-
35
- void zemu_io_out(void * context, zuint16 port, zuint8 value)
36
- {
37
- /* Z80 IO ports occupy the lower half of the address bus.
38
- * We cannot assume that the top half is valid.
39
- */
40
- port &= 0x00FF;
41
-
42
- <% io.each do |device| %>
43
- <%= device.write %>
44
- <% end %>
45
- }
46
-
47
- void zemu_io_clock(Z80 * instance)
48
- {
49
- <% io.each do |device| %>
50
- <%= device.clock %>
51
- <% end %>
52
- }
data/src/memory.c.erb DELETED
@@ -1,43 +0,0 @@
1
- #include "memory.h"
2
-
3
- <% memory.each do |mem| %>
4
- /* Initialization memory block "<%= mem.name %>" */
5
- <%= mem.readonly? ? "const " : "" %>zuint8 zemu_memory_block_<%= mem.name %>[0x<%= mem.size.to_s(16) %>] =
6
- {<% mem.contents.each_with_index do |b, i| %><%= (i % 16 == 0) ? "\n " : "" %><%= ("0x%02x, " % b) %><% end %>
7
- };
8
- <% end %>
9
-
10
- zuint8 zemu_memory_read(void * context, zuint16 address)
11
- {
12
- <% memory.each do |mem| %>
13
- if (address >= 0x<%= mem.address.to_s(16) %> && address < 0x<%= (mem.address + mem.size).to_s(16) %>)
14
- {
15
- return zemu_memory_block_<%= mem.name %>[address - 0x<%= mem.address.to_s(16) %>];
16
- }
17
- <% end %>
18
- /* Unmapped memory has a value of 0. */
19
- return 0;
20
- }
21
-
22
- void zemu_memory_write(void * context, zuint16 address, zuint8 value)
23
- {
24
- <% memory.each do |mem| %>
25
- <% next if mem.readonly? %>
26
- if (address >= 0x<%= mem.address.to_s(16) %> && address < 0x<%= (mem.address + mem.size).to_s(16) %>)
27
- {
28
- zemu_memory_block_<%= mem.name %>[address - 0x<%= mem.address.to_s(16) %>] = value;
29
- }
30
- <% end %>
31
- }
32
-
33
- zuint8 zemu_memory_peek(zuint16 address)
34
- {
35
- <% memory.each do |mem| %>
36
- if (address >= 0x<%= mem.address.to_s(16) %> && address < 0x<%= (mem.address + mem.size).to_s(16) %>)
37
- {
38
- return zemu_memory_block_<%= mem.name %>[address - 0x<%= mem.address.to_s(16) %>];
39
- }
40
- <% end %>
41
- /* Unmapped memory has a value of 0. */
42
- return 0;
43
- }
data/src/memory.h.erb DELETED
@@ -1,9 +0,0 @@
1
- #include "emulation/CPU/Z80.h"
2
-
3
- #include <stdio.h>
4
-
5
- zuint8 zemu_memory_read(void * context, zuint16 address);
6
-
7
- void zemu_memory_write(void * context, zuint16 address, zuint8 value);
8
-
9
- zuint8 zemu_memory_peek(zuint16 address);