chipdev

chipdev.io Solutions (0x6A73)
git clone https://git.pngu.org/chipdev
Log | Files | Refs | README

commit 9311e0af8002c3cf4f8e1c199c1a99d8e190febb
parent 80ab141c6154b79ce45b0cc433405c39b58408be
Author: Jack Sangdahl <jack@pngu.org>
Date:   Wed, 19 Nov 2025 11:55:51 -0700

Q2. Second Largest

Diffstat:
Aq2_second_largest/Makefile | 8++++++++
Aq2_second_largest/readme.md | 45+++++++++++++++++++++++++++++++++++++++++++++
Aq2_second_largest/second_largest.v | 24++++++++++++++++++++++++
Aq2_second_largest/second_largest_test.py | 50++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 127 insertions(+), 0 deletions(-)

diff --git a/q2_second_largest/Makefile b/q2_second_largest/Makefile @@ -0,0 +1,8 @@ +SIM = verilator +TOPLEVEL_LANG = verilog +VERILOG_SOURCES = $(PWD)/second_largest.v +COCOTB_TOPLEVEL = model +COCOTB_TEST_MODULES = second_largest_test +WAVES = 1 + +include $(shell cocotb-config --makefiles)/Makefile.sim diff --git a/q2_second_largest/readme.md b/q2_second_largest/readme.md @@ -0,0 +1,45 @@ +# Second Largest + +## Prompt +Given a clocked sequence of unsigned values, output the second-largest value seen so far in the sequence. If only one value is seen, then the output (`dout`) should equal 0. Note that the values are treated as separate candidates for being the second largest value. + +When the reset-low signal (`resetn`) goes low, all previous values seen in the input sequence should no longer be considered for thee calculation of the second largest value, and the output `dout` should restart from 0 on the next cycle. + +## Input & Output Signals +- `clk`: Clock signal. +- `resetn`: Synchronous reset-low signal. +- `din`: Input data sequence. +- `dout`: Second-largest value seen so far. + +## Output signals during reset +- `dout`: 0 when `resetn` is active. + +## Example +- Data width: 32 +- Clock cycle 1 + - `resetn`: `h0` + - `din`: `h2` +- Clock cycle 2 + - `resetn`: `h1` + - `din`: `h2` +- Clock cycle 3 + - `resetn`: `h1` + - `din`: `h6` +- Clock cycle 4 + - `resetn`: `h1` + - `din`: `h0` +- Clock cycle 5 + - `resetn`: `h1` + - `din`: `he` +- Clock cycle 6 + - `resetn`: `h1` + - `din`: `hc` +- Clock cycle 7 + - `resetn`: `h0` + - `din`: `h0` +- Clock cycle 8 + - `resetn`: `h1` + - `din`: `h1` +- Clock cycle 9 + - `resetn`: `h1` + - `din`: `h2` diff --git a/q2_second_largest/second_largest.v b/q2_second_largest/second_largest.v @@ -0,0 +1,24 @@ +module model #( + parameter DATA_WIDTH = 32 +) ( + input clk, + input resetn, + input [DATA_WIDTH-1:0] din, + output logic [DATA_WIDTH-1:0] dout +); + + logic [DATA_WIDTH-1:0] largest, second_largest; + always @(posedge clk) begin + if (~resetn) begin + largest <= '0; + second_largest <= '0; + end else if ((din > largest && din > second_largest)) begin + largest <= din; + second_largest <= largest; + end else if (din > second_largest) begin + second_largest <= din; + end + end + assign dout = second_largest; + +endmodule diff --git a/q2_second_largest/second_largest_test.py b/q2_second_largest/second_largest_test.py @@ -0,0 +1,50 @@ +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge, Timer + + +@cocotb.test() +async def test_second_largest(dut): + clock = Clock(dut.clk, 10, unit="ns") + cocotb.start_soon(clock.start()) + + dut.resetn.value = 0 + await RisingEdge(dut.clk) + dut.resetn.value = 1 + await RisingEdge(dut.clk) + + din1 = [0x2, 0x6, 0x0, 0xE, 0xC] + dout1 = [0x0, 0x2, 0x2, 0x6, 0xC] + + for i, (din_val, expected) in enumerate(zip(din1, dout1)): + dut.din.value = din_val + await RisingEdge(dut.clk) + await Timer(1, unit="ns") + + actual = dut.dout.value.to_unsigned() + dut._log.info( + f"pre-reset step {i + 1}: din = 0x{din_val:x}, dout = 0x{actual:x}, expected = 0x{expected:x}" + ) + assert actual == expected, ( + f"mismatch at step {i + 1}: got 0x{actual:x}, expected 0x{expected:x}" + ) + + dut.resetn.value = 0 + await RisingEdge(dut.clk) + dut.resetn.value = 1 + + din2 = [0x0, 0x1, 0x2] + dout2 = [0x0, 0x0, 0x1] + + for i, (din_val, expected) in enumerate(zip(din2, dout2)): + dut.din.value = din_val + await RisingEdge(dut.clk) + await Timer(1, unit="ns") + + actual = dut.dout.value.to_unsigned() + dut._log.info( + f"post-reset step {i + 1}: din = 0x{din_val:x}, dout = 0x{actual:x}, expected = 0x{expected:x}" + ) + assert actual == expected, ( + f"mismatch at step {i + 1}: got 0x{actual:x}, expected 0x{expected:x}" + )