zemu 0.2.2 → 0.3.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: 79900374a7a271fbfc1333290b4078e8e587ebbec09034c9cde520623459fcd4
4
- data.tar.gz: 6282f2f1d04cf8188d84a058100d7db55d9305c3c577104455ead68195d17adb
3
+ metadata.gz: dbdac0f92af987d3202f5975f4bc119c448a0c3356c5bfa069ff659977e6c150
4
+ data.tar.gz: 55becc89a08a3aee55baddf0dd172bd702dbfe2ab328340578f5ed313a983aa3
5
5
  SHA512:
6
- metadata.gz: 30dcdd1f3b79b767816a23a28c34107fb91ea48a8bbff445fa90228d4c2fe83276ba4f5ffb727f881e1864edeb40cbbefe1f637cb2e07a2793c0bbbab3ecf7fb
7
- data.tar.gz: cf6f4519a152b2f1372c581222a35bcd33a32934607bdeae878330216551a26f712a7837ddf5a9935389c4c6a1b2aeba600c2e0c178fc083bb5dce616542cf19
6
+ metadata.gz: a41f637706dc296b456da80be43af7cb1aeb7e7e34700c3d2e731f9da3698a16cb18f7b622b8a82054eb3c789d451bea6cbd73f145f9a76e6fd8c5850c9fbede
7
+ data.tar.gz: 8174742e9ab6adc69f284bd8a33763d03074daafaa638f385fc4ff3cc27db2ebbeed85d23999b77439a2340722882bc1048626a8b4bc5eda1768263cdecdbff4
data/lib/zemu/config.rb CHANGED
@@ -228,6 +228,10 @@ module Zemu
228
228
  end
229
229
 
230
230
  @ports = []
231
+ @setup_block = nil
232
+ @read_block = nil
233
+ @write_block = nil
234
+ @clock_block = nil
231
235
 
232
236
  super
233
237
  end
@@ -269,28 +273,46 @@ module Zemu
269
273
  @write_block = block
270
274
  end
271
275
 
276
+ # Defines the per-cycle behaviour of this IO device.
277
+ #
278
+ # Expects a block, the return value of which is a string
279
+ # defining the behaviour of the IO device on each system clock cycle.
280
+ # Care must be taken to ensure that this functionality does not conflict with that of
281
+ # any other IO devices.
282
+ #
283
+ # The block will be instance-evaluated at build-time, so it is possible to use
284
+ # instance variables of the IO device.
285
+ def when_clock(&block)
286
+ @clock_block = block
287
+ end
288
+
272
289
  # Evaluates the when_setup block of this IO device and returns the resulting string.
273
290
  def setup
274
- instance_eval(&@setup_block)
291
+ return instance_eval(&@setup_block) unless @setup_block.nil?
292
+ return ""
275
293
  end
276
294
 
277
295
  # Evaluates the when_read block of this IO device and returns the resulting string.
278
296
  def read
279
- instance_eval(&@read_block)
297
+ return instance_eval(&@read_block) unless @read_block.nil?
298
+ return ""
280
299
  end
281
300
 
282
301
  # Evaluates the when_write block of this IO device and returns the resulting string.
283
302
  def write
284
- instance_eval(&@write_block)
303
+ return instance_eval(&@write_block) unless @write_block.nil?
304
+ return ""
305
+ end
306
+
307
+ # Evaluates the when_clock block of this IO device and returns the resulting string.
308
+ def clock
309
+ return instance_eval(&@clock_block) unless @clock_block.nil?
310
+ return ""
285
311
  end
286
312
 
287
313
  # Defines FFI API which will be available to the instance wrapper if this IO device is used.
288
314
  def functions
289
- [
290
- {"name" => "zemu_io_#{name}_master_puts".to_sym, "args" => [:uint8], "return" => :void},
291
- {"name" => "zemu_io_#{name}_master_gets".to_sym, "args" => [], "return" => :uint8},
292
- {"name" => "zemu_io_#{name}_buffer_size".to_sym, "args" => [], "return" => :uint64}
293
- ]
315
+ []
294
316
  end
295
317
 
296
318
  # Valid parameters for this object.
@@ -401,6 +423,15 @@ module Zemu
401
423
  end
402
424
  end
403
425
 
