From 8b0e86773149db1009c0a0f7c3881d0606de1c5d Mon Sep 17 00:00:00 2001 From: pjht Date: Sun, 8 Jul 2018 14:09:22 -0500 Subject: [PATCH] Initial Commit --- old/README.md | 5 + old/kt8.rb | 182 +++++++++ old/net.rb | 223 +++++++++++ old/rcircuit_devices.txt | 15 + old/rcircuit_lib.rb | 837 +++++++++++++++++++++++++++++++++++++++ old/reg_fb_test.rb | 54 +++ old/reg_swap_test.rb | 45 +++ 7 files changed, 1361 insertions(+) create mode 100644 old/README.md create mode 100755 old/kt8.rb create mode 100755 old/net.rb create mode 100755 old/rcircuit_devices.txt create mode 100755 old/rcircuit_lib.rb create mode 100755 old/reg_fb_test.rb create mode 100755 old/reg_swap_test.rb diff --git a/old/README.md b/old/README.md new file mode 100644 index 0000000..1b17f49 --- /dev/null +++ b/old/README.md @@ -0,0 +1,5 @@ +# rcircuit +This is an HDL language for ruby. + +The braching system used is [OneFlow](http://endoflineblog.com/oneflow-a-git-branching-model-and-workflow), with one change: +When a branch is integrated with master, it is simply merged. diff --git a/old/kt8.rb b/old/kt8.rb new file mode 100755 index 0000000..4d36818 --- /dev/null +++ b/old/kt8.rb @@ -0,0 +1,182 @@ + +require_relative "rcircuit_lib" + + +class ALU < Device + def initialize(init_args={},width) + #define inputs and outputs + define_port('a', width) + define_port('b', width) + define_port('op', 4) + define_port('out', width) + #connect ports in init arguments + init_assign(init_args) + #create internal components + define_device("mux", Mux.new(8, 4).sel(op) + .in0(a + b) + .in1(a - b) + .in2(a & b) + .in3(a | b) + .in4(a ^ b) + .in5(!a) + .in6(!b) + .in7(a) + .in8(b) + .in9(a << 1) + .in10(a >> 1) + .in11(a + 1) + .in12(a - 1) + .in13(0) + .in14(0) + .in15(0) ) + mux.out.connect(out) + end +end + +def ALU.test + puts "ALU test:" + a=Port.new(8) + b=Port.new(8) + op=Port.new(4) + alu=ALU.new({"a"=>a,"b"=>b,"op"=>op},8) + dbg=Dbg.new({"a"=>a,"b"=>b,"op"=>op,"out"=>alu.out},true) + a.value=3 + b.value=10 + dbg.add_trigger("op") + for i in (0..15) do + op.value=i + end +end +class KT8Decoder < Device + def initialize(init_args={}) + define_port("ins",8) + init_assign(init_args) + define_port("aen") + define_port("ben") + define_port("ren") + define_port("wr") + define_port("rbsel") + define_port("den") + @ins4to7=ins.slice(4..7) + @ins0to3=ins.slice(0..3) + define_device("dec", Decoder.new(4) + .sel(@ins4to7) + .en(1) + .o0(aen) + .o1(ben) + .o2(wr) + .o3(rbsel) + .o8(ren) + .o11(den) ) + define_device("dec1", Decoder.new(4).sel(@ins0to3).en(den) ) + end + def on_change(new_val) + puts "ins:#{ins.value},ins[5:7]:#{@ins5to7.value},ins[4:7]:#{@ins4to7.value}" + if @ins5to7.value==0 + puts "5to7=0" + aen.value=1 + ben.value=0 + ren.value=0 + wr.value=0 + rbsel.value=0 + end + if @ins5to7.value==1 + puts "5to7=1" + aen.value=0 + ben.value=1 + ren.value=0 + wr.value=0 + rbsel.value=0 + end + if @ins5to7.value==2 + puts "5to7=2" + aen.value=0 + ben.value=0 + ren.value=0 + wr.value=1 + rbsel.value=0 + end + if @ins4to7.value==6 + puts "4to7=6" + aen.value=0 + ben.value=0 + ren.value=0 + wr.value=0 + rbsel.value=1 + end + if @ins4to7.value==7 + puts "4to7=7" + aen.value=0 + ben.value=0 + ren.value=0 + wr.value=0 + rbsel.value=2 + end + if @ins4to7.value==8 + puts "4to7=8" + aen.value=0 + ben.value=0 + ren.value=1 + wr.value=0 + rbsel.value=0 + end + end +end +#start of KT8 parts +class KT8 < Device + def initialize(init_args={}) + define_port("clk") + define_port("rst") + define_port("dout",8) + define_port("ins",8) + init_assign(init_args) + define_port("wr") + define_port("paddr",8) + define_port("daddr",5) + define_port("din",8) + define_device("dec", KT8Decoder.new().ins(ins).wr(wr)) + define_device("pc", Counter.new(8).clk(clk).rst(rst).load(0).out(paddr)) + define_device("reg_a", Reg.new(8).clk(clk).rst(rst).en(dec.aen)) + define_device("reg_b",Reg.new(8).clk(clk).rst(rst).en(dec.ben)) + define_device("reg_r",Reg.new(8).clk(clk).rst(rst).en(dec.ren)) + define_device("alu",ALU.new(8).a(reg_a.out).b(reg_b.out).op(ins.slice(0..3)).out(reg_r.in)) + daddr.connect(ins.slice(0..4)) + din.connect(reg_r.out) + #reg A input is always from data memory + reg_a.in(dout) + #reg B can be from memory or current value combined with immediate bits + low_bit_combine = reg_b.out.slice(4..7).join(ins.slice(0..3)) + high_bit_combine = ins.out.slice(0..3).join(reg_b.out.slice(0..3)) + reg_b_source = Mux.new(8,1).in0(dout).in1(low_bit_combine).sel(dec.rbsel) + reg_b.in(reg_b_source.out) + end +end + +clk=Port.new +rst=Port.new +prog_mem=Ram.new(8,8) +data_mem=Ram.new(8,5) +kt8=KT8.new("clk"=>clk,"rst"=>rst,"dout"=>data_mem.out,"ins"=>prog_mem.out) +prog_mem.addr(kt8.paddr).clk(clk).wr(0).in(0) +data_mem.addr(kt8.daddr).clk(clk).wr(kt8.wr).in(kt8.din) +dbg=Dbg.new("paddr"=>kt8.paddr,"daddr"=>kt8.daddr,"aval"=>kt8.reg_a.out,"rval"=>kt8.reg_r.out,"ins"=>kt8.ins,"aen"=>kt8.dec.aen,"ben"=>kt8.dec.ben,"ren"=>kt8.dec.ren,"wr"=>kt8.dec.wr,"rbsel"=>kt8.dec.rbsel,"aluop"=>prog_mem.out.slice(0..3)) +prog_mem[0]="00000000" +prog_mem[1]="10000111" +prog_mem[2]="01000001" +data_mem[0]="1011" +rst.value=0 +clk.value=0 +rst.value=1 +rst.value=0 +dbg.out +clk.value=1 +dbg.out +clk.value=0 +clk.value=1 +dbg.out +clk.value=0 +clk.value=1 +dbg.out + +puts "Putting.." +puts data_mem[1].inspect diff --git a/old/net.rb b/old/net.rb new file mode 100755 index 0000000..842ed7b --- /dev/null +++ b/old/net.rb @@ -0,0 +1,223 @@ +require 'set' +#endpoints for nets +class NetPort + + def initialize(width=1) + @callbacks = [] + @updating = false + #set up a new net with a matching width + Net.new(self, width) + end + + def connect(other) + if other.is_defined? + self.value = other.value #drive into the new net first + end + Net.get_net(self).connect(other) + self #return self for call chaining + end + + def value + Net.get_net(self).value + end + def bvalue + unless Net.get_net(self).value==nil + Net.get_net(self).value.to_s(2) + end + end + def width + Net.get_net(self).width + end + + def value=(new_value) + Net.get_net(self).drive(new_value) + end + + def posedge? + Net.get_net(self).posedge? + end + + def negedge? + Net.get_net(self).negedge? + end + + def is_defined? + self.value != nil + end + + def undefine + self.value = nil + end + + #called by Net, do not call directly + def _update(value) + if @updating + raise RuntimeError, "Signal loop detected in #{self.get_name}" + end + @updating = true + #send new value to each listener + @callbacks.each do |callback| + callback.call(value) + end + @updating = false + end + + def add_callback(&callback) + #add block to the list, put at head + @callbacks.insert(0, callback) + self #return self for call chaining + end + + def add_late_callback(&callback) + #add block to the list, put at end to be called last + @callbacks.push(callback) + self #return self for call chaining + end + + def set_name(name) + @name = name + end + + def set_parent(parent) + @parent = parent + end + + def get_name + if @name == nil + @name = self.class + end + if @parent != nil + @parent.get_name + "." + @name + else + @name + end + end + +end + +class Net + @@assignments = {} #table of nets assigned to ports + @@propagate_list = [] #nets that have changed during propagate call + @@propagate_flag = false + + def initialize(port, width=1) + if @@assignments.has_key?(port) + raise ArgumentError, "Repeat assignment of port to new net" + end + @ports = Set.new + @ports.add(port) + @width = width + @max_value = 2**@width - 1 + @value = nil + @posedge = false + @negedge = false + @@assignments[port] = self + end + + def ports + @ports + end + + def width + @width + end + + def connect(other) + if @width != other.width + raise ArgumentError, "Cannot connect nets of different widths" + end + if @@assignments.has_key?(other) + #net already assigned to other port. + #Merge them and update @@assignments table + other_net = @@assignments[other] + @ports.merge(other_net.ports) + other_net.ports.each { |port_in_other| @@assignments[port_in_other] = self } + else + #unassigned port, just add it + @ports.add(other) + @@assignments[other] = self + end + end + + def drive(new_value) + if new_value.is_a?(NetPort) + new_value=new_value.value + end + if new_value != nil && (new_value < 0 || new_value > @max_value) + raise ArgumentError, "Invalid value (#{new_value}) for net" + end + if new_value != @value + @new_value = new_value + @@propagate_list.push(self) #schedule to run update + if not @@propagate_flag + #automatically propagate the change and all changes that result + @@propagate_flag = true #prevent recursion + Net.propagate + @@propagate_flag = false #unlock for next time + end + end + end + + #loops until all updates complete + def self.propagate + #propagate list will grow as downstream nets are changed + #keep updating until none are left + while @@propagate_list.length > 0 do + net = @@propagate_list.shift + net.update + end + end + + def update + @posedge = (@value == 0 && @new_value != nil && @new_value > 0) + @negedge = (@value != nil && @value > 0 && @new_value == 0) + @value = @new_value + @ports.each { |driven| driven._update(@new_value) } + #edges only last for the current update + @posedge = false + @negedge = false + end + + def value + @value + end + + def posedge? + @posedge + end + + def negedge? + @negedge + end + + def value=(new_value) + drive(new_value) + end + + #get net currently assigned to the given port (or a new one) + def self.get_net(port) + if @@assignments.has_key?(port) + @@assignments[port] + else + self.new(port) + end + end + + def self.test + a = NetPort.new(4).add_callback { |value| puts "A set to #{value}" } + b = NetPort.new(4).add_callback { |value| puts "B set to #{value}" } + c = NetPort.new(4).add_callback { |value| puts "C set to #{value}" } + d = NetPort.new(4).add_callback { |value| puts "D set to #{value}" } + + #connect A-B and C-D + a.connect(b) + c.connect(d) + + a.value = 1 + c.value = 2 + #connect them all together + b.connect(c) + a.value = 3 + d.value = 4 + end +end diff --git a/old/rcircuit_devices.txt b/old/rcircuit_devices.txt new file mode 100755 index 0000000..fff9a64 --- /dev/null +++ b/old/rcircuit_devices.txt @@ -0,0 +1,15 @@ +Reg: + Inputs:in,clk,en,rst + Outputs:out +Counter: + Inputs:in,clk,load,rst + Outputs:out +Mux: + Inputs:in0,in1... + Outputs:out +Decoder: + Inputs:sel + Outputs:o0,o1... +Ram: + Inputs:in,clk,wr + Outputs:out \ No newline at end of file diff --git a/old/rcircuit_lib.rb b/old/rcircuit_lib.rb new file mode 100755 index 0000000..f8e2d72 --- /dev/null +++ b/old/rcircuit_lib.rb @@ -0,0 +1,837 @@ +# Ruby Circuit Simulator +# Library file + +# holds a digital value +# can call listener callbacks when value changes + +require_relative "net" +#add some extra functionality to the basic NetPort +class Port < NetPort + include Comparable + + #override to handle bitstrings + def value=(new_value) + if new_value.class == String + if new_value.length != self.width + raise ArgumentError, "Wrong width for bitstring: #{new_value}" + end + numval = 0 + new_value.reverse.each do |bit| + numval = numval << 1 + if bit == "1" + numval += 1 + elsif bit != "0" + raise ArgumentError, "String values (#{new_value}) must be binary" + end + end + super(numval) + else + super(new_value) + end + end + + def convert_port(otherval) + #checks if argument is a port or number + #if it is a number, convert it to a contant port + if otherval.class == Integer + return PortConstant.new(self.width, otherval) + else + return otherval + end + end + + def &(other) + other = convert_port(other) + return AndGate.new(self,other).out + end + + def |(other) + other = convert_port(other) + return OrGate.new(self,other).out + end + + def ^(other) + other = convert_port(other) + return XorGate.new(self, other).out + end + + def ! + return NotGate.new(self).out + end + + def +(other) + other = convert_port(other) + return Adder.new(self.width,{"a"=>self,"b"=>other}).out + end + + def -(other) + other = convert_port(other) + return Subtractor.new(self.width,{"a"=>self,"b"=>other}).out + end + + def slice(index) + if index.class==Integer + port=Port.new(1) #single line + mask = 1 << index + shift = index + else + port=Port.new(index.size) #range + mask = (2**(index.size) - 1) << index.first + shift = index.first + end + #copies slice to new port + self.add_callback do |new_value| + port.value = (new_value & mask) >> shift + end + return port + end + + def join(other,last=false) + port=Port.new(self.width+other.width) + def update_port(last,port,other) + if self.is_defined? && other.is_defined? + if last + port.value=(other.value << self.width) + self.value + else + port.value=(self.value << other.width) + other.value + end + else + port.undefine + end + end + self.add_callback {|value| update_port(last,port,other)} + other.add_callback {|value| update_port(last,port,other)} + return port + end + + def <=>(other) + other = convert_port(other) + return self.value<=>other.value + end + + def >>(shiftbits) + return LSR.new(self.width, shiftbits).in(self).out + end + + def <<(shiftbits) + return LSL.new(self.width, shiftbits).in(self).out + end + + def bitstring + if is_defined? + mask = 1 << (self.width - 1) + strval = "" + self.width.times do + if (self.value & mask) > 0 + strval += "1" + else + strval += "0" + end + mask = mask >> 1 + end + strval + else + "X"*self.width + end + end + + def method_missing(m, *args, &block) + return self + end +end + +class PortConstant < Port + def initialize(width, value) + super(width) + @assigned = false + self.value = value + @assigned = true + end + + def _update(newvalue) + if @assigned + #not initial assigment + #raise RuntimeError, "Cannot change value of constant port" + end + end +end + + +class Gate + def initialize(*args) + @inputs = [] + if args.length==0 + @width=1 + @out = Port.new(@width) + elsif args[0].class==Integer + @width=args.shift + @out = Port.new(@width) + args.each do |input| + add_input(input) + end + else + @width=args[0].width + @out = Port.new(@width) + args.each do |input| + add_input(input) + end + end + end + + def add_input(input_port) + if input_port.width != @width then + raise ArgumentError, "Incorrect port width" + end + @inputs.push(input_port) + input_port.add_callback {|value| self.input_changed(value)} + input_changed(input_port.value) + end + + def out + return @out + end + +end + + +class NotGate < Gate + def initialize(*args) + super + @outmask = (2**@width)-1 + end + + def add_input(input_port) + if @inputs.length > 0 then + raise ArgumentError, "Cannot add multiple inputs to NotGate" + end + super + end + + alias set_input add_input + + def input_changed(new_value) + inport=@inputs[0] + if inport.is_defined? + out.value = (~inport.value) & @outmask + else + out.undefine + end + end + + def self.test + puts "NOT Test:" + nin = Port.new() + not_gate = NotGate.new(nin) + dbg = Dbg.new( {"in"=>nin, "out"=>not_gate.out}) + dbg.out + nin.value = 0 + dbg.out + nin.value = 1 + dbg.out + end +end + +class AndGate < Gate + + def input_changed(new_value) + andval = nil + @inputs.each do |inport| + if inport.is_defined? + if andval == nil + andval = inport.value + else + andval = andval & inport.value + end + else + out.undefine + return + end + end + out.value = andval + end + + def self.test() + puts "AND Test:" + in_a = Port.new() + in_b = Port.new() + and_gate = AndGate.new(in_a, in_b) + dbg = Dbg.new( {"a"=>in_a, "b"=>in_b, "out"=>and_gate.out}) + dbg.out + in_a.value=0 + in_b.value=0 + dbg.out + in_a.value=1 + in_b.value=0 + dbg.out + in_a.value=0 + in_b.value=1 + dbg.out + in_a.value=1 + in_b.value=1 + dbg.out + end +end + +class OrGate < Gate + + def input_changed(new_value) + orval = nil + @inputs.each do |inport| + if inport.is_defined? + if orval == nil + orval = inport.value + else + orval = orval | inport.value + end + else + out.undefine + return + end + end + out.value = orval + end + + def self.test() + puts "OR Test:" + in_a = Port.new() + in_b = Port.new() + or_gate = OrGate.new(in_a, in_b) + dbg = Dbg.new( {"a"=>in_a, "b"=>in_b, "out"=>or_gate.out}) + dbg.out + in_a.value=0 + in_b.value=0 + dbg.out + in_a.value=1 + in_b.value=0 + dbg.out + in_a.value=0 + in_b.value=1 + dbg.out + in_a.value=1 + in_b.value=1 + dbg.out + end +end + + +class XorGate < Gate + + def input_changed(new_value) + xorval = nil + @inputs.each do |inport| + if inport.is_defined? + if xorval == nil + xorval = inport.value + else + xorval = xorval ^ inport.value + end + else + out.undefine + return + end + end + out.value = xorval + end + + def self.test() + puts "XOR Test:" + in_a = Port.new() + in_b = Port.new() + or_gate = OrGate.new(in_a, in_b) + dbg = Dbg.new( {"a"=>in_a, "b"=>in_b, "out"=>or_gate.out}) + dbg.out + in_a.value=0 + in_b.value=0 + dbg.out + in_a.value=1 + in_b.value=0 + dbg.out + in_a.value=0 + in_b.value=1 + dbg.out + in_a.value=1 + in_b.value=1 + dbg.out + end +end + + +class Device + def define_port(name, width=1, &callback) + #create a method with the same name as the input + #to assign a port to the input + var_name = "@" + name + port = Port.new(width) + port.set_name(name) + port.set_parent(self) + instance_variable_set(var_name, port) + define_singleton_method(name) do |other=nil| + if other.class == NilClass #avoids overloaded compare for Port + #getter + instance_variable_get(var_name) + else + #connect to given port + if other.class == Integer + #convert constant + other = PortConstant.new(width, other) + end + instance_variable_get(var_name).connect(other) + self #for chained init calls + end + end + if block_given? + port.add_callback(&callback) + end + port + end + + def define_input(name, width=1) + #automatically connects to on_change method + define_port(name, width) { |new_value| on_change(new_value) } + end + + #for contained subdevices + def define_device(name, device) + var_name = "@" + name + instance_variable_set(var_name, device) + define_singleton_method(name) { instance_variable_get(var_name) } + device.set_parent(self) + device.set_name(name) + end + + #call on the hash of arguments at init + def init_assign(hash) + hash.each do |name, port| + #check if there is a defined method (port) that matches + if self.respond_to?(name) + method(name).call(port) + else + raise ArgumentError, "No defined input '#{name}'" + end + end + end + + def set_name(name) + @name = name + end + + def set_parent(parent) + @parent = parent + end + + def get_name + if @name == nil + @name = self.class + end + if @parent != nil + @parent.get_name + "." + @name + else + @name + end + end + +end + +#logical shift right +class LSR < Device + def initialize(width, bitshift, init_args={}) + define_input("in", width) + define_port("out", width) + @bitshift = bitshift + init_assign(init_args) + end + + def on_change(data_val) + if @in.is_defined? + out.value = @in.value >> @bitshift + else + out.undefine + end + end +end + +#logical shift left +class LSL < Device + def initialize(width, bitshift, init_args={}) + define_input("in", width) + define_port("out", width) + @bitshift = bitshift + @outmask = (2**width) - 1 + init_assign(init_args) + end + + def on_change(data_val) + if @in.is_defined? + out.value = (@in.value << @bitshift) & @outmask + else + out.undefine + end + end +end + + +class Reg < Device + def initialize(width, init_args={}) + define_input("in", width) + define_port("out", width) + define_input("clk") + define_input("en") + define_input("rst") + init_assign(init_args) + end + + def on_change(data_val) + if rst.value == 1 + out.value = 0 + elsif en.value == 1 && clk.posedge? + out.value = @in.value + end + end +end + +class Counter < Device + def initialize(width, init_args={}) + define_input("in", width) + define_port("out", width) + define_input("clk") + define_input("load") + define_input("rst") + init_assign(init_args) + end + + def on_change(data_val) + #puts "on_change, clk=#{clk.value}, rst=#{rst.value}" + if out.undefined? + out.value=0 + end + if rst.value == 1 + #puts "resetting" + out.value = 0 + elsif clk.posedge? + #puts "posedge" + if load.value == 1 + out.value = @in.value + else + #puts "no load, old out=#{out.value}" + out.value = out.value + 1 + #puts "new out=#{out.value}" + end + end + end + + def self.test + puts "Reg Test:" + din = Port.new(8) + c = Port.new + e = Port.new + r = Port.new + reg = Reg.new(8,{"in"=>din,"clk"=>c,"en"=>e,"rst"=>r}) + dbg = Dbg.new({"in"=>din, "clk"=>c, "en"=>e, "rst"=>r, "out"=>reg.out}) + r.value = 1 + c.value = 0 + e.value = 0 + din.value = 23 + dbg.out + r.value = 1 + dbg.out + r.value = 0 + dbg.out + c.value = 1 + dbg.out + e.value = 1 + dbg.out + c.value = 0 + dbg.out + c.value = 1 + dbg.out + din.value = 37 + dbg.out + end + +end + +class Mux < Device + def initialize(data_width=1, select_width=1, init_args={}) + num_inputs = 2**select_width + i=0 + @inputs = [] + num_inputs.times do + @inputs << define_input("in"+i.to_s, data_width) + i += 1 + end + define_input("sel", select_width) + define_port("out", data_width) + init_assign(init_args) + end + + def on_change(new_value) + if sel.is_defined? + + out.value = @inputs[sel.value].value + else + out.undefine + end + end + + def self.test + puts "Mux test:" + select = Port.new(1) + a = Port.new(4) + b = Port.new(4) + mux = Mux.new(4, 1).sel(select).in0(a).in1(b) + dbg = Dbg.new({"sel"=>select, "0"=>a, "1"=>b, "out"=>mux.out}) + a.value = 3 + b.value = 14 + dbg.out + select.value = 0 + dbg.out + select.value = 1 + dbg.out + end +end + + +class Decoder < Device + def initialize(width, init_args={}) + @width=width + define_input("sel", width) + define_input("en") + num_of_outputs=2**width + i=0 + @outputs = [] + num_of_outputs.times do + #create an ordered list of all the outputs + @outputs << define_port("o"+i.to_s) + i+=1 + end + init_assign(init_args) + end + + def on_change(data_val) + if en + if sel.is_defined? + channel=sel.value + i=0 + (@width**2).times do + if i==channel + @outputs[i].value=1 + else + @outputs[i].value=0 + end + i+=1 + end + else + i=0 + (@width**2).times do + @outputs[i].undefine + i+=1 + end + end + else + i=0 + (@width**2).times do + @outputs[i].value=0 + i+=1 + end + end + end + + def self.test + puts "Decoder Test:" + select=Port.new(2) + decoder=Decoder.new(2,"sel"=>select) + dbg = Dbg.new({"sel"=>select, "0"=>decoder.o0, "1"=>decoder.o1, "2"=>decoder.o2, "3"=>decoder.o3}) + dbg.out + select.value=0 + dbg.out + select.value=1 + dbg.out + select.value=2 + dbg.out + select.value=3 + dbg.out + end +end + +class PEncoder < Device + def initialize(width, init_args={}) + define_port("out", width) + @inputs = [] + @num_inputs = width**2 + (0...@num_inputs).each do |i| + @inputs << define_input("in#{i}", 1) + end + init_assign(init_args) + end + + def on_change(data_val) + (0...@num_inputs).each do |i| + if @inputs[i].is_defined? + if @inputs[i].value == 1 + out.value = i + return + end + else + out.undefine + return + end + end + out.value = 0 #default, no active inputs + end + + def self.test + puts "PEncoder test:" + in0 = Port.new + in1 = Port.new + in2 = Port.new + in3 = Port.new + out = Port.new(2) + dut = PEncoder.new(2).in0(in0) + .in1(in1) + .in2(in2) + .in3(in3) + .out(out) + dbg = Dbg.new({"0"=>dut.in0, "1"=>dut.in1, "2"=>dut.in2, "3"=>dut.in3, "Out"=>dut.out}) + dbg.out + in0.value = 0 + in1.value = 0 + in2.value = 0 + in3.value = 0 + dbg.out + in2.value = 1 + dbg.out + in1.value = 1 + dbg.out + in3.value = 1 + dbg.out + end +end + +class Adder < Device + def initialize(width, init_args) + define_input("a", width) + define_input("b", width) + define_port("out", width) + init_assign(init_args) + @mask = 2**width - 1 + end + + def on_change(data_val) + if a.is_defined? && b.is_defined? + out.value = (a.value + b.value) & @mask + else + out.undefine + end + end +end + +class Subtractor < Device + def initialize(width, init_args) + define_input("a", width) + define_input("b", width) + define_port("out", width) + init_assign(init_args) + @mask = 2**width - 1 + end + + def on_change(data_val) + if a.is_defined? && b.is_defined? + out.value = (a.value - b.value) & @mask + else + out.undefine + end + end +end + +class Ram < Device + def initialize(data_width, addr_width, init_args={}) + @mem=[] + define_input("in", data_width) + define_port("out", data_width) + define_input("addr", addr_width) + define_input("clk") + define_input("wr") + init_assign(init_args) + end + + def set_data(init_array) + @mem = init_array + end + + def on_change(data_val) + if wr.value == 1 && clk.posedge? + @mem[addr.value]=@in.value + out.undefine + elsif addr.is_defined? && @mem[addr.value] != nil + out.value=@mem[addr.value] + else + out.value=0 + end + end + + def [](addr) + return @mem[addr] + end + def []=(addr,value) + if value.class==String + @mem[addr]=value.to_i(2) + else + @mem[addr]=value + end + end + def self.test + puts "RAM test:" + din=Port.new(8) + addr=Port.new(8) + wr=Port.new + clk=Port.new + ram=Ram.new(8,8,{"in"=>din,"addr"=>addr,"wr"=>wr,"clk"=>clk}) + dbg=Dbg.new({"in"=>din,"out"=>ram.out,"addr"=>addr,"wr"=>wr,"clk"=>clk}) + clk.value=0 + din.value=11 + addr.value=0 + wr.value=1 + clk.value=1 + dbg.out + clk.value=0 + end +end + +class Dbg + def initialize(ports,show_num=false) + @names = [] + @ports = {} + @show_num=show_num + ports.each do |name,port| + @names.push(name) + @ports[name] = port + end + end + + def add_trigger(port_name) + @ports[port_name].add_late_callback { |value| self.out } + end + + def out + watch_str = "" + if @show_num + @names.each { |name| watch_str += "#{name}=#{@ports[name].value} " } + else + @names.each { |name| watch_str += "#{name}=#{@ports[name].bitstring} " } + end + puts watch_str + end +end + +def test() + classes = [] + ObjectSpace.each_object { |o| classes.push o if o.class == Class } + classes.each do |c| + if c!=Object && c.methods.include?(:test) + c.test + end + end +end + +# PEncoder.test +test() diff --git a/old/reg_fb_test.rb b/old/reg_fb_test.rb new file mode 100755 index 0000000..2c92513 --- /dev/null +++ b/old/reg_fb_test.rb @@ -0,0 +1,54 @@ +#testing propagation of nets by putting three +#clocked registers in a loop + +require_relative "rcircuit_lib" + +clk = Port.new +sel = Port.new +rst = Port.new +reg_en = Port.new +init_val = Port.new(8) + +reg_a = Reg.new(8).clk(clk).rst(rst).en(reg_en) +reg_b = Reg.new(8).clk(clk).rst(rst).en(reg_en) +reg_c = Reg.new(8).clk(clk).rst(rst).en(reg_en) +#for loading reg_a with an initial value +init_mux = Mux.new(8,1).in0(reg_c.out).in1(init_val).sel(sel) +reg_a.in(init_mux.out) +reg_b.in(reg_a.out) +reg_c.in(reg_b.out) + +dbg=Dbg.new("clk"=>clk, + "init"=>init_val, + "a.out"=>reg_a.out, + "b.out"=>reg_b.out, + "c.out"=>reg_c.out) + +rst.value = 1 +clk.value = 0 +rst.value = 0 +reg_en.value = 1 +init_val.value = 1 +sel.value = 1 +puts "Loading 1 into A" +clk.value = 1 #loads 1 into A +dbg.out +init_val.value = 2 +clk.value = 0 +puts "Loading 2 into A, 1 into B" +clk.value = 1 #loads 2 into A, 1 into B +dbg.out +puts "4 clock clyles" +sel.value = 0 +clk.value = 0 +clk.value = 1 +dbg.out +clk.value = 0 +clk.value = 1 +dbg.out +clk.value = 0 +clk.value = 1 +dbg.out +clk.value = 0 +clk.value = 1 +dbg.out diff --git a/old/reg_swap_test.rb b/old/reg_swap_test.rb new file mode 100755 index 0000000..ca82186 --- /dev/null +++ b/old/reg_swap_test.rb @@ -0,0 +1,45 @@ +#testing propagation of nets by using two registers wired to each other + +require_relative "rcircuit_lib" + + +clk = Port.new +sel = Port.new +rst = Port.new +reg_en = Port.new +init_val = Port.new(8) + +reg_a = Reg.new(8).clk(clk).rst(rst).en(reg_en) +reg_b = Reg.new(8).clk(clk).rst(rst).en(reg_en) +#for loading reg_a with an initial value +init_mux = Mux.new(8,1).in0(reg_b.out).in1(init_val).sel(sel) +reg_a.in(init_mux.out) +reg_b.in(reg_a.out) + +dbg=Dbg.new("clk"=>clk,"init"=>init_val,"a.out"=>reg_a.out,"b.out"=>reg_b.out) + +rst.value = 1 +clk.value = 0 +rst.value = 0 +reg_en.value = 1 +init_val.value = 1 +sel.value = 1 +puts "Loading 1 into A" +clk.value = 1 #loads 1 into A +dbg.out +init_val.value = 2 +clk.value = 0 +puts "Loading 2 into A, 1 into B" +clk.value = 1 #loads 2 into A, 1 into B +dbg.out +puts "Swapping A<->B" +sel.value = 0 #set to swap A <-> B +clk.value = 0 +clk.value = 1 +dbg.out +clk.value = 0 +clk.value = 1 +dbg.out +clk.value = 0 +clk.value = 1 +dbg.out \ No newline at end of file