ucisc 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +4 -1
- data/core/stdlib.ucisc +101 -0
- data/examples/everest_12bit.ucisc +195 -0
- data/examples/factorial.ucisc +24 -22
- data/examples/fib.ucisc +40 -35
- data/examples/hello_world.ucisc +59 -68
- data/examples/paint_image.ucisc +261 -0
- data/exe/png_to_hex +38 -0
- data/exe/ucisc +8 -5
- data/lib/micro_cisc.rb +30 -7
- data/lib/micro_cisc/compile/compiler.rb +10 -2
- data/lib/micro_cisc/compile/instruction.rb +40 -13
- data/lib/micro_cisc/compile/statement.rb +118 -34
- data/lib/micro_cisc/version.rb +1 -1
- data/lib/micro_cisc/vm/color_lcd_display.rb +115 -0
- data/lib/micro_cisc/vm/device.rb +32 -21
- data/lib/micro_cisc/vm/processor.rb +20 -9
- data/lib/micro_cisc/vm/term_device.rb +4 -8
- data/ucisc.gemspec +2 -0
- data/ucisc.vim +14 -8
- metadata +36 -4
- data/examples/image.ucisc +0 -543
- data/lib/micro_cisc/vm/video.rb +0 -151
data/lib/micro_cisc/version.rb
CHANGED
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'gtk2'
|
2
|
+
|
3
|
+
module MicroCisc
|
4
|
+
module Vm
|
5
|
+
class ColorLcdDisplay < Device
|
6
|
+
COLOR_MODE_12BIT = 1
|
7
|
+
COLOR_MODE_16BIT = 2
|
8
|
+
COLOR_MODES = [COLOR_MODE_16BIT, COLOR_MODE_12BIT].freeze
|
9
|
+
|
10
|
+
def initialize(device_id, mem_blocks, width, height, bit_mode)
|
11
|
+
super(device_id, Device::TYPE_BLOCK_MEMORY, mem_blocks)
|
12
|
+
@w = width
|
13
|
+
@h = height
|
14
|
+
@bit_mode = COLOR_MODES.include?(bit_mode) ? bit_mode : COLOR_MODES.first
|
15
|
+
@image_data = Array.new(@w * @h * 3).map { 0 }
|
16
|
+
@scale =
|
17
|
+
if @w <= 320
|
18
|
+
4
|
19
|
+
elsif @w <= 640
|
20
|
+
2
|
21
|
+
else
|
22
|
+
1
|
23
|
+
end
|
24
|
+
@control_mem[6] = @w
|
25
|
+
@control_mem[7] = @h
|
26
|
+
@privileged_read = @privileged_read | 0x0C0
|
27
|
+
|
28
|
+
Gtk.init
|
29
|
+
|
30
|
+
@window = Gtk::Window.new.set_default_size(@w * @scale, @h * @scale)
|
31
|
+
@window.set_title("uCISC Virtual Machine")
|
32
|
+
@window.set_resizable(false)
|
33
|
+
|
34
|
+
update_screen
|
35
|
+
|
36
|
+
@window.signal_connect("destroy") do
|
37
|
+
Gtk.main_quit
|
38
|
+
end
|
39
|
+
GLib::Timeout.add(5) do
|
40
|
+
do_update
|
41
|
+
true
|
42
|
+
end
|
43
|
+
@window.show
|
44
|
+
|
45
|
+
@window_thread = Thread.new do
|
46
|
+
Gtk.main
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def join
|
51
|
+
@window_thread.join
|
52
|
+
end
|
53
|
+
|
54
|
+
def update_screen
|
55
|
+
pixel_buffer = GdkPixbuf::Pixbuf.new(
|
56
|
+
data: @image_data.pack("C*"),
|
57
|
+
colorspace: GdkPixbuf::Colorspace::RGB,
|
58
|
+
has_alpha: false,
|
59
|
+
bits_per_sample: 8,
|
60
|
+
width: @w,
|
61
|
+
height: @h
|
62
|
+
)
|
63
|
+
pixel_buffer = pixel_buffer.scale_simple(@w * @scale, @h * @scale, 0)
|
64
|
+
new_image = Gtk::Image.new(pixel_buffer)
|
65
|
+
@window.remove(@image) if @image
|
66
|
+
@window.add(new_image)
|
67
|
+
new_image.show
|
68
|
+
@window.show
|
69
|
+
@image = new_image
|
70
|
+
end
|
71
|
+
|
72
|
+
def do_update
|
73
|
+
@t0 ||= Time.now
|
74
|
+
@tcount ||= 0
|
75
|
+
|
76
|
+
update_image_data
|
77
|
+
update_screen
|
78
|
+
|
79
|
+
@tcount += 1
|
80
|
+
if @tcount == 60
|
81
|
+
delta = Time.now - @t0
|
82
|
+
#puts "60 frames in #{delta}s (#{60 / delta} fps)"
|
83
|
+
@t0 = Time.now
|
84
|
+
@tcount = 0
|
85
|
+
end
|
86
|
+
rescue Interrupt
|
87
|
+
end
|
88
|
+
|
89
|
+
def update_image_data
|
90
|
+
(0...@w).each do |x|
|
91
|
+
(0...@h).each do |y|
|
92
|
+
word_offset = y * @w + x
|
93
|
+
pixel_offset = word_offset * 3
|
94
|
+
word = read_mem(@id, word_offset, true)
|
95
|
+
if (@bit_mode == COLOR_MODE_16BIT)
|
96
|
+
r = (word & 0x0F00) >> 8
|
97
|
+
@image_data[pixel_offset] = r + (r >> 5)
|
98
|
+
g = (word & 0x07E0) >> 3
|
99
|
+
@image_data[pixel_offset + 1] = g + (g >> 5)
|
100
|
+
b = (word & 0x001F) << 3
|
101
|
+
@image_data[pixel_offset + 2] = b + (b >> 5)
|
102
|
+
elsif (@bit_mode == COLOR_MODE_12BIT)
|
103
|
+
r = (word & 0x0F00) >> 4
|
104
|
+
@image_data[pixel_offset] = r + (r >> 4)
|
105
|
+
g = word & 0x00F0
|
106
|
+
@image_data[pixel_offset + 1] = g + (g >> 4)
|
107
|
+
b = (word & 0x000F) << 4
|
108
|
+
@image_data[pixel_offset + 2] = b + (b >> 4)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
data/lib/micro_cisc/vm/device.rb
CHANGED
@@ -4,21 +4,30 @@ module MicroCisc
|
|
4
4
|
#
|
5
5
|
# From the docs, the control word layout is as follows:
|
6
6
|
#
|
7
|
-
# * 0x0 - Device ID
|
8
|
-
# * 0x1 -
|
9
|
-
# * 0x2 -
|
10
|
-
# * 0x3 -
|
11
|
-
# * 0x4 -
|
12
|
-
# * 0x5
|
7
|
+
# * 0x0 - Device ID - read only. Unique system wide.
|
8
|
+
# * 0x1 - Local bank block (MSB) | Device type (LSB) - read only
|
9
|
+
# * 0x2 - Init device ID - read only if set, writable if 0 or by init device
|
10
|
+
# * 0x3 - Accessed device block address (LSB) - writable by init device
|
11
|
+
# * 0x4 - <Reserved> (MSB) | Device status (LSB)
|
12
|
+
# * 0x5 - Local register with interrupt handler address (read/write)
|
13
|
+
# * 0x6 to 0xF - Device type specific (see below)
|
13
14
|
class Device
|
15
|
+
TYPE_INVALID = 0
|
16
|
+
TYPE_PROCESSOR = 1
|
17
|
+
TYPE_BLOCK_MEMORY = 2
|
18
|
+
TYPE_BLOCK_IO = 3
|
19
|
+
TYPE_SERIAL = 4
|
20
|
+
TYPE_HID = 5
|
21
|
+
TYPE_TERMINAL = 6
|
22
|
+
|
14
23
|
attr_reader :id
|
15
24
|
|
16
25
|
def initialize(id, type, local_blocks, rom_blocks = [])
|
17
26
|
@id = id
|
18
|
-
@external_read =
|
19
|
-
@privileged_read =
|
20
|
-
@privileged_write =
|
21
|
-
@internal_write =
|
27
|
+
@external_read = 0x003F
|
28
|
+
@privileged_read = 0x003F
|
29
|
+
@privileged_write = 0x002C
|
30
|
+
@internal_write = 0x0010
|
22
31
|
|
23
32
|
@local_blocks = local_blocks
|
24
33
|
rom_blocks.each { |block| block.freeze }
|
@@ -31,6 +40,7 @@ module MicroCisc
|
|
31
40
|
@control_mem = Array.new(16).map { 0 }
|
32
41
|
@control_mem[0] = id
|
33
42
|
@control_mem[1] = type & 0xFF
|
43
|
+
@control_mem[2] = 0
|
34
44
|
|
35
45
|
@devices = [self]
|
36
46
|
end
|
@@ -44,17 +54,16 @@ module MicroCisc
|
|
44
54
|
@devices.each_with_index { |device, index| device.bank_index = index }
|
45
55
|
end
|
46
56
|
|
47
|
-
def source_halted(source_device_id)
|
48
|
-
@control_mem[2] = 0 if source_device_id == @control_mem[2]
|
49
|
-
end
|
50
|
-
|
51
57
|
def write_control(source_device_id, address, value)
|
52
58
|
address = address & 0xF
|
53
59
|
return if address == 0
|
54
60
|
if source_device_id == @id
|
55
61
|
return if (1 << (address - 1)) & @internal_write == 0
|
56
62
|
@control_mem[address] = value
|
57
|
-
elsif source_device_id == @control_mem[2]
|
63
|
+
elsif @control_mem[2] == 0 || source_device_id == @control_mem[2]
|
64
|
+
# Special case where a processor can "claim" the device
|
65
|
+
@control_mem[2] = source_device_id
|
66
|
+
|
58
67
|
return if (1 << (address - 1)) & @privileged_write == 0
|
59
68
|
@control_mem[address] = value
|
60
69
|
handle_control_update(address, value)
|
@@ -62,8 +71,10 @@ module MicroCisc
|
|
62
71
|
end
|
63
72
|
|
64
73
|
def read_control(source_device_id, address)
|
65
|
-
|
66
|
-
|
74
|
+
if address == 0
|
75
|
+
handle_control_read(address)
|
76
|
+
@control_mem[0]
|
77
|
+
elsif source_device_id == @id || source_device_id == @control_mem[2]
|
67
78
|
return 0 if (1 << (address - 1)) & @privileged_read == 0
|
68
79
|
handle_control_read(address)
|
69
80
|
@control_mem[address]
|
@@ -106,11 +117,11 @@ module MicroCisc
|
|
106
117
|
@local_mem[page][address & 0xFF] = value
|
107
118
|
end
|
108
119
|
elsif !banked && source_device_id == @id
|
109
|
-
|
110
|
-
@local_mem[
|
120
|
+
block = (address & 0xFF00) >> 8
|
121
|
+
@local_mem[block][address & 0xFF] = value
|
111
122
|
elsif source_device_id == @control_mem[2]
|
112
|
-
|
113
|
-
@local_mem[
|
123
|
+
block = @control_mem[3]
|
124
|
+
@local_mem[block][address & 0xFF] = value if @local_mem[block]
|
114
125
|
end
|
115
126
|
end
|
116
127
|
|
@@ -55,6 +55,7 @@ module MicroCisc
|
|
55
55
|
@run = false
|
56
56
|
@pc_modified = false
|
57
57
|
@count = 0
|
58
|
+
@clocks_per_second = 200_000
|
58
59
|
end
|
59
60
|
|
60
61
|
def handle_control_update(address, value)
|
@@ -134,13 +135,13 @@ module MicroCisc
|
|
134
135
|
def source_value(source, immediate)
|
135
136
|
case source
|
136
137
|
when 0
|
137
|
-
@pc + immediate
|
138
|
+
(@pc + immediate) & 0xFFFF
|
138
139
|
when 1,2,3
|
139
|
-
read_mem(@id, @registers[source] + immediate)
|
140
|
+
read_mem(@id, (@registers[source] + immediate) & 0xFFFF)
|
140
141
|
when 4
|
141
142
|
immediate
|
142
143
|
else
|
143
|
-
@registers[source - 4] + immediate
|
144
|
+
(@registers[source - 4] + immediate) & 0xFFFF
|
144
145
|
end
|
145
146
|
end
|
146
147
|
|
@@ -149,7 +150,7 @@ module MicroCisc
|
|
149
150
|
when 0
|
150
151
|
@pc
|
151
152
|
when 1,2,3
|
152
|
-
read_mem(@id, @registers[destination] + immediate)
|
153
|
+
read_mem(@id, (@registers[destination] + immediate) & 0xFFFF)
|
153
154
|
when 4
|
154
155
|
@control
|
155
156
|
else
|
@@ -177,7 +178,14 @@ module MicroCisc
|
|
177
178
|
store_result(result, source, destination, immediates, push, 0)
|
178
179
|
|
179
180
|
# Detect halt instruction
|
180
|
-
|
181
|
+
if immediates.first == 0 && source == 0 && destination == 0
|
182
|
+
if alu == 0
|
183
|
+
return 1
|
184
|
+
else
|
185
|
+
@pc += 1
|
186
|
+
return 2
|
187
|
+
end
|
188
|
+
end
|
181
189
|
0
|
182
190
|
end
|
183
191
|
|
@@ -347,9 +355,12 @@ module MicroCisc
|
|
347
355
|
@pc += 1
|
348
356
|
end
|
349
357
|
@count += 1
|
350
|
-
|
351
|
-
|
352
|
-
|
358
|
+
|
359
|
+
allowed_count = (Time.now - @t0) * @clocks_per_second
|
360
|
+
while @count >= allowed_count
|
361
|
+
sleep(1.0 / @clocks_per_second)
|
362
|
+
allowed_count = (Time.now - @t0) * @clocks_per_second
|
363
|
+
end
|
353
364
|
end
|
354
365
|
end
|
355
366
|
|
@@ -440,7 +451,7 @@ module MicroCisc
|
|
440
451
|
ins = is_copy ? 'copy' : 'compute'
|
441
452
|
|
442
453
|
|
443
|
-
"Stack: #{stack_string}\n#{ins} #{alu}#{src} #{imm0} #{dest} #{imm1}#{eff} #{push}# value: #{value} (0x#{'%04x' % value}), result: #{result} (0x#{'%04x' % result}), #{'not ' if !store}stored"
|
454
|
+
"Stack: #{stack_string}\n#{ins} #{alu}#{src} #{imm0} #{dest} #{imm1}#{eff} #{push}# value: #{value} (0x#{'%04x' % (value & 0xFFFF)}), result: #{result} (0x#{'%04x' % (result & 0xFFFF)}), #{'not ' if !store}stored"
|
444
455
|
end
|
445
456
|
end
|
446
457
|
end
|
@@ -2,14 +2,10 @@ module MicroCisc
|
|
2
2
|
module Vm
|
3
3
|
class TermDevice < Device
|
4
4
|
def initialize(device_id)
|
5
|
-
super(device_id,
|
5
|
+
super(device_id, Device::TYPE_TERMINAL, 1)
|
6
6
|
# Init device specific read/write controls
|
7
|
-
@privileged_read = @privileged_read |
|
8
|
-
@privileged_write = @privileged_write |
|
9
|
-
end
|
10
|
-
|
11
|
-
def host_device=(device_id)
|
12
|
-
@control_mem[2] = device_id
|
7
|
+
@privileged_read = @privileged_read | 0x1C0
|
8
|
+
@privileged_write = @privileged_write | 0x40
|
13
9
|
end
|
14
10
|
|
15
11
|
def handle_control_read(address)
|
@@ -22,7 +18,7 @@ module MicroCisc
|
|
22
18
|
end
|
23
19
|
|
24
20
|
def handle_control_update(address, value)
|
25
|
-
if address ==
|
21
|
+
if address == 6
|
26
22
|
# value is number of bytes to send
|
27
23
|
words = (value + 1) / 2
|
28
24
|
string = @local_mem[0][0...words].pack("S>*")[0...value]
|
data/ucisc.gemspec
CHANGED
@@ -29,6 +29,8 @@ Gem::Specification.new do |spec|
|
|
29
29
|
spec.add_runtime_dependency "byebug"
|
30
30
|
spec.add_runtime_dependency "tty-screen"
|
31
31
|
spec.add_runtime_dependency "gtk2"
|
32
|
+
spec.add_runtime_dependency "chunky_png"
|
33
|
+
spec.add_runtime_dependency "bundler"
|
32
34
|
|
33
35
|
spec.add_development_dependency "rake"
|
34
36
|
spec.add_development_dependency "minitest"
|
data/ucisc.vim
CHANGED
@@ -14,19 +14,22 @@ set cpo&vim
|
|
14
14
|
setlocal formatoptions-=t " allow long lines
|
15
15
|
setlocal formatoptions+=c " but comments should still wrap
|
16
16
|
|
17
|
-
setlocal iskeyword+=-,?,<,>
|
17
|
+
" setlocal iskeyword+=-,?,<,>
|
18
18
|
|
19
|
-
syntax keyword uciscOpcode copy compute
|
20
|
-
highlight link uciscOpcode Function
|
19
|
+
" syntax keyword uciscOpcode copy compute
|
20
|
+
" highlight link uciscOpcode Function
|
21
21
|
|
22
22
|
syntax match uciscComment /#.*/
|
23
23
|
syntax match uciscComment /\/[^\/]*\//
|
24
24
|
syntax match uciscComment /'[^ ]*/
|
25
25
|
highlight link uciscComment Comment
|
26
26
|
|
27
|
-
syntax match uciscLabel
|
27
|
+
syntax match uciscLabel /&[a-zA-Z0-9_:&@!?]\+/
|
28
28
|
highlight link uciscLabel Identifier
|
29
29
|
|
30
|
+
syntax match uciscFunction /\([^a-zA-Z_:&@!]*\)\@=[a-zA-Z_:&@!][a-zA-Z0-9_:&@!\.]*:/
|
31
|
+
highlight link uciscFunction Function
|
32
|
+
|
30
33
|
syntax match uciscControl /[(){}]/
|
31
34
|
syntax match uciscControl /\(break\|loop\)/
|
32
35
|
highlight link uciscControl Statement
|
@@ -34,14 +37,17 @@ highlight link uciscControl Statement
|
|
34
37
|
syntax match uciscImmediate /\<\((\)\?\(-\)\?\(0x\)\?[0-9a-fA-F]\+\([/.]\|\s\|,\)\@=/
|
35
38
|
highlight link uciscImmediate Number
|
36
39
|
|
37
|
-
syntax match uciscArg
|
38
|
-
highlight link uciscArg
|
40
|
+
syntax match uciscArg /\$[a-zA-Z0-9_:&@!?]\+/
|
41
|
+
highlight link uciscArg Define
|
42
|
+
|
43
|
+
syntax match uciscAssign /=/
|
44
|
+
syntax keyword uciscAssign push pop as
|
45
|
+
highlight link uciscAssign Function
|
39
46
|
|
40
|
-
syntax keyword uciscOption push pop as
|
41
47
|
syntax match uciscOption /\(.\)\@=\<\(disp\|imm\)\>\(\/\|\s\|,\|)\|$\)\@=/
|
42
48
|
syntax match uciscOption /\(.\)\@=\<\(reg\|mem\|val\)\>\(\/\|\s\|,\|)\|$\)\@=/
|
43
49
|
syntax match uciscOption /\(.\)\@=\<\(op\|inc\|eff\)\>\(\/\|\s\|$\)\@=/
|
44
|
-
highlight link uciscOption
|
50
|
+
highlight link uciscOption Comment
|
45
51
|
|
46
52
|
syntax match uciscData /^[ ]*% *\([0-9a-fA-F][0-9a-fA-F][ ]*\)*/
|
47
53
|
highlight link uciscData Number
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ucisc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Butler
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-07-
|
11
|
+
date: 2020-07-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: byebug
|
@@ -52,6 +52,34 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: chunky_png
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: rake
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -84,6 +112,7 @@ description:
|
|
84
112
|
email:
|
85
113
|
- robert at grokthiscommunity.net
|
86
114
|
executables:
|
115
|
+
- png_to_hex
|
87
116
|
- ucisc
|
88
117
|
extensions: []
|
89
118
|
extra_rdoc_files: []
|
@@ -98,10 +127,13 @@ files:
|
|
98
127
|
- Rakefile
|
99
128
|
- bin/console
|
100
129
|
- bin/setup
|
130
|
+
- core/stdlib.ucisc
|
131
|
+
- examples/everest_12bit.ucisc
|
101
132
|
- examples/factorial.ucisc
|
102
133
|
- examples/fib.ucisc
|
103
134
|
- examples/hello_world.ucisc
|
104
|
-
- examples/
|
135
|
+
- examples/paint_image.ucisc
|
136
|
+
- exe/png_to_hex
|
105
137
|
- exe/ucisc
|
106
138
|
- lib/micro_cisc.rb
|
107
139
|
- lib/micro_cisc/compile/compiler.rb
|
@@ -109,11 +141,11 @@ files:
|
|
109
141
|
- lib/micro_cisc/compile/label_generator.rb
|
110
142
|
- lib/micro_cisc/compile/statement.rb
|
111
143
|
- lib/micro_cisc/version.rb
|
144
|
+
- lib/micro_cisc/vm/color_lcd_display.rb
|
112
145
|
- lib/micro_cisc/vm/device.rb
|
113
146
|
- lib/micro_cisc/vm/empty_device.rb
|
114
147
|
- lib/micro_cisc/vm/processor.rb
|
115
148
|
- lib/micro_cisc/vm/term_device.rb
|
116
|
-
- lib/micro_cisc/vm/video.rb
|
117
149
|
- ucisc.gemspec
|
118
150
|
- ucisc.vim
|
119
151
|
homepage: https://github.com/grokthis/ucisc-ruby
|