MLRelated.com
Blogs

Thirty-year coding veteran vs AI

Leonard DieguezOctober 13, 2023

There has been a lot of discussion around chat GPT lately and some of my friends have started using GPT4 for coding. So in traditional Bob Pease vernacular “What’s all this ChatGPT stuff anyhow?”

I figured I was a very, very late adopter of the new fancy thing we used to refer to as a “cell phone”, and I shall not repeat that again. I was having motivation issues with producing a good architecture for a complex-valued constellation mapper. I posed the question to chat GPT3. To my surprise it came up with some good examples, while not 100% correct they were workable. On a separate issue, I had a bug in my code so I asked ChatGPT4 to code the same encoder and decoder pairs to see what it came up with. The results were very similar to what I coded but the simulated values were completely wrong. ChatGPT4 was having issues with the concept of blocking and non-blocking assignments.  Okay, not too bad, since I love to type so much, I figured I could potentially allow it to produce a framework or a template for me to edit. Save me some time on the old keyboard with these old joints. There are a lot of good things about getting older but one of them is not how the body treats you. Fast forward.

Would I rather argue with an AI or a new college graduate

I work with a couple of young engineers, one is a new college graduate (NCG) with, by definition, zero experience but lots of knowledge. Trying to get him to do anything useful can be challenging. I recently posed a couple of questions to ChatGPT4 and had very similar results. This article is about that interaction. So here goes.

Problem statement number 1

Me: in VHDL code a RGMII to GMII interface

GPT4: Certainly! The Reduced Gigabit Media Independent Interface (RGMII) is a simpler version of the Gigabit Media Independent Interface (GMII). Converting between these two interfaces would involve adjusting timing and dealing with the differences in signal count and behavior.

Here's a simple VHDL example of an RGMII to GMII converter. This is a very basic example and may need adjustments to suit a particular FPGA family or application.

(note from editor: emphasis on may need adjustments, I would probably say will need, or does need)

<code>-- vhdl
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity RGMII_to_GMII is
    Port (
        -- RGMII Inputs
        rgmii_rx_clk       : in  std_logic;
        rgmii_rxd          : in  std_logic_vector(3 downto 0);
        rgmii_rx_ctl       : in  std_logic;
        rgmii_rx_dv        : in  std_logic;
        
        -- GMII Outputs
        gmii_rx_clk        : out std_logic;
        gmii_rxd           : out std_logic_vector(7 downto 0);
        gmii_rx_er         : out std_logic;
        gmii_rx_dv         : out std_logic
    );
end RGMII_to_GMII;

architecture Behavioral of RGMII_to_GMII is
    signal rx_data_shift  : std_logic_vector(7 downto 0) := "00000000";
begin
    gmii_rx_clk <= rgmii_rx_clk;
    
    process(rgmii_rx_clk)
    begin
        if rising_edge(rgmii_rx_clk) then
            rx_data_shift <= rgmii_rxd & rx_data_shift(7 downto 1);
        end if;
    end process;
    
    gmii_rxd   <= rx_data_shift;
    gmii_rx_er <= rgmii_rx_ctl;
    gmii_rx_dv <= rgmii_rx_dv;

end Behavioral;
</code>

 This code is a basic illustration. Some points to consider:

Clock Domains: In real-world applications, RGMII and GMII might operate in different clock domains. If this is the case, you will need synchronization mechanisms, such as FIFOs or dual-clock FIFOs, to bridge between them.

Data Valid (DV) Handling: The GMII data valid might need additional logic if the RGMII interface uses it differently.

Timing Requirements: Real RGMII interfaces often have specific timing requirements for the data signals relative to the clock, often implemented using delays. Depending on your FPGA family, these might need to be adjusted or implemented using specific resources like IDELAY for Xilinx FPGAs.

(at this point I would ask the audience, can you spot the issues here?)

Clarifying question to GPT4

Me: RGMII is normally a DDR interface where is the DDR function in the above code?

ChatGPT4: Apologies for the oversight. You're right: RGMII utilizes double data rate (DDR) signaling on the data and control signals. Let's add that aspect to the conversion.

(wow, how polite NCG would still be arguing how the above code is correct)

Given the DDR nature of the RGMII interface, on every clock edge (both rising and falling), there is valid data. This means for every GMII clock, you'll capture data from both the rising and falling edge of the RGMII clock.

Here's a revised version of the RGMII to GMII converter with DDR implementation:

