Câu hỏi phỏng vấn VHDL - phát hiện nếu một số có thể được chia cho 5 mà không có phần còn lại


24

Tôi thấy một câu hỏi phỏng vấn hay cho VHDL - xây dựng một hệ thống nhận số và phát hiện nếu nó có thể được chia cho 5 mà không có phần còn lại. Tôi đã cố gắng giải quyết điều đó bằng một máy trạng thái (tôi cho rằng họ không muốn bạn sử dụng mod hoặc rem ) và trong khi tôi đã thành công ban đầu (các số như 5, 10, 15 và các số như 20, 40, 80 đã hoạt động ), các số khác như 130, 75 và không thành công đối với tôi.

Tôi sẽ cho xem máy trạng thái của mình nhưng nó là một mớ hỗn độn (nó không phải là mã, nó là bản vẽ), và như tôi đã nói, thậm chí không hoạt động.

Về cơ bản những gì tôi đã cố gắng làm là viết ra các số nhị phân chia hết cho 5 và xây dựng một máy trạng thái sẽ hoạt động cho chúng.

Tôi sẽ rất vui nếu bạn có thể chỉ cho tôi cách giải quyết vấn đề này và cách suy nghĩ khi đối mặt với điều gì đó như thế này.

Cảm ơn bạn!


Bạn có nghĩa là một triển khai phần cứng (tổng hợp), không chỉ là mã để kiểm tra nếu một số nguyên bằng số chia hết cho 5 (ví dụ: đối với testbench).
smci

@smci Tôi thực sự đã yêu cầu một sơ đồ / bản vẽ của một máy trạng thái, nhưng một mã của máy trạng thái đó sẽ không bị tổn thương. Dave Tweed đã trả lời câu hỏi hoàn hảo mặc dù.
Eran

sau đó tôi sẽ đặt lại tên đó * "Câu hỏi phỏng vấn VHDL - cct để phát hiện nếu ..."
smci 16/12/17

Trả lời ở đây bằng egreg math.stackexchange.com/a/2569882/213607 có thể mang lại một số cảm hứng cho một cách tiếp cận song song hơn.
toán học

Câu trả lời:


37

Thực hiện một thao tác còn lại trong thời trang nối tiếp thực sự khá dễ dàng. Giả định chính là dữ liệu xuất hiện trong MSB-đầu tiên nếu nó nối tiếp. Bạn chỉ cần N trạng thái để tính toán một modulo còn lại. Bắt đầu ở trạng thái "0" và nếu bạn kết thúc ở trạng thái "0" sau bit cuối cùng (không quan trọng là có bao nhiêu bit), phần còn lại là số không.

sơ đồ

mô phỏng mạch này - Sơ đồ được tạo bằng CircuitLab

Hãy suy nghĩ về cách bạn thực hiện phân chia dài nếu điều duy nhất bạn cần theo dõi là phần còn lại:

process (clk)
begin
  if rising_edge(clk) then
    if reset = 1 then
      state <= 0;
    else
      if (state & din) >= N then
        state <= (state & din) - N;
      else
        state <= state & din;
      end if;
    end if;
  end if;
end process;

6
Ồ, tôi thấy rằng nó hoạt động nhưng bạn có thể giải thích làm thế nào bạn đến với máy trạng thái? Điểm bắt đầu là gì? Tôi chưa bao giờ thấy điều này được thực hiện trước khi tôi chỉ tò mò logic là gì với cách làm thế nào để đưa ra nó?
zoder

7
Biểu đồ trạng thái chỉ là những gì bạn nhận được từ mã VHDL cho trường hợp cụ thể là N = 5. Nói cách khác, nếu trạng thái đại diện cho phần còn lại hiện tại, trạng thái tiếp theo là những gì bạn nhận được khi bạn dịch chuyển trạng thái sang trái một bit, thêm bit đầu vào vào nó và sau đó trừ 5 nếu cần.
Dave Tweed

