จะแปลงจำนวนเต็มใหญ่เป็นจำนวนเต็มเล็กใน vhdl ได้อย่างไร?

ฉันมีรหัส VHDL ที่ฉันพยายามคูณค่าพิกเซล ฉันมีเอนทิตีดังต่อไปนี้:

entity xGradient is

port(
    clk : in std_logic;
    x11, x12, x13, x21, x22, x23, x31, x32, x33 : in integer range 0 to 255;
    gradientInX : out integer range 0 to 255
);

end xGradient;

ฉันดำเนินการต่อไปนี้กับสิ่งเหล่านี้:

gradientInX <= x11 + 2*x21 + x31 - x13 - 2*x23 - x33;

ปัญหาที่คุณอาจสังเกตเห็นคือค่าที่ได้รับจากการดำเนินการเกินช่วงของค่าที่เป็นไปได้ที่จำนวนเต็มเอาต์พุตของฉันสามารถเป็นได้ การจำลองของฉันล้มเหลวเมื่อสิ่งนี้เกิดขึ้น ฉันไม่รู้ว่าคำที่ถูกต้องสำหรับสิ่งที่ฉันพยายามทำอยู่ ดังนั้นจึงดูเหมือนจะไม่สามารถหาวิธีแก้ไขปัญหานี้ได้ และมันทำให้ฉันแทบบ้า โดยพื้นฐานแล้วฉันแค่ต้องการตัดทอนหรือลดขนาดของเอาต์พุตเพื่อให้แน่ใจว่าพอดีกับพอร์ตเอาท์พุตของการไล่ระดับสี InX ฉันลองใช้บล็อกกระบวนการเช่นนี้:

-- declared signals
signal gradientMem: integer;

--beginning of my architecture
begin 

SobelOperator : process(gradientMem)

begin
    gradientMem <= x11 + 2*x21 + x31 - x13 - 2*x23 - x33;

    if (gradientMem > 255) then
        gradientMem <= 255;
    elsif (gradientMem < 0) then
        gradientMem <= 0;
    end if;

end process SobelOperator;

จากนั้นกำหนดไล่ระดับMemให้กับgradientInXแต่มันไม่ทำงานด้วยเหตุผลบางประการ ความช่วยเหลือใด ๆ ที่จะได้รับการชื่นชมจริงๆ หมายเหตุ: ฉันไม่ได้รวมโค้ด VHDL ทั้งหมดเนื่องจากฉันคิดว่ามันจะยาวโดยไม่จำเป็น ข้อความแสดงข้อผิดพลาดที่ฉันได้รับคือสัญญาณผลลัพธ์จากการดำเนินการอยู่นอกช่วง (เนื่องจากค่าผลลัพธ์เป็นลบและเอาต์พุตมีช่วงเพียง 0 ถึง 255)

แมทธิว


person Omnomnious    schedule 09.04.2017    source แหล่งที่มา
comment
คำถามของคุณขาดสองส่วนสำคัญ: 1) การประกาศ gradientMen และ 2) ข้อความแสดงข้อผิดพลาด VHDL ตรวจสอบขอบเขตของช่วงที่ได้รับมอบหมาย คุณต้องการสร้างเลขคณิตความอิ่มตัว ดังนั้นกำหนด gradientMem ด้วยช่วงที่ใหญ่กว่า   -  person Paebbels    schedule 09.04.2017
comment
ฉันเพิ่งแก้ไขเพื่อรวมสิ่งเหล่านั้น ฉันเดาว่าปัญหาหลักของฉันคือรายการความลับไม่ถูกต้อง ฉันยังสงสัยด้วยว่า VHDL มีการดำเนินการเฉพาะจำนวนเต็มซึ่งบังคับให้ผลลัพธ์อยู่ในช่วงใดช่วงหนึ่ง แต่ฉันเดาว่าไม่มีฟังก์ชันหรือการดำเนินการดังกล่าว ดังนั้นฉันจึงต้องนำไปใช้ด้วยตัวเอง ไม่ว่าจะด้วยวิธีใดก็ตามดูเหมือนว่าปัญหาของฉันก็ได้รับการแก้ไขแล้ว ขอบคุณสำหรับการตอบกลับของคุณและอย่าลังเลที่จะเพิ่มสิ่งอื่นใด   -  person Omnomnious    schedule 09.04.2017


คำตอบ (3)


นี่เป็นหนึ่งในไม่กี่สถานการณ์ที่คุณควรใช้ตัวแปรแทนสัญญาณ

SobelOperator : process(x11, x21, x31, x13, x23, x33)
    variable gradientMem : integer;
begin
    gradientMem := x11 + 2*x21 + x31 - x13 - 2*x23 - x33;

    if (gradientMem > 255) then
        gradientMem := 255;
    elsif (gradientMem < 0) then
        gradientMem := 0;
    end if;
    gradientInX <= gradientMem;
end process SobelOperator;

อย่างไรก็ตาม การดำเนินการนี้เรียกว่า การตัดภาพ

หากคุณต้องการ ตัดทอน กระบวนการควรเขียนดังนี้:

SobelOperator : process(x11, x21, x31, x13, x23, x33)
    variable gradientMem : integer;
