Use of Fork-Join in Verilog - task

I would like to do a task that checks in parallel one of the two statements commented below and that doesn't break the execution of the program that follows it:
The Task checks if startTx has been generated. It must wait for startTx signal 5 clock cycles. If the startTx is asserted, it prints a successful message. If not (after the timeout), it prints an error message and increases the error counter.
What I've done so far is:
task checkStart;
begin
fork
// evento 1
begin
waitCycles(5); // timeOut
$display("[Error! %t] Time Out has been reached", $time);
errors = errors + 1;
end
// evento 2
begin
#(posedge(startTx))
$display("[Info] startTx has been generated successfully");
end
join
disable fork;
end
endtask
But doesn't seem to be working as it apparently checks for both statements to be true and I would like something as 'join_any' from SystemVerilog that breaks whenever one of both statements become true.

This works without using the SystemVerilog join_any. Comment startTx or uncomment it to see the two conditions that occur.
module tb ();
bit SIGNAL;
bit startTx;
int errors;
task checkStart;
fork
// evento 1
begin : timeout
#500; // timeOut
$display("[Error! %t] Time Out has been reached", $time);
errors = errors + 1;
$finish;
end
// evento 2
begin :wait_for_signal
#(posedge(startTx))
$display("[Info] startTx has been generated successfully");
disable timeout;
end
//
join
//
$display("+++++ Finished checkStart ++++++");
endtask
initial
begin
checkStart();
// Do something else
#20;
$display("**** normal finish ****");
$finish;
end
initial
begin
#1;
// coment one of these at a time
//startTx = 1;
startTx = 0;
end
endmodule

Related

Task does not update testbench sclk

I'm trying to understand why my signal is not updating when it is processed by the task.
As you could see below, the problem is related to the signal that internally on the task are changing correctly but even in a hierarchical call do not change the signal outside the task.
//-------------------------------
timeunit 1ps;
timeprecision 1ps;
`define CLK_HALF_PERIOD 10
`define SCK_HALF_PERIOD 30
module tbench ();
logic clk;
logic sclk;
logic RST;
hwpe_stream_intf_stream MOSI();
hwpe_stream_intf_stream MISO();
logic try;
initial begin
spi_send (.addr({1'b1,3'b111,12'd1,16'd0 }),
.data(1),
.MISO(try),
.MOSI(MOSI.data),
.SCK(sclk));
end
always
begin
# `CLK_HALF_PERIOD clk = 1;
# `CLK_HALF_PERIOD clk = 0;
end
task automatic spi_send (
input logic [31:0] addr,
input logic [31:0] data,
input logic MISO, // not used
ref logic MOSI,
ref logic SCK
);
integer i = 0;
$display ("add=%-32d",addr );
for (i=0; i<32; i=i+1) begin
//$display("add", 31-i , " MOSI ",MOSI);
// MOSI = ;
MOSI = addr[31-i];
tbench.try = MOSI;
#`SCK_HALF_PERIOD
tbench.sclk = 1'b1;
#`SCK_HALF_PERIOD;
tbench.sclk = 1'b0;
$display("add", addr[30-i] , " MOSI ",MOSI);
end
endtask
endmodule
tbench.sclk and MOSI are not changing globally, but only locally.
Here is the interface:
interface hwpe_stream_intf_stream() ;
logic valid;
logic ready;
logic data;
logic [8/8-1:0] strb;
modport source (
output valid, data, strb,
input ready
);
modport sink (
input valid, data, strb,
output ready
);
endinterface
You need to zoom in to the beginning of your waveforms to see sclk toggling. It toggles between 0 and 2000ps, then stops toggling.
You can add this to your testbench to stop the simulation much sooner to make it more obvious:
initial #3ns $finish;

Verifying single port RAM using Verilog