426
+ # Defines FFI API which will be available to the instance wrapper if this IO device is used.
427
+ def functions
428
+ [
429
+ {"name" => "zemu_io_#{name}_master_puts".to_sym, "args" => [:uint8], "return" => :void},
430
+ {"name" => "zemu_io_#{name}_master_gets".to_sym, "args" => [], "return" => :uint8},
431
+ {"name" => "zemu_io_#{name}_buffer_size".to_sym, "args" => [], "return" => :uint64}
432
+ ]
433
+ end
434
+
404
435
  # Valid parameters for a SerialPort, along with those
405
436
  # defined in [Zemu::Config::IOPort].
406
437
  def params
@@ -408,6 +439,44 @@ module Zemu
408
439
  end
409
440
  end
410
441
 
442
+ # Non-Maskable Interrupt Timer
443
+ #
444
+ # Represents a timer device, the period of which can be controlled
445
+ # by the CPU through an IO port. The timer generates an NMI once this
446
+ # period has expired. The timer can be reset via a control port.
447
+ class Timer < IOPort
448
+ def initialize
449
+ super
450
+
451
+ when_setup do
452
+ "zuint8 io_#{name}_count;\n" +
453
+ "zuint8 io_#{name}_running = 0;\n"
454
+ end
455
+
456
+ when_read do
457
+ end
458
+
459
+ when_write do
460
+ "if (port == #{count_port}) io_#{name}_count = value;\n" +
461
+ "else if (port == #{control_port}) io_#{name}_running = value;\n"
462
+ end
463
+
464
+ when_clock do
465
+ "if (io_#{name}_running)\n" +
466
+ "{\n" +
467
+ " if (io_#{name}_count > 0) io_#{name}_count--;\n" +
468
+ " else zemu_io_nmi(instance);\n" +
469
+ "}\n"
470
+ end
471
+ end
472
+
473
+ # Valid parameters for a Timer, along with those defined in
474
+ # [Zemu::Config::IOPort].
475
+ def params
476
+ super + %w(count_port control_port)
477
+ end
478
+ end
479
+
411
480
  # Gets a binding for this object.
412
481
  def get_binding
413
482
  return binding
data/lib/zemu/instance.rb CHANGED
@@ -37,6 +37,21 @@ module Zemu
37
37
  "L'" => 19
38
38
  }
39
39
 
40
+ # States that the emulated machine can be in.
41
+ class RunState
42
+ # Currently executing an instruction.
43
+ RUNNING = 0
44
+
45
+ # Executed a HALT instruction in the previous cycle.
46
+ HALTED = 1
47
+
48
+ # Hit a breakpoint in the previous cycle.
49
+ BREAK = 2
50
+
51
+ # Undefined. Emulated machine has not yet reached a well-defined state.
52
+ UNDEFINED = -1
53
+ end
54
+
40
55
  def initialize(configuration)
41
56
  @clock = configuration.clock_speed
42
57
 
@@ -47,6 +62,10 @@ module Zemu
47
62
  @instance = @wrapper.zemu_init
48
63
  @wrapper.zemu_power_on(@instance)
49
64
  @wrapper.zemu_reset(@instance)
65
+
66
+ @state = RunState::UNDEFINED
67
+
68
+ @breakpoints = []
50
69
  end
51
70
 
52
71
  # Returns the clock speed of this instance in Hz.
@@ -124,7 +143,32 @@ module Zemu
124
143
  #
125
144
  # Returns the number of cycles executed.
126
145
  def continue(run_cycles=-1)
127
- return @wrapper.zemu_debug_continue(@instance, run_cycles)
146
+ # Return immediately if we're HALTED.
147
+ return if @state == RunState::HALTED
148
+
149
+ cycles_executed = 0
150
+
151
+ @state = RunState::RUNNING
152
+
153
+ # Run as long as:
154
+ # We haven't hit a breakpoint
155
+ # We haven't halted
156
+ # We haven't hit the number of cycles we've been told to execute for.
157
+ while (run_cycles == -1 || cycles_executed < run_cycles) && (@state == RunState::RUNNING)
158
+ cycles_executed += @wrapper.zemu_debug_step(@instance)
159
+
160
+ pc = @wrapper.zemu_debug_pc(@instance)
161
+
162
+ # If the PC is now pointing to one of our breakpoints,
163
+ # we're in the BREAK state.
164
+ if (@breakpoints.select { |b| b == pc }.size) > 0
165
+ @state = RunState::BREAK
166
+ elsif @wrapper.zemu_debug_halted()
167
+ @state = RunState::HALTED
168
+ end
169
+ end
170
+
171
+ return cycles_executed
128
172
  end
