zemu 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/zemu/config.rb +182 -2
- data/lib/zemu/instance.rb +5 -3
- data/src/io.c.erb +3 -100
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 79900374a7a271fbfc1333290b4078e8e587ebbec09034c9cde520623459fcd4
|
4
|
+
data.tar.gz: 6282f2f1d04cf8188d84a058100d7db55d9305c3c577104455ead68195d17adb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 30dcdd1f3b79b767816a23a28c34107fb91ea48a8bbff445fa90228d4c2fe83276ba4f5ffb727f881e1864edeb40cbbefe1f637cb2e07a2793c0bbbab3ecf7fb
|
7
|
+
data.tar.gz: cf6f4519a152b2f1372c581222a35bcd33a32934607bdeae878330216551a26f712a7837ddf5a9935389c4c6a1b2aeba600c2e0c178fc083bb5dce616542cf19
|
data/lib/zemu/config.rb
CHANGED
@@ -169,6 +169,53 @@ module Zemu
|
|
169
169
|
# Input/Output Port object
|
170
170
|
#
|
171
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
|
+
#
|
172
219
|
class IOPort < ConfigObject
|
173
220
|
attr_reader :io_type
|
174
221
|
|
@@ -185,6 +232,67 @@ module Zemu
|
|
185
232
|
super
|
186
233
|
end
|
187
234
|
|
235
|
+
# Defines the setup behaviour of this IO device.
|
236
|
+
#
|
237
|
+
# Expects a block, the return value of which is a string
|
238
|
+
# containing all data and function declarations required by this IO device.
|
239
|
+
#
|
240
|
+
# The block will be instance-evaluated at build-time, so it is possible to use
|
241
|
+
# instance variables of the IO device.
|
242
|
+
def when_setup(&block)
|
243
|
+
@setup_block = block
|
244
|
+
end
|
245
|
+
|
246
|
+
# Defines the read behaviour of this IO device.
|
247
|
+
#
|
248
|
+
# Expects a block, the return value of which is a string
|
249
|
+
# containing the behaviour of this IO device when a value is read from the IO bus.
|
250
|
+
# Care must be taken to ensure that this functionality does not conflict with that of
|
251
|
+
# any other IO devices.
|
252
|
+
#
|
253
|
+
# The block will be instance-evaluated at build-time, so it is possible to use
|
254
|
+
# instance variables of the IO device.
|
255
|
+
def when_read(&block)
|
256
|
+
@read_block = block
|
257
|
+
end
|
258
|
+
|
259
|
+
# Defines the write behaviour of this IO device.
|
260
|
+
#
|
261
|
+
# Expects a block, the return value of which is a string
|
262
|
+
# containing the behaviour of this IO device when a value is written to the IO bus.
|
263
|
+
# Care must be taken to ensure that this functionality does not conflict with that of
|
264
|
+
# any other IO devices.
|
265
|
+
#
|
266
|
+
# The block will be instance-evaluated at build-time, so it is possible to use
|
267
|
+
# instance variables of the IO device.
|
268
|
+
def when_write(&block)
|
269
|
+
@write_block = block
|
270
|
+
end
|
271
|
+
|
272
|
+
# Evaluates the when_setup block of this IO device and returns the resulting string.
|
273
|
+
def setup
|
274
|
+
instance_eval(&@setup_block)
|
275
|
+
end
|
276
|
+
|
277
|
+
# Evaluates the when_read block of this IO device and returns the resulting string.
|
278
|
+
def read
|
279
|
+
instance_eval(&@read_block)
|
280
|
+
end
|
281
|
+
|
282
|
+
# Evaluates the when_write block of this IO device and returns the resulting string.
|
283
|
+
def write
|
284
|
+
instance_eval(&@write_block)
|
285
|
+
end
|
286
|
+
|
287
|
+
# Defines FFI API which will be available to the instance wrapper if this IO device is used.
|
288
|
+
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
|
+
]
|
294
|
+
end
|
295
|
+
|
188
296
|
# Valid parameters for this object.
|
189
297
|
# Should be extended by subclasses but NOT REPLACED.
|
190
298
|
def params
|
@@ -217,8 +325,80 @@ module Zemu
|
|
217
325
|
#
|
218
326
|
def initialize
|
219
327
|
super
|
220
|
-
|
221
|
-
|
328
|
+
|
329
|
+
when_setup do
|
330
|
+
"SerialBuffer io_#{name}_buffer_master = { .head = 0, .tail = 0 };\n" +
|
331
|
+
"SerialBuffer io_#{name}_buffer_slave = { .head = 0, .tail = 0 };\n" +
|
332
|
+
"\n" +
|
333
|
+
"zusize zemu_io_#{name}_buffer_size(void)\n" +
|
334
|
+
"{\n" +
|
335
|
+
" zusize start = io_#{name}_buffer_slave.head;\n" +
|
336
|
+
" zusize end = io_#{name}_buffer_slave.tail\n;" +
|
337
|
+
" if (end < start) end += ZEMU_IO_SERIAL_BUFFER_SIZE;\n" +
|
338
|
+
" return end - start;\n" +
|
339
|
+
"}\n" +
|
340
|
+
"\n" +
|
341
|
+
"void zemu_io_#{name}_slave_puts(zuint8 val)\n" +
|
342
|
+
"{\n" +
|
343
|
+
" io_#{name}_buffer_slave.buffer[io_#{name}_buffer_slave.tail] = val;\n" +
|
344
|
+
" io_#{name}_buffer_slave.tail++;\n" +
|
345
|
+
" if (io_#{name}_buffer_slave.tail >= ZEMU_IO_SERIAL_BUFFER_SIZE)\n" +
|
346
|
+
" io_#{name}_buffer_slave.tail = 0;\n" +
|
347
|
+
"}\n" +
|
348
|
+
"\n" +
|
349
|
+
"zuint8 zemu_io_#{name}_slave_gets(void)\n" +
|
350
|
+
"{\n" +
|
351
|
+
" zuint8 val = io_#{name}_buffer_master.buffer[io_#{name}_buffer_master.head];\n" +
|
352
|
+
" io_#{name}_buffer_master.head++;\n" +
|
353
|
+
" if (io_#{name}_buffer_master.head >= ZEMU_IO_SERIAL_BUFFER_SIZE)\n" +
|
354
|
+
" io_#{name}_buffer_master.head = 0;\n" +
|
355
|
+
"\n" +
|
356
|
+
" return val;\n" +
|
357
|
+
"}\n" +
|
358
|
+
"\n" +
|
359
|
+
"void zemu_io_#{name}_master_puts(zuint8 val)\n" +
|
360
|
+
"{\n" +
|
361
|
+
" io_#{name}_buffer_master.buffer[io_#{name}_buffer_master.tail] = val;\n" +
|
362
|
+
" io_#{name}_buffer_master.tail++;\n" +
|
363
|
+
" if (io_#{name}_buffer_master.tail >= ZEMU_IO_SERIAL_BUFFER_SIZE)\n" +
|
364
|
+
" io_#{name}_buffer_master.tail = 0;\n" +
|
365
|
+
"}\n" +
|
366
|
+
"\n" +
|
367
|
+
"zuint8 zemu_io_#{name}_master_gets(void)\n" +
|
368
|
+
"{\n" +
|
369
|
+
" zuint8 val = io_#{name}_buffer_slave.buffer[io_#{name}_buffer_slave.head];\n" +
|
370
|
+
" io_#{name}_buffer_slave.head++;\n" +
|
371
|
+
" if (io_#{name}_buffer_slave.head >= ZEMU_IO_SERIAL_BUFFER_SIZE)\n" +
|
372
|
+
" io_#{name}_buffer_slave.head = 0;\n" +
|
373
|
+
"\n" +
|
374
|
+
" return val;\n" +
|
375
|
+
"}\n"
|
376
|
+
end
|
377
|
+
|
378
|
+
when_read do
|
379
|
+
"if (port == #{in_port})\n" +
|
380
|
+
"{\n" +
|
381
|
+
" return zemu_io_#{name}_slave_gets();\n" +
|
382
|
+
"}\n" +
|
383
|
+
"else if (port == #{ready_port})\n" +
|
384
|
+
"{\n" +
|
385
|
+
" if (io_#{name}_buffer_master.head == io_#{name}_buffer_master.tail)\n" +
|
386
|
+
" {\n" +
|
387
|
+
" return 0;\n" +
|
388
|
+
" }\n" +
|
389
|
+
" else\n" +
|
390
|
+
" {\n" +
|
391
|
+
" return 1;\n" +
|
392
|
+
" }\n" +
|
393
|
+
"}\n"
|
394
|
+
end
|
395
|
+
|
396
|
+
when_write do
|
397
|
+
"if (port == #{out_port})\n" +
|
398
|
+
"{\n" +
|
399
|
+
" zemu_io_#{name}_slave_puts(value);\n" +
|
400
|
+
"}\n"
|
401
|
+
end
|
222
402
|
end
|
223
403
|
|
224
404
|
# Valid parameters for a SerialPort, along with those
|
data/lib/zemu/instance.rb
CHANGED
@@ -179,9 +179,11 @@ module Zemu
|
|
179
179
|
|
180
180
|
wrapper.attach_function :zemu_debug_get_memory, [:uint16], :uint8
|
181
181
|
|
182
|
-
|
183
|
-
|
184
|
-
|
182
|
+
configuration.io.each do |device|
|
183
|
+
device.functions.each do |f|
|
184
|
+
wrapper.attach_function(f["name"], f["args"], f["return"])
|
185
|
+
end
|
186
|
+
end
|
185
187
|
|
186
188
|
return wrapper
|
187
189
|
end
|
data/src/io.c.erb
CHANGED
@@ -1,83 +1,8 @@
|
|
1
1
|
#include "io.h"
|
2
2
|
|
3
3
|
<% io.each do |device| %>
|
4
|
-
|
5
|
-
/* Buffer to which the master pushes data, slave pulls. */
|
6
|
-
SerialBuffer io_serial_buffer_master = { .head = 0, .tail = 0 };
|
7
|
-
|
8
|
-
/* Buffer to which the slave pushes data, master pulls. */
|
9
|
-
SerialBuffer io_serial_buffer_slave = { .head = 0, .tail = 0 };
|
10
|
-
<% end %>
|
11
|
-
<% end %>
|
12
|
-
|
13
|
-
zusize zemu_io_serial_buffer_size(void)
|
14
|
-
{
|
15
|
-
<% unless io.empty? %>
|
16
|
-
zusize start = io_serial_buffer_slave.head;
|
17
|
-
zusize end = io_serial_buffer_slave.tail;
|
18
|
-
|
19
|
-
if (end < start)
|
20
|
-
{
|
21
|
-
end += ZEMU_IO_SERIAL_BUFFER_SIZE;
|
22
|
-
}
|
23
|
-
|
24
|
-
return end - start;
|
25
|
-
<% else %>
|
26
|
-
return 0;
|
27
|
-
<% end %>
|
28
|
-
}
|
29
|
-
|
30
|
-
void zemu_io_serial_slave_puts(zuint8 val)
|
31
|
-
{
|
32
|
-
<% unless io.empty? %>
|
33
|
-
io_serial_buffer_slave.buffer[io_serial_buffer_slave.tail] = val;
|
34
|
-
io_serial_buffer_slave.tail++;
|
35
|
-
|
36
|
-
if (io_serial_buffer_slave.tail >= ZEMU_IO_SERIAL_BUFFER_SIZE)
|
37
|
-
io_serial_buffer_slave.tail = 0;
|
38
|
-
<% end %>
|
39
|
-
}
|
40
|
-
|
41
|
-
zuint8 zemu_io_serial_slave_gets(void)
|
42
|
-
{
|
43
|
-
<% unless io.empty? %>
|
44
|
-
zuint8 val = io_serial_buffer_master.buffer[io_serial_buffer_master.head];
|
45
|
-
io_serial_buffer_master.head++;
|
46
|
-
|
47
|
-
if (io_serial_buffer_master.head >= ZEMU_IO_SERIAL_BUFFER_SIZE)
|
48
|
-
io_serial_buffer_master.head = 0;
|
49
|
-
|
50
|
-
return val;
|
51
|
-
<% else %>
|
52
|
-
return 0;
|
53
|
-
<% end %>
|
54
|
-
}
|
55
|
-
|
56
|
-
void zemu_io_serial_master_puts(zuint8 val)
|
57
|
-
{
|
58
|
-
<% unless io.empty? %>
|
59
|
-
io_serial_buffer_master.buffer[io_serial_buffer_master.tail] = val;
|
60
|
-
io_serial_buffer_master.tail++;
|
61
|
-
|
62
|
-
if (io_serial_buffer_master.tail >= ZEMU_IO_SERIAL_BUFFER_SIZE)
|
63
|
-
io_serial_buffer_master.tail = 0;
|
64
|
-
<% end %>
|
65
|
-
}
|
66
|
-
|
67
|
-
zuint8 zemu_io_serial_master_gets(void)
|
68
|
-
{
|
69
|
-
<% unless io.empty? %>
|
70
|
-
zuint8 val = io_serial_buffer_slave.buffer[io_serial_buffer_slave.head];
|
71
|
-
io_serial_buffer_slave.head++;
|
72
|
-
|
73
|
-
if (io_serial_buffer_slave.head >= ZEMU_IO_SERIAL_BUFFER_SIZE)
|
74
|
-
io_serial_buffer_slave.head = 0;
|
75
|
-
|
76
|
-
return val;
|
77
|
-
<% else %>
|
78
|
-
return 0;
|
4
|
+
<%= device.setup %>
|
79
5
|
<% end %>
|
80
|
-
}
|
81
6
|
|
82
7
|
zuint8 zemu_io_in(void * context, zuint16 port)
|
83
8
|
{
|
@@ -87,24 +12,7 @@ zuint8 zemu_io_in(void * context, zuint16 port)
|
|
87
12
|
port &= 0x00FF;
|
88
13
|
|
89
14
|
<% io.each do |device| %>
|
90
|
-
|
91
|
-
if (port == <%= device.in_port %>)
|
92
|
-
{
|
93
|
-
return zemu_io_serial_slave_gets();
|
94
|
-
}
|
95
|
-
|
96
|
-
else if (port == <%= device.ready_port %>)
|
97
|
-
{
|
98
|
-
if (io_serial_buffer_master.head == io_serial_buffer_master.tail)
|
99
|
-
{
|
100
|
-
return 0;
|
101
|
-
}
|
102
|
-
else
|
103
|
-
{
|
104
|
-
return 1;
|
105
|
-
}
|
106
|
-
}
|
107
|
-
<% end %>
|
15
|
+
<%= device.read %>
|
108
16
|
<% end %>
|
109
17
|
return 0;
|
110
18
|
}
|
@@ -117,11 +25,6 @@ void zemu_io_out(void * context, zuint16 port, zuint8 value)
|
|
117
25
|
port &= 0x00FF;
|
118
26
|
|
119
27
|
<% io.each do |device| %>
|
120
|
-
|
121
|
-
if (port == <%= device.out_port %>)
|
122
|
-
{
|
123
|
-
zemu_io_serial_slave_puts(value);
|
124
|
-
}
|
125
|
-
<% end %>
|
28
|
+
<%= device.write %>
|
126
29
|
<% end %>
|
127
30
|
}
|
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.
|
4
|
+
version: 0.2.2
|
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-
|
11
|
+
date: 2020-02-29 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
|