origen_link 0.1.0.pre0
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 +7 -0
- data/config/application.rb +105 -0
- data/config/boot.rb +7 -0
- data/config/commands.rb +74 -0
- data/config/version.rb +8 -0
- data/lib/origen_link/includes_vector_based.rb +76 -0
- data/lib/origen_link/test/regression_tests.rb +68 -0
- data/lib/origen_link/test/test_dut.rb +46 -0
- data/lib/origen_link/test/test_dut_controller.rb +42 -0
- data/lib/origen_link/test/vector_based_redefs.rb +17 -0
- data/lib/origen_link/vector_based.rb +254 -0
- data/lib/origen_link.rb +18 -0
- data/lib/origen_link_server/LinkSequencer.rb +333 -0
- data/lib/origen_link_server/LinkTCPServer.rb +45 -0
- data/lib/origen_link_server/jtag_interface.rb +177 -0
- data/lib/origen_link_server/pin_interface.rb +134 -0
- data/lib/origen_link_server/test/test_Sequencer.rb +51 -0
- data/lib/tasks/origen_link.rake +6 -0
- data/pattern/example.rb +4 -0
- data/pattern/jtag_100_operations.rb +14 -0
- data/pattern/jtag_comm_fail_test.rb +13 -0
- data/pattern/jtag_comm_test.rb +11 -0
- data/templates/web/index.md.erb +19 -0
- data/templates/web/layouts/_basic.html.erb +13 -0
- data/templates/web/partials/_navbar.html.erb +20 -0
- data/templates/web/release_notes.md.erb +5 -0
- metadata +125 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0e1bcf6176e63bcb31f823ec75e8171d5f41f678
|
4
|
+
data.tar.gz: b8773221ecda2487be4b458341b07260f3298a38
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e5f8bb591f2113d737a4e2ec9adcb035aab944e61558e7927004ef3ed6327c4438f9a0619c1ab181a41d124505aa1e6fe0e47238af876a26d1c4b88740b0f19f
|
7
|
+
data.tar.gz: 5a345ff111d0fe9779bff83d317878addc8baec9551c546c471dcda03f65534d9360679e56b5d6519b66d22560975349921bc9e4bfc6b3a96f423c256e8acd3e
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'origen'
|
2
|
+
class OrigenLinkApplication < Origen::Application
|
3
|
+
|
4
|
+
# See http://origen-sdk.org/origen/api/Origen/Application/Configuration.html
|
5
|
+
# for a full list of the configuration options available
|
6
|
+
|
7
|
+
# These attributes should never be changed, the duplication here will be resolved in future
|
8
|
+
# by condensing these attributes that do similar things
|
9
|
+
self.name = "origen_link"
|
10
|
+
self.namespace = "OrigenLink"
|
11
|
+
config.name = "origen_link"
|
12
|
+
config.initials = "OrigenLink"
|
13
|
+
# Change this to point to the revision control repository for this application
|
14
|
+
config.rc_url = "git@github.com:Origen-SDK/OrigenLink.git"
|
15
|
+
config.release_externally = true
|
16
|
+
|
17
|
+
# To enable deployment of your documentation to a web server (via the 'origen web'
|
18
|
+
# command) fill in these attributes.
|
19
|
+
#config.web_directory = "/path/to/server/origen_link"
|
20
|
+
#config.web_domain = "http://origen.mycompany.net/origen_link"
|
21
|
+
config.web_directory = "git@github.com:Origen-SDK/Origen-SDK.github.io.git/OrigenLink"
|
22
|
+
config.web_domain = "http://origen-sdk.org/OrigenLink"
|
23
|
+
|
24
|
+
# When false Origen will be less strict about checking for some common coding errors,
|
25
|
+
# it is recommended that you leave this to true for better feedback and easier debug.
|
26
|
+
# This will be the default setting in Origen v3.
|
27
|
+
config.strict_errors = true
|
28
|
+
|
29
|
+
# See: http://origen-sdk.org/origen/latest/guides/utilities/lint/
|
30
|
+
config.lint_test = {
|
31
|
+
# Require the lint tests to pass before allowing a release to proceed
|
32
|
+
run_on_tag: true,
|
33
|
+
# Auto correct violations where possible whenever 'origen lint' is run
|
34
|
+
auto_correct: true,
|
35
|
+
# Limit the testing for large legacy applications
|
36
|
+
#level: :easy,
|
37
|
+
# Run on these directories/files by default
|
38
|
+
#files: ["lib", "config/application.rb"],
|
39
|
+
}
|
40
|
+
|
41
|
+
config.semantically_version = true
|
42
|
+
|
43
|
+
# An example of how to set application specific LSF parameters
|
44
|
+
#config.lsf.project = "msg.te"
|
45
|
+
|
46
|
+
# An example of how to specify a prefix to add to all generated patterns
|
47
|
+
#config.pattern_prefix = "nvm"
|
48
|
+
|
49
|
+
# An example of how to add header comments to all generated patterns
|
50
|
+
#config.pattern_header do
|
51
|
+
# cc "This is a pattern created by the example origen application"
|
52
|
+
#end
|
53
|
+
|
54
|
+
# By default all generated output will end up in ./output.
|
55
|
+
# Here you can specify an alternative directory entirely, or make it dynamic such that
|
56
|
+
# the output ends up in a setup specific directory.
|
57
|
+
#config.output_directory do
|
58
|
+
# "#{Origen.root}/output/#{$dut.class}"
|
59
|
+
#end
|
60
|
+
|
61
|
+
# Similarly for the reference files, generally you want to setup the reference directory
|
62
|
+
# structure to mirror that of your output directory structure.
|
63
|
+
#config.reference_directory do
|
64
|
+
# "#{Origen.root}/.ref/#{$dut.class}"
|
65
|
+
#end
|
66
|
+
|
67
|
+
# This will automatically deploy your documentation after every tag
|
68
|
+
#def after_release_email(tag, note, type, selector, options)
|
69
|
+
# command = "origen web compile --remote --api"
|
70
|
+
# Dir.chdir Origen.root do
|
71
|
+
# system command
|
72
|
+
# end
|
73
|
+
#end
|
74
|
+
|
75
|
+
# Ensure that all tests pass before allowing a release to continue
|
76
|
+
#def validate_release
|
77
|
+
# if !system("origen specs") || !system("origen examples")
|
78
|
+
# puts "Sorry but you can't release with failing tests, please fix them and try again."
|
79
|
+
# exit 1
|
80
|
+
# else
|
81
|
+
# puts "All tests passing, proceeding with release process!"
|
82
|
+
# end
|
83
|
+
#end
|
84
|
+
|
85
|
+
# To enabled source-less pattern generation create a class (for example PatternDispatcher)
|
86
|
+
# to generate the pattern. This should return false if the requested pattern has been
|
87
|
+
# dispatched, otherwise Origen will proceed with looking up a pattern source as normal.
|
88
|
+
#def before_pattern_lookup(requested_pattern)
|
89
|
+
# PatternDispatcher.new.dispatch_or_return(requested_pattern)
|
90
|
+
#end
|
91
|
+
|
92
|
+
# If you use pattern iterators you may come across the case where you request a pattern
|
93
|
+
# like this:
|
94
|
+
# origen g example_pat_b0.atp
|
95
|
+
#
|
96
|
+
# However it cannot be found by Origen since the pattern name is actually example_pat_bx.atp
|
97
|
+
# In the case where the pattern cannot be found Origen will pass the name to this translator
|
98
|
+
# if it exists, and here you can make any substitutions to help Origen find the file you
|
99
|
+
# want. In this example any instances of _b\d, where \d means a number, are replaced by
|
100
|
+
# _bx.
|
101
|
+
#config.pattern_name_translator do |name|
|
102
|
+
# name.gsub(/_b\d/, "_bx")
|
103
|
+
#end
|
104
|
+
|
105
|
+
end
|
data/config/boot.rb
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
# This file will be loaded by Origen to boot your application, just leave it as
|
2
|
+
# is and modify lib/origen_link.rb to load the additional resources that your
|
3
|
+
# application requires
|
4
|
+
require "origen_link"
|
5
|
+
|
6
|
+
require "origen_link/test/test_dut"
|
7
|
+
require "origen_link/test/test_dut_controller"
|
data/config/commands.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# This file should be used to extend the origen with application specific commands
|
2
|
+
|
3
|
+
# Map any command aliases here, for example to allow 'origen ex' to refer to a
|
4
|
+
# command called execute you would add a reference as shown below:
|
5
|
+
aliases ={
|
6
|
+
# "ex" => "execute",
|
7
|
+
}
|
8
|
+
|
9
|
+
# The requested command is passed in here as @command, this checks it against
|
10
|
+
# the above alias table and should not be removed.
|
11
|
+
@command = aliases[@command] || @command
|
12
|
+
|
13
|
+
# Now branch to the specific task code
|
14
|
+
case @command
|
15
|
+
|
16
|
+
# Here is an example of how to implement a command, the logic can go straight
|
17
|
+
# in here or you can require an external file if preferred.
|
18
|
+
when "my_command"
|
19
|
+
puts "Doing something..."
|
20
|
+
#require "commands/my_command" # Would load file lib/commands/my_command.rb
|
21
|
+
# You must always exit upon successfully capturing a command to prevent
|
22
|
+
# control flowing back to Origen
|
23
|
+
exit 0
|
24
|
+
|
25
|
+
## Example of how to make a command to run unit tests, this simply invokes RSpec on
|
26
|
+
## the spec directory
|
27
|
+
#when "specs"
|
28
|
+
# require "rspec"
|
29
|
+
# exit RSpec::Core::Runner.run(['spec'])
|
30
|
+
|
31
|
+
## Example of how to make a command to run diff-based tests
|
32
|
+
#when "examples", "test"
|
33
|
+
# Origen.load_application
|
34
|
+
# status = 0
|
35
|
+
#
|
36
|
+
# # Compiler tests
|
37
|
+
# ARGV = %w(templates/example.txt.erb -t debug -r approved)
|
38
|
+
# load "origen/commands/compile.rb"
|
39
|
+
# # Pattern generator tests
|
40
|
+
# #ARGV = %w(some_pattern -t debug -r approved)
|
41
|
+
# #load "#{Origen.top}/lib/origen/commands/generate.rb"
|
42
|
+
#
|
43
|
+
# if Origen.app.stats.changed_files == 0 &&
|
44
|
+
# Origen.app.stats.new_files == 0 &&
|
45
|
+
# Origen.app.stats.changed_patterns == 0 &&
|
46
|
+
# Origen.app.stats.new_patterns == 0
|
47
|
+
#
|
48
|
+
# Origen.app.stats.report_pass
|
49
|
+
# else
|
50
|
+
# Origen.app.stats.report_fail
|
51
|
+
# status = 1
|
52
|
+
# end
|
53
|
+
# puts
|
54
|
+
# if @command == "test"
|
55
|
+
# Origen.app.unload_target!
|
56
|
+
# require "rspec"
|
57
|
+
# result = RSpec::Core::Runner.run(['spec'])
|
58
|
+
# status = status == 1 ? 1 : result
|
59
|
+
# end
|
60
|
+
# exit status # Exit with a 1 on the event of a failure per std unix result codes
|
61
|
+
|
62
|
+
# Always leave an else clause to allow control to fall back through to the
|
63
|
+
# Origen command handler.
|
64
|
+
else
|
65
|
+
# You probably want to also add the your commands to the help shown via
|
66
|
+
# origen -h, you can do this be assigning the required text to @application_commands
|
67
|
+
# before handing control back to Origen. Un-comment the example below to get started.
|
68
|
+
# @application_commands = <<-EOT
|
69
|
+
# specs Run the specs (tests), -c will enable coverage
|
70
|
+
# examples Run the examples (tests), -c will enable coverage
|
71
|
+
# test Run both specs and examples, -c will enable coverage
|
72
|
+
# EOT
|
73
|
+
|
74
|
+
end
|
data/config/version.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
module OrigenLink
|
2
|
+
class VectorBased
|
3
|
+
include OrigenTesters::VectorBasedTester
|
4
|
+
|
5
|
+
# send_cmd(cmdstr, argstr)
|
6
|
+
# cmdstr is a valid command. <category>_<command>
|
7
|
+
# Ex: 'pin_assign'
|
8
|
+
# argstr is a valid comma separated, no white space argument string.
|
9
|
+
# Ex: 'tclk,26,tms,19,tdi,16,tdo,23'
|
10
|
+
#
|
11
|
+
# returns: response from server
|
12
|
+
#
|
13
|
+
# This method connects to the socket being served by the debugger, sends
|
14
|
+
# the command and arguments separated by a semicolon (Ex: 'pin_cycle:110H'),
|
15
|
+
# then waits for a response. The response is returned to the caller.
|
16
|
+
#
|
17
|
+
# In addition, this method also keeps track of time elapsed transfering data
|
18
|
+
# and waiting for a response.
|
19
|
+
def send_cmd(cmdstr, argstr)
|
20
|
+
# objects have to be created outside of the block
|
21
|
+
# to be accessible outside of the block
|
22
|
+
t2 = 0
|
23
|
+
t3 = 0
|
24
|
+
t4 = 0
|
25
|
+
t5 = 0
|
26
|
+
response = ''
|
27
|
+
t1 = Time.now
|
28
|
+
|
29
|
+
# open a connection to the server, send the command and wait for a response
|
30
|
+
TCPSocket.open(@address, @port) do |link|
|
31
|
+
t2 = Time.now
|
32
|
+
link.puts(cmdstr + ':' + argstr)
|
33
|
+
t3 = Time.now
|
34
|
+
response = link.gets
|
35
|
+
t4 = Time.now
|
36
|
+
end
|
37
|
+
|
38
|
+
t5 = Time.now
|
39
|
+
@total_comm_time += (t5 - t1)
|
40
|
+
if @max_packet_time < (t5 - t1)
|
41
|
+
@max_packet_time = (t5 - t1)
|
42
|
+
@longest_packet = cmdstr + ':' + argstr
|
43
|
+
end
|
44
|
+
@total_connect_time += (t2 - t1)
|
45
|
+
@total_xmit_time += (t3 - t2)
|
46
|
+
@total_recv_time += (t4 - t3)
|
47
|
+
@max_receive_time = (t4 - t3) if @max_receive_time < (t4 - t3)
|
48
|
+
@total_packets += 1
|
49
|
+
Origen.log.error 'nil reponse from server (likely died) for command(' + cmdstr + ':' + argstr + ')' if response.nil?
|
50
|
+
response # ensure the response is passed along
|
51
|
+
end
|
52
|
+
|
53
|
+
# setup_cmd_response_logger
|
54
|
+
# There are several setup commands that initialize the debugger device with
|
55
|
+
# information about how to interact with the dut. All of the setup commands
|
56
|
+
# return pass or fail. This method exists so that the code doesn't have to
|
57
|
+
# be duplicated by every setup method.
|
58
|
+
def setup_cmd_response_logger(command, response)
|
59
|
+
if !response.nil?
|
60
|
+
# if the server died (which hopefully it never will) response is nil
|
61
|
+
case response.chr
|
62
|
+
when 'P'
|
63
|
+
Origen.log.info command + ' setup was successful'
|
64
|
+
when 'F'
|
65
|
+
Origen.log.error command + ' setup FAILED with the following message:'
|
66
|
+
Origen.log.error response.chomp
|
67
|
+
else
|
68
|
+
Origen.log.error 'Non standard response from ' + command + ' setup: ' + response
|
69
|
+
end
|
70
|
+
else
|
71
|
+
# response was nil. The server died
|
72
|
+
Origen.log.error command + ' caused a nil response. The server likely died.'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require_relative '..\vector_based'
|
2
|
+
require_relative 'vector_based_redefs'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
class DummyTset
|
6
|
+
attr_accessor :name
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@name = 'default'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class TestVectorBased < Test::Unit::TestCase
|
14
|
+
def test_stuff
|
15
|
+
timeset_sim_obj = DummyTset.new
|
16
|
+
|
17
|
+
test_obj = OrigenLink::VectorBased.new('localhost', 12_777)
|
18
|
+
# setup pinmap
|
19
|
+
test_obj.pinmap = 'tck, 5, tdo, 8, tms, 10, tdi, 15'
|
20
|
+
assert_equal('pin_assign:tck,5,tdo,8,tms,10,tdi,15', test_obj.message)
|
21
|
+
|
22
|
+
# setup pin order ---- notice there's currently no error checking to see if pinmap and pinorder have the same pins !!!
|
23
|
+
test_obj.pinorder = 'tck,tdo, tdi, extal'
|
24
|
+
assert_equal('pin_patternorder:tck,tdo,tdi,extal', test_obj.message)
|
25
|
+
|
26
|
+
assert_equal(true, test_obj.link?)
|
27
|
+
assert_equal('OrigenLink::VectorBased', test_obj.to_s)
|
28
|
+
|
29
|
+
test_obj.message = ''
|
30
|
+
test_obj.push_vector(timeset: timeset_sim_obj, pin_vals: '1100')
|
31
|
+
# check that pin values are being accumulated and not sent
|
32
|
+
assert_equal('', test_obj.message)
|
33
|
+
assert_equal(1, test_obj.vector_repeatcount)
|
34
|
+
|
35
|
+
# check that different vector data causes previous to be sent
|
36
|
+
test_obj.microcodestr = ''
|
37
|
+
test_obj.test_response = 'P:1100'
|
38
|
+
test_obj.push_vector(timeset: timeset_sim_obj, pin_vals: '1000')
|
39
|
+
assert_equal('pin_cycle:1100', test_obj.message)
|
40
|
+
assert_equal('P:1100', test_obj.microcodestr)
|
41
|
+
|
42
|
+
# check that repeat count accumulates
|
43
|
+
test_obj.microcodestr = ''
|
44
|
+
test_obj.push_vector(timeset: timeset_sim_obj, pin_vals: '1000')
|
45
|
+
assert_equal(2, test_obj.vector_repeatcount)
|
46
|
+
|
47
|
+
# check that repeat count is correctly sent
|
48
|
+
test_obj.test_response = 'P:repeat2,1000'
|
49
|
+
test_obj.flush_vector
|
50
|
+
assert_equal('pin_cycle:repeat2,1000', test_obj.message)
|
51
|
+
|
52
|
+
# check pin format setup
|
53
|
+
test_obj.test_response = 'P:'
|
54
|
+
test_obj.pinformat = 'func_25mhz, tck, rl'
|
55
|
+
assert_equal('pin_format:1,tck,rl', test_obj.message)
|
56
|
+
|
57
|
+
# check timing setup
|
58
|
+
test_obj.pintiming = 'func_25mhz, tdi, 0, tdo, 1, tms, 0'
|
59
|
+
assert_equal('pin_timing:1,tdi,0,tdo,1,tms,0', test_obj.message)
|
60
|
+
|
61
|
+
# check pin_cycle works correctly with tsets programmed
|
62
|
+
test_obj.test_response = 'P:tset0,1000'
|
63
|
+
timeset_sim_obj.name = 'func_25mhz'
|
64
|
+
test_obj.push_vector(timeset: timeset_sim_obj, pin_vals: '1000')
|
65
|
+
test_obj.flush_vector
|
66
|
+
assert_equal('pin_cycle:tset1,1000', test_obj.message)
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module TestDut
|
2
|
+
class TopLevel
|
3
|
+
include Origen::TopLevel
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
instantiate_pins(options)
|
7
|
+
instantiate_registers(options)
|
8
|
+
instantiate_sub_blocks(options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def instantiate_pins(options = {})
|
12
|
+
options = {
|
13
|
+
jtag_comm_config: false,
|
14
|
+
invalid_pin_number_test: false,
|
15
|
+
missing_pinmap_test: false
|
16
|
+
}.merge(options)
|
17
|
+
add_pin :tclk
|
18
|
+
add_pin :tdi
|
19
|
+
add_pin :tdo
|
20
|
+
add_pin :tms
|
21
|
+
add_pin :resetb
|
22
|
+
add_pins :port_a, size: 8
|
23
|
+
|
24
|
+
pin_pattern_order :tclk, :tms, :tdi, :tdo, only: true if options[:jtag_comm_config]
|
25
|
+
|
26
|
+
# if tester.link? #.to_s == 'OrigenLink::VectorBased'
|
27
|
+
if tester.to_s == 'OrigenLink::VectorBased'
|
28
|
+
if options[:invalid_pin_number_test]
|
29
|
+
tester.pinmap = 'tclk,119,tms,1900,tdi,116,tdo,124'
|
30
|
+
else
|
31
|
+
tester.pinmap = 'tclk,119,tms,6,tdi,116,tdo,124' unless options[:missing_pinmap_test]
|
32
|
+
end
|
33
|
+
tester.pinorder = 'tclk,tms,tdi,tdo'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def instantiate_registers(options = {})
|
38
|
+
reg :testreg, 0 do |reg|
|
39
|
+
reg.bits 31..0, :value
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def instantiate_sub_blocks(options = {})
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module TestDut
|
2
|
+
class TopLevelController
|
3
|
+
include Origen::Controller
|
4
|
+
|
5
|
+
include OrigenJTAG
|
6
|
+
|
7
|
+
JTAG_CONFIG = {
|
8
|
+
#:tclk_format => :rl,
|
9
|
+
tclk_format: :rh,
|
10
|
+
#:tclk_multiple => 1,
|
11
|
+
tclk_multiple: 4,
|
12
|
+
tdo_strobe: :tclk_high,
|
13
|
+
tdo_store_cycle: 3,
|
14
|
+
init_state: :idle
|
15
|
+
}
|
16
|
+
|
17
|
+
def startup(options)
|
18
|
+
pp 'Enter test mode' do
|
19
|
+
# if tester.link?
|
20
|
+
if tester.to_s == 'OrigenLink::VectorBased'
|
21
|
+
tester.initialize_pattern
|
22
|
+
# below is for testing return format timing, requires tclk to be rl and multiple of 1
|
23
|
+
# tester.pinformat = 'func_25mhz,tclk,rl'
|
24
|
+
# tester.pintiming = 'func_25mhz,tdi,0,tms,0,tdo,1'
|
25
|
+
end
|
26
|
+
tester.set_timeset('func_25mhz', 40) # Where 40 is the period in ns
|
27
|
+
tester.wait time_in_us: 100
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def shutdown(options)
|
32
|
+
pp 'Reset the device' do
|
33
|
+
pin(:resetb).drive!(0)
|
34
|
+
pin(:tclk).drive!(0)
|
35
|
+
end
|
36
|
+
# if tester.link?
|
37
|
+
if tester.to_s == 'OrigenLink::VectorBased'
|
38
|
+
tester.finalize_pattern
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module OrigenLink
|
2
|
+
class VectorBased
|
3
|
+
attr_accessor :message, :microcodestr, :test_response
|
4
|
+
|
5
|
+
def send_cmd(cmdstr, argstr)
|
6
|
+
@message = cmdstr + ':' + argstr
|
7
|
+
@test_response
|
8
|
+
end
|
9
|
+
|
10
|
+
def setup_cmd_response_logger(command, response)
|
11
|
+
end
|
12
|
+
|
13
|
+
def microcode(msg)
|
14
|
+
@microcodestr = @microcodestr + msg
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|