<code>-- vhdl
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity RGMII_to_GMII is
    Port (
        -- RGMII Inputs
        rgmii_rx_clk       : in  std_logic;
        rgmii_rxd          : in  std_logic_vector(3 downto 0);
        rgmii_rx_ctl       : in  std_logic;
        
        -- GMII Outputs
        gmii_rx_clk        : out std_logic;
        gmii_rxd           : out std_logic_vector(7 downto 0);
        gmii_rx_er         : out std_logic;
        gmii_rx_dv         : out std_logic
    );
end RGMII_to_GMII;

architecture Behavioral of RGMII_to_GMII is
    signal rgmii_rx_clk_inv : std_logic;
    signal prev_rgmii_rxd   : std_logic_vector(3 downto 0);
    signal prev_rgmii_rx_ctl: std_logic;
begin
    -- Invert RGMII clock for falling edge detection
    rgmii_rx_clk_inv <= not rgmii_rx_clk;

    gmii_rx_clk <= rgmii_rx_clk;

    process(rgmii_rx_clk, rgmii_rx_clk_inv)
    begin
        if rising_edge(rgmii_rx_clk) then
            gmii_rxd(7 downto 4) <= rgmii_rxd;
            gmii_rxd(3 downto 0) <= prev_rgmii_rxd;
            gmii_rx_er          <= rgmii_rx_ctl;
        elsif rising_edge(rgmii_rx_clk_inv) then
            prev_rgmii_rxd      <= rgmii_rxd;
            prev_rgmii_rx_ctl   <= rgmii_rx_ctl;
        end if;
    end process;

    gmii_rx_dv <= '1'; -- Assuming always valid for this example, adjust as necessary.

end Behavioral;
</code>

OK so ChatGPT realizes that there is a DDR issue. What it does not explain is that the rising edge of the RGMII clock represents the lower nibble of the data byte and the falling edge of the RGMII clock represents the upper nibble of the GMII data byte. Also does not explain that RGMII ctl is a multiplexed signal of error and enable signals.

Problem statement number 2

Here is where things become interesting, I will not bore you will all the back and forth.

Me: If I wanted the code to 4 x oversample the RGMII interface and select the best sample how would I do that?

ChatGPT4: Oversampling the RGMII interface requires running a sampling clock at a multiple (in this case, 4x) of the RGMII clock. By doing so, you can sample the data four times every RGMII clock cycle and then select the best sample among the four.

A common approach to selecting the "best" sample is to use a voting mechanism: If the majority of samples within a bit period have a certain value, that value is considered the accurate representation of the data.

Here's a basic example of a 4x oversampled RGMII to GMII converter using a majority voting mechanism:

<code>--vhdl
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity RGMII_to_GMII_oversampled is
    Port (
        -- RGMII Inputs
        rgmii_rx_clk       : in  std_logic;
        rgmii_rxd          : in  std_logic_vector(3 downto 0);
        rgmii_rx_ctl       : in  std_logic;
        
        -- GMII Outputs
        gmii_rx_clk        : out std_logic;
        gmii_rxd           : out std_logic_vector(7 downto 0);
        gmii_rx_er         : out std_logic;
        gmii_rx_dv         : out std_logic;
        
        -- 4x Oversampling Clock
        oversample_clk     : in  std_logic
    );
end RGMII_to_GMII_oversampled;

architecture Behavioral of RGMII_to_GMII_oversampled is
    signal sample_data : std_logic_vector(3 downto 0) := "0000";
    signal sample_count : integer := 0;
    
    function majority_vote(data: std_logic_vector) return std_logic is
    begin
        if data'length - 2 < (data'length / 2) then
            return '0';
        else
            return '1';
        end if;
    end function;
    
