Repository: cocotb/cocotb

Issue:
Deprecate the ``<=`` syntax for setting values on handles
> I'm OK with this change. The `<=` notation was a neat idea, but it has three problems, IMO.
> 
> * It doesn't always work (and there's no way of fixing it). That's what triggered this PR, ultimately.
> * It's not obvious what it does for someone knowing Python. I know that I got the question multiple times what the strange syntax does, and every intro presentation of cocotb I've done has a paragraph on it.
> * It provides more than one way of doing things, which is bad for teaching cocotb.
> 
> With all that in mind, deprecating and ultimately removing the `<=` syntax makes sense to me.

Originally posted by @imphil in https://github.com/cocotb/cocotb/pull/2667#pullrequestreview-734467878

xref #2658.


Discussion:

Resolving patch:
diff --git a/cocotb/clock.py b/cocotb/clock.py
--- a/cocotb/clock.py
+++ b/cocotb/clock.py
@@ -82,9 +82,9 @@ async def custom_clock():
             low_time = Timer(low_delay, units="ns")
             await Timer(initial_delay, units="ns")
             while True:
-                dut.clk <= 1
+                dut.clk.value = 1
                 await high_time
-                dut.clk <= 0
+                dut.clk.value = 0
                 await low_time
 
     If you also want to change the timing during simulation,
@@ -96,9 +96,9 @@ async def custom_clock():
 
         async def custom_clock():
             while True:
-                dut.clk <= 1
+                dut.clk.value = 1
                 await Timer(high_delay, units="ns")
-                dut.clk <= 0
+                dut.clk.value = 0
                 await Timer(low_delay, units="ns")
 
         high_delay = low_delay = 100
@@ -152,15 +152,15 @@ async def start(self, cycles=None, start_high=True):
         # branch outside for loop for performance (decision has to be taken only once)
         if start_high:
             for _ in it:
-                self.signal <= 1
+                self.signal.value = 1
                 await t
-                self.signal <= 0
+                self.signal.value = 0
                 await t
         else:
             for _ in it:
-                self.signal <= 0
+                self.signal.value = 0
                 await t
-                self.signal <= 1
+                self.signal.value = 1
                 await t
 
     def __str__(self):
diff --git a/cocotb/handle.py b/cocotb/handle.py
--- a/cocotb/handle.py
+++ b/cocotb/handle.py
@@ -317,7 +317,7 @@ def __setattr__(self, name, value):
         if sub is not None:
             warnings.warn(
                 "Setting values on handles using the ``dut.handle = value`` syntax is deprecated. "
-                "Instead use the ``handle.value = value`` or ``handle <= value`` syntax",
+                "Instead use the ``handle.value = value`` syntax",
                 DeprecationWarning, stacklevel=2)
             sub.value = value
             return
