diff --git a/IO_Experiments_2/IO_Experiments_2.alp b/IO_Experiments_2/IO_Experiments_2.alp index 94ea605..6ba60e6 100644 --- a/IO_Experiments_2/IO_Experiments_2.alp +++ b/IO_Experiments_2/IO_Experiments_2.alp @@ -50,7 +50,7 @@ { "file": { "type": "DiskFile", - "path": "source/mul10_addbcd.luc" + "path": "source/bcd_to_bin.luc" } }, { diff --git a/IO_Experiments_2/source/alchitry_top.luc b/IO_Experiments_2/source/alchitry_top.luc index e070589..f34edab 100644 --- a/IO_Experiments_2/source/alchitry_top.luc +++ b/IO_Experiments_2/source/alchitry_top.luc @@ -26,8 +26,8 @@ module alchitry_top ( sig rst // reset signal - mul10_addbcd bcd_to_bin_a(#DIGITS(4)) - mul10_addbcd bcd_to_bin_b(#DIGITS(4)) + bcd_to_bin bcd_to_bin_a(#DIGITS(4)) + bcd_to_bin bcd_to_bin_b(#DIGITS(4)) bin_to_dec btd(#DIGITS(4), #LEADING_ZEROS(1)) diff --git a/IO_Experiments_2/source/bcd_to_bin.luc b/IO_Experiments_2/source/bcd_to_bin.luc new file mode 100644 index 0000000..c8d45da --- /dev/null +++ b/IO_Experiments_2/source/bcd_to_bin.luc @@ -0,0 +1,17 @@ +module bcd_to_bin #(DIGITS = 4 : DIGITS > 0 && DIGITS < 16) +( + input bcd[DIGITS][4], // bcd digits + output result[$clog2($pow(10, DIGITS)) + 2] // result + +) { + + sig temp[DIGITS][$clog2($pow(10, DIGITS)) + 2] + + always { + temp[DIGITS-1] = bcd[DIGITS-1] + repeat(i, DIGITS-1, DIGITS-1, -1) { + temp[i-1] = (temp[i] << 3) + (temp[i] << 1) + bcd[i-1] + } + result = temp[0] + } +} \ No newline at end of file diff --git a/io_add_binary/README.md b/io_add_binary/README.md new file mode 100644 index 0000000..4258350 --- /dev/null +++ b/io_add_binary/README.md @@ -0,0 +1,26 @@ +### A BCD adder for two 4-digit numbers a and b on the Alchitry AU FPGA kit with the IO Element board. + +The 5 buttons on the IO board allow you to enter the two numbers a and b and compute the sum: + +- use the up/down button to increment/decrement the currently selected digit +- use the left/right button to select the next/previous digit in a or b +- use the center button to advance state: enter a => enter b => show sum => enter a etc... + +The currently selected digit is shown on leds[3:0] an the AU board + +The current state (a, b, sum) is shown on io leds [2][3:0] + +The currently selected digit value of or b is shown on the io board: + - on io_leds[0][3:0] + - on the seven segment display + +The sum is shown on the 7 segment display until the center button is pressed again,ready for the next a value + +An overflow condition is shown on the leftmost io led [2][7:7] + +The code is written in Alchitry Labs Lucid, a more ergonomic version of Verilog. +The Alchitry IDE converts this to Verilog and compiles it with Vivado. + +A picture of the result of adding 9999 + 9999 : + +![bcd adder](https://github.com/user-attachments/assets/99d17364-7336-4259-8767-2ef69e75b5ef) diff --git a/io_add_binary/io_add_binary.alp b/io_add_binary/io_add_binary.alp new file mode 100644 index 0000000..76a0838 --- /dev/null +++ b/io_add_binary/io_add_binary.alp @@ -0,0 +1,97 @@ +{ + "project": { + "type": "V1.2", + "projectName": "io_add_binary", + "board": "Alchitry Au", + "sourceFiles": [ + { + "file": { + "type": "DiskFile", + "path": "source/alchitry_top.luc" + }, + "top": true + }, + { + "file": { + "type": "Component", + "path": "Conditioning/reset_conditioner.luc" + } + }, + { + "file": { + "type": "DiskFile", + "path": "source/multi_seven_seg.luc" + } + }, + { + "file": { + "type": "DiskFile", + "path": "source/seven_seg.luc" + } + }, + { + "file": { + "type": "Component", + "path": "Miscellaneous/counter.luc" + } + }, + { + "file": { + "type": "Component", + "path": "Miscellaneous/decoder.luc" + } + }, + { + "file": { + "type": "Component", + "path": "Miscellaneous/bin_to_dec.luc" + } + }, + { + "file": { + "type": "DiskFile", + "path": "source/bcd_to_bin.luc" + } + }, + { + "file": { + "type": "DiskFile", + "path": "source/btn_press.luc" + } + }, + { + "file": { + "type": "Component", + "path": "Miscellaneous/pipeline.luc" + } + }, + { + "file": { + "type": "Component", + "path": "Conditioning/button_conditioner.luc" + } + }, + { + "file": { + "type": "Component", + "path": "Pulses/edge_detector.luc" + } + } + ], + "constraintFiles": [ + { + "file": { + "type": "Component", + "path": "Constraints/alchitry.acf" + } + }, + { + "file": { + "type": "Component", + "path": "Constraints/io.acf" + } + } + ], + "ipCores": [] + } +} \ No newline at end of file diff --git a/io_add_binary/source/alchitry_top.luc b/io_add_binary/source/alchitry_top.luc new file mode 100644 index 0000000..f34edab --- /dev/null +++ b/io_add_binary/source/alchitry_top.luc @@ -0,0 +1,160 @@ +// reference: https://natalieagus.github.io/50002/fpga/fpga_2 +// Note: Lucid V1 fsm = V2 enum !! +module alchitry_top ( + input clk, // 100MHz clock + input rst_n, // reset button (active low) + output led[8], // 8 user controllable LEDs + input usb_rx, // USB->Serial input + output usb_tx, // USB->Serial output + output io_led[3][8], // LEDs on IO Shield + output io_segment[8], // 7-segment LEDs on IO Shield + output io_select[4], // Digit select on IO Shield + input io_button[5], // 5 buttons on IO Shield + input io_dip[3][8] // DIP switches on IO Shield +) { + + // the push buttons + const UP = 0 + const CENTER = 1 + const DOWN = 2 + const LEFT = 3 + const RIGHT = 4 + const NBUTTONS = 5 + + // the FSM + enum State {A, B, SUM} // A: input a, B: input b, SUM: compute and show sum + + sig rst // reset signal + + bcd_to_bin bcd_to_bin_a(#DIGITS(4)) + bcd_to_bin bcd_to_bin_b(#DIGITS(4)) + + bin_to_dec btd(#DIGITS(4), #LEADING_ZEROS(1)) + + .clk(clk) { + // The reset conditioner is used to synchronize the reset signal to the FPGA + // clock. This ensures the entire FPGA comes out of reset at the same time. + reset_conditioner reset_cond + btn_press btn_chk[NBUTTONS] + .rst(rst) { + dff state[$width(State)](#INIT(State.A)) // state fsm + dff digit_adder[4][4] // 4 bcd adders, one for each decimal digit + dff a[4][4] // 4 bcd digits, a input for adder + dff b[4][4] // 4 bcd digits, b input for adder + dff digit_index[2] // the current decimal digit position in a or b + multi_seven_seg seg (#DIV($is_sim() ? 1 : 16), #DIGITS(4)) // 4 digit 7-segment display + } + } + + + + always { + reset_cond.in = ~rst_n // input raw inverted reset signal + rst = reset_cond.out // conditioned reset + + led = 8h00 // turn LEDs off + io_led = 3x{{8h00}} + io_segment = 8h_f_f + io_select = 4h_f + + // clear the sum + bcd_to_bin_a.bcd = 4x{{4h0}} + bcd_to_bin_b.bcd = 4x{{4h0}} + btd.value = 0 + + // show currently active digit on AU leds [0-3] + led[digit_index.q] = 1 + // show current digit value on right io_leds bank + io_led[0][3:0] = digit_adder.q[digit_index.q] + // show current FSM state on left io_led bank [2:0] + io_led[2][0] = state.q == State.A + io_led[2][1] = state.q == State.B + io_led[2][2] = state.q == State.SUM + + // show the current a or b or sum digits on the display + case (state.q) { + State.A: + seg.values = digit_adder.q + State.B: + seg.values = digit_adder.q + State.SUM: + bcd_to_bin_a.bcd = a.q + sig partiala[16] = bcd_to_bin_a.result + bcd_to_bin_b.bcd = b.q + sig partialb[16] = bcd_to_bin_b.result + sig binsum[18] = partiala + partialb + btd.value = binsum[13:0] + seg.values = btd.digits + sig carry[1] = binsum > 9999 + if (carry) { + seg.values = 4x{{hb}} + } + io_led[2][7:7] = carry // set overflow indicator + default: + // should never happen + seg.values = 4x{{4bxxx}} + } + io_segment = ~seg.seg // connect segments to the driver + io_select = ~seg.sel // connect digit select to the driver + + // get the debounced buttons pressed state + btn_chk.btn_in[NBUTTONS-1:0] = io_button + sig add = btn_chk.btn_down[UP] + sig sub = btn_chk.btn_down[DOWN] + sig nxt = btn_chk.btn_down[LEFT] + sig prv = btn_chk.btn_down[RIGHT] + sig enter = btn_chk.btn_down[CENTER] + + if (add) { // inc the current digit + if (digit_adder.q[digit_index.q] == 9) { + digit_adder.d[digit_index.q] = 0 + } else { + digit_adder.d[digit_index.q] = digit_adder.q[digit_index.q] + 1 + } + } else if (sub) { // dec the current digit + if (digit_adder.q[digit_index.q] == 0) { + digit_adder.d[digit_index.q] = 9 + } else { + digit_adder.d[digit_index.q] = digit_adder.q[digit_index.q] - 1 + } + } else if (nxt) { // next digit position + digit_index.d = digit_index.q + 1 + } else if (prv) { // previous digit position + digit_index.d = digit_index.q - 1 + } else if (enter) { // advance state machine + case (state.q) { + State.A: + a.d = digit_adder.q // remember x value + state.d = State.B // set next state + State.B: + b.d = digit_adder.q // remember y value + state.d = State.SUM // set next state (activates bcd adder) + State.SUM: + state.d = State.A // set next state + default: + // should not happen + state.d = State.A + } + // clean-up for next state + digit_adder.d = 4x{{4h0}} // clear a or b + digit_index.d = 0 // reset to enter 1st digit + } + +/* + va.x = 1 + va.y = 2 + va.cin = 0 + io_led = $build(va.sum, 3) + + btd.value = va.sum[13:0] + sig result[4][4] = btd.digits + seg.values = result + io_segment = ~seg.seg // connect segments to the driver + io_select = ~seg.sel // connect digit select to the driver + */ + + usb_tx = usb_rx // loop serial port + + + } +} \ No newline at end of file diff --git a/io_add_binary/source/bcd_to_bin.luc b/io_add_binary/source/bcd_to_bin.luc new file mode 100644 index 0000000..c8d45da --- /dev/null +++ b/io_add_binary/source/bcd_to_bin.luc @@ -0,0 +1,17 @@ +module bcd_to_bin #(DIGITS = 4 : DIGITS > 0 && DIGITS < 16) +( + input bcd[DIGITS][4], // bcd digits + output result[$clog2($pow(10, DIGITS)) + 2] // result + +) { + + sig temp[DIGITS][$clog2($pow(10, DIGITS)) + 2] + + always { + temp[DIGITS-1] = bcd[DIGITS-1] + repeat(i, DIGITS-1, DIGITS-1, -1) { + temp[i-1] = (temp[i] << 3) + (temp[i] << 1) + bcd[i-1] + } + result = temp[0] + } +} \ No newline at end of file diff --git a/io_add_binary/source/btn_press.luc b/io_add_binary/source/btn_press.luc new file mode 100644 index 0000000..22d6bee --- /dev/null +++ b/io_add_binary/source/btn_press.luc @@ -0,0 +1,17 @@ +module btn_press ( + input clk, // clock + input btn_in, + output btn_down +) { + .clk(clk) { + edge_detector edge(#RISE(1), #FALL(0)) // detect rising edges + + button_conditioner btn_cond(#CLK_FREQ($is_sim() ? 1_000 : 100_000_000)) // button input conditioner + + } + always { + btn_cond.in = btn_in // raw button input + edge.in = btn_cond.out // input to the edge_detector + btn_down = edge.out // output the state + } +} \ No newline at end of file diff --git a/io_add_binary/source/mul10_addbcd.luc b/io_add_binary/source/mul10_addbcd.luc new file mode 100644 index 0000000..502b706 --- /dev/null +++ b/io_add_binary/source/mul10_addbcd.luc @@ -0,0 +1,17 @@ +module mul10_addbcd #(DIGITS = 4 : DIGITS > 0 && DIGITS < 16) +( + input bcd[DIGITS][4], // bcd digits + output result[$clog2($pow(10, DIGITS)) + 2] // result + +) { + + sig temp[DIGITS][$clog2($pow(10, DIGITS)) + 2] + + always { + temp[DIGITS-1] = bcd[DIGITS-1] + repeat(i, DIGITS-1, DIGITS-1, -1) { + temp[i-1] = (temp[i] << 3) + (temp[i] << 1) + bcd[i-1] + } + result = temp[0] + } +} \ No newline at end of file diff --git a/io_add_binary/source/multi_seven_seg.luc b/io_add_binary/source/multi_seven_seg.luc new file mode 100644 index 0000000..c882b93 --- /dev/null +++ b/io_add_binary/source/multi_seven_seg.luc @@ -0,0 +1,29 @@ +module multi_seven_seg #( + DIGITS = 4 : DIGITS > 0, + DIV = $is_sim() ? 0 : 16 : DIV >= 0 +)( + input clk, // clock + input rst, // reset + input values[DIGITS][4], // values to show + output seg[7], // LED segments + output sel[DIGITS] // Digit select +) { + + // number of bits required to store DIGITS-1 + const DIGIT_BITS = $clog2(DIGITS) + + .clk(clk), .rst(rst) { + counter ctr (#DIV(DIV), #SIZE(DIGIT_BITS), #TOP(DIGITS-1)) + } + + seven_seg seg_dec // segment decoder + decoder digit_dec(#WIDTH(DIGIT_BITS)) // digit decoder + + always { + seg_dec.char = values[ctr.value] // select the value for the active digit + seg = seg_dec.segs // output the decoded value + + digit_dec.in = ctr.value // decode active digit to one-hot + sel = digit_dec.out // output the active digit + } +} \ No newline at end of file diff --git a/io_add_binary/source/seven_seg.luc b/io_add_binary/source/seven_seg.luc new file mode 100644 index 0000000..5681904 --- /dev/null +++ b/io_add_binary/source/seven_seg.luc @@ -0,0 +1,26 @@ +module seven_seg ( + input char[4], + output segs[7] +) { + always { + case (char) { + 0: segs = 7b0111111 + 1: segs = 7b0000110 + 2: segs = 7b1011011 + 3: segs = 7b1001111 + 4: segs = 7b1100110 + 5: segs = 7b1101101 + 6: segs = 7b1111101 + 7: segs = 7b0000111 + 8: segs = 7b1111111 + 9: segs = 7b1100111 + 10: segs = 7b1110111 // A + 11: segs = 7b1111100 // b + 12: segs = 7b0111001 // C + 13: segs = 7b1011110 // d + 14: segs = 7b1111001 // E + 15: segs = 7b1110001 // F + default: segs = 7b0000000 + } + } +} diff --git a/io_add_decimal/README.md b/io_add_decimal/README.md new file mode 100644 index 0000000..4258350 --- /dev/null +++ b/io_add_decimal/README.md @@ -0,0 +1,26 @@ +### A BCD adder for two 4-digit numbers a and b on the Alchitry AU FPGA kit with the IO Element board. + +The 5 buttons on the IO board allow you to enter the two numbers a and b and compute the sum: + +- use the up/down button to increment/decrement the currently selected digit +- use the left/right button to select the next/previous digit in a or b +- use the center button to advance state: enter a => enter b => show sum => enter a etc... + +The currently selected digit is shown on leds[3:0] an the AU board + +The current state (a, b, sum) is shown on io leds [2][3:0] + +The currently selected digit value of or b is shown on the io board: + - on io_leds[0][3:0] + - on the seven segment display + +The sum is shown on the 7 segment display until the center button is pressed again,ready for the next a value + +An overflow condition is shown on the leftmost io led [2][7:7] + +The code is written in Alchitry Labs Lucid, a more ergonomic version of Verilog. +The Alchitry IDE converts this to Verilog and compiles it with Vivado. + +A picture of the result of adding 9999 + 9999 : + +![bcd adder](https://github.com/user-attachments/assets/99d17364-7336-4259-8767-2ef69e75b5ef) diff --git a/io_add_decimal/io_add_decimal.alp b/io_add_decimal/io_add_decimal.alp new file mode 100644 index 0000000..bea8470 --- /dev/null +++ b/io_add_decimal/io_add_decimal.alp @@ -0,0 +1,97 @@ +{ + "project": { + "type": "V1.2", + "projectName": "io_add_decimal", + "board": "Alchitry Au", + "sourceFiles": [ + { + "file": { + "type": "DiskFile", + "path": "source/alchitry_top.luc" + }, + "top": true + }, + { + "file": { + "type": "Component", + "path": "Conditioning/reset_conditioner.luc" + } + }, + { + "file": { + "type": "Component", + "path": "Miscellaneous/pipeline.luc" + } + }, + { + "file": { + "type": "DiskFile", + "path": "source/btn_press.luc" + } + }, + { + "file": { + "type": "Component", + "path": "Pulses/edge_detector.luc" + } + }, + { + "file": { + "type": "Component", + "path": "Conditioning/button_conditioner.luc" + } + }, + { + "file": { + "type": "DiskFile", + "path": "source/multi_seven_seg.luc" + } + }, + { + "file": { + "type": "DiskFile", + "path": "source/seven_seg.luc" + } + }, + { + "file": { + "type": "Component", + "path": "Miscellaneous/counter.luc" + } + }, + { + "file": { + "type": "Component", + "path": "Miscellaneous/decoder.luc" + } + }, + { + "file": { + "type": "DiskFile", + "path": "source/bcd_add.luc" + } + }, + { + "file": { + "type": "DiskFile", + "path": "source/bcd_add_n.luc" + } + } + ], + "constraintFiles": [ + { + "file": { + "type": "Component", + "path": "Constraints/alchitry.acf" + } + }, + { + "file": { + "type": "Component", + "path": "Constraints/io.acf" + } + } + ], + "ipCores": [] + } +} \ No newline at end of file diff --git a/io_add_decimal/source/alchitry_top.luc b/io_add_decimal/source/alchitry_top.luc new file mode 100644 index 0000000..e8f4ada --- /dev/null +++ b/io_add_decimal/source/alchitry_top.luc @@ -0,0 +1,156 @@ +// A simple adder for two 4-digits inputs with overflow indication +// up/down button => increment/decrement the currently selected digit +// left/right button => select the next/previous digit to enter +// center button => next state: +// enter a value => enter b value => show sum => restart +// the currently selected digit is shown on AU leds[3:0] +// the currently selected digit value is shown +// - on io_leds[0][3:0] +// - on the io seven segment display +// the sum is shown on the 7 segment display until the center button is pressed again + +module alchitry_top ( + input clk, // 100MHz clock + input rst_n, // reset button (active low) + output led[8], // 8 user controllable LEDs + input usb_rx, // USB->Serial input + output usb_tx, // USB->Serial output + output io_led[3][8], // LEDs on IO Shield + output io_segment[8], // 7-segment LEDs on IO Shield + output io_select[4], // Digit select on IO Shield + input io_button[5], // 5 buttons on IO Shield + input io_dip[3][8] // DIP switches on IO Shield +) { + sig rst + + // the push buttons + const UP = 0 + const CENTER = 1 + const DOWN = 2 + const LEFT = 3 + const RIGHT = 4 + const NBUTTONS = 5 + + // the FSM + enum State {A, B, SUM} // A: input a, B: input b, SUM: compute and show sum + + // the 4-digit BCD adder + bcd_add_n bcda(#DIGITS(4)) + // the sum + sig sum[5][4] // the adder sum, 5 bcd digits + + + .clk(clk) { + // The reset coditioner is used to synchronize the reset signal to the FPGA + // clock. This ensures the entire FPGA comes out of reset at the same time. + reset_conditioner reset_cond + // debounce the button press + btn_press btn_chk[NBUTTONS] + + .rst(rst) { + dff state[$width(State)](#INIT(State.A)) // state fsm + dff digit_adder[4][4] // 4 bcd adders, one for each decimal digit + dff a[4][4] // 4 bcd digits, a input for adder + dff b[4][4] // 4 bcd digits, b input for adder + dff digit_index[2] // the current decimal digit position in a or b + multi_seven_seg seg (#DIV($is_sim() ? 1 : 16), #DIGITS(4)) // 4 digit 7-segment display + } + } + + + always { + reset_cond.in = ~rst_n // input raw inverted reset signal + rst = reset_cond.out // conditioned reset + + // read dips switches, unused for now + sig dips[3][8] = io_dip + + // initial state of indicators + led = 8h00 + io_led = 3x{{8h00}} + io_select = 4b1 + io_segment = 8b1 + + // clear the bcd adder + bcda.a = 4x{{4h0}} + bcda.b = 4x{{4h0}} + bcda.carry_in = 1b0 + // clear the sum + sum = 5x{{4h0}} + + // show currently active digit on AU leds [0-3] + led[digit_index.q] = 1 + // show current digit value on right io_leds bank + io_led[0][3:0] = digit_adder.q[digit_index.q] + // show current FSM state on left io_led bank [2:0] + io_led[2][0] = state.q == State.A + io_led[2][1] = state.q == State.B + io_led[2][2] = state.q == State.SUM + + // show the current a or b or sum digits on the display + case (state.q) { + State.A: + seg.values = digit_adder.q + State.B: + seg.values = digit_adder.q + State.SUM: + bcda.a = a.q + bcda.b = b.q + bcda.carry_in = 0 + sum[3:0] = bcda.sum + sum[4][0:0] = bcda.carry + seg.values = sum[3:0] + io_led[2][7:7] = bcda.carry // set overflow indicator + default: + // should never happen + seg.values = 4x{{4bxxx}} + } + io_segment = ~seg.seg // connect segments to the driver + io_select = ~seg.sel // connect digit select to the driver + + // get the debounced buttons pressed state + btn_chk.btn_in[NBUTTONS-1:0] = io_button + sig add = btn_chk.btn_down[UP] + sig sub = btn_chk.btn_down[DOWN] + sig nxt = btn_chk.btn_down[LEFT] + sig prv = btn_chk.btn_down[RIGHT] + sig enter = btn_chk.btn_down[CENTER] + + if (add) { // inc the current digit + if (digit_adder.q[digit_index.q] == 9) { + digit_adder.d[digit_index.q] = 0 + } else { + digit_adder.d[digit_index.q] = digit_adder.q[digit_index.q] + 1 + } + } else if (sub) { // dec the current digit + if (digit_adder.q[digit_index.q] == 0) { + digit_adder.d[digit_index.q] = 9 + } else { + digit_adder.d[digit_index.q] = digit_adder.q[digit_index.q] - 1 + } + } else if (nxt) { // next digit position + digit_index.d = digit_index.q + 1 + } else if (prv) { // previous digit position + digit_index.d = digit_index.q - 1 + } else if (enter) { // advance state machine + case (state.q) { + State.A: + a.d = digit_adder.q // remember x value + state.d = State.B // set next state + State.B: + b.d = digit_adder.q // remember y value + state.d = State.SUM // set next state (activates bcd adder) + State.SUM: + state.d = State.A // set next state + default: + // should not happen + state.d = State.A + } + // clean-up for next state + digit_adder.d = 4x{{4h0}} // clear a or b + digit_index.d = 0 // reset to enter 1st digit + } + + usb_tx = usb_rx // loop serial port + } +} diff --git a/io_add_decimal/source/bcd_add.luc b/io_add_decimal/source/bcd_add.luc new file mode 100644 index 0000000..cd3b946 --- /dev/null +++ b/io_add_decimal/source/bcd_add.luc @@ -0,0 +1,23 @@ +module bcd_add ( + input a[4], + input b[4], + input carry_in[1], + output sum[4], + output carry[1] +){ + sig sum_temp[5] + + always { + sum_temp = a + b + carry_in //add all the inputs + if (sum_temp > 9) { + sum_temp = sum_temp + 6 //add 6, if result is more than 9. + carry = 1 //set the carry output + sum = sum_temp[3:0] + } else { + carry = 0 + sum = sum_temp[3:0] + } + } +} + + diff --git a/io_add_decimal/source/bcd_add_n.luc b/io_add_decimal/source/bcd_add_n.luc new file mode 100644 index 0000000..0e6f39f --- /dev/null +++ b/io_add_decimal/source/bcd_add_n.luc @@ -0,0 +1,23 @@ +module bcd_add_n #(DIGITS = 4 : DIGITS > 1) +( + input a[DIGITS][4], + input b[DIGITS][4], + input carry_in[1], + output sum[DIGITS][4], + output carry[1] +) { + bcd_add bcd_add[DIGITS] + + always { + bcd_add.a[0] = a[0] + bcd_add.b[0] = b[0] + bcd_add.carry_in[0] = carry_in + repeat (i, DIGITS - 1) { + bcd_add.a[i + 1] = a[i + 1] + bcd_add.b[i + 1] = b[i + 1] + bcd_add.carry_in[i + 1] = bcd_add.carry[i] + } + sum[3:0] = bcd_add.sum[3:0] + carry = bcd_add.carry[3] + } +} \ No newline at end of file diff --git a/io_add_decimal/source/btn_press.luc b/io_add_decimal/source/btn_press.luc new file mode 100644 index 0000000..22d6bee --- /dev/null +++ b/io_add_decimal/source/btn_press.luc @@ -0,0 +1,17 @@ +module btn_press ( + input clk, // clock + input btn_in, + output btn_down +) { + .clk(clk) { + edge_detector edge(#RISE(1), #FALL(0)) // detect rising edges + + button_conditioner btn_cond(#CLK_FREQ($is_sim() ? 1_000 : 100_000_000)) // button input conditioner + + } + always { + btn_cond.in = btn_in // raw button input + edge.in = btn_cond.out // input to the edge_detector + btn_down = edge.out // output the state + } +} \ No newline at end of file diff --git a/io_add_decimal/source/multi_seven_seg.luc b/io_add_decimal/source/multi_seven_seg.luc new file mode 100644 index 0000000..c882b93 --- /dev/null +++ b/io_add_decimal/source/multi_seven_seg.luc @@ -0,0 +1,29 @@ +module multi_seven_seg #( + DIGITS = 4 : DIGITS > 0, + DIV = $is_sim() ? 0 : 16 : DIV >= 0 +)( + input clk, // clock + input rst, // reset + input values[DIGITS][4], // values to show + output seg[7], // LED segments + output sel[DIGITS] // Digit select +) { + + // number of bits required to store DIGITS-1 + const DIGIT_BITS = $clog2(DIGITS) + + .clk(clk), .rst(rst) { + counter ctr (#DIV(DIV), #SIZE(DIGIT_BITS), #TOP(DIGITS-1)) + } + + seven_seg seg_dec // segment decoder + decoder digit_dec(#WIDTH(DIGIT_BITS)) // digit decoder + + always { + seg_dec.char = values[ctr.value] // select the value for the active digit + seg = seg_dec.segs // output the decoded value + + digit_dec.in = ctr.value // decode active digit to one-hot + sel = digit_dec.out // output the active digit + } +} \ No newline at end of file diff --git a/io_add_decimal/source/seven_seg.luc b/io_add_decimal/source/seven_seg.luc new file mode 100644 index 0000000..5681904 --- /dev/null +++ b/io_add_decimal/source/seven_seg.luc @@ -0,0 +1,26 @@ +module seven_seg ( + input char[4], + output segs[7] +) { + always { + case (char) { + 0: segs = 7b0111111 + 1: segs = 7b0000110 + 2: segs = 7b1011011 + 3: segs = 7b1001111 + 4: segs = 7b1100110 + 5: segs = 7b1101101 + 6: segs = 7b1111101 + 7: segs = 7b0000111 + 8: segs = 7b1111111 + 9: segs = 7b1100111 + 10: segs = 7b1110111 // A + 11: segs = 7b1111100 // b + 12: segs = 7b0111001 // C + 13: segs = 7b1011110 // d + 14: segs = 7b1111001 // E + 15: segs = 7b1110001 // F + default: segs = 7b0000000 + } + } +}