zemu 0.4.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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);