@@ -479,6 +479,11 @@ def __le__(self, value):
         Example:
         >>> module.signal <= 2
         """
+        warnings.warn(
+            "Setting values on handles using the ``handle <= value`` syntax is deprecated. "
+            "Instead use the ``handle.value = value`` syntax",
+            DeprecationWarning,
+            stacklevel=2)
         self.value = value
         return _AssignmentResult(self, value)
 
@@ -587,7 +592,7 @@ def __setitem__(self, index, value):
         """Provide transparent assignment to indexed array handles."""
         warnings.warn(
             "Setting values on handles using the ``dut.handle[i] = value`` syntax is deprecated. "
-            "Instead use the ``handle[i].value = value`` or ``handle[i] <= value`` syntax",
+            "Instead use the ``handle[i].value = value`` syntax",
             DeprecationWarning, stacklevel=2)
         self[index].value = value
 


Test patch:
diff --git a/examples/adder/tests/test_adder.py b/examples/adder/tests/test_adder.py
--- a/examples/adder/tests/test_adder.py
+++ b/examples/adder/tests/test_adder.py
@@ -14,8 +14,8 @@ async def adder_basic_test(dut):
     A = 5
     B = 10
 
-    dut.A <= A
-    dut.B <= B
+    dut.A.value = A
+    dut.B.value = B
 
     await Timer(2, units='ns')
 
@@ -31,8 +31,8 @@ async def adder_randomised_test(dut):
         A = random.randint(0, 15)
         B = random.randint(0, 15)
 
-        dut.A <= A
-        dut.B <= B
+        dut.A.value = A
+        dut.B.value = B
 
         await Timer(2, units='ns')
 
diff --git a/examples/analog_model/test_analog_model.py b/examples/analog_model/test_analog_model.py
--- a/examples/analog_model/test_analog_model.py
+++ b/examples/analog_model/test_analog_model.py
@@ -57,8 +57,8 @@ async def test_analog_model(digital) -> None:
         # hand digital value over as "meas_val" to digital part (HDL)
         # "meas_val_valid" pulses for one clock cycle
         await RisingEdge(digital.clk)
-        digital.meas_val <= afe_out
-        digital.meas_val_valid <= 1
+        digital.meas_val.value = afe_out
+        digital.meas_val_valid.value = 1
         await RisingEdge(digital.clk)
-        digital.meas_val_valid <= 0
+        digital.meas_val_valid.value = 0
         await Timer(3.3, "us")
diff --git a/examples/matrix_multiplier/tests/test_matrix_multiplier.py b/examples/matrix_multiplier/tests/test_matrix_multiplier.py
--- a/examples/matrix_multiplier/tests/test_matrix_multiplier.py
+++ b/examples/matrix_multiplier/tests/test_matrix_multiplier.py
@@ -152,15 +152,15 @@ async def test_multiply(dut):
     dut._log.info("Initialize and reset model")
 
     # Initial values
-    dut.valid_i <= 0
-    dut.a_i <= create_a(lambda x: 0)
-    dut.b_i <= create_b(lambda x: 0)
+    dut.valid_i.value = 0
+    dut.a_i.value = create_a(lambda x: 0)
+    dut.b_i.value = create_b(lambda x: 0)
 
     # Reset DUT
-    dut.reset_i <= 1
+    dut.reset_i.value = 1
     for _ in range(3):
         await RisingEdge(dut.clk_i)
-    dut.reset_i <= 0
+    dut.reset_i.value = 0
 
     # start tester after reset so we know it's in a good state
     tester.start()
@@ -170,12 +170,12 @@ async def test_multiply(dut):
     # Do multiplication operations
     for i, (A, B) in enumerate(zip(gen_a(), gen_b())):
         await RisingEdge(dut.clk_i)
-        dut.a_i <= A
-        dut.b_i <= B
-        dut.valid_i <= 1
+        dut.a_i.value = A
+        dut.b_i.value = B
+        dut.valid_i.value = 1
 
         await RisingEdge(dut.clk_i)
-        dut.valid_i <= 0
+        dut.valid_i.value = 0
 
         if i % 100 == 0:
             dut._log.info(f"{i} / {NUM_SAMPLES}")
diff --git a/examples/mixed_language/tests/test_mixed_language.py b/examples/mixed_language/tests/test_mixed_language.py
--- a/examples/mixed_language/tests/test_mixed_language.py
+++ b/examples/mixed_language/tests/test_mixed_language.py
@@ -13,10 +13,10 @@ async def mixed_language_test(dut):
     vhdl = dut.i_swapper_vhdl
     dut._log.info("Got: %s" % repr(vhdl._name))
 
-    verilog.reset_n <= 1
+    verilog.reset_n.value = 1
     await Timer(100, units='ns')
 
-    vhdl.reset_n <= 1
+    vhdl.reset_n.value = 1
     await Timer(100, units='ns')
 
     assert int(verilog.reset_n) == int(vhdl.reset_n), "reset_n signals were different"
diff --git a/examples/mixed_signal/tests/test_regulator_plot.py b/examples/mixed_signal/tests/test_regulator_plot.py
--- a/examples/mixed_signal/tests/test_regulator_plot.py
+++ b/examples/mixed_signal/tests/test_regulator_plot.py
@@ -12,12 +12,12 @@ async def test_trim_vals(tb_hdl):
     """Set trim value of regulator and measure resulting voltage."""
 
     probed_node = "tb_regulator.i_regulator.vout"
-    tb_hdl.vdd_val <= 7.7
-    tb_hdl.vss_val <= 0.0
+    tb_hdl.vdd_val.value = 7.7
+    tb_hdl.vss_val.value = 0.0
 
     probedata = []
     for trim_val in [0, 3, -5]:
-        tb_hdl.trim_val <= trim_val
+        tb_hdl.trim_val.value = trim_val
         await Timer(1, units="ns")
         trimmed_volt = await get_voltage(tb_hdl, probed_node)
         tb_hdl._log.info(
@@ -35,8 +35,8 @@ async def test_trim_vals(tb_hdl):
 async def get_voltage(tb_hdl, node):
     """Measure voltage on *node*."""
     await Timer(1, units="ps")  # let trim_val take effect
-    tb_hdl.i_analog_probe.node_to_probe <= node.encode("ascii")
-    tb_hdl.i_analog_probe.probe_voltage_toggle <= ~int(tb_hdl.i_analog_probe.probe_voltage_toggle)
+    tb_hdl.i_analog_probe.node_to_probe.value = node.encode("ascii")
+    tb_hdl.i_analog_probe.probe_voltage_toggle.value = ~int(tb_hdl.i_analog_probe.probe_voltage_toggle)
     await Timer(1, units="ps")  # waiting time needed for the analog values to be updated
     tb_hdl._log.debug("Voltage on node {} is {:.4} V".format(
         node, tb_hdl.i_analog_probe.voltage.value))
diff --git a/examples/mixed_signal/tests/test_regulator_trim.py b/examples/mixed_signal/tests/test_regulator_trim.py
--- a/examples/mixed_signal/tests/test_regulator_trim.py
+++ b/examples/mixed_signal/tests/test_regulator_trim.py
@@ -29,8 +29,8 @@ def __init__(self, tb_hdl, settling_time_ns=1):
     async def get_voltage(self, node):
         """Measure voltage on *node*."""
         toggle = next(self._bit_toggle_stream)
-        self.tb_hdl.i_analog_probe.node_to_probe <= node.encode("ascii")
-        self.analog_probe.probe_voltage_toggle <= toggle
+        self.tb_hdl.i_analog_probe.node_to_probe.value = node.encode("ascii")
+        self.analog_probe.probe_voltage_toggle.value = toggle
         await Timer(1, units="ps")  # waiting time needed for the analog values to be updated
         self.tb_hdl._log.debug(
             "trim value={}: {}={:.4} V".format(
@@ -61,11 +61,11 @@ async def find_trim_val(self, probed_node, target_volt, trim_val_node):
         trim_val_max = 2 ** (trim_val_node.value.n_bits - 1) - 1
         # the actual trimming procedure:
         # minimum values
-        trim_val_node <= trim_val_min
+        trim_val_node.value = trim_val_min
         await Timer(self.settling_time_ns, units="ns")
         volt_min = await self.get_voltage(probed_node)
         # maximum values
-        trim_val_node <= trim_val_max
+        trim_val_node.value = trim_val_max
         await Timer(self.settling_time_ns, units="ns")
         volt_max = await self.get_voltage(probed_node)
         if target_volt > volt_max:
@@ -110,7 +110,7 @@ async def run_test(tb_hdl):
         probed_node=node, target_volt=target_volt, trim_val_node=tb_py.tb_hdl.trim_val
     )
     best_trim_rounded = round(best_trim_float)
-    tb_py.tb_hdl.trim_val <= best_trim_rounded
+    tb_py.tb_hdl.trim_val.value = best_trim_rounded
     await Timer(tb_py.settling_time_ns, units="ns")
     trimmed_volt = await tb_py.get_voltage(node)
     tb_py.tb_hdl._log.info(
diff --git a/examples/mixed_signal/tests/test_rescap.py b/examples/mixed_signal/tests/test_rescap.py
--- a/examples/mixed_signal/tests/test_rescap.py
+++ b/examples/mixed_signal/tests/test_rescap.py
@@ -25,9 +25,9 @@ def __init__(self, tb_hdl):
 
     async def _get_single_sample(self, node):
         toggle = next(self.togglestream)
-        self.tb_hdl.i_analog_probe.node_to_probe <= node.encode('ascii')
-        self.analog_probe.probe_voltage_toggle <= toggle
-        self.analog_probe.probe_current_toggle <= toggle
+        self.tb_hdl.i_analog_probe.node_to_probe.value = node.encode('ascii')
+        self.analog_probe.probe_voltage_toggle.value = toggle
+        self.analog_probe.probe_current_toggle.value = toggle
         await Timer(1, units="ps")  # waiting time needed for the analog values to be updated
         dataset = Dataset(
             time=get_sim_time(units="ns"),
@@ -110,15 +110,15 @@ async def run_test(tb_hdl):
     probedata = defaultdict(list)
 
     vdd = 0.0
-    tb_py.tb_hdl.vdd_val <= vdd
-    tb_py.tb_hdl.vss_val <= 0.0
+    tb_py.tb_hdl.vdd_val.value = vdd
+    tb_py.tb_hdl.vss_val.value = 0.0
     tb_py.tb_hdl._log.info(f"Setting vdd={vdd:.4} V")
     # dummy read appears to be necessary for the analog solver
     _ = await tb_py.get_sample_data(nodes=nodes_to_probe)
 
     for vdd in [5.55, -3.33]:
-        tb_py.tb_hdl.vdd_val <= vdd
-        tb_py.tb_hdl.vss_val <= 0.0
+        tb_py.tb_hdl.vdd_val.value = vdd
+        tb_py.tb_hdl.vss_val.value = 0.0
         tb_py.tb_hdl._log.info(f"Setting vdd={vdd:.4} V")
         data = await tb_py.get_sample_data(num=60, delay_ns=5, nodes=nodes_to_probe)
         for node in nodes_to_probe:
diff --git a/examples/mixed_signal/tests/test_rescap_minimalist.py b/examples/mixed_signal/tests/test_rescap_minimalist.py
--- a/examples/mixed_signal/tests/test_rescap_minimalist.py
+++ b/examples/mixed_signal/tests/test_rescap_minimalist.py
@@ -9,14 +9,14 @@
 async def rescap_minimalist_test(tb_hdl):
     """Mixed signal resistor/capacitor simulation, minimalistic."""
 
-    tb_hdl.vdd_val <= 7.7
-    tb_hdl.vss_val <= 0.0
-    tb_hdl.i_analog_probe.node_to_probe <= b"tb_rescap.i_rescap.vout"
+    tb_hdl.vdd_val.value = 7.7
+    tb_hdl.vss_val.value = 0.0
+    tb_hdl.i_analog_probe.node_to_probe.value = b"tb_rescap.i_rescap.vout"
 
     for toggle in [1, 0, 1, 0, 1, 0]:
         await Timer(50, units="ns")
-        tb_hdl.i_analog_probe.probe_voltage_toggle <= toggle
-        tb_hdl.i_analog_probe.probe_current_toggle <= toggle
+        tb_hdl.i_analog_probe.probe_voltage_toggle.value = toggle
+        tb_hdl.i_analog_probe.probe_current_toggle.value = toggle
         await Timer(1, units="ps")  # waiting time needed for the analog values to be updated
         tb_hdl._log.info(
             "tb_hdl.i_analog_probe@{}={:.4} V  {:.4} A".format(
diff --git a/examples/simple_dff/test_dff.py b/examples/simple_dff/test_dff.py
--- a/examples/simple_dff/test_dff.py
+++ b/examples/simple_dff/test_dff.py
@@ -17,6 +17,6 @@ async def test_dff_simple(dut):
     await FallingEdge(dut.clk)  # Synchronize with the clock
     for i in range(10):
         val = random.randint(0, 1)
-        dut.d <= val  # Assign the random value val to the input port d
+        dut.d.value = val  # Assign the random value val to the input port d
         await FallingEdge(dut.clk)
         assert dut.q.value == val, f"output q was incorrect on the {i}th cycle"
diff --git a/tests/test_cases/issue_120/issue_120.py b/tests/test_cases/issue_120/issue_120.py
--- a/tests/test_cases/issue_120/issue_120.py
+++ b/tests/test_cases/issue_120/issue_120.py
@@ -6,9 +6,9 @@
 
 
 async def send_data(dut):
-    dut.stream_in_valid <= 1
+    dut.stream_in_valid.value = 1
     await RisingEdge(dut.clk)
-    dut.stream_in_valid <= 0
+    dut.stream_in_valid.value = 0
 
 
 async def monitor(dut):
@@ -28,17 +28,17 @@ async def issue_120_scheduling(dut):
 
     # First attempt, not from coroutine - works as expected
     for i in range(2):
-        dut.stream_in_valid <= 1
+        dut.stream_in_valid.value = 1
         await RisingEdge(dut.clk)
-        dut.stream_in_valid <= 0
+        dut.stream_in_valid.value = 0
 
     await RisingEdge(dut.clk)
 
     # Failure - we don't drive valid on the rising edge even though
     # behaviour should be identical to the above
     await send_data(dut)
-    dut.stream_in_valid <= 1
+    dut.stream_in_valid.value = 1
     await RisingEdge(dut.clk)
-    dut.stream_in_valid <= 0
+    dut.stream_in_valid.value = 0
 
     await RisingEdge(dut.clk)
diff --git a/tests/test_cases/issue_142/issue_142.py b/tests/test_cases/issue_142/issue_142.py
--- a/tests/test_cases/issue_142/issue_142.py
+++ b/tests/test_cases/issue_142/issue_142.py
@@ -21,9 +21,9 @@ def _compare(value):
     # Wider values are transparently converted to BinaryValues
     for value in [0, 0x7FFFFFFF, 0x7FFFFFFFFFFF, BinaryValue(0x7FFFFFFFFFFFFF,len(dut.stream_in_data_wide),bigEndian=False)]:
 
-        dut.stream_in_data_wide <= value
+        dut.stream_in_data_wide.value = value
         await RisingEdge(dut.clk)
         _compare(value)
-        dut.stream_in_data_wide <= value
+        dut.stream_in_data_wide.value = value
         await RisingEdge(dut.clk)
         _compare(value)
diff --git a/tests/test_cases/issue_253/issue_253.py b/tests/test_cases/issue_253/issue_253.py
--- a/tests/test_cases/issue_253/issue_253.py
+++ b/tests/test_cases/issue_253/issue_253.py
@@ -5,10 +5,10 @@
 
 
 async def toggle_clock(dut):
-    dut.clk <= 0
+    dut.clk.value = 0
     await Timer(10, 'ns')
     assert dut.clk.value.integer == 0, "Clock not set to 0 as expected"
-    dut.clk <= 1
+    dut.clk.value = 1
     await Timer(10, 'ns')
     assert dut.clk.value.integer == 1, "Clock not set to 1 as expected"
 
diff --git a/tests/test_cases/issue_348/issue_348.py b/tests/test_cases/issue_348/issue_348.py
--- a/tests/test_cases/issue_348/issue_348.py
+++ b/tests/test_cases/issue_348/issue_348.py
@@ -5,9 +5,9 @@
 
 async def clock_gen(signal, num):
     for x in range(num):
-        signal <= 0
+        signal.value = 0
         await Timer(5, 'ns')
-        signal <= 1
+        signal.value = 1
         await Timer(5, 'ns')
 
 
diff --git a/tests/test_cases/test_array/test_array.py b/tests/test_cases/test_array/test_array.py
--- a/tests/test_cases/test_array/test_array.py
+++ b/tests/test_cases/test_array/test_array.py
@@ -104,15 +104,15 @@ async def test_read_write(dut):
             _check_logic(tlog, dut.const_cmplx[2].b[1], 0xFF)
             _check_logic(tlog, dut.const_cmplx[2].b[2], 0xFF)
 
-    dut.select_in         <= 2
+    dut.select_in        .value = 2
 
     await Timer(10, "ns")
 
     tlog.info("Writing the signals!!!")
-    dut.sig_logic         <= 1
-    dut.sig_logic_vec     <= 0xCC
-    dut.sig_t2 <= [0xCC, 0xDD, 0xEE, 0xFF]
-    dut.sig_t4 <= [
+    dut.sig_logic        .value = 1
+    dut.sig_logic_vec    .value = 0xCC
+    dut.sig_t2.value = [0xCC, 0xDD, 0xEE, 0xFF]
+    dut.sig_t4.value = [
         [0x00, 0x11, 0x22, 0x33],
         [0x44, 0x55, 0x66, 0x77],
         [0x88, 0x99, 0xAA, 0xBB],
@@ -120,23 +120,23 @@ async def test_read_write(dut):
     ]
 
     if cocotb.LANGUAGE in ["vhdl"]:
-        dut.sig_bool          <= 1
-        dut.sig_int           <= 5000
-        dut.sig_real          <= 22.54
-        dut.sig_char          <= ord('Z')
-        dut.sig_str           <= "Testing"
-        dut.sig_rec.a         <= 1
-        dut.sig_rec.b[0]      <= 0x01
-        dut.sig_rec.b[1]      <= 0x23
-        dut.sig_rec.b[2]      <= 0x45
-        dut.sig_cmplx[0].a    <= 0
-        dut.sig_cmplx[0].b[0] <= 0x67
-        dut.sig_cmplx[0].b[1] <= 0x89
-        dut.sig_cmplx[0].b[2] <= 0xAB
-        dut.sig_cmplx[1].a    <= 1
-        dut.sig_cmplx[1].b[0] <= 0xCD
-        dut.sig_cmplx[1].b[1] <= 0xEF
-        dut.sig_cmplx[1].b[2] <= 0x55
+        dut.sig_bool         .value = 1
+        dut.sig_int          .value = 5000
+        dut.sig_real         .value = 22.54
+        dut.sig_char         .value = ord('Z')
+        dut.sig_str          .value = "Testing"
+        dut.sig_rec.a        .value = 1
+        dut.sig_rec.b[0]     .value = 0x01
+        dut.sig_rec.b[1]     .value = 0x23
+        dut.sig_rec.b[2]     .value = 0x45
+        dut.sig_cmplx[0].a   .value = 0
+        dut.sig_cmplx[0].b[0].value = 0x67
+        dut.sig_cmplx[0].b[1].value = 0x89
+        dut.sig_cmplx[0].b[2].value = 0xAB
+        dut.sig_cmplx[1].a   .value = 1
+        dut.sig_cmplx[1].b[0].value = 0xCD
+        dut.sig_cmplx[1].b[1].value = 0xEF
+        dut.sig_cmplx[1].b[2].value = 0x55
 
     await Timer(10, "ns")
 
@@ -170,17 +170,17 @@ async def test_read_write(dut):
         _check_logic(tlog, dut.port_cmplx_out[1].b[2], 0x55)
 
     tlog.info("Writing a few signal sub-indices!!!")
-    dut.sig_logic_vec[2]     <= 0
+    dut.sig_logic_vec[2]    .value = 0
     if cocotb.LANGUAGE in ["vhdl"] or not (cocotb.SIM_NAME.lower().startswith(("ncsim", "xmsim")) or
                                            (cocotb.SIM_NAME.lower().startswith("riviera") and
                                             cocotb.SIM_VERSION.startswith(("2016.06", "2016.10", "2017.02")))):
-        dut.sig_t6[1][3][2]      <= 1
-        dut.sig_t6[0][2][7]      <= 0
+        dut.sig_t6[1][3][2]     .value = 1
+        dut.sig_t6[0][2][7]     .value = 0
 
     if cocotb.LANGUAGE in ["vhdl"]:
-        dut.sig_str[2]           <= ord('E')
-        dut.sig_rec.b[1][7]      <= 1
-        dut.sig_cmplx[1].b[1][0] <= 0
+        dut.sig_str[2]          .value = ord('E')
+        dut.sig_rec.b[1][7]     .value = 1
+        dut.sig_cmplx[1].b[1][0].value = 0
 
     await Timer(10, "ns")
 
@@ -420,15 +420,15 @@ async def test_direct_signal_indexing(dut):
 
     cocotb.fork(Clock(dut.clk, 10, "ns").start())
 
-    dut.port_desc_in <= 0
-    dut.port_asc_in  <= 0
-    dut.port_ofst_in <= 0
+    dut.port_desc_in.value = 0
+    dut.port_asc_in .value = 0
+    dut.port_ofst_in.value = 0
 
     await Timer(20, "ns")
 
-    dut.port_desc_in[2] <= 1
-    dut.port_asc_in[2]  <= 1
-    dut.port_ofst_in[2] <= 1
+    dut.port_desc_in[2].value = 1
+    dut.port_asc_in[2] .value = 1
+    dut.port_ofst_in[2].value = 1
 
     await Timer(20, "ns")
 
diff --git a/tests/test_cases/test_array_simple/test_array_simple.py b/tests/test_cases/test_array_simple/test_array_simple.py
--- a/tests/test_cases/test_array_simple/test_array_simple.py
+++ b/tests/test_cases/test_array_simple/test_array_simple.py
@@ -28,10 +28,10 @@ async def test_1dim_array_handles(dut):
     cocotb.fork(Clock(dut.clk, 1000, 'ns').start())
 
     # Set values with '<=' operator
-    dut.array_7_downto_4 <= [0xF0, 0xE0, 0xD0, 0xC0]
-    dut.array_4_to_7     <= [0xB0, 0xA0, 0x90, 0x80]
-    dut.array_3_downto_0 <= [0x70, 0x60, 0x50, 0x40]
-    dut.array_0_to_3     <= [0x30, 0x20, 0x10, 0x00]
+    dut.array_7_downto_4.value = [0xF0, 0xE0, 0xD0, 0xC0]
+    dut.array_4_to_7.value = [0xB0, 0xA0, 0x90, 0x80]
+    dut.array_3_downto_0.value = [0x70, 0x60, 0x50, 0x40]
+    dut.array_0_to_3.value = [0x30, 0x20, 0x10, 0x00]
 
     await Timer(1000, 'ns')
 
@@ -54,7 +54,7 @@ async def test_ndim_array_handles(dut):
     cocotb.fork(Clock(dut.clk, 1000, 'ns').start())
 
     # Set values with '<=' operator
-    dut.array_2d <= [
+    dut.array_2d.value = [
         [0xF0, 0xE0, 0xD0, 0xC0],
         [0xB0, 0xA0, 0x90, 0x80]
     ]
@@ -71,10 +71,10 @@ async def test_1dim_array_indexes(dut):
 
     cocotb.fork(Clock(dut.clk, 1000, 'ns').start())
 
-    dut.array_7_downto_4 <= [0xF0, 0xE0, 0xD0, 0xC0]
-    dut.array_4_to_7     <= [0xB0, 0xA0, 0x90, 0x80]
-    dut.array_3_downto_0 <= [0x70, 0x60, 0x50, 0x40]
-    dut.array_0_to_3     <= [0x30, 0x20, 0x10, 0x00]
+    dut.array_7_downto_4.value = [0xF0, 0xE0, 0xD0, 0xC0]
+    dut.array_4_to_7.value = [0xB0, 0xA0, 0x90, 0x80]
+    dut.array_3_downto_0.value = [0x70, 0x60, 0x50, 0x40]
+    dut.array_0_to_3.value = [0x30, 0x20, 0x10, 0x00]
 
     await Timer(1000, 'ns')
 
@@ -90,11 +90,11 @@ async def test_1dim_array_indexes(dut):
     _check_value(tlog, dut.array_0_to_3[1]    , 0x20)
 
     # Get sub-handles through NonHierarchyIndexableObject.__getitem__
-    dut.array_7_downto_4[7] <= 0xDE
-    dut.array_4_to_7[4]     <= 0xFC
-    dut.array_3_downto_0[0] <= 0xAB
-    dut.array_0_to_3[1]     <= 0x7A
-    dut.array_0_to_3[3]     <= 0x42
+    dut.array_7_downto_4[7].value = 0xDE
+    dut.array_4_to_7[4].value = 0xFC
+    dut.array_3_downto_0[0].value = 0xAB
+    dut.array_0_to_3[1].value = 0x7A
+    dut.array_0_to_3[3].value = 0x42
 
     await Timer(1000, 'ns')
 
@@ -117,7 +117,7 @@ async def test_ndim_array_indexes(dut):
 
     cocotb.fork(Clock(dut.clk, 1000, 'ns').start())
 
-    dut.array_2d <= [
+    dut.array_2d.value = [
         [0xF0, 0xE0, 0xD0, 0xC0],
         [0xB0, 0xA0, 0x90, 0x80]
     ]
@@ -131,8 +131,8 @@ async def test_ndim_array_indexes(dut):
     _check_value(tlog, dut.array_2d[1][28], 0x80)
 
     # Get sub-handles through NonHierarchyIndexableObject.__getitem__
-    dut.array_2d[1]     <= [0xDE, 0xAD, 0xBE, 0xEF]
-    dut.array_2d[0][31] <= 0x0F
+    dut.array_2d[1].value = [0xDE, 0xAD, 0xBE, 0xEF]
+    dut.array_2d[0][31].value = 0x0F
 
     await Timer(1000, 'ns')
 
@@ -148,10 +148,10 @@ async def test_ndim_array_indexes(dut):
 async def test_struct(dut):
     """Test setting and getting values of structs."""
     cocotb.fork(Clock(dut.clk, 1000, 'ns').start())
-    dut.inout_if.a_in <= 1
+    dut.inout_if.a_in.value = 1
     await Timer(1000, 'ns')
     _check_value(tlog, dut.inout_if.a_in, 1)
-    dut.inout_if.a_in <= 0
+    dut.inout_if.a_in.value = 0
     await Timer(1000, 'ns')
     _check_value(tlog, dut.inout_if.a_in, 0)
 
@@ -170,10 +170,10 @@ def assert_raises(exc_type):
 async def test_exceptions(dut):
     """Test that correct Exceptions are raised."""
     with assert_raises(TypeError):
-        dut.array_7_downto_4 <= (0xF0, 0xE0, 0xD0, 0xC0)
+        dut.array_7_downto_4.value = (0xF0, 0xE0, 0xD0, 0xC0)
     with assert_raises(TypeError):
-        dut.array_4_to_7     <= Exception("Exception Object")
+        dut.array_4_to_7.value = Exception("Exception Object")
     with assert_raises(ValueError):
-        dut.array_3_downto_0 <= [0x70, 0x60, 0x50]
+        dut.array_3_downto_0.value = [0x70, 0x60, 0x50]
     with assert_raises(ValueError):
-        dut.array_0_to_3     <= [0x40, 0x30, 0x20, 0x10, 0x00]
+        dut.array_0_to_3.value = [0x40, 0x30, 0x20, 0x10, 0x00]
diff --git a/tests/test_cases/test_cocotb/common.py b/tests/test_cases/test_cocotb/common.py
--- a/tests/test_cases/test_cocotb/common.py
+++ b/tests/test_cases/test_cocotb/common.py
@@ -14,9 +14,9 @@
 async def clock_gen(clock):
     """Example clock gen for test use"""
     for i in range(5):
-        clock <= 0
+        clock.value = 0
         await Timer(100, "ns")
-        clock <= 1
+        clock.value = 1
         await Timer(100, "ns")
     clock._log.warning("Clock generator finished!")
 
diff --git a/tests/test_cases/test_cocotb/test_deprecated.py b/tests/test_cases/test_cocotb/test_deprecated.py
--- a/tests/test_cases/test_cocotb/test_deprecated.py
+++ b/tests/test_cases/test_cocotb/test_deprecated.py
@@ -10,6 +10,7 @@
 from common import assert_raises
 from typing import List
 from cocotb._sim_versions import IcarusVersion
+import pytest
 
 
 @contextmanager
@@ -44,14 +45,14 @@ def get_value():
 @cocotb.test(expect_error=AssertionError if cocotb.SIM_NAME.lower().startswith(("icarus", "ghdl")) else ())
 async def test_unicode_handle_assignment_deprecated(dut):
     with assert_deprecated() as warns:
-        dut.stream_in_string <= "Bad idea"
+        dut.stream_in_string.value = "Bad idea"
         await cocotb.triggers.ReadWrite()
     assert "bytes" in str(warns[0].message)
 
 
 @cocotb.test()
 async def test_convert_handle_to_string_deprecated(dut):
-    dut.stream_in_data <= 0
+    dut.stream_in_data.value = 0
     await cocotb.triggers.Timer(1, units='ns')
 
     with assert_deprecated(FutureWarning) as warns:
@@ -107,7 +108,7 @@ async def test_handle_compat_mapping(dut):
 
 @cocotb.test()
 async def test_assigning_structure_deprecated(dut):
-    """signal <= ctypes.Structure assignment is deprecated"""
+    """signal.value = ctypes.Structure assignment is deprecated"""
 
     class Example(ctypes.Structure):
         _fields_ = [
@@ -117,7 +118,7 @@ class Example(ctypes.Structure):
     e = Example(a=0xCC, b=0x12345678)
 
     with assert_deprecated():
-        dut.stream_in_data_wide <= e
+        dut.stream_in_data_wide.value = e
 
     await Timer(1, 'step')
 
@@ -160,7 +161,7 @@ async def test_dict_signal_assignment_deprecated(dut):
     d = dict(values=[0xC, 0x5], bits=4)
 
     with assert_deprecated():
-        dut.stream_in_data <= d
+        dut.stream_in_data.value = d
 
     await Timer(1, 'step')
 
@@ -188,3 +189,18 @@ async def test_assigning_setitem_syntax_deprecated(dut):
         with assert_raises(IndexError):
             # attempt to use __setitem__ syntax on signal that doesn't exist
             dut.stream_in_data[800000] = 1
+
+
+@cocotb.test()
+async def test_assigning_less_than_syntax_deprecated(dut):
+    with assert_deprecated(DeprecationWarning):
+        dut.stream_in_data <= 1
+
+
+@cocotb.test()
+async def test_lessthan_raises_error(dut):
+    with warnings.catch_warnings():
+        warnings.simplefilter("ignore")
+        ret = dut.stream_in_data <= 0x12
+    with pytest.raises(TypeError):
+        bool(ret)
diff --git a/tests/test_cases/test_cocotb/test_edge_triggers.py b/tests/test_cases/test_cocotb/test_edge_triggers.py
--- a/tests/test_cases/test_cocotb/test_edge_triggers.py
+++ b/tests/test_cases/test_cocotb/test_edge_triggers.py
@@ -41,11 +41,11 @@ async def do_single_edge_check(dut, level):
 @cocotb.test()
 async def test_rising_edge(dut):
     """Test that a rising edge can be awaited on"""
-    dut.clk <= 0
+    dut.clk.value = 0
     await Timer(1, "ns")
     test = cocotb.fork(do_single_edge_check(dut, 1))
     await Timer(10, "ns")
-    dut.clk <= 1
+    dut.clk.value = 1
     fail_timer = Timer(1000, "ns")
     result = await First(fail_timer, test.join())
     assert result is not fail_timer, "Test timed out"
@@ -54,11 +54,11 @@ async def test_rising_edge(dut):
 @cocotb.test()
 async def test_falling_edge(dut):
     """Test that a falling edge can be awaited on"""
-    dut.clk <= 1
+    dut.clk.value = 1
     await Timer(1, "ns")
     test = cocotb.fork(do_single_edge_check(dut, 0))
     await Timer(10, "ns")
-    dut.clk <= 0
+    dut.clk.value = 0
     fail_timer = Timer(1000, "ns")
     result = await First(fail_timer, test.join())
     assert result is not fail_timer, "Test timed out"
@@ -67,29 +67,29 @@ async def test_falling_edge(dut):
 @cocotb.test()
 async def test_either_edge(dut):
     """Test that either edge can be triggered on"""
-    dut.clk <= 0
+    dut.clk.value = 0
     await Timer(1, "ns")
-    dut.clk <= 1
+    dut.clk.value = 1
     await Edge(dut.clk)
     assert dut.clk.value.integer == 1
     await Timer(10, "ns")
-    dut.clk <= 0
+    dut.clk.value = 0
     await Edge(dut.clk)
     assert dut.clk.value.integer == 0
     await Timer(10, "ns")
-    dut.clk <= 1
+    dut.clk.value = 1
     await Edge(dut.clk)
     assert dut.clk.value.integer == 1
     await Timer(10, "ns")
-    dut.clk <= 0
+    dut.clk.value = 0
     await Edge(dut.clk)
     assert dut.clk.value.integer == 0
     await Timer(10, "ns")
-    dut.clk <= 1
+    dut.clk.value = 1
     await Edge(dut.clk)
     assert dut.clk.value.integer == 1
     await Timer(10, "ns")
-    dut.clk <= 0
+    dut.clk.value = 0
     await Edge(dut.clk)
     assert dut.clk.value.integer == 0
 
@@ -123,9 +123,9 @@ async def do_clock(dut, limit, period):
     wait_period = period / 2
     while limit:
         await Timer(wait_period, "ns")
-        dut.clk <= 0
+        dut.clk.value = 0
         await Timer(wait_period, "ns")
-        dut.clk <= 1
+        dut.clk.value = 1
         limit -= 1
 
 
@@ -253,15 +253,15 @@ async def wait_edge():
 
     cocotb.fork(wait_edge())
 
-    dut.stream_in_data <= 0
+    dut.stream_in_data.value = 0
     await RisingEdge(dut.clk)
 
     for val in range(1, 2**len(dut.stream_in_data)-1):
         # produce an edge by setting a value != 0:
-        dut.stream_in_data <= val
+        dut.stream_in_data.value = val
         await RisingEdge(dut.clk)
         # set back to all-0:
-        dut.stream_in_data <= 0
+        dut.stream_in_data.value = 0
         await RisingEdge(dut.clk)
 
     assert edge_cnt == 2 * ((2**len(dut.stream_in_data)-1)-1)
diff --git a/tests/test_cases/test_cocotb/test_handle.py b/tests/test_cases/test_cocotb/test_handle.py
--- a/tests/test_cases/test_cocotb/test_handle.py
+++ b/tests/test_cases/test_cocotb/test_handle.py
@@ -15,20 +15,6 @@
 SIM_NAME = cocotb.SIM_NAME.lower()
 
 
-@cocotb.test()
-async def test_lessthan_raises_error(dut):
-    """
-    Test that trying to use <= as if it were a comparison produces an error
-    """
-    ret = dut.stream_in_data <= 0x12
-    try:
-        bool(ret)
-    except TypeError:
-        pass
-    else:
-        assert False, "No exception was raised when confusing comparison with assignment"
-
-
 @cocotb.test()
 async def test_bad_attr(dut):
 
@@ -105,9 +91,9 @@ async def test_delayed_assignment_still_errors(dut):
         dut.stream_in_int.setimmediatevalue([])
 
     with assert_raises(ValueError):
-        dut.stream_in_int <= "1010 not a real binary string"
+        dut.stream_in_int.value = "1010 not a real binary string"
     with assert_raises(TypeError):
-        dut.stream_in_int <= []
+        dut.stream_in_int.value = []
 
 
 async def int_values_test(signal, n_bits, limits=_Limits.VECTOR_NBIT):
@@ -115,7 +101,7 @@ async def int_values_test(signal, n_bits, limits=_Limits.VECTOR_NBIT):
     log = logging.getLogger("cocotb.test")
     values = gen_int_test_values(n_bits, limits)
     for val in values:
-        signal <= val
+        signal.value = val
         await Timer(1, 'ns')
 
         if limits == _Limits.VECTOR_NBIT:
@@ -154,7 +140,7 @@ async def int_overflow_test(signal, n_bits, test_mode, limits=_Limits.VECTOR_NBI
         value = None
 
     with assert_raises(OverflowError):
-        signal <= value
+        signal.value = value
 
 
 def gen_int_ovfl_value(n_bits, limits=_Limits.VECTOR_NBIT):
@@ -323,7 +309,7 @@ async def test_real_assign_double(dut):
     timer_shortest = Timer(1, "step")
     await timer_shortest
     log.info("Setting the value %g" % val)
-    dut.stream_in_real <= val
+    dut.stream_in_real.value = val
     await timer_shortest
     await timer_shortest  # FIXME: Workaround for VHPI scheduling - needs investigation
     got = float(dut.stream_out_real)
@@ -349,7 +335,7 @@ async def test_real_assign_int(dut):
     timer_shortest = Timer(1, "step")
     await timer_shortest
     log.info("Setting the value %i" % val)
-    dut.stream_in_real <= val
+    dut.stream_in_real.value = val
     await timer_shortest
     await timer_shortest  # FIXME: Workaround for VHPI scheduling - needs investigation
     got = dut.stream_out_real
@@ -366,12 +352,12 @@ async def test_access_underscore_name(dut):
         dut._underscore_name
 
     # indirect access works
-    dut._id("_underscore_name", extended=False) <= 0
+    dut._id("_underscore_name", extended=False).value = 0
     await Timer(1, 'ns')
     assert dut._id("_underscore_name", extended=False).value == 0
-    dut._id("_underscore_name", extended=False) <= 1
+    dut._id("_underscore_name", extended=False).value = 1
     await Timer(1, 'ns')
     assert dut._id("_underscore_name", extended=False).value == 1
-    dut._id("_underscore_name", extended=False) <= 0
+    dut._id("_underscore_name", extended=False).value = 0
     await Timer(1, 'ns')
     assert dut._id("_underscore_name", extended=False).value == 0
diff --git a/tests/test_cases/test_cocotb/test_scheduler.py b/tests/test_cases/test_cocotb/test_scheduler.py
--- a/tests/test_cases/test_cocotb/test_scheduler.py
+++ b/tests/test_cases/test_cocotb/test_scheduler.py
@@ -212,7 +212,7 @@ async def killer():
     cocotb.fork(killer())
 
     await Timer(2, "step")  # allow Timer in victim to pass making it schedule RisingEdge after the killer
-    dut.clk <= 1
+    dut.clk.value = 1
     await Timer(1, "step")
     assert not victim_resumed
 
@@ -286,16 +286,16 @@ async def test_last_scheduled_write_wins(dut):
     @cocotb.coroutine   # TODO: Remove once Combine accepts bare coroutines
     async def first():
         await Timer(1, "ns")
-        log.info("scheduling stream_in_data <= 1")
-        dut.stream_in_data <= 1
+        log.info("scheduling stream_in_data.value = 1")
+        dut.stream_in_data.value = 1
         e.set()
 
     @cocotb.coroutine   # TODO: Remove once Combine accepts bare coroutines
     async def second():
         await Timer(1, "ns")
         await e.wait()
-        log.info("scheduling stream_in_data <= 2")
-        dut.stream_in_data <= 2
+        log.info("scheduling stream_in_data.value = 2")
+        dut.stream_in_data.value = 2
 
     await Combine(first(), second())
 
@@ -310,8 +310,8 @@ async def test_last_scheduled_write_wins_array(dut):
     """
     Test that the last scheduled write for an *arrayed* signal handle is the value that is written.
     """
-    dut.array_7_downto_4 <= [1, 2, 3, 4]
-    dut.array_7_downto_4[7] <= 10
+    dut.array_7_downto_4.value = [1, 2, 3, 4]
+    dut.array_7_downto_4[7].value = 10
 
     await ReadOnly()
 
diff --git a/tests/test_cases/test_cocotb/test_timing_triggers.py b/tests/test_cases/test_cocotb/test_timing_triggers.py
--- a/tests/test_cases/test_cocotb/test_timing_triggers.py
+++ b/tests/test_cases/test_cocotb/test_timing_triggers.py
@@ -28,9 +28,9 @@ async def test_function_reentrant_clock(dut):
     clock = dut.clk
     timer = Timer(100, "ns")
     for i in range(10):
-        clock <= 0
+        clock.value = 0
         await timer
-        clock <= 1
+        clock.value = 1
         await timer
 
 
@@ -98,7 +98,7 @@ async def do_test_cached_write_in_readonly(dut):
     global exited
     await RisingEdge(dut.clk)
     await ReadOnly()
-    dut.clk <= 0
+    dut.clk.value = 0
     exited = True
 
 
@@ -170,7 +170,7 @@ async def write_manually():
     waiter = cocotb.fork(write_manually())
 
     # do a delayed write. This will be overwritten
-    dut.stream_in_data <= 3
+    dut.stream_in_data.value = 3
     await waiter
 
     # check that the write we expected took precedence
@@ -205,7 +205,7 @@ async def test_readwrite(dut):
     """ Test that ReadWrite can be waited on """
     # gh-759
     await Timer(1, "ns")
-    dut.clk <= 1
+    dut.clk.value = 1
     await ReadWrite()
 
 
diff --git a/tests/test_cases/test_compare/test_compare.py b/tests/test_cases/test_compare/test_compare.py
--- a/tests/test_cases/test_compare/test_compare.py
+++ b/tests/test_cases/test_compare/test_compare.py
@@ -20,10 +20,10 @@ def __init__(self, dut):
     async def initialise(self):
         """Initalise the testbench"""
         cocotb.fork(Clock(self.dut.clk, 10).start())
-        self.dut.reset <= 0
+        self.dut.reset.value = 0
         for _ in range(2):
             await self.clkedge
-        self.dut.reset <= 1
+        self.dut.reset.value = 1
         for _ in range(3):
             await self.clkedge
 
diff --git a/tests/test_cases/test_discovery/test_discovery.py b/tests/test_cases/test_discovery/test_discovery.py
--- a/tests/test_cases/test_discovery/test_discovery.py
+++ b/tests/test_cases/test_discovery/test_discovery.py
@@ -99,17 +99,17 @@ async def access_type_bit_verilog(dut):
     """Access type bit in SystemVerilog"""
     await Timer(1, "step")
     assert dut.mybit.value == 1, "The default value was incorrect"
-    dut.mybit <= 0
+    dut.mybit.value = 0
     await Timer(1, "ns")
     assert dut.mybit.value == 0, "The assigned value was incorrect"
 
     assert dut.mybits.value == 0b11, "The default value was incorrect"
-    dut.mybits <= 0b00
+    dut.mybits.value = 0b00
     await Timer(1, "ns")
     assert dut.mybits.value == 0b00, "The assigned value was incorrect"
 
     assert dut.mybits_uninitialized.value == 0b00, "The default value was incorrect"
-    dut.mybits_uninitialized <= 0b11
+    dut.mybits_uninitialized.value = 0b11
     await Timer(1, "ns")
     assert dut.mybits_uninitialized.value == 0b11, "The assigned value was incorrect"
 
@@ -122,7 +122,7 @@ async def access_type_bit_verilog_metavalues(dut):
     The metavalues still may show up as `0` and `1` in HDL (Xcelium and Riviera).
     """
     await Timer(1, "ns")
