Skip to content
Shunning Jiang edited this page May 3, 2017 · 5 revisions

class GcdUnitCS( PortBundle ):

def init( s ): s.a_mux_sel = ValuePort(int) s.a_reg_en = ValuePort(int) s.b_mux_sel = ValuePort(int) s.b_reg_en = ValuePort(int) s.is_b_zero = ValuePort(int) s.is_a_lt_b = ValuePort(int)

class GcdUnitDpath( Updates ):

def init( s ):

s.req_msg_a = ValuePort(int)
s.req_msg_b = ValuePort(int)
s.resp_msg  = ValuePort(int)
s.cs        = GcdUnitCS()

s.sub_out   = Wire(int)

s.a_reg = RegEn( Bits32 )( en = s.cs.a_reg_en )
s.b_reg = RegEn( Bits32 )( en = s.cs.b_reg_en )

s.a_mux = Mux( Bits32, 3 )(
  out = s.a.reg.in_,
  sel = s.cs.b_mux_sel,
)
# one way is to use |= for all elements in the array
s.a_mux.in_[A_MUX_SEL_IN]  |= s.req_msg_a
s.a_mux.in_[A_MUX_SEL_SUB] |= s.sub_out
s.a_mux.in_[A_MUX_SEL_B]   |= s.b_reg.out

# the keyword args won't work for "in_[B_MUX_SEL_A]"
ins    = [None] * 2
ins[B_MUX_SEL_A]  = s.a_reg.out
ins[B_MUX_SEL_IN] = s.req_msg_b
s.b_mux = Mux( Bits32, 2 )(
  out = s.b.reg.in_,
  sel = s.cs.b_mux_sel,
  in_ = ins, # inside component I will connect based on index?
)

s.b_zcp = ZeroComp()( in_ = s.b_reg.out, out = s.cs.is_b_zero )

s.b_ltc = LTComp()(
  in0 = s.a_reg.out,
  in1 = s.b_reg.out,
  out = s.cs.is_a_lt_b,
)

s.b_sub = Subtractor()(
  in0 = s.a_reg.out,
  in1 = s.b_reg.out,
  out = s.resp_msg,
)
s.sub_out |= s.b_sub.out # out = x cannot do fan-out, maybe "out=[x,y,z] means fan-out?"

class GcdUnitCtrl( Updates ):

def init( s ):

s.req_val  = ValuePort(int)
s.req_rdy  = ValuePort(int)
s.resp_val = ValuePort(int)
s.resp_rdy = ValuePort(int)

s.state = Reg()

s.STATE_IDLE = 0
s.STATE_CALC = 1
s.STATE_DONE = 2

s.cs = GcdUnitCS()

@s.update
def state_transitions():

  curr_state = s.state.out

  if   curr_state == s.STATE_IDLE:
    if s.req_val and s.req_rdy:
      s.state.in_ = s.STATE_CALC

  elif curr_state == s.STATE_CALC:
    if not s.cs.is_a_lt_b and s.cs.is_b_zero:
      s.state.in_ = s.STATE_DONE

  elif curr_state == s.STATE_DONE:
    if s.resp_val and s.resp_rdy:
      s.state.in_ = s.STATE_IDLE

@s.update
def state_outputs():

  curr_state = s.state.out

  s.req_rdy   = 0
  s.resp_val  = 0
  s.cs.a_mux_sel = 0
  s.cs.a_reg_en  = 0
  s.cs.b_mux_sel = 0
  s.cs.b_reg_en  = 0

  # In IDLE state we simply wait for inputs to arrive and latch them

  if curr_state == s.STATE_IDLE:
    s.req_rdy   = 1
    s.resp_val  = 0

    s.cs.a_mux_sel = A_MUX_SEL_IN
    s.cs.b_mux_sel = B_MUX_SEL_IN
    s.cs.a_reg_en  = 1
    s.cs.b_reg_en  = 1

  # In CALC state we iteratively swap/sub to calculate GCD

  elif curr_state == s.STATE_CALC:

    s.req_rdy   = s.resp_val  = 0
    s.cs.a_mux_sel = A_MUX_SEL_B if s.cs.is_a_lt_b else A_MUX_SEL_SUB
    s.cs.a_reg_en  = 1
    s.cs.b_mux_sel = B_MUX_SEL_A
    s.cs.b_reg_en  = s.cs.is_a_lt_b

  # In DONE state we simply wait for output transaction to occur

  elif curr_state == s.STATE_DONE:
    s.req_rdy   = 0
    s.resp_val  = 1
    s.cs.a_mux_sel = A_MUX_SEL_X
    s.cs.b_mux_sel = B_MUX_SEL_X
    s.cs.a_reg_en  = 0
    s.cs.b_reg_en  = 0

class GcdUnit( Updates ):

def init( s ):

s.req  = ValRdyBundle()
s.resp = ValRdyBundle()

s.dpath = GcdUnitDpath()(
  req_msg_a = s.req.msg[0:32],
  req_msg_b = s.req.msg[32:64],
  resp_msg  = s.resp.msg,
)
s.ctrl  = GcdUnitCtrl()(
  req_val  = s.req.val,
  req_rdy  = s.req.rdy,
  resp_val = s.resp.val,
  cs       = s.dpath.cs,
)

def line_trace( s ): return s.dpath.a_reg.line_trace() + s.dpath.b_reg.line_trace()

Clone this wiki locally