In [1]:
# Imports
from BinPy import *
In [2]:
# XOR GATE in BinPy
# Create a gate instance
xor1 = XOR(1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1)
xor1.output()
Out[2]:
In [3]:
# Using a Connector in BinPy
A = Connector(1) # input 1
B = Connector(0) # input 2
C = Connector() # output
xor1.set_inputs(A, B) # Overrides previous inputs
xor1.set_output(C)
In [4]:
C.get_logic() # or use C.state
Out[4]:
In [5]:
A.set_logic(0);
C.get_logic()
Out[5]:
In [6]:
# Using Bus in BinPy
In [7]:
# Initiating the Bus with connectors
bit_1 = Connector(0)
bit_2 = Connector(1)
bit_3 = Connector(0)
bit_4 = Connector(0)
bus_a = Bus(bit_1, bit_2, bit_3, bit_4)
In [8]:
# Probing the logic of the Bus
bus_a.get_logic_all(as_list=False)
Out[8]:
In [9]:
# Probing the voltage of the Bus -- The logic states can be represented by a 5v logic
# To get another logic family edit the binpy.config file to set the desired logic HIGH and logic LOW parameters
bus_a.get_voltage_all()
Out[9]:
In [10]:
# Creating another Bus from an existing Bus
bus_b = Bus(bus_a)
bus_b.get_voltage_all()
Out[10]:
In [11]:
# Concatenating the two Bus-es
bus_c = bus_a + bus_b
bus_c
Out[11]:
In [12]:
# Copying values between buses
bus_d = Bus(8) # 8 indicates the length of the Bus. By default all busses will be digital in type
print (bus_d)
In [13]:
bus_d.copy_values_from(bus_c)
print (bus_d)
In [14]:
# Iterating through a bus and setting names ( TAG's ) for connectors
i = 7
for connector in bus_d:
connector.set_name("B"+str(i))
print ( connector )
i -= 1
In [15]:
# Probing the connector tags of each bus
print (" ".join( [ connector.name for connector in bus_d ]))
In [16]:
# Analog Bus
PWR = Bus(Connector(voltage=5.2), Connector(voltage=0))
print (PWR)
In [17]:
# Bus is an abstraction over the python lists, so you can do all list operations on it
# Slicing Bus-es
bus_e = Bus(bus_d[:-4])
print (bus_e == bus_b)
In [18]:
# Circulary rotating the bits of the Bus-es
print ("Before rotation, bus_e : ", bus_e)
print ("After circularly rotating right by 3 positions, bits of bus_e: ", bus_e >> 3)
# Note that this returns a list of the Connectors and not a bus object. Use Bus(bus_e>>2) to return a Bus object
print ("After circularly rotating left by 3 positions, bits of bus_e: ", bus_e << 3)
In [19]:
# Using the linker module to connect two Bus-es
CNTRL_V = Bus(4)
CNTRL_V.set_voltage_all(5.0,5.0,2.0,2.5)
VCC = Bus(Connector(voltage = 5.2), Connector(voltage=0))
In [20]:
SLAVE0, SLAVE1 = Bus(4), Bus(4)
SLAVE0.set_type(analog = True)
SLAVE1.set_type(analog = True)
# Connecting the first two bits of CNTRL_V to the middle two bits of SLAVE0
AutoUpdater.add_link(CNTRL_V[:2], SLAVE0[1:-1])
# Connecting the last two bits of CNTRL_V to the middle two bits of SLAVE1
AutoUpdater.add_link(CNTRL_V[-2:], SLAVE1[1:-1])
# Impressing 5v and 0v on the SLAVE0 Bus
AutoUpdater.add_link(VCC[0], SLAVE0[0])
AutoUpdater.add_link(VCC[1], SLAVE0[-1])
# Impressing 5v and 0v on the SLAVE1 Bus
AutoUpdater.add_link(VCC[0], SLAVE1[0])
AutoUpdater.add_link(VCC[1], SLAVE1[-1])
In [21]:
print (SLAVE0.get_voltage_all())
In [22]:
print (SLAVE1.get_voltage_all())
In [23]:
CNTRL_V.set_voltage_all(5.0, 6.0, 2.0, 1.1)
In [24]:
# The Slave Bus-es have been updated with the updated voltage in CNTRL_V
print (SLAVE0.get_voltage_all())
In [25]:
print (SLAVE1.get_voltage_all())
In [26]:
# Unlinking the SLAVE0 from CNTRL_V
AutoUpdater.remove_link(SLAVE0[1:-1]) # Only the middle 2 ports are connected to CNTRL_V
# VCC is still connected to SLAVE0
In [27]:
CNTRL_V.set_voltage_all(3.0, 2, 1, 6.2)
In [28]:
# SLAVE0 Retains the last held value
print (SLAVE0.get_voltage_all())
In [29]:
# SLAVE1 however is updated
print (SLAVE1.get_voltage_all())
In [30]:
# Change in VCC is reflected to both SLAVE0 and SLAVE1
VCC[0].set_voltage(5.5)
print (SLAVE0[0].get_voltage())
In [31]:
print (SLAVE1[0].get_voltage())
BinPyBits
is a class inheriting from the bitstring.BitArray
class. It will be used for efficient manipulation / handling of Bit vectors.
In [32]:
from BinPy import *
# Initializing a BinPyBits object
bit_vector = BinPyBits(5)
In [33]:
# By default all BinPyBits objects are not signed
bit_vector.signed
Out[33]:
In [34]:
# Getting the decimal value
bit_vector.uint
Out[34]:
In [35]:
# Getting the binary string
bit_vector.bin
Out[35]:
In [36]:
# Do not use int with unsigned BinPyBits objects
bit_vector.int
Out[36]:
In [37]:
# This returns -3 since '101' ==> -3 ( 2's Complement representation )
# You could use :
int_value = bit_vector.int if bit_vector.signed else bit_vector.uint
print int_value
In [38]:
# Creating a BinPyBits object using binary string
bit_vector = BinPyBits('1111', signed=False)
# Converting to decimal
int_value = bit_vector.int if bit_vector.signed else bit_vector.uint
print int_value
In [39]:
# Creating a signed BinPyBits
bit_vector = BinPyBits('1111', signed=True)
# Converting to decimal
int_value = bit_vector.int if bit_vector.signed else bit_vector.uint
print int_value
In [40]:
# Converting to hex
bit_vector.hex
Out[40]:
Refer the documentation of bittstring to discover additional functionality.
In [41]:
# The speciality of BinPyBits lies in the fact that it can be initialized from various types of inputs
# Except for the initialization, the rest of the functionalities remain similar to that of the bitstring.BitArray
# Initializing a signed value using - sign
bit_vector = BinPyBits('-1111', signed=True)
print bit_vector.int
In [42]:
product = robertsons_multiply('111111', '111111', 7)
print product
In [43]:
to_unsigned_int(product)
Out[43]:
In [44]:
product = robertsons_multiply('111111', '000001', 7, signed=True)
print product
In [45]:
to_signed_int(product)
Out[45]:
In [46]:
product = booths_multiply('110011', '111001')
print product
In [47]:
to_unsigned_int(product)
Out[47]:
In [48]:
product = booths_multiply(bin(-5), bin(-5), signed=True)
print product
In [49]:
to_signed_int(product)
Out[49]:
In [50]:
product = karatsuba_multiply('1010', '1001')
print product
In [51]:
print to_unsigned_int(product)
In [52]:
product = karatsuba_multiply('1010', '1001', signed=True) # --6 * -7 = 42
print product
In [53]:
print to_unsigned_int(product)
In [54]:
# Usage of IC 7400:
ic1 = IC_7400()
print(ic.__doc__)
In [55]:
ic1.draw_IC()
In [56]:
pin_dict = {1: 1, 2: 0, 4: 0, 5: 0, 7: 0, 9: 1, 10: 1, 12: 0, 13: 0, 14: 1}
ic1.set_IC(pin_dict)
ic1.run()
Out[56]:
In [57]:
ic1.draw_IC()
In [58]:
alu = IC_74181()
In [59]:
print alu.__doc__
In [60]:
alu.draw_IC()
In [61]:
# Complementing A Bus and B Bus
#_ = [ ( NOT(A[i]).set_output(A_Compl[i]), NOT(B[i]).set_output(B_Compl[i]) ) for i in range(4) ]
In [62]:
# Input Bus A and B
A, B = Bus(4), Bus(4)
# Power supply of VCC 5v / GND 0v
PWR = Bus(Connector(voltage=0), Connector(voltage=5.0))
MOD = 1
SEL = list(reversed([1, 1, 1, 0]))
CAR = 1
In [63]:
A.set_logic_all('1000') # 8
B.set_logic_all('0001') # 1
A_ = A.get_logic_all() # I might as well store A_ directly as a list of logic bits ...
B_ = B.get_logic_all()
alu.set_IC({ 1:B_[0],
2:A_[0],
3:SEL[3],
4:SEL[2],
5:SEL[1],
6:SEL[0],
7:CAR,
8:MOD,
12:int(PWR[0]),
18:B_[3],
19:A_[3],
20:B_[2],
21:A_[2],
22:B_[1],
23:A_[1],
24:int(PWR[1])
})
alu.run()
Out[63]:
In [64]:
alu.draw_IC()
In [65]:
# Initializing the DEMUX class
# Must be a single input
demux = DEMUX(1)
# Put select lines
# Select Lines must be power of 2
demux.select_lines(0, 1) # a, b
# Output of demux
print (demux.output()) # D0, D1, D2, D3
In [66]:
print(FullAdder.__doc__)
In [67]:
a, b, ci, s, co = Connector(1), Connector(0), Connector(1), Connector(), Connector()
# Initializing full adder using connectors
fa = FullAdder(a, b, ci)
# Connect outputs
fa.set_output(0, co)
fa.set_output(1, s)
In [68]:
print (co.get_logic(), s.get_logic())
In [69]:
# Initializing the MUX class
mux = MUX(0, 1, 1, 0)
# Put select lines
mux.select_lines(0, 0)
# Output of mux
print (mux.output())
In [70]:
j, k, p, q = Connector(1), Connector(0), Connector(0), Connector(1)
# A clock of 4 hertz frequency initialized to 1
clock = Clock(0, 4)
jkff = JKFlipFlop(j, k, Connector(1), clock.A, clear=Connector(1))
# To connect outputs use s.set_outputs(op1,op2)
jkff.set_outputs(A=p, B=q)
# Initiating the oscilloscope
o = Oscilloscope((clock.A, 'CLK'), (j, 'J'), (
k, 'k'), (p, 'OUT'), (q, 'OUT!'), (Connector(1), 'ENABLE'))
o.start()
o.set_scale(0.02) # Set scale by trial and error.
o.set_width(100)
o.unhold()
# For each j,k in 0,0 / 0,1 / 1,0 / 1,1 Trigger ( Send a Falling edge clock pulse to the jkff module )
from time import sleep
for j.state, k.state in zip([0, 0, 1, 0, 1], [0, 0, 0, 1, 1]):
print "j,k = ", ( j.state, k.state )
# Sending One Clock Pulse
# The same thing can also be done by --> jkff.setInputs(j = 1, k = 0)
while True:
if clock.A.state == 0:
# Falling edge will trigger the FF
jkff.trigger()
break
print (jkff.state())
# Sending a positive edge to jkff
while True:
if clock.A.state == 1:
# Falling edge will trigger the FF
jkff.trigger()
break
o.display()
In [71]:
# MODE selects the mode of operation of the multivibrator.
# Mode No. : Description
# 1 Monostable
# 2 Astable
# 3 Bistable
out = Connector()
In [72]:
# Initialize mutivibrator in MODE 1
m = Multivibrator(0, mode=1, time_period=1)
m.set_output(out)
# Initialize the oscilloscope
o = Oscilloscope((out, 'OUT'))
o.set_scale(0.005) # Set scale by trial and error.
o.set_width(100)
o.unhold()
time.sleep(0.1)
m.trigger() # Also works with m()
time.sleep(0.1)
# Display the oscilloscope
o.display()
m.kill()
o.kill()
In [73]:
# Source Bus
a = Bus(4)
a.set_type(analog=True)
a.set_voltage_all(3.5, 6.7, 2.2, 1.1)
# Ouput Bus
b = Bus(4)
b.set_type(analog=True)
# Enable input
e = Bus(1)
e.set_logic_all(1)
In [74]:
# Initializing an analog Buffer
buff1 = AnalogBuffer(a, b, e, 0.8) # With an attenuation of 0.8, relay the input to the output
In [75]:
print b.get_voltage_all()
In [76]:
# BinPy automatically converts the voltage to logic state based on 5v-0v logic
print b.get_logic_all()
In [77]:
print b.get_voltage_all()
In [78]:
# Changing the input
a.set_voltage_all(1,1,1,1)
In [79]:
b.get_voltage_all()
Out[79]:
In [80]:
# Changing the attenuation level
buff1.set_attenuation(0)
In [81]:
b.get_voltage_all()
Out[81]:
In [82]:
# AM Signal generation using 2 intances of Signal Generator modules.
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
import math, time
# Message sine signal generator of frequency 10 Hz and 1 Vpp amplitude
m_t = SignalGenerator(typ = 0, freq = 10, ampl = 1)
m_t.set_offset(-0.5)
# Carrier sine signal generator of frequency 100 Hz and 10 Vpp amplitude
c_t = SignalGenerator(typ = 0, freq = 100, ampl = 10)
c_t.set_offset(-5) # To make the range as [-5, 5]
c_t.set_modulation_input(m_t.outputs)
c_t.set_modulation_type(1)
time.sleep(0.5) # To allow setup time
c_t.last_updated_time, (c_t.outputs[0].voltage - c_t.outputs[1].voltage)
# Populate the plot points to data array
data = np.zeros(shape = (2, math.ceil(m_t.time_period / c_t.sampling_time_interval)))
for i in range(data.shape[1]):
data[0][i] = m_t.last_updated_time + m_t.time_period * i
data[1][i] = c_t.outputs[0].voltage
time.sleep(c_t.sampling_time_interval)
# Plot the modulated signal for the given timeframe
fig, ax = plt.subplots()
ax.plot(data[0], data[1])
plt.show()
# Kill the signal generator threads after use
m_t.kill()
c_t.kill()