Class: HDLRuby::High::Std::SequencerFunctionI

Inherits:
Object
  • Object
show all
Defined in:
lib/HDLRuby/std/sequencer_func.rb

Overview

Describes a sequencer function instance.

Constant Summary collapse

ZERO =
SequencerFunctionT::ZERO
ONE =
SequencerFunctionT::ONE
@@current_stack =

The stack of current function instance.

[]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(funcE) ⇒ SequencerFunctionI

Creates a new instance of function from +funcE+ eigen function, and possible default stack depth +depth+.



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/HDLRuby/std/sequencer_func.rb', line 186

def initialize(funcE)
    # Sets the eigen function.
    @funcE = funcE
    # Initialize the depth.
    # At first, no recursion is assumed, hence the depth is 1.
    @depth = 1
    # Create the table of signal stacks (by name).
    # For further updating.
    @stack_sigs = [] # Signal stacks
    # Signal stacks pointer.
    stack_ptr = nil
    depth = @depth
    HDLRuby::High.cur_system.open do
        stack_ptr  = bit[depth.width].inner(HDLRuby.uniq_name(:stack_ptr) => 0)
    end
    @stack_ptr = stack_ptr
    # Create the stack for the returns.
    # @returnIdx = self.make_stack(bit[SequencerT.current.size.width])
    @returnIdx = self.make_stack(bit[8])
    # Create the stacks for the arguments.
    @funcE.each_argT { |argT| self.make_stack(argT) }
    # @argsIdx = @returnIdx + 2
    @argsIdx = @returnIdx + ONE

    # Create the return value, however, at first their type is unknown
    # to set it as a simple bit.
    # The type of the return value is built when calling make_return.
    # @returnValIdx = self.make_stack(bit[1])
    # puts "@returnValIdx=#{@returnValIdx}"
    returnValue = nil
    name = @funcE.name
    HDLRuby::High.cur_system.open do
        returnValue = bit[1].inner(
                              HDLRuby.uniq_name("#{name}_return"))
    end
    @returnValue = returnValue
    
    # Initialize the state where the initial function call will be.
    @state = nil
end

Instance Attribute Details

#depthObject (readonly)

The depth of the stack.



182
183
184
# File 'lib/HDLRuby/std/sequencer_func.rb', line 182

def depth
  @depth
end

#funcEObject (readonly)

The eigen function.



173
174
175
# File 'lib/HDLRuby/std/sequencer_func.rb', line 173

def funcE
  @funcE
end

#returnIdxObject (readonly)

The return index in the stacks.



176
177
178
# File 'lib/HDLRuby/std/sequencer_func.rb', line 176

def returnIdx
  @returnIdx
end

#stack_ptrObject (readonly)

The stack pointer register.



179
180
181
# File 'lib/HDLRuby/std/sequencer_func.rb', line 179

def stack_ptr
  @stack_ptr
end

Class Method Details

.currentObject

Get the function instance currently processing.



168
169
170
# File 'lib/HDLRuby/std/sequencer_func.rb', line 168

def self.current
    @@current_stack[-1]
end

.recursion(funcE) ⇒ Object

Check if the current function call with eigen +funcE+ would be recursive or not.



389
390
391
392
# File 'lib/HDLRuby/std/sequencer_func.rb', line 389

def self.recursion(funcE)
    # puts "recursion with funcE=#{funcE}"
    return @@current_stack.find {|funcI| funcI.funcE == funcE }
end

Instance Method Details

#buildObject

Builds the code of the function. Returns the last state of the buit function, will serve for computing the return state of the first call.



261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/HDLRuby/std/sequencer_func.rb', line 261

def build
    # Saves the current function to detect recursion.
    @@current_stack.push(self)

    # Get the body.
    body = @funcE.body

    # Create a state starting the function.
    SequencerT.current.step

    # Get the arguments.
    args = (@argsIdx...(@argsIdx+body.arity)).map {|idx| self.peek(idx) }
    # Place the body.
    # SequencerT.current.instance_exec(*args,&body)
    HDLRuby::High.top_user.instance_exec(*args,&body)
    # # Free the stack of current frame.
    # Moved to return...
    # self.pop_all

    # Create a state for returning.
    st = self.make_return

    # The function is built, remove it from recursion detection..
    @@current_stack.pop

    return st