I've written a Verilog testbench for a single PORT SRAM with write operation at address i, and reading it successively at i-1 address. something like this below
task write_read;
integer i;
begin
for (i=1,i<=20,i=i+1) begin
write_mode(i,$urandom); // i= address, $urandom=data
read_mode(i-1); //i-1 address
end
end
endtask
PS: write_mode, read_mode are tasks that set wen, cs, and some scan mode pins along with delays.
I'm seeing correct read and write operations in the Verdi waveform visually. But, I want to verify data at the address i being written is the same as the data at the address i being read from the log files. If they don't match, it should display an ERROR.
I'm not sure how to implement this in the code. When I've hundreds of compilers, I can't go inside all the compiler paths, open their waveform files and check read, write operations manually.
I tried to store $urandom data for a particular address location, but it gets overwritten with each iterative cycle. I can use a function to return the $urandom value, but my environment contains delays, so I can't use functions.
In a nutshell, I'm looking for Verilog code help on memory verification without dumping waveforms.
can someone please help? please, Let me know if more details are needed
Thanks
Using the Kristen framework you get some test bench code generated which is available for reuse. Below is one file from that test bench called test_support.vh. The file contains functions for displaying errors and counting errors. I would recommend that you use === or !== when comparing memory locations as undefined signals can match inadvertently. At the end of the test, you call the display_test_final_status and that will create an overal test report for you in the log file. After your full regression completes you may now run a grep on the log files looking for ERROR and it will show anything that failed in a consistent mannor.
I have a ovearching Perl regression script that runs all of my tests and does the grep automagically afterwords and sends a success or fail email.
On a per test basis, you will need to set some defines to indicate the test name, and whether you want errors to halt the test immediately.
Good luck.
// -----------------------------------------------------------
// test_support.vh
// Generated file specifies which numerical test cases to run.
// Kristen Software License - Version 1.0 - January 1st, 2019
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
// GENERATED FILE - DO NOT MODIFY THIS FILE MANUALLY.
// -----------------------------------------------------------
logic[63:0] error_count = 0;
logic[63:0] lcl_error_count = 0;
logic bool_quick_mode = 0;
logic[511:0] support_test_passes;
logic[15:0] support_test_fails [0:511];
logic[511:0] support_test_was_run;
task test_init;
error_count = 0;
lcl_error_count = 0;
endtask
task display_test_begin_status;
begin
`ifdef QUICK_MODE
bool_quick_mode = 1;
`endif
$display("=========================================================================");
$display("| Test: %s QUICK_MODE = %s", `TEST_NAME_STR, bool_quick_mode ? "ON" : "OFF");
$display("| VERBOSE = %0d", `VERBOSE);
$display("=========================================================================");
end
endtask
task display_test_start;
input[31:0] test_id;
input string test_description;
begin
lcl_error_count = 0;
$display("=========================================================================");
$display("%0t: Test %0d : %s.", $time, test_id, test_description);
$display("=========================================================================");
end
endtask
task display_test_end;
input[31:0] test_id;
begin
$display("=========================================================================");
$display("%0t: Test %0d Complete with %0d ERRORS.", $time, test_id, lcl_error_count);
$display("=========================================================================");
support_test_was_run[test_id] = 1'b1;
if (lcl_error_count == 0)
support_test_passes[test_id] = 1'b1;
else
support_test_fails[test_id] = lcl_error_count;
end
endtask
task display_error_inc;
input string error_description;
begin
error_count++;
lcl_error_count++;
//$display("=========================================================================");
$display("%0t: ERROR: %s : error_count: %0d",$time, error_description, error_count );
//$display("=========================================================================");
`ifdef TEST_STOP_ON_ERROR
if (error_count >= `TEST_STOP_ON_ERROR_LIMIT) begin
$display("%0t, Stopping on error count = %d, %m", $time, error_count);
$finish();
end
`endif
end
endtask
task display_test_final_status;
//input string testname;
begin
$display("=========================================================================");
$display("%0t: Test %s %s with %0d ERRORS",$time, `TEST_NAME_STR, error_count > 0 ? "FAILS" : "PASSES",error_count);
$display("=========================================================================");
if (error_count !== 'h0)
begin
$display("Test failures:");
for (int err_fail_cnt = 0;err_fail_cnt < 512; err_fail_cnt = err_fail_cnt + 1)
begin
if (support_test_was_run[err_fail_cnt] == 1'b1 && support_test_passes[err_fail_cnt] != 1'b1)
begin
$display("Test %d, fails with %d errors", err_fail_cnt, support_test_fails[err_fail_cnt]);
end
end
end
end
endtask
task display_no_test_found;
input[31:0] test_id;
input string test_description;
begin
lcl_error_count = 0;
$display("=========================================================================");
$display("%0t: Test %0d : %s NOT FOUND SKIPPING.", $time, test_id, test_description);
$display("=========================================================================");
end
endtask
From the Kristen generated test bench, when a RAM unit is detected, this is the test that is run. I would treat this as an algorithmic solution, as you would have to generate several vector strings and additional functions that convert those strings to addresses.
xreg_v1_0_0_write_mpi_test is a task that writes to the RAM and xreg_v1_0_0_read_mpi_test is a task that reads from the RAM. There is a compare task xreg_v1_0_0_register_compare_with_error which obviously generates an error. I'll show those below as well.
// This is a casex snippet from the RAM test
7'd2: begin
// xreg_v1_0_0_mem_ack test
$display("%0t, xreg_v1_0_0_mem_ack test", $time);
oo_limit = get_entries_by_index(tc_index) > 256 ? 256 : get_entries_by_index(tc_index); //Max number of entries for this test
mm_step = get_entry_offset(tc_index);
nn_limit = perfect_by_datawidth(get_size_by_index(get_address_by_index(tc_index)),DATAPATH_WIDTH)/8; // Number of bytes for this entry
nn_step = DATAPATH_WIDTH == 8 ? 1 : DATAPATH_WIDTH == 16 ? 2 : DATAPATH_WIDTH == 32 ? 4 : 8;
for(oo = 0; oo < oo_limit; oo = oo + 1) // Move through each entry we will be testing
begin
for (nn = 0; nn < nn_limit; nn = nn + nn_step) // Walk through each access of a given entry
begin
test_address = get_address_by_index(tc_index) + (oo*mm_step) + nn;
expected = oo[7:0] ^ nn[7:0] ^ mm_step[7:0] ^ nn_step[7:0];
expected = {expected[6:0],expected[7],expected[2:0],expected[7:3],expected[5],expected[3],expected[1],expected[7],expected[0],expected[2],expected[6],expected[4],expected[7:0]};
xreg_v1_0_0_write_mpi_test(aclk, test_address, expected);
end
end
for(oo = 0; oo < oo_limit; oo = oo + 1) // Move through each entry we will be testing
begin
for (nn = 0; nn < nn_limit; nn = nn + nn_step) // Walk through each access of a given entry
begin
test_address = get_address_by_index(tc_index) + (oo*mm_step) + nn;
mask = get_entry_mask_by_index(tc_index);
expected = oo[7:0] ^ nn[7:0] ^ mm_step[7:0] ^ nn_step[7:0];
expected = {expected[6:0],expected[7],expected[2:0],expected[7:3],expected[5],expected[3],expected[1],expected[7],expected[0],expected[2],expected[6],expected[4],expected[7:0]} & (get_entry_mask_by_index(tc_index) >> (nn*8));
xreg_v1_0_0_read_mpi_test(aclk, test_address, result);
xreg_v1_0_0_register_compare_with_error(test_address,expected,result);
end
end
end
And here are some of the referenced tasks that show writes, reads and compares as implemented. Some of this is System Verilog I think, so you will have to treat it as algorithmic.
task automatic xreg_v1_0_0_read_mpi_test;
ref logic clock;
input [`TEST_ADDR_WIDTH-1:0] address;
output [`TEST_DATA_WIDTH-1:0] result;
begin
$display("ENTER >>> xreg_v1_0_0_read_mpi_test");
repeat(1) #(posedge clock);
`TEST_MPI_ADDR = address;
`TEST_MPI_RD_REQ = 1'b1;
`TEST_MPI_ENABLE = 1'b1;
while (!`TEST_MPI_ACK) repeat(1) #(posedge clock);
`TEST_MPI_ADDR = 'h0;
`TEST_MPI_RD_REQ = 1'b0;
`TEST_MPI_ENABLE = 1'b0;
result = `TEST_MPI_RD_DATA;
$display("WAITING ACK <<< xreg_v1_0_0_read_mpi_test");
while (`TEST_MPI_ACK) repeat(1) #(posedge clock);
$display("EXIT <<< xreg_v1_0_0_read_mpi_test");
end
endtask
task automatic xreg_v1_0_0_write_mpi_test;
ref logic clock;
input [`TEST_ADDR_WIDTH-1:0] address;
input [`TEST_DATA_WIDTH-1:0] data;
begin
$display("ENTER >>> xreg_v1_0_0_write_mpi_test");
repeat(1) #(posedge clock);
`TEST_MPI_ADDR = address;
`TEST_MPI_WR_DATA = data;
`TEST_MPI_WR_REQ = 1'b1;
`TEST_MPI_ENABLE = 1'b1;
while (!`TEST_MPI_ACK) repeat(1) #(posedge clock);
`TEST_MPI_ADDR = 'h0;
`TEST_MPI_WR_DATA = 'h0;
`TEST_MPI_WR_REQ = 1'b0;
`TEST_MPI_ENABLE = 1'b0;
$display("WAITING ACK <<< xreg_v1_0_0_write_mpi_test");
while (`TEST_MPI_ACK) repeat(1) #(posedge clock);
$display("EXIT <<< xreg_v1_0_0_write_mpi_test");
end
endtask
task automatic xreg_v1_0_0_register_compare_with_error;
input [`TEST_ADDR_WIDTH-1:0] address;
input [`TEST_DATA_WIDTH-1:0] expected;
input [`TEST_DATA_WIDTH-1:0] result;
begin
$display("ENTER >>> xreg_v1_0_0_register_compare_with_error");
if (expected !== result)
begin
$display("%0t, Address = 0x%X", $time, address);
$display("%0t, Expected 0x%X", $time, expected);
$display("%0t, Read 0x%X", $time, result);
display_error_inc("xreg_v1_0_0_rdconst_test: Mismatch between read and expected data.");
end
$display("EXIT <<< xreg_v1_0_0_register_compare_with_error");
end
endtask
You would want to first store the write data in a queue. Then when reading the SRAM pass the address to the queue and compare the queue_data_out and the sram_data_out. print ERROR if the comparison fails.
See pseudo code below.
task write_read;
integer i;
bit write_data_queue [$];
begin
for (i=1,i<=20,i=i+1) begin
write_mode(i,$urandom); // i= address, $urandom=data
write_data_queue.push_front($urandom);
read_mode(i-1); //i-1 address
queue_data = write_data_queue.pop_front();
if(queue_data != read_mode(i-1))
$display("ERROR'\n")
end
end
endtask