3
Điều này nếu đẹp, tôi sẽ thực sự ấn tượng nếu ai đó tự nghĩ ra điều này trong một cuộc phỏng vấn. Và sau đó tôi vui vẻ yêu cầu họ nhận xét về kết quả tổng hợp sẽ khác như thế nào so với việc chỉ sử dụng toán tử rem để xử lý một vectơ đầy đủ trong mỗi chu kỳ đồng hồ.
Casperrw

8
@zoder Các trạng thái là dư lượng mod 5; mũi tên 0 chỉ vào 2n mod 5và mũi tên 1 chỉ vào (2n + 1) mod 5.
hobbs 16/12/17

2
Bạn có thể thêm các tờ khai của state, dinNmã của bạn?
mkrieger1

15

Bạn cũng có thể thiết kế một máy trạng thái nếu dữ liệu đến trước LSB:

Một đại diện đồ họa của DFA như được mô tả ở cuối câu trả lời này trong phần phụ lục.

Sự tồn tại của một máy tự động hữu hạn xác định (DFA) trực tiếp tiếp theo từ câu trả lời khác , mô tả DFA cho MSB-đầu tiên. Bởi vì các ngôn ngữ được DFA chấp nhận là ngôn ngữ thông thường và ngôn ngữ thông thường được biết là bị đóng dưới sự đảo ngược (ví dụ: xem ở đây ), phải có một DFA chấp nhận ngôn ngữ sau:

.L={w{0,1}| reverse(w)10 is divisible by 5}

Xây dựng

  1. Sao chép DFA đầu tiên của MSB từ câu trả lời của Dave Tweed . Tôi đã sử dụng công cụ tự động JFLAP cho điều đó.

  2. Áp dụng thuật toán chuyển đổi rõ ràng cho các đảo ngược DFA, ví dụ như được mô tả trên CS.SE: Thiết kế một DFA và đảo ngược của nó .
    Bạn có thể thấy kết quả (chưa được tối ưu hóa) của bước này trong bản sửa đổi cũ của câu trả lời này.




  3. q0q1

Thật vậy, automaton kết quả cho câu trả lời đúng:

Bảng có hai cột "Đầu vào" và "Kết quả" liệt kê cho dù số lượng khác nhau dẫn đến "Chấp nhận" hoặc "Từ chối".


Arev5=(Q,Σ,δ,q0,F)Q={q0,q1,q2,q3,q4}Σ={0,1}F={q0}δ

δ(q0,0)=q0,δ(q0,1)=q1δ(q1,0)=q4,δ(q1,1)=q3δ(q2,0)=q1,δ(q2,1)=q2δ(q3,0)=q2,δ(q3,1)=q4δ(q4,0)=q3,δ(q4,1)=q0


Nếu bạn gặp khó khăn khi đảo ngược DFA, bạn cũng có thể đảo ngược phương trình: Thay vì đầu vào new_state = state * 2 +, bạn có thể sử dụng (new_state - input) / 2 = state, sau đó trao đổi trạng thái và new_state. DFA cho phương trình mới sẽ giải quyết vấn đề đầu tiên LSB.
Mắt

Tại sao q3 & q4 được dán nhãn như vậy & không phải ngược lại? Hoán đổi nhãn q3 & q4 và máy thực hiện thuật toán "một nửa (mod 5) và thêm bit đầu vào".
Rosie F

2
@RosieF: Cụm từ "một nửa (mod 5)" có lẽ có thể sử dụng một số giải thích thêm cho những người không quen thuộc với toán học rời rạc. Việc phân chia trong bối cảnh này đòi hỏi phải thêm bất kỳ bội số nào của cơ sở để làm cho số chia đều, vì vậy 3/2 (mod 5) sẽ là (3 + 5) / 2, tức là 4.
supercat

7

Một cách để đưa ra máy trạng thái (MSB đầu tiên) như sau:

  1. Số lượng nhận được cho đến nay là N. Giả sử bạn biết phần còn lại M = N mod 5.

  2. Có một chút mới đến và giá trị mới bây giờ N' = N*2 + b.

  3. Còn lại là mới M' = (N*2 + b) mod 5 = (M*2 + b) mod 5.