end

#first_call(*args) ⇒ Object

Call the function with arguments +args+ for the first time.



290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
# File 'lib/HDLRuby/std/sequencer_func.rb', line 290

def first_call(*args)
    # # Create a state for the call.
    # call_state = SequencerT.current.step

    # Push a new frame.
    self.push_all

    # Adds the arguments and the return state to the current stack frame.
    args.each_with_index { |arg,i| self.poke(@argsIdx + i,arg) }
    # The return is set afterward when the end of the function is
    # known, since the return position for the first call is just
    # after it.
    # self.poke(@returnIdx,call_state.value + 1)

    # Create a state for the call.
    call_state = SequencerT.current.step


    # Get the state value of the function: it is the state
    # following the first function call.
    func_state_value = call_state.value + ONE
    # Do the call.
    call_state.gotos << proc do
        HDLRuby::High.top_user.instance_exec do
            next_state_sig <= func_state_value
        end
    end

    # Sets the state of the first function call.
    @state = call_state

    # Return the state for inserting the push of the return state.
    return call_state
end

#make_depth(depth) ⇒ Object

There is actually recurse, compute the depth: if +depth+ is given as argument, this is the depth, otherwise compute it from the bit width of the argument.

NOTE: uses the heuristic that the depth is more or less equal to the bit width of the largest argument type.



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/HDLRuby/std/sequencer_func.rb', line 240

def make_depth(depth)
    if depth then
        @depth = depth
    else
        # There is no default depth, use the heuristic that the
        # depth is more or less equal to the bit width of the
        # largest argument type.
        @depth = @funcE.each_argT.map {|t| t.width }.max
    end
    # Resize the stackes according to the depth.
    @stack_sigs.each do |sig|
        sig.type.instance_variable_set(:@range,0..@depth-1)
    end
    @stack_ptr.type.instance_variable_set(:@range,(@depth+1).width-1..0)
end

#make_return(val = nil) ⇒ Object

Creates a return point with value +val+. Returns the created state.

NOTE: when val is nil, no return value is provided.



447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
# File 'lib/HDLRuby/std/sequencer_func.rb', line 447

def make_return(val = nil)
    SequencerT.current.step
    # puts "make_return with val=#{val}"
    # Update the type of the return value.
    if val then
        # Update the type.
        @returnValue.instance_variable_set(:@type, @returnValue.type.resolve(val.to_expr.type))
        # Sets the return value if any.
        self.return_value <= val
    end
    # Create the state for the return command.
    state = SequencerT.current.step
    # Get the return state value.
    # ret_state_value = self.peek(@returnIdx, HDLRuby::High.top_user.mux(@stack_ptr < @depth,-1,0))
    # Peek before the stack pointer value to account from the fact that
    # the pop is performed beforehand.
    ret_state_value = self.peek(@returnIdx, HDLRuby::High.top_user.mux(@stack_ptr < @depth,ZERO,ONE))
    # Return.
    this = self
    state.gotos << proc do
        HDLRuby::High.top_user.instance_exec do
            # Set the next state.
            next_state_sig <= ret_state_value
            # # Pop must be place after setting the return state.
            # this.pop_all
        end
    end
    # Pop (done at clock edge, hence before the update of the state).
    old_code = state.code
    state.code = proc do
        old_code.call
        HDLRuby::High.top_user.instance_exec do
            this.pop_all
        end
    end

    return state
end

#make_stack(typ) ⇒ Object

Create a stack for elements of types +typ+.



395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
# File 'lib/HDLRuby/std/sequencer_func.rb', line 395

def make_stack(typ)
    # Create the signal array representing the stack.
    depth = @depth
    # puts "make stack with @depth=#{@depth}"
    stack_sig = nil
    name = @funcE.name
    HDLRuby::High.cur_system.open do
        stack_sig = typ[-depth].inner(
                              HDLRuby.uniq_name("#{name}_stack"))
    end
    # Add it to the list of stacks to handle.
    @stack_sigs << stack_sig

    # Returns the index of the newly created stack.
    return @stack_sigs.size - ONE
