ucisc 0.1.3 → 0.1.4
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 +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
|