ComputerCraft tracking Lua "io" library exceptions

I am currently trying to debug a Minecraft-based turtle farming script with functions and API functions.
When I am executing I get an 'io' exception (which is understandable as I am trying to write to a log for each loop), but it doesn't tell me which script it is in or the line number. Are there any solutions apart from printing throughout program execution?
Exception I have been getting:
io:107: index expected, got nil
main turtle-farming script:
--[[main script for farming procedure]]
--load functions responsible for positioning/repositioning/farming
os.loadAPI("APIS/positioners");
os.loadAPI("APIS/farmers");
--action turtle start farming condition
assert(positioners.check_start_pos(), "Could not initialise the turtle for the farming procedure\nCould not identify it's starting location\n(are there birch planks directly above and beneath it?");
--check Netherrack can be found from start block, declare 'dir' also as local
local init_result, dir = positioners.find_next_neth()
assert(init_result, "Could not find the appropriate direction to travel in from\n the turtle starting position, is the farm set up correctly?");
local loop_vars = {["count"] = 0, ["blockId"] = nil, ["dir"] = nil, ["prevManvr"] = nil, ["action"] = ""};
--**input** assertion tests for required fuel level and seed requirements
assert(turtle.getFuelLevel() > 50, "Fuel level is below required level to start farming, - terminating");
--given 'result' == true can start farming
turtle.forward();
--open log file (overwrite) and save to io class handle
log = io.open("logs/proc_log", "w");
--start main farming process loop
while turtle.getFuelLevel() > 0 do
--reset action variable
loop_vars["action"] = "";
--sort log variables
loop_vars["count"] = loop_vars["count"] + 1;
--identify the block above (returns inv slot(1-4) it matches with or false if it doesn't)
loop_vars["blockId"] = positioners.id();
if blockId == 1 then
loop_vars["action"] = "Netherrack above ";
if loop_vars["dir"] == nil then
print("Netherrack found, planting");
farmers.plant();
--shift turtle forward such that it can evaluate a new block. Ensure that moves forward in case of obstruction
assert(turtle.forward(), "The turtle is impeded from moving forwards in farming route");
--log statement
loop_vars["action"] = loop_vars["action"].."plant and move forward";
else
--initiate change in direction procedure
assert(positioners.change_direction(loop_vars["dir"]), "Failed to complete turtle change direction procedure");
--reset dir
loop_vars["dir"] = nil;
loop_vars["action"] = loop_vars["action"].." actioned 'positioners.change_position(dir)'.";
end;
elseif blockId == 3 then
turtle.forward();
--log statement
loop_vars["action"] = "Proceeding past marble block";
elseif blockId == false then
print("Finding next Netherrack block.");
--retrace back to the most recent 'legitimate' block");
turtle.back();
--call function to reposition turtle for next farming line
result, loop_vars["dir"] = positioners.find_next_neth(loop_vars["prevMan"]);
assert(result, "A new netherrack block could not be found in any direction.");
--assign dir result to prevMan (information for next positioners.change_position() call
loop_vars["prevMan"] = loop_vars["dir"];
--log statement
loop_vars["action"] = "No 'legitimate' block above, 'positioners.find_next_neth() successful,\nassigning dir accordingly.";
else
--log statement
log.write("Unhandled exception in farm_proc main loop");
log.close();
error("positioners.find_next_neth() did not find an appropriate block above it.");
end;
print("farm_proc loop");
--write current turn to log file
log.write("Turn no: "..loop_vars["count"].."\n Id()== "..tostring(loop_vars["blockId"]).."\n Action: "..loop_vars["action"].."\n Previous maneuver: "..loop_vars["prevMan"].."\n\n");
end;
--updating log
log.write("Error - turtle ran out of fuel\n");
log.close();
error("Turtle ran out of fuel whilst planting - terminated");
'positioners' api (movement/detection based tasks):
function find_next_neth(prevMan)
--[[Find direction of the next overhead block of Netherrack from turtle's current pos,
Order;
N
E
W
S
Error (no direction found)]]
--define numbers corresponding to directions
local dirs = {"Back", "Left", "Right", "Forward"};
--create a loop counter to ensure does not exceed full checking loop
local counter = 4;
--loop through movement proc. until netherrack (slot 1) is found above it (if at all)
while true do
print("Looping, current loop counter is: ", counter);
local idAhead = id_ahead();
if counter == 4 then
--placeholder, script should never need to find forwards
elseif counter == 3 then
turtle.turnLeft();
elseif counter == 2 then
turtle.turnRight();
turtle.turnRight();
elseif counter == 1 then
turtle.turnRight();
--decremented counter has reached it's minimum
elseif counter < 1 then
return false, nil;
else
error("For find_next_neth iteration counter out of range");
end;
--decrement counter variable
counter = counter - 1;
--boolean condition to determine whether function is complete, incomplete or broken. 'prevMan' as a logical statement will return true if var has value, and false if not
local testPrev = (not prevMan == dir[(math.abs(counter - 4) + 1))] or not prevMan);
local validBlock = (idAhead == 1 or idAhead == 3)
if testPrev and validBlock then
--all tests are valid - break loop to return
break;
end;
--report success and return result
print("Nether found!\n");
return true, dirs[counter];
end;
end;
function change_direction(dir)
--intialise a base error string
local errMsg = "Could not action positioners.change_direction(dir, prevMan) ";
if dir == "East" then
assert(turtle.forward(), errMsg.."Obstruction to route");
--this should finalise a 180deg turn to the left
turtle.turnLeft()
elseif dir == "West" then
assert(turtle.forward(), errMsg.."Obstruction to route");
--180deg turn left
turtle.turnRight()
elseif dir == "North" then
--no action
elseif dir == "South" then
error("Return to start not yet implemented");
else
error("positioners.change_direction() parameter not as expected");
end;
return true;
end;
function id(slot)
--[[Determines if netherrack is currently above turtle.
Return false means the block
above does not match slots 1-4 of the
turtle's inv. Takes optional int
for specific block slot index
in turtle compare]]
--checking argument
if slot ~= nil then
--select slot given as argument
turtle.select(slot);
if turtle.compareUp() then
--don't return int because specific material requested
return true;
else
return false;
end;
end;
counter = 1
while counter < 5 do
turtle.select(counter);
--identify whether the current selected slot item matches the blovk overhead
if turtle.compareUp() then
--return block above's corresponding slot index
return counter
end;
counter = counter + 1;
end;
--return number indicating unidentfied block
return false;
end;
function id_ahead(slot)
if turtle.forward() then
--save value of id call for later return
local rtn = id(slot)
turtle.back();
return rtn
else
error("turtle could not move forwards in id_ahead(slot)");
end;
end;
function check_start_pos()
--set selected slot to birch planks (no currently selected method implemented so cannot revert this change internally)
turtle.select(2);
--save boolean variables for comparison of blocks above and below position
local up = turtle.compareUp();
local down = turtle.compareDown();
--test if above boolean values are true (turtle in designated start position)
if up and down then
return true;
else
print("Not in appropriate farming start position");
return false;
end;
end;
(The 'farmers' api simply checks current seeds and then plants a crop through farmers.plant())
I believe I have found the solution - the debug library, specifically debug.traceback() allows you to introspect the call stack more closely when catching an error
debug library index

Eiffel - How do I make my classes readable?

I'm new to Eiffel and I'm trying to use the LINKED_LIST class for organizing instances of other class "MONOMIO" I've made. I added a function for ordering this elements and I use the remove and the cursor movement features and when I try to execute the code it raises an exception saying that the objects contained should be readable and writable. I would like to know how to do it, this is my class:
class
MONOMIO
feature --Initialization
make (coef:INTEGER; expX:INTEGER; expY:INTEGER)
do
coeficiente := coef
exponenteX := expX
exponenteY := expY
end
feature
evaluar(valX: INTEGER; valY: INTEGER): REAL_64
do
Result := coeficiente*(valX^exponenteX)*(valY^exponenteY)
end;
coeficiente: INTEGER;
exponenteX: INTEGER;
exponenteY: INTEGER;
feature --setter
set_coeficiente(val: INTEGER)
do
coeficiente := val
end;
end
I think the exception raises because of this feature I've made for a class that has as a feature the LINKED_LIST[MONOMIO] and it's called "contenido":
simplificar
local
tamanio_polinomio: INTEGER -- NĂºmero de monomios que tiene el polinomio
contador: INTEGER
monomio_a_comparar: MONOMIO -- Auxiliar
coeficiente_total:INTEGER -- Auxiliar
indice_monomio_en_revision:INTEGER
do
from
contenido.start
indice_monomio_en_revision := 0
tamanio_polinomio := contenido.count
until
indice_monomio_en_revision = tamanio_polinomio
loop
contenido.start
contenido.move (indice_monomio_en_revision)
monomio_a_comparar := contenido.item
from
contador := indice_monomio_en_revision
coeficiente_total := monomio_a_comparar.coeficiente
contenido.forth
until
contador = tamanio_polinomio
loop
if
(monomio_a_comparar.exponentex = contenido.item.exponentex) and
(monomio_a_comparar.exponentey = contenido.item.exponentey)
then
coeficiente_total := coeficiente_total + contenido.item.coeficiente
contenido.remove -- Mueve el cursor a la derecha
tamanio_polinomio := tamanio_polinomio - 1
contador := contador - 1
else
if
not contenido.islast
then
contenido.forth
end
end
contador := contador + 1
end
contenido.start
contenido.move (indice_monomio_en_revision)
contenido.item.set_coeficiente (coeficiente_total)
indice_monomio_en_revision := indice_monomio_en_revision + 1
end
end;
I hope anyone can help me with this problem. Thanks.
Suppose you have a list with 1 element. Then we enter the outer loop and move to the first element. Then we execute contador := indice_monomio_en_revision that is still 0 at this point and do contenido.forth. Now we are beyond the list because there is only one element. However contador = tamanio_polinomio is false (0 = 1), so we enter the inner loop and try to retrieve the second (non-existing) item. BOOM!
Other issues include:
There are multiple calls like contenido.start followed by contenido.move. You could use a single call to go_i_th instead.
Instead of counting number of items in the list I would look at the feature after. It tells when you reach an end of the list. It would simplify the logic of your loop (e.g. the call to islast would be removed) and let you to remove some local variables.
Taking the last point into account I would write the inner loop condition as
contenido.after
At least this would avoid the crash you experience. As to the logic, you may need to check features start, after, forth and remove to see what effect they have. The usual way to write loops in such cases is like
from
l.start
until
l.after
loop
... -- Use l.item
l.forth
end
In case of remove probably you do not need to call forth.

Lock between Lua lanes

I am trying to use locks between 2 Lua lanes,but observed that both the lanes are entering lock_func simultaneously..Below is the snippet
Code Snippet
==================
require"lanes"
local linda = lanes.linda()
lock_func = lanes.genlock(linda,"M",1)
local function lock_func()
print("Lock Acquired")
while(true) do
end
end
local function readerThread()
print("readerThread acquiring lock")
lock_func()
end
local function writerThread()
print("writerThread acquiring lock")
lock_func()
end
Thread1= lanes.gen("*",{globals = _G},writerThread)
Thread2= lanes.gen("*",{globals = _G},readerThread)
T1 = Thread1()
T2 = Thread2()
T1:join()
T2:join()
From the ouput below we can see both the lanes have entered the lock_func function simultaneously
output
==================
writerThread acquiring lock
Lock Acquired
readerThread acquiring lock
Lock Acquired
Is there any problem with the implementation of the lock from the above code?
The implementation of locks in lua can be done as in the below code snippet. Only the print from writer or reader lane will be executed from the below code, as which ever lane acquiring the lock will go into an infinite loop(just to see locks are working as expected) & other lane will wait for the lock to get released.
require"lanes"
local linda = lanes.linda()
f = lanes.genlock(linda,"M",1)
local function readerThread()
require"lanes"
f(1)
print("readerThread acquiring lock")
while(true) do
end
f(-1)
end
local function writerThread()
require"lanes"
f(1)
print("writerThread acquiring lock")
while(true) do
end
f(-1)
end
Thread1= lanes.gen("*",{globals = _G},writerThread)
Thread2= lanes.gen("*",{globals = _G},readerThread)
T1 = Thread1()
T2 = Thread2()
T1:join()
T2:join()

Resources