129
173
 
130
174
  # Set a breakpoint of the given type at the given address.
@@ -133,17 +177,26 @@ module Zemu
133
177
  # @param type The type of breakpoint:
134
178
  # * :program => Break when the program counter hits the address given.
135
179
  def break(address, type)
136
- @wrapper.zemu_debug_set_breakpoint(address)
180
+ @breakpoints << address
181
+ end
182
+
183
+ # Remove a breakpoint of the given type at the given address.
184
+ # Does nothing if no breakpoint previously existed at that address.
185
+ #
186
+ # @param address The address of the breakpoint to be removed.
187
+ # @param type The type of breakpoint. See Instance#break.
188
+ def remove_break(address, type)
189
+ @breakpoints.reject! { |b| b == address }
137
190
  end
138
191
 
139
192
  # Returns true if the CPU has halted, false otherwise.
140
193
  def halted?
141
- return @wrapper.zemu_debug_halted
194
+ return @state == RunState::HALTED
142
195
  end
143
196
 
144
197
  # Returns true if a breakpoint has been hit, false otherwise.
145
198
  def break?
146
- return @wrapper.zemu_debug_break
199
+ return @state == RunState::BREAK
147
200
  end
148
201
 
149
202
  # Powers off the emulated CPU and destroys this instance.
@@ -168,14 +221,12 @@ module Zemu
168
221
 
169
222
  wrapper.attach_function :zemu_reset, [:pointer], :void
170
223
 
171
- wrapper.attach_function :zemu_debug_continue, [:pointer, :int64], :uint64
224
+ wrapper.attach_function :zemu_debug_step, [:pointer], :uint64
172
225
 
173
226
  wrapper.attach_function :zemu_debug_halted, [], :bool
174
- wrapper.attach_function :zemu_debug_break, [], :bool
175
-
176
- wrapper.attach_function :zemu_debug_set_breakpoint, [:uint16], :void
177
227
 
178
228
  wrapper.attach_function :zemu_debug_register, [:pointer, :uint16], :uint16
229
+ wrapper.attach_function :zemu_debug_pc, [:pointer], :uint16
179
230
 
180
231
  wrapper.attach_function :zemu_debug_get_memory, [:uint16], :uint8
181
232
 
data/src/debug.c CHANGED
@@ -1,69 +1,16 @@
1
1
  #include "debug.h"
2
2
 
3
- RunState zemu_debug_state = UNDEFINED;
4
-
5
- /* Currently, the number of breakpoints is defined statically.
6
- * Perhaps in future there will be an unlimited number.
7
- */
8
- zuint16 breakpoints[ZEMU_DEBUG_MAX_BREAKPOINTS];
9
- unsigned int breakpoint_count = 0;
10
-
11
- zusize zemu_debug_continue(Z80 * instance, zinteger run_cycles)
12
- {
13
- /* Return if we've halted. */
14
- if (zemu_debug_state == HALTED) return 0;
15
-
16
- zusize cycles = 0;
17
-
18
- zemu_debug_state = RUNNING;
19
-
20
- /* Run as long as:
21
- * We don't hit a breakpoint
22
- * We haven't run for more than the number of cycles given
23
- */
24
- while (zemu_debug_state == RUNNING && (run_cycles < 0 || cycles < run_cycles))
25
- {
26
- cycles += zemu_debug_step(instance);
27
-
28
- /* See if the Program Counter now matches any address
29
- * in the breakpoint array.
30
- */
31
- for (unsigned int b = 0; b < breakpoint_count; b++)
32
- {
33
- if (instance->state.pc == breakpoints[b])
34
- {
35
- zemu_debug_state = BREAK;
36
- }
37
- }
38
- }
39
-
40
- return cycles;
41
- }
3
+ zboolean halted = FALSE;
42
4
 
43
5
  zusize zemu_debug_step(Z80 * instance)
