SR Flip Flop

Discussion in 'VHDL' started by Nirav, Sep 9, 2007.

  1. Nirav

    Nirav Guest

    Hello Everybody,

    I'm the student of Electronics and Communication Engineering and
    finding a problem in implementing SR Flip flop on VHDL Platform, using
    Quartus 7.1 tool. Please help me out.

    I've made a few programs for that but in all those I'm finding same or
    other Problem or not perfect output, Can you please let me know where
    I'm making this mistake ??

    1st Program :

    library IEEE;
    use IEEE.STD_LOGIC_1164.all;

    entity RSFF_NRK is
    port(s,r,clk : in BIT ; q,qbar : buffer BIT);
    end RSFF_NRK;

    architecture RSFF_NRK_ARC of RSFF_NRK is
    begin

    process(clk)
    begin

    if (clk'event and clk = '1') then

    if( r = '1' and s = '0' ) then

    q <= r nor qsbar;
    qs <= r nor qsbar;

    qbar <= s nor qs;
    qsbar <= s nor qs;

    elsif(s= '1' and r = '0') then

    qbar <= s nor qs;
    qsbar <= s nor qs;

    q <= r nor qsbar;
    qs <= r nor qsbar;


    elsif(s = '1' and r = '1') then

    q <= '1';
    qbar <= '1';

    end if;

    end if;

    end process;

    end RSFF_NRK_ARC;

    Here the program runs well but its RTL schematic shows a very large
    circuit instead of having only 2 gates.

    2nd Program :

    library IEEE;
    use IEEE.STD_LOGIC_1164.all;

    entity RSFF_NRK is
    port(ip : in std_logic_vector (1 downto 0); clk : in BIT ; q,qbar :
    out BIT);
    signal qs,qsbar : BIT;
    signal sel : INTEGER;
    end RSFF_NRK;

    architecture RSFF_NRK_ARC of RSFF_NRK is
    begin

    p:process(clk,ip)
    begin

    if (clk'event and clk = '1') then


    case ip is

    when "00" => sel <= 0;
    when "01" => sel <= 1;
    when "10" => sel <= 2;
    when "11" => sel <= 3;

    end case;

    if(sel = 1) then

    q <= ip[0] nor qsbar;
    qs <=ip[0] nor qsbar;

    qbar <=ip[1] nor qs;
    qsbar <=ip[1] nor qs;

    elsif(sel=2) then

    qbar <=ip[1] nor qs;
    qsbar <=ip[1] nor qs;

    q <=ip[0] nor qsbar;
    qs <=ip[0] nor qsbar;

    elsif(sel=3) then

    q <= ip[1] ;
    qbar <= ip[0] ;

    end if;


    end if;

    end process;

    end RSFF_NRK_ARC;

    Here, I've made the program but ip[_] is not being supported, always
    at this point I'm given an error report.

    3rd Program :


    library IEEE;
    use IEEE.STD_LOGIC_1164.all;

    entity RSFF_NRK is
    port(s,r,clk : in BIT ; q,qbar : out BIT);
    end RSFF_NRK;

    architecture RSFF_NRK_ARC of RSFF_NRK is
    begin

    process(clk)
    begin

    if (clk'event and clk = '1') then

    if( r = '1' and s = '0' ) then
    q <= s;
    qbar <= r;
    elsif(s= '1' and r = '0') then
    qbar <= r;
    q <= s;
    elsif(s = '1' and r = '1') then

    q <= s;
    qbar <= r;

    end if;

    end if;

    end process;

    end RSFF_NRK_ARC;

    Here program works well but circuit becomes much a complex.

    Please point out my error or let me have an alternate solution.

    Nirav
     
    Nirav, Sep 9, 2007
    #1
    1. Advertising

  2. Nirav

    beckjer Guest

    In program 1, (common problem in all 3 programs) add an 'else'
    statement to complete all the transistions. Leaving off the else
    clause can make for some large and messy circuits. A simple fix is:
    if your_happy = '1' AND youknowit = '1' then
    clapYourHands; -- proc call :p
    else
    null;
    end if;

    Null is a wonderful statement. It's great for creating sections you
    want to go back to (an inherant comment - of I'm not done yet) or
    closing if then else groups.

    In program 2 I see that you are combining std_logic_vector with bit
    for operations. Try defining all the entity names with std_logic
    instead of bit. That or you will need to convert the bit (or
    std_logic_vector) for the nor operation to work properly.


    In program 3 it looks like you always have:
    q <= s; qbar <= r;

    I would change the structure to
    if r = '1' or s = '1' then
    q <= s;
    qbar <= r;
    else --you are missing the final 'else' keyword. This can make for
    rather large circuits.
    null;
    end if;
     
    beckjer, Sep 10, 2007
    #2
    1. Advertising

  3. Nirav

    jens Guest

    > Null is a wonderful statement. It's great for creating sections you
    > want to go back to (an inherant comment - of I'm not done yet) or
    > closing if then else groups.


    I guess I fail to see the point of adding two lines of code to every
    if statement to tell it to do nothing, it'll do nothing just fine on
    it its own. The suggestion of converting everything to std_logic is a
    good one.

    To answer the original question...

    Every signal assigned in a clocked process will create a flip-flip, so
    the first two examples will create 4 flip-flops, one each for q, qs,
    qbar and qsbar. Also, the outputs of some of those flip-flops will
    feed into the inputs of other flip-flops, which will delay signals in
    a way you didn't intend. Using variables instead of signals could
    have change the behavior, but would still be needlessly complex. The
    third one is better with only two flip-flops (q and qbar). The key to
    create one SR flip-flop is to create only one flip-flop for q and
    derive qbar from q. Also, the logic is more complex than it needs to
    be, as it handles the illegal case separately and also assign outputs
    to input values rather than constants. As is usually the case, look
    for a simpler answer rather than a more complicated answer. Try
    something like this:

    process( clk )
    begin
    if ( r = '1' ) then -- R wins in the illegal case of RS=11
    q <= '0';
    elsif ( s = '1' ) then
    q <= '1';
    end if;
    end process;

    qbar <= not q;
     
    jens, Sep 11, 2007
    #3
  4. Nirav

    jens Guest

    > Null is a wonderful statement. It's great for creating sections you
    > want to go back to (an inherant comment - of I'm not done yet) or
    > closing if then else groups.


    I guess I fail to see the point of adding two lines of code to every
    if statement to tell it to do nothing, it'll do nothing just fine on
    it its own. The suggestion of converting everything to std_logic is a
    good one.

    To answer the original question...

    Every signal assigned in a clocked process will create a flip-flip, so
    the first two examples will create 4 flip-flops, one each for q, qs,
    qbar and qsbar. Also, the outputs of some of those flip-flops will
    feed into the inputs of other flip-flops, which will delay signals in
    a way you didn't intend. Using variables instead of signals could
    have changed the behavior, but would still be needlessly complex. The
    third one is better with only two flip-flops (q and qbar). The key to
    create one SR flip-flop is to create only one flip-flop for q and
    derive qbar from q. Also, the logic is more complex than it needs to
    be, as it handles the illegal case separately and also assign outputs
    to input values rather than constants. As is usually the case, look
    for a simpler answer rather than a more complicated answer. Try
    something like this:

    process( clk )
    begin

    if ( r = '1' ) then -- R wins in the illegal case of RS=11
    q <= '0';
    elsif ( s = '1' ) then
    q <= '1';
    end if;
    end process;

    qbar <= not q;
     
    jens, Sep 12, 2007
    #4
  5. Nirav

    jens Guest

    > Null is a wonderful statement. It's great for creating sections you
    > want to go back to (an inherant comment - of I'm not done yet) or
    > closing if then else groups.


    I guess I fail to see the point of adding two lines of code to every
    if statement to tell it to do nothing, it'll do nothing just fine on
    it its own. The suggestion of converting everything to std_logic is a
    good one.

    To answer the original question...

    Every signal assigned in a clocked process will create a flip-flip, so
    the first two examples will create 4 flip-flops, one each for q, qs,
    qbar and qsbar. Also, the outputs of some of those flip-flops will
    feed into the inputs of other flip-flops, which will delay signals in
    a way you didn't intend. Using variables instead of signals could
    have changed the behavior, but would still be needlessly complex. The
    third one is better with only two flip-flops (q and qbar). The key to
    create one SR flip-flop is to create only one flip-flop for q and
    derive qbar from q. Also, the logic is more complex than it needs to
    be, as it handles the illegal case separately and also assign outputs
    to input values rather than constants. As is usually the case, look
    for a simpler answer rather than a more complicated answer. Try
    something like this:

    process(clk)
    begin
    if rising_edge(clk) then
    if r = '1' then -- R wins in the illegal case of RS=11
    q <= '0';
    elsif s = '1' then
    q <= '1';
    end if;
    end if;
    end process;

    qbar <= not q;
     
    jens, Sep 12, 2007
    #5
  6. Nirav

    Andy Guest

    > Null is a wonderful statement. It's great for creating sections you
    > want to go back to (an inherant comment - of I'm not done yet) or
    > closing if then else groups.


    Your comments about NULL completing an if-else statement got my
    attention.

    Are you trying to avoid latches, by any chance?

    In clocked processes, if-then statements (without else) can result in
    clock enables, but not latches.

    Latches are caused by combinatorial processes that execute, but, under
    some circumstances do not assign a signal that is assigned under
    other circumstances. When the signal is not assigned, it is forced to
    "remember" its previous state, and a latch is inferred to do that. The
    common (and I believe outdated) admonition to always have an 'else'
    with every 'if-(elsif)-then' statement to avoid latches in
    combinatorial processes is not a reliable way to avoid latches.

    There are many more effective approaches to avoiding latches. First,
    avoid combinatorial processes, and you won't have any latches.

    If you have to use a combinatorial process (you probably really don't
    but if you think you have to), then provide default assignments to
    every signal driven by the process, right up front in the process,
    before any if/case/loop/etc. statements. By assigning everything a
    default value in one place, it makes it easier to review/audit the
    code, and verify that no latches will be produced. Then you don't have
    to worry about whether every if has an else (and contains all the
    assignments in needs), etc.

    For example, rather than write:

    if condition = '1' then
    a <= b;
    else
    a <= '0';
    end if;

    you could re-write it as:

    a <= '0'; -- default
    if condition = '1' then
    a <= b;
    end if;

    Of course, the advantages become more clear as the number of signals
    and conditions grows.

    Andy
     
    Andy, Sep 12, 2007
    #6
  7. Nirav

    beckjer Guest

    On Sep 11, 4:39 pm, jens <> wrote:
    > > Null is a wonderful statement. It's great for creating sections you
    > > want to go back to (an inherant comment - of I'm not done yet) or
    > > closing if then else groups.

    >
    > I guess I fail to see the point of adding two lines of code to every
    > if statement to tell it to do nothing, it'll do nothing just fine on
    > it its own. The suggestion of converting everything to std_logic is a
    > good one.
    >

    I meant closing case statements, not if statements (which would make
    it a useless comment). Not enough coffee the other day I guess.
     
    beckjer, Sep 12, 2007
    #7
  8. Nirav

    Andy Guest

    On Sep 12, 12:47 pm, beckjer <> wrote:
    > On Sep 11, 4:39 pm, jens <> wrote:> > Null is a wonderful statement. It's great for creating sections you
    > > > want to go back to (an inherant comment - of I'm not done yet) or
    > > > closing if then else groups.

    >
    > > I guess I fail to see the point of adding two lines of code to every
    > > if statement to tell it to do nothing, it'll do nothing just fine on
    > > it its own. The suggestion of converting everything to std_logic is a
    > > good one.

    >
    > I meant closing case statements, not if statements (which would make
    > it a useless comment). Not enough coffee the other day I guess.


    Oh,... nevermind.
    Disregard my comments regarding latch avoidance.

    Andy
     
    Andy, Sep 12, 2007
    #8
  9. beckjer wrote:

    > On Sep 11, 4:39 pm, jens <> wrote:
    >> > Null is a wonderful statement. It's great for creating sections you
    >> > want to go back to (an inherant comment - of I'm not done yet) or
    >> > closing if then else groups.

    >>
    >> I guess I fail to see the point of adding two lines of code to every
    >> if statement to tell it to do nothing, it'll do nothing just fine on
    >> it its own. The suggestion of converting everything to std_logic is a
    >> good one.
    >>

    > I meant closing case statements, not if statements (which would make
    > it a useless comment). Not enough coffee the other day I guess.


    Also there NULL makes no sense, in my opinion. A choice is allowed to be
    empty. Something along these lines is valid VHDL:

    case my_enum is
    when => e_plus
    a := b + c;
    when => e_min
    a := b - c;
    when others =>
    -- Do nothing (no NULL needed here)
    end case;

    --
    Paul Uiterlinden
    www.aimvalley.nl
    e-mail addres: remove the not.
     
    Paul Uiterlinden, Sep 13, 2007
    #9
  10. On Thu, 13 Sep 2007 23:08:46 +0200, Paul
    Uiterlinden <> wrote:

    > Something along these lines is valid VHDL:
    >
    > case my_enum is
    > when e_plus => -- JB fixed minor syntax error
    > a := b + c;
    > when e_min =>
    > a := b - c;
    > when others =>
    > -- Do nothing (no NULL needed here)
    > end case;


    Agreed, but... when I write control structures
    I typically write the WHOLE control structure
    and then start filling in the bodies. This
    prevents me from making silly nesting errors.
    So I might write:

    case my_enum is
    when e_plus =>
    when e_min =>
    when others =>
    end case;

    and then start adding code to each branch.

    A completely empty branch is a good clue that I
    forgot to do something. Consequently, I generally
    prefer to put an explicit "null;" in branches that
    I *intended* to be empty, to distinguish them from
    branches that I didn't get around to completing yet.

    Users of the kind of highly automated text editor
    that makes my brain explode will doubtless tell me
    there's a better way to write code... :)
    --
    Jonathan Bromley, Consultant

    DOULOS - Developing Design Know-how
    VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

    Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK

    http://www.MYCOMPANY.com

    The contents of this message may contain personal views which
    are not the views of Doulos Ltd., unless specifically stated.
     
    Jonathan Bromley, Sep 14, 2007
    #10
  11. Jonathan Bromley wrote:
    >
    > Agreed, but... when I write control structures
    > I typically write the WHOLE control structure
    > and then start filling in the bodies. This
    > prevents me from making silly nesting errors.
    > So I might write:
    >
    > case my_enum is
    > when e_plus =>
    > when e_min =>
    > when others =>
    > end case;
    >
    > and then start adding code to each branch.
    >
    > A completely empty branch is a good clue that I
    > forgot to do something. Consequently, I generally
    > prefer to put an explicit "null;" in branches that
    > I *intended* to be empty, to distinguish them from
    > branches that I didn't get around to completing yet.


    Sounds sensible. I guess I'm just used to put "-- Do nothing" where you
    put "null;". No real difference.

    And talking about "when others =>": in behavioral code I avoid using it all
    together. When I later add a member to the enumeration type, the compiler
    nicely puts it to my attention that I should add a choice to the case
    statement.

    > Users of the kind of highly automated text editor
    > that makes my brain explode will doubtless tell me
    > there's a better way to write code... :)


    Naaaah...

    --
    Paul Uiterlinden
    www.aimvalley.nl
    e-mail addres: remove the not.
     
    Paul Uiterlinden, Sep 14, 2007
    #11
  12. Nirav

    KJ Guest

    On Sep 14, 4:57 am, Paul Uiterlinden <> wrote:
    > Jonathan Bromley wrote:
    >
    > > Agreed, but... when I write control structures
    > > I typically write the WHOLE control structure
    > > and then start filling in the bodies. This
    > > prevents me from making silly nesting errors.
    > > So I might write:

    >
    > > case my_enum is
    > > when e_plus =>
    > > when e_min =>
    > > when others =>
    > > end case;

    >
    > > and then start adding code to each branch.

    >
    > > A completely empty branch is a good clue that I
    > > forgot to do something. Consequently, I generally
    > > prefer to put an explicit "null;" in branches that
    > > I *intended* to be empty, to distinguish them from
    > > branches that I didn't get around to completing yet.

    >
    > Sounds sensible. I guess I'm just used to put "-- Do nothing" where you
    > put "null;". No real difference.
    >
    > And talking about "when others =>": in behavioral code I avoid using it all
    > together. When I later add a member to the enumeration type, the compiler
    > nicely puts it to my attention that I should add a choice to the case
    > statement.
    >

    That's why I find it better to have something like the following as
    the default...

    when others =>
    assert FALSE report "OOPS! Unexpected value" severity ERROR;

    It's the wordiest of the bunch but also throws a sim exception when
    you add an enumeration member and don't update all of the places where
    you use it or, like Jon mentioned, you haven't gotten around to coding
    it yet.

    KJ
     
    KJ, Sep 14, 2007
    #12
  13. KJ wrote:
    >
    >> And talking about "when others =>": in behavioral code I avoid using it
    >> all together. When I later add a member to the enumeration type, the
    >> compiler nicely puts it to my attention that I should add a choice to the
    >> case statement.
    >>

    > That's why I find it better to have something like the following as
    > the default...
    >
    > when others =>
    > assert FALSE report "OOPS! Unexpected value" severity ERROR;


    Still, this work only in _simulation_, and you have to hit the condition. By
    not using the others choice at all, the error is already caught during
    _analysis_. That's what I like about not using the "when others". For
    synthesisable code however, the "when others" is needed most of the time,
    so I agree with your solution.

    --
    Paul Uiterlinden
    www.aimvalley.nl
    e-mail addres: remove the not.
     
    Paul Uiterlinden, Sep 14, 2007
    #13
  14. Nirav

    Andy Guest

    On Sep 14, 8:00 am, Paul Uiterlinden <> wrote:
    > KJ wrote:
    >
    > >> And talking about "when others =>": in behavioral code I avoid using it
    > >> all together. When I later add a member to the enumeration type, the
    > >> compiler nicely puts it to my attention that I should add a choice to the
    > >> case statement.

    >
    > > That's why I find it better to have something like the following as
    > > the default...

    >
    > > when others =>
    > > assert FALSE report "OOPS! Unexpected value" severity ERROR;

    >
    > Still, this work only in _simulation_, and you have to hit the condition. By
    > not using the others choice at all, the error is already caught during
    > _analysis_. That's what I like about not using the "when others". For
    > synthesisable code however, the "when others" is needed most of the time,
    > so I agree with your solution.
    >
    > --
    > Paul Uiterlindenwww.aimvalley.nl
    > e-mail addres: remove the not.


    Does any synthesis vendor interpret "when others =>", even if not
    reachable formally (i.e. all enumerated values are covered), as
    instructions for what to do in the case of an unused digital code? It
    would be nice to be able to use it to specify recovery from illegal
    states, but that is probably a whole 'nother can of worms.

    Andy
     
    Andy, Sep 14, 2007
    #14
  15. Nirav

    KJ Guest

    "Paul Uiterlinden" <> wrote in message
    news:46ea85d2$0$245$4all.nl...
    > KJ wrote:
    >>
    >>> And talking about "when others =>": in behavioral code I avoid using it
    >>> all together. When I later add a member to the enumeration type, the
    >>> compiler nicely puts it to my attention that I should add a choice to
    >>> the
    >>> case statement.
    >>>

    >> That's why I find it better to have something like the following as
    >> the default...
    >>
    >> when others =>
    >> assert FALSE report "OOPS! Unexpected value" severity ERROR;

    >
    > Still, this work only in _simulation_, and you have to hit the condition.
    > By
    > not using the others choice at all, the error is already caught during
    > _analysis_. That's what I like about not using the "when others". For
    > synthesisable code however, the "when others" is needed most of the time,
    > so I agree with your solution.


    When I was first posting it, I was thinking more along the lines of the
    situation that Jonathon was describing which was more for a placeholder for
    code that hasn't been written yet. Probably a better 'report' string for me
    to have put down would've been something like "This code hasn't been written
    yet" and use that type of assertion wherever needed (i.e. in other case
    values, 'if/elsif' statement branches, etc).

    Having said though, and after reading your post and Andy's reply got me to
    wondering again how is synthesis handling 'when others' now-a-daze. Back ~8
    years or so ago, whatever tool it was that I was using treated 'when others'
    a bit more seriously in that if the synthesizer turned an eight state
    enumeration into an 8 flip flop one hot that 'when others' would pick up the
    248 uncoded (and supposedly not reachable) states. At the time it seemed to
    be a perfectly reasonable thing to do in response to the 'when others' in
    order to force recovery from an illegal state...and if there was no 'when
    others' that no logic would be added to cover those conditions.

    Flash forward to modern tools and that no longer seems to be the case (as
    Andy queried). Now it takes a compiler option (at least with Quartus) to
    get an output that can only occur in 'illegal' states to be anything other
    than '0' which seems reasonable too and somewhat user controllable. But now
    there would seem to be no reason to code the 'when others' path explicitly
    since it will either get optomized away or handled by coding of each of the
    enumerated cases (depending on how the compiler setting is set). I haven't
    tried it yet with Synplify or ISE yet to see how to handle things there.

    Given all that I agree that your approach of simply coding all the
    enumerations and leaving out the 'when others' is the better approach since
    the compiler catches the problem earlier on and controlling how the
    synthesis operation generates logic has been moved to a compiler setting
    (not sure I 'like' that, but one needs to work with the tools).

    By the way, now that we each agree with the others approach....at the end of
    your post you said "For synthesisable code however, the "when others" is
    needed most of the time...", what tool and settings are you using that
    caused you to say that 'when others' is usually needed for synthesizable
    code?

    KJ
     
    KJ, Sep 15, 2007
    #15
  16. Andy wrote:
    > Does any synthesis vendor interpret "when others =>", even if not
    > reachable formally (i.e. all enumerated values are covered), as
    > instructions for what to do in the case of an unused digital code? It
    > would be nice to be able to use it to specify recovery from illegal
    > states, but that is probably a whole 'nother can of worms.


    As far as I know (I do not know much about synthesis, so somebody correct me
    if I'm talking nonsense) this is exactly the reason why the "others" choice
    must be used in synthesis.

    When you have an enumeration type with three members, and all these members
    are covered in a case statement (in an FSM, for example), the "others"
    choice is not needed in VHDL.

    However, for storing the FSM state there will be two flip-flops (assuming
    binary encoding), giving four possible states. If for some reason the FSM
    gets in the fourth (unused) state, it will be stuck forever without
    the "when others" choice.

    If the "when others" choice is present (with an assignment to one of the
    three vailid states), it will be honored by the synthesis tool and the FSM
    will recover. As far as I know this is at least valid for Quartus.

    Another approach would be to make sure that the enumeration type for the
    states of an FSM contains 2**N states.

    --
    Paul Uiterlinden
    www.aimvalley.nl
    e-mail addres: remove the not.
     
    Paul Uiterlinden, Sep 16, 2007
    #16
  17. > Andy wrote:
    >> Does any synthesis vendor interpret "when others =>", even if not
    >> reachable formally (i.e. all enumerated values are covered), as
    >> instructions for what to do in the case of an unused digital code? It
    >> would be nice to be able to use it to specify recovery from illegal
    >> states, but that is probably a whole 'nother can of worms.


    Yes it is.
    VHDL makes no assumption about how the enum is encoded,
    so such countermeasures are left to synthesis,
    and synthesis assumes that the hardware works.
    If any flop can change state at any time,
    there is really nothing that synthesis can do
    to fix this up.
    I use "when others =>" for a valid transition.

    Paul Uiterlinden wrote:
    > Another approach would be to make sure that the enumeration type for the
    > states of an FSM contains 2**N states.


    This assumes that I have made a synthesis
    setting for binary encoding.

    If flops can flop at random,
    state machines won't be the
    only problem in the design.

    -- Mike Treseler
     
    Mike Treseler, Sep 17, 2007
    #17
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John

    Flip Flop Synchronization

    John, Jan 3, 2004, in forum: VHDL
    Replies:
    3
    Views:
    9,793
    valentin tihomirov
    Jan 5, 2004
  2. eric
    Replies:
    15
    Views:
    1,458
  3. Weng Tianxiang

    IC area of flip-flop and SRAM?

    Weng Tianxiang, May 19, 2004, in forum: VHDL
    Replies:
    1
    Views:
    1,213
    Samuel Fuhrer
    May 23, 2004
  4. Weng Tianxiang

    Best book on a flip flop circuit

    Weng Tianxiang, May 19, 2004, in forum: VHDL
    Replies:
    1
    Views:
    827
    Mike Treseler
    May 20, 2004
  5. Jim

    Tristate Flip Flop

    Jim, Oct 27, 2004, in forum: VHDL
    Replies:
    12
    Views:
    4,909
    Ho. Li
    Nov 18, 2004
Loading...

Share This Page