end

#peek(idx, off = 0) ⇒ Object

Get a value from the top of stack number +idx+ If +off+ is the offeset in the stack.



426
427
428
# File 'lib/HDLRuby/std/sequencer_func.rb', line 426

def peek(idx, off = 0)
    return @stack_sigs[idx][(@stack_ptr-ONE)+off]
end

#poke(idx, val, off = 0) ⇒ Object

Sets value +val+ to the top of stack number +idx+. If +off+ is the offeset in the stack.



432
433
434
435
# File 'lib/HDLRuby/std/sequencer_func.rb', line 432

def poke(idx,val, off = 0)
    # puts "idx=#{idx} val=#{val} sig=#{@stack_sigs[idx].name}"
    @stack_sigs[idx][@stack_ptr-ONE+off] <= val
end

#pop_allObject

Remove the top frame from the stacks.



419
420
421
422
# File 'lib/HDLRuby/std/sequencer_func.rb', line 419

def pop_all
    # HDLRuby::High.cur_system.hprint("pop_all\n")
    @stack_ptr <= @stack_ptr - ONE
end

#push_allObject

Pushes a new frame to the top of the stacks.



413
414
415
416
# File 'lib/HDLRuby/std/sequencer_func.rb', line 413

def push_all
    # HDLRuby::High.cur_system.hprint("push_all\n")
    @stack_ptr <= @stack_ptr + ONE
end

#recurse_call(*args) ⇒ Object

Call the function with arguments +args+ for recursion.



326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
# File 'lib/HDLRuby/std/sequencer_func.rb', line 326

def recurse_call(*args)
    # # create a state for the call.
    # call_state = SequencerT.current.step

    # Get the variables for handling the stack overflow.
    stack_ptr = @stack_ptr
    depth = @depth 
    argsIdx = @argsIdx
    this = self

    # Adds the argument to the stack if no overflow.
    HDLRuby::High.top_user.hif(stack_ptr < depth) do
        # hprint("stack_ptr=",stack_ptr," depth=",depth,"\n")
        # Adds the arguments and the return state to the current stack frame.
        # Since not pushed the stack yet for not loosing the previous
        # arguments, add +1 to the offset when poking the new arguments.
        # args.each_with_index { |arg,i| self.poke(@argsIdx + i,arg,1) }
        args.each_with_index { |arg,i| this.poke(argsIdx + i,arg,ONE) }
    end

    # Push a new frame.
    self.push_all

    # create a state for the call.
    call_state = SequencerT.current.step

    # Prepare the handling of overflow
    call_state_value = call_state.value
    overflow = @funcE.overflow
    if overflow then
        HDLRuby::High.top_user.hif(stack_ptr > depth) do
            HDLRuby::High.top_user.instance_exec(&overflow)
        end
    end

    # Get the state value of the function: it is the state
    # following the first function call.
    func_state_value = @state.value + ONE
    # Do the call.
    call_state.gotos << proc do
        HDLRuby::High.top_user.instance_exec do
            hif(stack_ptr <= depth) do
                next_state_sig <= func_state_value
            end
            helse do
                # Overflow! Skip the call.
                next_state_sig <= call_state_value + ONE
                # if overflow then
                #     # There is some overflow code to execute.
                #     HDLRuby::High.top_user.instance_exec(&overflow)
                # end
            end
        end
    end

    return call_state
end

#return_valueObject

Access the return value signal.



438
439
440
441
# File 'lib/HDLRuby/std/sequencer_func.rb', line 438

def return_value
    # return @stack_sigs[@returnValIdx][@stack_ptr-1]
    @returnValue
end

#to_exprObject

Give access to the return value.

NOTE: is automatically called when within an expression.



230
231
232
# File 'lib/HDLRuby/std/sequencer_func.rb', line 230

def to_expr
    return self.return_value
end