Điều này là đủ dễ dàng để lập bảng bằng tay:

    M b | M '
------------------
    0 0 | 0
    1 0 | 2
    2 0 | 4
    3 0 | 1
    4 0 | 3
    0 1 | 1
    1 1 | 3
    2 1 | 0
    3 1 | 2
    4 1 | 4

Điều này phù hợp với máy trạng thái trong câu trả lời của Dave Tweed.


5

Một người hy vọng câu hỏi phỏng vấn là về cách bạn sẽ giải quyết vấn đề, chứ không phải là vấn đề của VHDL hay Verilog. Các chi tiết ngôn ngữ rất đơn giản khi bạn có một thuật toán.

S=0S(2S+d) mod 5 SS,dS=0,,4

S=0,k=0S(S+2kd) mod 5,kk+1k24=1 mod 5S(S+2kd) mod 5,k(k+1) mod 4S,k,d(S,k)S=0,,4k=0,,3


3

Tùy thuộc vào những gì VHDL đang được viết, bạn có thể muốn thực hiện một cách tiếp cận mô tả nó như là một phép tính trực tiếp, kết hợp. Nhận được một số có thể có nghĩa là toàn bộ số sẽ nằm trong một thanh ghi cho một chu kỳ đồng hồ.

Ví dụ, bạn có thể ghi lại mod 5 của giá trị mà mỗi bit đại diện, cộng chúng lại với nhau và sau đó lặp lại quy trình cho đến khi bạn còn lại một cái gì đó nhỏ hơn 5. Thực hiện kết hợp điều này cho tất cả các bước giảm, hoặc sử dụng lại logic cho một số chu kỳ nhỏ.

Nhưng nếu bạn sử dụng toán tử rem VHDL, đó có thể là câu trả lời đúng. Giả sử công ty có các công cụ tổng hợp tốt, điều đó sẽ cung cấp cho bạn một triển khai khá hiệu quả - nhiều hơn một chút so với các giải pháp máy nhà nước có lẽ, nhưng thông lượng đầy đủ và do đó có thể là năng lượng tốt cho mỗi tính toán. Đó là tùy chọn sẽ tốn ít thời gian nhất để thực hiện và do đó có lẽ là ít tiền nhất cho nhà tuyển dụng!

Công bằng mà nói, có lẽ đó không phải là câu trả lời mà họ đang tìm kiếm với một câu hỏi như vậy - nhưng đó cũng là cơ hội để thể hiện bất kỳ trải nghiệm thiết kế thực tế nào.


3

Nếu số được trình bày trong các khối lớn hơn một bit, có thể hữu ích khi sử dụng một số tính toán song song để tính toán dư lượng mod 15, với một điều kiện là tính toán có thể mang lại 15 chính xác nếu dư lượng bằng không. Một cách đơn giản để tính toán dư lượng mod-15 là quan sát rằng với bất kỳ giá trị nào của N> = 1, việc thêm các bit 4N ngoài cùng bên trái vào phần của một số vượt quá sẽ mang lại giá trị phù hợp với mod ban đầu 15. Điều này cho phép vấn đề được chia nhỏ theo nhiều cách khác nhau tùy thuộc vào các tài nguyên có sẵn.

Ví dụ: nếu một bắt đầu bằng giá trị 32 bit, có thể được coi là tám giá trị 4 bit. Chúng có thể được thêm vào cùng nhau theo cặp để mang lại bốn giá trị 5 bit, lần lượt có thể được kết hợp thành hai giá trị 6 bit hoặc một giá trị 7 bit. Thêm ba bit trên của giá trị 7 bit đó vào 4 bit thấp hơn sẽ mang lại giá trị 5 bit nhiều nhất là 21. Do đó, người ta có thể xác định xem giá trị ban đầu có phải là bội số của 5 hay không bằng cách quan sát xem giá trị cuối cùng có phải là một trong 0, 5, 10, 15 hoặc 20.