44
6
  {
45
7
  /* Will run for at least one cycle. */
46
8
  zusize cycles = z80_run(instance, 1);
47
9
 
48
- return cycles;
49
- }
50
-
51
- void zemu_debug_halt(void * context, zboolean state)
52
- {
53
- if (state)
54
- {
55
- zemu_debug_state = HALTED;
56
- }
57
- else
58
- {
59
- zemu_debug_state = RUNNING;
60
- }
61
- }
10
+ /* Execute the per-cycle behaviour of the peripheral devices. */
11
+ for (zusize i = 0; i < cycles; i++) zemu_io_clock(instance);
62
12
 
63
- void zemu_debug_set_breakpoint(zuint16 address)
64
- {
65
- breakpoints[breakpoint_count] = address;
66
- breakpoint_count++;
13
+ return cycles;
67
14
  }
68
15
 
69
16
  zuint16 zemu_debug_register(Z80 * instance, zuint16 r)
@@ -106,14 +53,19 @@ zuint16 zemu_debug_register(Z80 * instance, zuint16 r)
106
53
  }
107
54
  }
108
55
 
109
- zboolean zemu_debug_halted(void)
56
+ zuint16 zemu_debug_pc(Z80 * instance)
57
+ {
58
+ return instance->state.pc;
59
+ }
60
+
61
+ void zemu_debug_halt(void * context, zboolean state)
110
62
  {
111
- return (zemu_debug_state == HALTED);
63
+ halted = state;
112
64
  }
113
65
 
114
- zboolean zemu_debug_break(void)
66
+ zboolean zemu_debug_halted(void)
115
67
  {
116
- return (zemu_debug_state == BREAK);
68
+ return (halted);
117
69
  }
118
70
 
119
71
  zuint8 zemu_debug_get_memory(zuint16 address)
data/src/debug.h CHANGED
@@ -3,28 +3,16 @@
3
3
  #include <stdio.h>
4
4
 
5
5
  #include "memory.h"
6
-
7
- /* Define number of breakpoints, if not done so already. */
8
- #ifndef ZEMU_DEBUG_MAX_BREAKPOINTS
9
- #define ZEMU_DEBUG_MAX_BREAKPOINTS 256
10
- #endif
11
-
12
- typedef enum RunState
13
- {
14
- RUNNING,
15
- HALTED,
16
- BREAK,
17
- UNDEFINED
18
- } RunState;
19
-
20
- zusize zemu_debug_continue(Z80 * instance, zinteger run_cycles);
6
+ #include "io.h"
21
7
 
22
8
  zusize zemu_debug_step(Z80 * instance);
23
9
 
24
10
  void zemu_debug_halt(void * context, zboolean state);
25
11
 
26
12
  zboolean zemu_debug_halted(void);
27
-
28
- void zemu_debug_set_breakpoint(zuint16 address);
13
+ zboolean zemu_debug_break(void);
14
+ zboolean zemu_debug_running(void);
29
15
 
30
16
  zuint16 zemu_debug_register(Z80 * instance, zuint16 r);
17
+
18
+ zuint16 zemu_debug_pc(Z80 * instance);
data/src/io.c.erb CHANGED
@@ -28,3 +28,15 @@ void zemu_io_out(void * context, zuint16 port, zuint8 value)
28
28
  <%= device.write %>
29
29
  <% end %>
30
30
  }
31
+
32
+ void zemu_io_nmi(Z80 * instance)
33
+ {
34
+ z80_nmi(instance);
35
+ }
36
+
37
+ void zemu_io_clock(Z80 * instance)
38
+ {
39
+ <% io.each do |device| %>
40
+ <%= device.clock %>
41
+ <% end %>
42
+ }
data/src/io.h.erb CHANGED
@@ -1,3 +1,6 @@
1
+ #ifndef _ZEMU_IO_H
2
+ #define _ZEMU_IO_H
3
+
1
4
  #include "emulation/CPU/Z80.h"
2
5
 
3
6
  #ifndef ZEMU_IO_SERIAL_BUFFER_SIZE
@@ -16,3 +19,7 @@ zusize zemu_io_serial_buffer_size(void);
16
19
 
17
20
  zuint8 zemu_io_in(void * context, zuint16 port);
18
21
  void zemu_io_out(void * context, zuint16 port, zuint8 value);
22
+ void zemu_io_nmi(Z80 * instance);
23
+ void zemu_io_clock(Z80 * instance);
24
+
25
+ #endif
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zemu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.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: 2020-02-29 00:00:00.000000000 Z
11
+ date: 2020-03-05 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