begin
    gradientMem := x11 + 2*x21 + x31 - x13 - 2*x23 - x33;

    gradientInX <= gradientMem mod 256;
end process SobelOperator;
person JHBonarius    schedule 10.04.2017

ดังที่ @Paebbels แนะนำในความคิดเห็น ส่วนใหญ่แล้วช่วงของ gradientMem จะไม่เพียงพอที่จะจัดการเอาต์พุตของการดำเนินการ

สิ่งที่ควรทราบ: ในการดำเนินการจำนวนเต็ม ช่วงกลาง (ส่วนใหญ่) ถือเป็นลายเซ็น 32b และช่วงจะถูกตรวจสอบในงานมอบหมาย สิ่งนี้ให้อะไรค่อนข้างมากในการคาดเดาเกี่ยวกับเครื่องมือสังเคราะห์ และอาจทำให้การออกแบบมีขนาดใหญ่กว่าความเหมาะสมมาก

เพื่อแก้ไขปัญหานี้ ieee.numeric_std.all จึงใช้สำหรับประเภทและการดำเนินการที่ไม่ได้ลงนามและลงนาม ซึ่งให้การควบคุมที่สมบูรณ์สำหรับความยาวเวกเตอร์ระดับกลาง นอกจากนี้ยังบังคับให้คุณทำความเข้าใจกับสิ่งที่เกิดขึ้น นอกจากนี้ การลบ การคูณ ฯลฯ ซึ่งโดยทั่วไปจะช่วยในการออกแบบ RTL

อย่างไรก็ตาม สิ่งที่ควรทราบก็คือ ในรูปแบบเวกเตอร์ การดำเนินการจะถูกประเมินเป็นคู่โดยใช้ค่าที่ยาวที่สุดของทั้งสองเป็นความยาวเวกเตอร์ระดับกลาง

ตัวอย่างเช่น:

  process
    variable i1      : integer range 0 to 15 := 15;
    variable i2      : integer range 0 to 15 := 9;
    variable i3      : integer range 0 to 15 := 11;
    variable i4      : integer range 0 to 31 := 2;
    variable iSum    : integer range 0 to 63;
    variable u1      : unsigned(3 downto 0) := to_unsigned(15,4);
    variable u2      : unsigned(3 downto 0) := to_unsigned(9,4);
    variable u3      : unsigned(3 downto 0) := to_unsigned(11,4);
    variable u4      : unsigned(5 downto 0) := to_unsigned(2,6);
    variable uSum    : unsigned(5 downto 0);
  begin
    iSum := i1 + i2 + i3 + i4;
    uSum := u1 + u2 + u3 + u4;
    write(output, "int: " & to_string(iSum) & lf &
                  "us : " & to_string(to_integer(uSum)) & lf);
    wait;
  end process;

ให้:

# int: 37
# us : 5

การใช้วงเล็บช่วยแก้ปัญหา:

uSum := (u1 + (u2 + (u3 + u4)));
person FritzDC    schedule 10.04.2017

มีข้อผิดพลาดอยู่ในรายการความลับของกระบวนการของคุณ SobelOperator : process(gradientMem) ในที่นี้ต้องเป็นสัญญาณที่มีอิทธิพลต่อสัญญาณผลลัพธ์ กล่าวอีกนัยหนึ่งนี่คือรายการสัญญาณที่กระบวนการมีความอ่อนไหว ดังนั้นควรมี x11, x21, x31, x13, x23 และ x33 เช่น SobelOperator : process(x11, x21, x31, x13, x23, x33)

person Roman    schedule 09.04.2017
comment
เฮ้ ขอบคุณสำหรับการตอบกลับของคุณ! ใช่แล้ว ฉันสังเกตเห็นสิ่งนั้นจริง ๆ ขณะที่เขียนคำถามของฉัน ฉันจะพยายามแก้ไขและดูว่าเกิดอะไรขึ้น ฉันยังต้องการทราบว่ามีฟังก์ชันในไลบรารีตัวเลขหรือไม่ เช่น ที่จะตัดทอนสัญญาณจำนวนเต็มจากช่วงหนึ่งไปยังช่วงที่เล็กกว่า - person Omnomnious; 09.04.2017
comment
สำหรับการตัดทอนเอาต์พุตคุณสามารถใช้ประเภท std_logic_vector และรับจากบัสเพียงบิตที่คุณต้องการแล้วแปลงเป็นจำนวนเต็มหากคุณต้องการเอาต์พุตเป็นประเภท integer - person Roman; 09.04.2017
comment
ใช่ รายการความไวผิด แต่ไม่ใช่สาเหตุของปัญหาระยะของเขา... - person Paebbels; 09.04.2017
comment
@Paebbles ฉันไม่สามารถเพิ่มความคิดเห็นได้เนื่องจากฉันไม่มีชื่อเสียงเพียงพอดังนั้นฉันจึงโพสต์เป็นคำตอบ หรือฉันควรทำอย่างไร? - person Roman; 09.04.2017
comment
การเขียนคำตอบเป็นเรื่องปกติ แต่การเปลี่ยนแปลงเพียงรายการความไวยังไม่เพียงพอ มันไม่ได้แก้ไขข้อผิดพลาดนอกขอบเขต - person Paebbels; 10.04.2017