-    dut.mybits <= BinaryValue("XZ")
+    dut.mybits.value = BinaryValue("XZ")
     await Timer(1, "ns")
     print(dut.mybits.value.binstr)
     if cocotb.SIM_NAME.lower().startswith(("icarus", "ncsim", "xmsim")):
@@ -132,7 +132,7 @@ async def access_type_bit_verilog_metavalues(dut):
     else:
         assert dut.mybits.value.binstr.lower() == "00", "The assigned value was incorrect"
 
-    dut.mybits <= BinaryValue("ZX")
+    dut.mybits.value = BinaryValue("ZX")
     await Timer(1, "ns")
     print(dut.mybits.value.binstr)
     if cocotb.SIM_NAME.lower().startswith(("icarus", "ncsim", "xmsim")):
@@ -149,11 +149,11 @@ async def access_type_bit_verilog_metavalues(dut):
     skip=cocotb.LANGUAGE in ["vhdl"])
 async def access_single_bit(dut):
     """Access a single bit in a vector of the DUT"""
-    dut.stream_in_data <= 0
+    dut.stream_in_data.value = 0
     await Timer(1, "ns")
     dut._log.info("%s = %d bits" %
                   (dut.stream_in_data._path, len(dut.stream_in_data)))
-    dut.stream_in_data[2] <= 1
+    dut.stream_in_data[2].value = 1
     await Timer(1, "ns")
     if dut.stream_out_data_comb.value.integer != (1 << 2):
         raise TestError("%s.%s != %d" %
@@ -167,7 +167,7 @@ async def access_single_bit_erroneous(dut):
     dut._log.info("%s = %d bits" %
                   (dut.stream_in_data._path, len(dut.stream_in_data)))
     bit = len(dut.stream_in_data) + 4
-    dut.stream_in_data[bit] <= 1
+    dut.stream_in_data[bit].value = 1
 
 
 # Riviera discovers integers as nets (gh-2597)
@@ -314,7 +314,7 @@ async def access_const_string_verilog(dut):
         raise TestFailure(f"Initial value of STRING_CONST was not == b\'TESTING_CONST\' but {string_const.value} instead")
 
     tlog.info("Modifying const string")
-    string_const <= b"MODIFIED"
+    string_const.value = b"MODIFIED"
     await Timer(10, "ns")
     if string_const != b"TESTING_CONST":
         raise TestFailure(f"STRING_CONST was not still b\'TESTING_CONST\' after modification but {string_const.value} instead")
@@ -335,7 +335,7 @@ async def access_var_string_verilog(dut):
         raise TestFailure(f"Initial value of STRING_VAR was not == b\'TESTING_VAR\' but {string_var.value} instead")
 
     tlog.info("Modifying var string")
-    string_var <= b"MODIFIED"
+    string_var.value = b"MODIFIED"
     await Timer(10, "ns")
     if string_var != b"MODIFIED":
         raise TestFailure(f"STRING_VAR was not == b\'MODIFIED\' after modification but {string_var.value} instead")
@@ -415,7 +415,7 @@ async def skip_a_test(dut):
     dut._log.info("%s = %d bits" %
                   (dut.stream_in_data._path, len(dut.stream_in_data)))
     bit = len(dut.stream_in_data) + 4
-    dut.stream_in_data[bit] <= 1
+    dut.stream_in_data[bit].value = 1
 
 
 @cocotb.test(skip=cocotb.LANGUAGE in ["vhdl"],
diff --git a/tests/test_cases/test_force_release/test_force_release.py b/tests/test_cases/test_force_release/test_force_release.py
--- a/tests/test_cases/test_force_release/test_force_release.py
+++ b/tests/test_cases/test_force_release/test_force_release.py
@@ -17,8 +17,8 @@ async def test_force_release(dut):
     """
     log = logging.getLogger("cocotb.test")
     await Timer(10, "ns")
-    dut.stream_in_data <= 4
-    dut.stream_out_data_comb <= Force(5)
+    dut.stream_in_data.value = 4
+    dut.stream_out_data_comb.value = Force(5)
     await Timer(10, "ns")
     got_in = int(dut.stream_in_data)
     got_out = int(dut.stream_out_data_comb)
@@ -26,8 +26,8 @@ async def test_force_release(dut):
     log.info("dut.stream_out_data_comb = %d" % got_out)
     assert got_in != got_out
 
-    dut.stream_out_data_comb <= Release()
-    dut.stream_in_data <= 3
+    dut.stream_out_data_comb.value = Release()
+    dut.stream_in_data.value = 3
     await Timer(10, "ns")
     got_in = int(dut.stream_in_data)
     got_out = int(dut.stream_out_data_comb)
diff --git a/tests/test_cases/test_vhdl_libraries/test_ab.py b/tests/test_cases/test_vhdl_libraries/test_ab.py
--- a/tests/test_cases/test_vhdl_libraries/test_ab.py
+++ b/tests/test_cases/test_vhdl_libraries/test_ab.py
@@ -8,4 +8,4 @@ async def test(dut):
     #
     #   b.vhdl:9:5:@0ms:(report note): :a(structural):b@b(structural):
     #
-    dut.x <= False
+    dut.x.value = False
diff --git a/tests/test_cases/test_vhdl_zerovector/test_vhdl_zerovector.py b/tests/test_cases/test_vhdl_zerovector/test_vhdl_zerovector.py
--- a/tests/test_cases/test_vhdl_zerovector/test_vhdl_zerovector.py
+++ b/tests/test_cases/test_vhdl_zerovector/test_vhdl_zerovector.py
@@ -10,7 +10,7 @@
 @cocotb.test()
 async def test_long_signal(dut):
     """ Write and read a normal signal (longer than 0)."""
-    dut.data_in <= 0x5
+    dut.data_in.value = 0x5
     await Timer(1, "ns")
     assert dut.data_out == 0x5, "Failed to readback dut.data_out"
 
@@ -26,7 +26,7 @@ async def test_read_zero_signal(dut):
     ("ghdl", "xmsim", "ncsim", "riviera", "aldec")) else ())
 async def test_write_zero_signal_with_0(dut):
     """ Write a zero vector with 0."""
-    dut.Cntrl_out <= 0x0
+    dut.Cntrl_out.value = 0x0
     await Timer(1, "ns")
     assert dut.Cntrl_out == 0, "Failed to readback dut.Cntrl_out"
 
@@ -36,4 +36,4 @@ async def test_write_zero_signal_with_0(dut):
 async def test_write_zero_signal_with_1(dut):
     """ Write a zero vector with 1. Should catch a "out of range" exception."""
     with pytest.raises(OverflowError):
-        dut.Cntrl_out <= 0x1
+        dut.Cntrl_out.value = 0x1