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.
@@ -1,3 +1,3 @@
1
1
  module MicroCisc
2
- VERSION = "0.1.3"
2
+ VERSION = "0.1.4"
3
3
  end
@@ -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
@@ -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, read only. Unique system wide.
8
- # * 0x1 - Bank address (MSB) | Device type (LSB)
9
- # * 0x2 - Bus access device ID
10
- # * 0x3 - Interrupt code (MSB) | Device status (LSB)
11
- # * 0x4 - Local register with interrupt handler address (read/write)
12
- # * 0x5 to 0xF - Device type specific
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 = 0x001F
19
- @privileged_read = 0x001F
20
- @privileged_write = 0x0010
21
- @internal_write = 0x000C
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
- return @control_mem[0] if address == 0
66
- if source_device_id == @id || source_device_id == @control_mem[2]
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
- page = (address & 0xFF00) >> 8
110
- @local_mem[page][address & 0xFF] = value
120
+ block = (address & 0xFF00) >> 8
121
+ @local_mem[block][address & 0xFF] = value
111
122
  elsif source_device_id == @control_mem[2]
112
- page = (@control_mem[3] & 0xFF00) >> 8
113
- @local_mem[page][address & 0xFF] = value
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
- return 1 if immediates.first == 0 && source == 0 && destination == 0
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
- # if count & 0xFF == 0
351
- # read_from_processor
352
- # end
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, 9, 1)
5
+ super(device_id, Device::TYPE_TERMINAL, 1)
6
6
  # Init device specific read/write controls
7
- @privileged_read = @privileged_read | 0xE0
8
- @privileged_write = @privileged_write | 0x20
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 == 5
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]
@@ -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 /\([^a-zA-Z_:&@!]*\)\@=[a-zA-Z_:&@!][a-zA-Z0-9_:&@!]*:/
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 /\(\$\|&\)[a-zA-Z0-9_:&@!?*]\+/
38
- highlight link uciscArg Type
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 Define
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.3
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-09 00:00:00.000000000 Z
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/image.ucisc
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