... Hoặc bạn có thể sử dụng các bộ cộng 4 bit trong suốt và chỉ cần đảm bảo rằng mỗi bộ mang trở thành vật mang cho bộ cộng sau trong mạch. Sau ba lớp thêm, bạn có một kết quả 4 bit và bốn mang chưa được sử dụng. Thêm ba trong số các vật mang với nhau song song với phép cộng 4 bit cuối cùng và cộng tổng của chúng vào kết quả với lần mang cuối cùng là mang theo. Điều này mang lại nhiều nhất là 19, vì vậy bạn không cần phải khớp vào ngày 20 sau đó.
Henning Makholm

@HenningMakholm: Có nhiều cách sắp xếp các bộ cộng để mang lại kết quả mong muốn. Cách tiếp cận nào tốt hơn trong một tình huống nhất định có thể sẽ phụ thuộc vào các vấn đề định tuyến hoặc sử dụng tài nguyên cụ thể của dự án. Một mẹo khác là sử dụng các bộ cộng mang theo, nhưng khai thác thực tế là bit trên cùng của đầu ra được dịch chuyển có thể được chuyển xuống dưới cùng. Do đó, một lớp có thể biến 8 đầu vào thành 6, rồi 6 thành 4, rồi 4 thành 3 và 3 thành 2. Một đầu ra của mỗi lớp chỉ đơn giản là cổng AND và một cổng XOR khác, vì vậy thời gian lan truyền để xuống cặp giá trị 4 bit cho ...
supercat

... một và chỉ mang chuỗi sẽ là bốn cổng xor. Còn về việc tốt hơn là lấy đầu ra dưới 19, hay tốt hơn là kiểm tra 20 như là dư lượng có thể, điều đó có thể phụ thuộc vào mức độ sẵn có và sử dụng tài nguyên. Cho một số không quá 30, thêm số nybble trên và dưới sẽ mang lại giá trị tối đa là 15 (16 + 14-> 1 + 14 hoặc 0 + 15-> 0 + 15), nhưng thêm rõ ràng kiểm tra một số hoặc tất cả (20, 25, 30) có thể rẻ hơn.
supercat

2

Tôi không thể nhớ VHDL của mình, nhưng đây là bản phác thảo ý tưởng đầu tiên xuất hiện:

Các chữ số cuối cùng (trong cơ sở 10) của các lũy thừa đầu tiên của hai là 1, 2, 4, 8, 6, 2, ... và chu kỳ lặp lại. Do đó, phần còn lại của mod 5 sức mạnh của hai là 1, 2, 4, 3, ....

Sử dụng điều đó, chúng ta có thể thay đổi bit từ LSB và tích lũy mod 5 còn lại tương ứng với vị trí bất cứ khi nào 1nhìn thấy một bit. Thực hiện mod 5 tích lũy, và nó đủ để kiểm tra xem tổng có bằng không ở cuối không.


1

Chúng ta có thể sử dụng ý tưởng từ câu trả lời ở đây , rằng trong cơ sở 4, chúng ta có thể rút ra rằng một số chia hết cho 5 chỉ khi tổng các chữ số xen kẽ là. Do đó chúng tôi

  1. nhóm các chữ số 2 bằng 2,
  2. tính tổng số lẻ và trừ các khối chẵn 2 bit.
  3. Nếu kết quả nằm trong vùng bổ sung của một vài bit, ví dụ [-4,3] (dễ kiểm tra giả sử chúng tôi sử dụng hai phần bổ sung) thì chúng tôi đã kết thúc và chúng tôi chỉ có thể chia số gốc cho 5 nếu kết quả của tổng là 0, đây là một biểu thức logic rất đơn giản để kiểm tra (về cơ bản chỉ là một số lớn cũng như trên tất cả các bit kết quả, phải không?)
  4. mặt khác, chúng tôi lặp lại trên số mới (số ngắn hơn nhiều).

Hãy để chúng tôi thử số 166 = (10) (10) (01) (10): 2,2,1,2

2-2 + 1-2 = -1

đó là <= 3 về giá trị tuyệt đối chứ không phải 0 tại sao chúng ta có thể kết luận chỉ trong một lần lặp mà 166 không được chia đều cho 5.

Có thể là một bộ nhớ nhỏ có thể rẻ hơn / tốt hơn về tốc độ / nr của cổng so với lặp. Tất nhiên người ta có thể định trước kết quả tồi tệ nhất (kết quả lớn nhất có thể được đưa ra cho các đầu vào được phép) và lên kế hoạch thiết kế cho phù hợp.


1

Cách tiếp cận MSB chắc chắn dễ dàng hơn, nhưng tôi đã xoay sở để thực hiện sơ đồ trạng thái LSB mà không cần phải tạo ra giải pháp MSB ... tôi chỉ mất vài giờ. Nó hóa ra tương đương với cái được hiển thị bởi @ComFalet, chỉ được chú thích khác nhau.

Chúng tôi sẽ theo dõi hai số. Đầu tiên, chúng tôi sẽ theo dõi tổng chạy, modulo 5 ("SUM"). Thứ hai, chúng tôi sẽ theo dõi giá trị của sức mạnh tiếp theo của 2 sẽ được chuyển sang, modulo 5 ("TIẾP THEO"). Tôi sẽ đại diện cho mỗi trạng thái với các giá trị có thể cho "SUM" ở trên cùng và các giá trị "TIẾP THEO" tương ứng của chúng bên dưới chúng.

Chúng ta sẽ bắt đầu với trường hợp "SUM" modulo 5 là 0:

Initial

Lưu ý rằng một trạng thái trông giống như:
3,2,4,1
1,4,3,2

tương đương với:
1,3,4,2
2,1,3,4

Bởi vì cả hai trạng thái đại diện cho rằng:
SUM = 1 và NEXT = 4 HOẶC
SUM = 2 và NEXT = 3 HOẶC
SUM = 3 và NEXT = 2 HOẶC
SUM = 4 và NEXT = 1.

Được rồi, vì vậy bây giờ chúng ta cần phát triển thêm các trạng thái, vì hầu hết những người phỏng vấn sẽ không bị ấn tượng bởi một sơ đồ trạng thái chỉ có một trạng thái. Chúng ta đã hoàn thành khi mỗi tiểu bang có hai lần chuyển đổi.

Bất cứ khi nào bạn chuyển sang trạng thái mới, mỗi số trong "TIẾP THEO" sẽ được nhân đôi, sau đó sửa đổi 5. Đối với "SUM", hãy làm theo các quy tắc sau:

  • Nếu bạn đã chuyển đổi dọc theo 0, hàng trên cùng sẽ giữ các giá trị của nó.
  • Nếu bạn đã chuyển đổi dọc theo 1, thì mỗi cột là modulo "SUM" + "NEXT" của trạng thái cũ.

Vì vậy, hãy bắt đầu bằng cách điền vào các chuyển đổi khi bit đến là 1.

All 1's

Được rồi, bây giờ chúng tôi điền vào số không. Chỉ có một trạng thái được thêm vào, vì vậy chúng tôi sẽ tiếp tục và điền vào phần chuyển tiếp của nó.

Complete

Và Voila! Chúng tôi đã có một máy trạng thái chấp nhận LSB trước mà không phải tạo giải pháp MSB.


1

Tất cả những điều trên có vẻ rất phức tạp! Có một cách toán học dễ dàng để phát hiện nếu một số nguyên nhị phân chia hết cho năm. Để bắt đầu, bạn có nhớ làm thế nào để "bỏ số tiền phạt" trong số học thập phân thông thường không? Modulo dư 9 của một số nguyên thập phân giống như modulo dư 9 của tổng các chữ số của nó. Điều này hoạt động vì 9 là một ít hơn cơ sở số.

Có một quy trình tương tự, "bỏ ra độ cao", trong đó các dấu của các chữ số thay thế được đặt âm. Điều này hoạt động vì mười một là lớn hơn cơ sở số.

Vì vậy, nếu chúng tôi muốn "bỏ đi những người vợ", chúng tôi có thể đại diện cho số nguyên của chúng tôi trong số bốn cơ sở. Sau đó, chúng tôi bắt đầu với cặp chữ số thấp nhất dưới dạng tổng ban đầu và trừ nó khỏi cặp chữ số tiếp theo để có được tổng tiếp theo. Sau khi đi qua số nguyên ứng cử viên của chúng tôi theo cách này, tổng cuối cùng sẽ bằng 0 hoặc chia hết cho 5 nếu số nguyên ban đầu của chúng tôi chia hết cho 5.

Ví dụ 70: 01 00 01 10 -> 01 00 -1 -> 01 01 -> 00, chia hết cho 5 Ví dụ 49: 11 00 01 -> 11 -1 -> 1 00 -> 1, KHÔNG chia hết cho 5

Lưu ý rằng bạn phải mang thêm một bit cho dấu hiệu của chênh lệch tích lũy và cho các trường hợp khi có mang.

Một cách khác để đi, là chỉ cần thêm các chữ số hex để có modulo dư. Tất nhiên bạn cần một bước logic cuối cùng để xác định ba kết quả chấp nhận được là 0, năm và mười.

Ví dụ 70: 4 6 -> A, do đó 70 chia hết cho 5 (nhưng không chia cho 15) Ví dụ 49: 3 1 -> 4, vì vậy 70 KHÔNG chia hết cho 5.

Lưu ý rằng bạn có thể sử dụng các cơ sở số khác nhau để xây dựng nhiều bài kiểm tra khả năng phân chia, mặc dù trong logic máy tính, các cơ sở cho quyền hạn 2 +/- 1 là dễ thực hiện nhất.

Trong số học thập phân, một trong những mục yêu thích của tôi là kiểm tra dư lượng mod 7. Lưu ý rằng 100 lớn hơn hai bội số của 7, vì vậy hãy nhóm các chữ số thành cặp (làm việc trong cơ sở số 100) và thêm hàng trăm TWICE từ các đơn vị. Ở đây chúng tôi làm việc từ trái sang phải ...

Ví dụ: 98 76 -> 2 72 -> 76, vì vậy 9876 không chia hết cho 7. Đó là 6 mod 7. Ví dụ: 03 45 67 -> 51 67 -> 1 69 -> 71 vì vậy nó là 1 mod 7.

Tất nhiên, trong hệ nhị phân, chỉ cần lấy tổng các chữ số bát phân (nhóm 3 bit).

Xin lỗi, tôi ước mình là một bậc thầy Verilog, nhưng số học là tất cả những gì tôi có thể cung cấp ở giai đoạn này của cuộc đời. Xem "Xác định chết" của Ron Doerfler để biết nhiều mánh khóe như thế này.


Tôi tự hỏi nếu anh em họ Canada của chúng tôi có thể có một số thuật toán đặc biệt. Vì họ ngoài vòng pháp luật Canada, tất cả giá được làm tròn đến 0,05 đô la gần nhất.
richard1941

1

Một câu hỏi phỏng vấn VHDL sẽ dẫn đến một số mã VHDL.

Tôi đã có dịp tìm thấy một lỗi phụ trợ ghdl llvm với việc triển khai bảng chuyển đổi trạng thái của Dave Tweed nơi tác giả của ghdl đã chắt lọc việc thực hiện trong một hàm thành 17 dòng:

type remains is (r0, r1, r2, r3, r4); -- remainder values

    function mod5 (dividend: bit_vector) return boolean is
        type remain_array is array (NBITS downto 0) of remains;
        type branch is array (remains, bit) of remains;
        constant br_table:  branch := ( r0 => ('0' => r0, '1' => r1),
                                        r1 => ('0' => r2, '1' => r3),
                                        r2 => ('0' => r4, '1' => r0),
                                        r3 => ('0' => r1, '1' => r2),
                                        r4 => ('0' => r3, '1' => r4)
                                      );
        variable  remaind:    remains := r0;
        variable tbit:        bit_vector (NBITS - 1 downto 0) := dividend;
    begin
        for i in dividend'length - 1 downto 0 loop
            remaind := br_table(remaind,tbit(i));
        end loop;
        return remaind = r0;
end function;

Trường hợp thử nghiệm liên quan khá nhỏ cho phép gỡ lỗi dễ dàng hơn và sử dụng các tên trạng thái tương thích với VHDL trong kiểu liệt kê vẫn còn:

dave_tweed.png (được tạo bằng Dia)

Ý tưởng ở đây là hàm (hoặc thậm chí là một chương trình VHDL ví dụ gồm 27 dòng) đủ ngắn để viết câu trả lời VHDL trong một cuộc phỏng vấn. Không cần phải lo lắng về việc làm hỏng một câu hỏi phỏng vấn đòi hỏi phải thể hiện cả kiến ​​thức và kỹ năng, một người được phỏng vấn sẽ được bảo vệ thực hiện khi được hỏi.

(Lỗi phụ trợ llvm đã được sửa trong cam kết 1f5df6e vào hôm nay.)

Một trong những điều cần lưu ý là bảng chuyển đổi trạng thái cũng cho chúng ta biết bit thương số sẽ là '1' được hiển thị bằng cách chuyển sang trạng thái có giá trị còn lại thấp hơn (hoặc cả hai lần chuyển đổi cho r4) khi trừ 5 từ cổ tức. Điều đó có thể được mã hóa trong một bảng riêng biệt (hoặc một bảng thuộc loại bản ghi có vẻ rườm rà). Chúng tôi thực hiện điều này trong lịch sử phần cứng đồ họa xử lý độ phân giải màn hình ngang bội số 5 pixel.

Làm như vậy sẽ cho chúng ta một div / mod5 tạo ra thương số và phần còn lại:

library ieee;
use ieee.std_logic_1164.all;

entity divmod5 is
    generic (
        NBITS:  natural := 13 
    );
    port (
        clk:        in  std_logic;
        dividend:   in  std_logic_vector (NBITS - 1 downto 0);
        load:       in  std_logic;
        quotient:   out std_logic_vector (NBITS - 3 downto 0);
        remainder:  out std_logic_vector (2 downto 0);
        remzero:    out std_logic
    );
end entity;

architecture foo of divmod5 is
    type remains is (r0, r1, r2, r3, r4); -- remainder values
    type remain_array is array (NBITS downto 0) of remains;
    signal remaindr:    remain_array := (others => r0);
    signal dividendreg: std_logic_vector (NBITS - 1 downto 0);
    signal quot:        std_logic_vector (NBITS - 3 downto 0);
begin

parallel:
    for i in NBITS - 1 downto 0 generate
        type branch is array (remains, bit) of remains;
        -- Dave Tweeds state transition table:
        constant br_table:  branch := ( r0 => ('0' => r0, '1' => r1),
                                        r1 => ('0' => r2, '1' => r3),
                                        r2 => ('0' => r4, '1' => r0),
                                        r3 => ('0' => r1, '1' => r2),
                                        r4 => ('0' => r3, '1' => r4)
                                      );

        type qt is array (remains, bit) of std_ulogic;
    -- Generate quotient bits from Dave Tweeds state machine using q_table.
    -- A '1' when a remainder goes to a lower remainder or for both branches
    -- of r4. A '0' for all other branches.

        constant q_table:   qt :=     ( r0 => (others => '0'),
                                        r1 => (others => '0'),
                                        r2 => ('0' => '0', '1' => '1'),
                                        r3 => (others => '1'),
                                        r4 => (others => '1')
                                      );
        signal tbit:    bit;
    begin
        tbit <= to_bit(dividendreg(i));
        remaindr(i) <= br_table(remaindr(i + 1),tbit);
do_quotient:
        if i < quot'length generate   
            quot(i) <= q_table(remaindr(i + 1),tbit);
        end generate;
    end generate;

dividend_reg:
    process (clk)
    begin
        if rising_edge(clk) then
            if load = '1' then
                dividendreg <= dividend;
            end if;
        end if;
    end process;

quotient_reg:
    process (clk)
    begin
        if rising_edge (clk) then
            quotient <=  quot;
        end if;
    end process;

remainders:
    process (clk)
    begin
        if rising_edge(clk) then 
            remzero <= '0';
            case remaindr(0) is
                when r0 =>
                    remainder <= "000";
                    remzero <= '1';
                when r1 =>
                    remainder <= "001";
                when r2 =>
                    remainder <= "010";
                when r3 =>
                    remainder <= "011";
                when r4 =>
                    remainder <= "100";
            end case;
        end if;
    end process;

end architecture;

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity divmod5_tb is
end entity;

architecture foo of divmod5_tb is
    constant NBITS:    integer range 0 to 13 := 8;
    signal clk:        std_logic := '0';
    signal dividend:   std_logic_vector (NBITS - 1 downto 0);
    signal load:       std_logic := '0';

    signal quotient:   std_logic_vector (NBITS - 3 downto 0);
    signal remainder:  std_logic_vector (2 downto 0);
    signal remzero:    std_logic;
    signal psample:    std_ulogic;
    signal sample:     std_ulogic;
    signal done:       boolean;
begin
DUT:
    entity work.divmod5
        generic map  (NBITS)
        port map (
            clk => clk,
            dividend => dividend,
            load => load,
            quotient => quotient,
            remainder => remainder,
            remzero => remzero
        );
CLOCK:
    process
    begin
        wait for 5 ns;
        clk <= not clk;
        if done'delayed(30 ns) then
            wait;
        end if;
    end process;
STIMULI:
    process
    begin
        for i in 0 to 2 ** NBITS - 1 loop
            wait for 10 ns;
            dividend <= std_logic_vector(to_unsigned(i,NBITS));
            wait for 10 ns;
            load <= '1';
            wait for 10 ns;
            load <= '0';
        end loop;
        wait for 15 ns;
        done <= true;
        wait;
    end process;

SAMPLER:
    process (clk)
    begin
        if rising_edge(clk) then
            psample <= load;
            sample <= psample after 4 ns;
        end if;
    end process;

MONITOR:
    process (sample)
        variable i:     integer;
        variable div5:  integer;
        variable rem5:  integer;
    begin
        if rising_edge (sample) then
            i := to_integer(unsigned(dividend));
            div5 := i / 5;
            assert div5 = unsigned(quotient)
                report LF & HT &
                    "i = " & integer'image(i) &
                    " div 5 expected " & integer'image(div5) & 
                    " got " & integer'image(to_integer(unsigned(quotient)))
                SEVERITY ERROR;
            rem5 := i mod 5;
            assert rem5 = unsigned(remainder)
                report LF & HT &
                    "i = " & integer'image(i) &
                    " rem 5 expected " & integer'image(rem5) & 
                    " got " & integer'image(to_integer(unsigned(remainder)))
                SEVERITY ERROR;
        end if;
    end process;

end architecture;

Được triển khai ở đây với một câu lệnh tạo, một câu lệnh tạo bên trong tạo ra các bit thương. Mảng remaindr cung cấp một dấu vết chuyển trạng thái:

divmod5_tb.png

Tất cả không có một phép toán số học.

Cũng có thể thực hiện trong một thủ tục mà không cần tất cả các thanh ghi tận dụng các tham số với chế độ tắt. Điều đó sẽ tiếp cận một số dòng tối thiểu cho một cuộc phỏng vấn.

Việc thực hiện tuần tự theo đồng hồ sẽ yêu cầu bộ đếm bit và kiểm soát dòng chảy (một flip flip flop và một vài cổng).

Có sự đánh đổi thời gian / sự phức tạp tùy thuộc vào quy mô cổ tức mà bạn cũng có thể được yêu cầu bảo vệ trong một cuộc phỏng vấn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.