begin
    gmii_rx_clk <= rgmii_rx_clk;

    process(oversample_clk)
    begin
        if rising_edge(oversample_clk) then
            sample_data <= rgmii_rxd & sample_data(sample_data'length-1 downto 1);
            sample_count <= sample_count + 1;
            
            if sample_count = 4 then
                gmii_rxd(7 downto 4) <= majority_vote(sample_data);
                gmii_rxd(3 downto 0) <= majority_vote(sample_data);
                gmii_rx_er          <= majority_vote(rgmii_rx_ctl);
                sample_count <= 0;
            end if;
        end if;
    end process;

    gmii_rx_dv <= '1'; -- Assuming always valid for this example, adjust as necessary.

end Behavioral;</code>

Here are some important things to consider:

Majority Vote Mechanism: The function majority_vote currently returns '1' if more than half the samples are '1' and '0' otherwise. This might need adjustments based on the exact requirements.

4x Clock Source: The oversample_clk is assumed to be 4 times the frequency of the RGMII clock and phase-aligned to get meaningful samples. Adjustments might be necessary depending on your clock generation mechanism.

Clock Domains: Handling multiple clock domains can introduce metastability issues. Care should be taken to handle data transfer between different clock domains, such as using synchronizer flip-flops.

Clock Skew: Clock skew between rgmii_rx_clk and oversample_clk can affect sampling, especially when the clocks aren't generated from the same source.

Sample Count Reset: The sample count resets after every four samples, assuming each RGMII bit lasts for exactly four oversample clock cycles.

 (Not even sure where to start on this one but again where is the DDR interface? Also Majority vote has issues as a solution here.)

The next question is:

Me: in the last code example is the RGMII interface a DDR interface?

ChatGPT: You're right, my apologies for the oversight. The previous code does not handle the DDR nature of the RGMII interface.

(What? You just admitted 2 questions ago that RGMII has a DDR interface and you are making the exact same mistake?)

Given the DDR nature of the RGMII, if you're oversampling at 4x the RGMII clock rate, you'll actually be sampling each bit 8 times (4 samples on the rising edge and 4 on the falling edge).

Let's integrate this DDR aspect into the RGMII to GMII conversion while oversampling.

(At this point it produces code, not including it here. I strongly suggest looking at the code above)

Next question.

Me: how does the majority_vote function in the code above

The majority_vote function in the provided code is intended to determine the most common value within a set of sampled bits. However, there's an oversight in the code I provided earlier. The function doesn't actually perform a majority vote; instead, it checks if the number of '1' bits is above a threshold.

Let's correct the majority_vote function to properly compute the majority for the set of sampled bits.

(more Chat GPT code, but it admits to the error)

Next question

Me: in the code you provided earlier if it checks if the number of '1' bits is above a threshold how does it work

ChatGPT: You're correct. Let's discuss the erroneous majority_vote function I provided in the earlier code:

<code>-- Vhdl:
function majority_vote(data: std_logic_vector) return std_logic is
begin
    if data'length - 4 < (data'length / 2) then
        return '0';
    else
        return '1';
    end if;
end function;</code>

This function will always evaluate to '1' since the condition data'length - 4 < (data'length / 2) will always be true. This is because subtracting 4 from the length will always produce a value that is less than half the length of the vector data.

(At this point it has made a double mistake first GPT4 said that the function was a majority vote function, then it said the code would check the number of ‘1’s over a threshold, then it says that it does not even do that, the function always returns true.)

This function was clearly flawed, and it would not correctly vote for the majority bit. My apologies for the oversight.

The correct implementation, which I provided in the subsequent message, counts the number of '1's in the vector and returns '1' if they constitute a majority.

Thank you for pointing it out. Always ensure that your code, especially when dealing with such critical components, is thoroughly verified through simulations and potentially other forms of validation.

(Yes, especially if you are putting a lander on the moon)

I would probably not use majority vote to solve the original question. It has many issues with determining of the oversampled bit it is a "1" or "0". I did ask it to determine the where in the serialized oversampled stream the transition edge was. There was much back and forth "arguments" trying to correct the code and asking clarifying questions. Each time it would find there was an issue and try to correct it with not-so-good results.

Summary

Enough about chat GPT, I feel that my job is safe for just a bit longer. I may be possible for me to retire with dignity. I asked chat GPT4 a variety of questions. Some complex and some easy, some with fine nuances. Most all the answers had issues but they provided clues to how I may solve issues or where to look for debugging code. At a minimum it is a tool that can help. Working with chat GPT reminds me of the saying "Garbage in, Garbage out".

While I was working on one of the issues one of the new engineers came by and recognized that I had a chat GPT window up. His statement was that he loved using it. My thoughts were “that explains some of your code” and the other was “I hope you are checking your work”.

A friend of mine said to me yesterday that she saw a blog post of some code that solved some issue and in the post it stated that the code was developed by an AI and untested. When you realize that there is a bunch of bad code posted on the internet and that AI’s are scraping the internet to learn from it, there should be no wonder that some of the results are as they are. So in closing, your mileage may vary when using these tools. Sometimes correcting an AI can be satisfying and always, always check and verify your work. 



To post reply to a comment, click on the 'reply' button attached to each comment. To post a new comment (not a reply to a comment) check out the 'Write a Comment' tab at the top of the comments.

Please login (on the right) if you already have an account on this platform.

Otherwise, please use this form to register (free) an join one of the largest online community for Electrical/Embedded/DSP/FPGA/ML engineers: