├── .gitignore
├── .gitmodules
├── LICENSE.txt
├── README.md
├── docs
└── README.md
├── helpers
├── 53-lattice-ftdi.rules
├── generate_target_vh.py
├── midstate
│ ├── Makefile
│ ├── midstate.py
│ ├── midstate_sha256.c
│ └── midstate_test.py
├── setup-dev-environment.sh
└── verify-result
│ ├── example.toml
│ └── verify.py
└── src
├── Makefile
├── SHA256_K.v
├── external_io.v
├── pinout-ice40hx8k-b-evn.pcf
├── pinout-icepool-ice40hx8k.pcf
├── pinout-icepool-ice40up5k.pcf
├── sha_round.v
├── sha_unit.v
├── shapool.v
├── targets
├── target-1.vh
├── target-1024.vh
├── target-128.vh
├── target-16.vh
├── target-2.vh
├── target-2048.vh
├── target-256.vh
├── target-32.vh
├── target-4.vh
├── target-4096.vh
├── target-512.vh
├── target-64.vh
├── target-8.vh
└── target-8192.vh
├── tests
├── Makefile
├── btc_four_zeroes
│ ├── Makefile
│ ├── main.c
│ └── rtl
│ │ ├── Makefile
│ │ └── top_test.v
├── btc_sixteen_zeroes
│ ├── Makefile
│ ├── main.c
│ └── rtl
│ │ ├── Makefile
│ │ └── top_test.v
├── external_io_usage_tb.v
├── ram_init_test
│ ├── Makefile
│ ├── main.c
│ └── rtl
│ │ ├── Makefile
│ │ └── top_test.v
├── sha_round_usage_tb.v
├── sha_unit_btc_tb.v
├── sha_unit_usage_tb.v
├── shapool_usage_tb.v
└── top_usage_tb.v
├── top.v
├── top_hx8k.v
├── top_up5k.v
└── w_expand.v
/.gitignore:
--------------------------------------------------------------------------------
1 | # Gateware build artifacts
2 | *.out
3 | *.blif
4 | *.json
5 | *.asc
6 | *.bin
7 |
8 | # iverilog artifacts
9 | obj_dir/
10 |
11 | # Test bench artifacts
12 | *.vcd
13 |
14 | # Hardware test artifacts
15 | *.o
16 | *.a
17 |
18 | # Python
19 | dist/
20 | build/
21 | __pycache__/
22 | .pytest_cache/
23 | *.pyc
24 | *.egg-info/
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "src/tests/btc_four_zeroes/icepool-driver"]
2 | path = src/tests/vendor/icepool-driver
3 | url = https://github.com/jkiv/icepool-driver
4 | [submodule "src/tests/vendor/munit"]
5 | path = src/tests/vendor/munit
6 | url = https://github.com/nemequ/munit
7 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright 2018 Jon Kivinen (jkiv)
2 |
3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4 |
5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6 |
7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8 |
9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10 |
11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # shapool-core
2 |
3 | `shapool-core` is an FPGA core for SHA256d mining (e.g. BTC) for use with
4 | Lattice Semiconductor [iCE40](https://www.latticesemi.com/iCE40) devices using the open-source [Project IceStorm](http://www.clifford.at/icestorm/)
5 | toolchain.
6 |
7 | The purpose of this project is to evaluate the iCE40 devices for mining and
8 | produce a hobbyist/DIY low power FPGA SHA256d miner.
9 |
10 | This project aims to support multiple targets including
11 |
12 | * [ICE40HX8K-B-EVN](http://www.latticesemi.com/en/Products/DevelopmentBoardsAndKits/iCE40HX8KBreakoutBoard.aspx)
13 | * [jkiv/icepool-board](https://github.com/jkiv/icepool-board)
14 | * ... and others.
15 |
16 | (Support for [ECP5](https://www.latticesemi.com/Products/FPGAandCPLD/ECP5) boards using the [Project Trellis](https://github.com/YosysHQ/prjtrellis) open-source toolchain is [planned](https://github.com/jkiv/shapool-core/issues/5) as well.)
17 |
18 | ### Support
19 |
20 | Please consider supporting this project and others like it by donating:
21 |
22 | * ☕: [ko-fi.com/jkiv_](https://ko-fi.com/jkiv_)
23 | * ₿: `13zRrs1YDdooUN5WtfXRSDn8KnJdok4qG9`
24 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | ## About `shapool-core`
2 |
3 | `shapool-core` is an FPGA core that computes double-SHA256 hashes for the purposes of cryptocurrency mining, e.g. Bitcoin.
4 |
5 | `shapool-core` is intended to be used in a cluster-like environment but should work as a stand-alone core, i.e. a cluster of one.
6 |
7 | Each `shapool-core` device in a cluster is given the same job data by the host device. Each device works on the job until it either finishes or is interrupted by the host device.
8 |
9 | The work required for each job can be divided among the cluster by providing each `shapool-core` device with unique parameters such that no two devices will perform the same work.
10 |
11 | ## Signal Descriptions
12 |
13 | ```
14 | shapool-core
15 | +---------------+
16 | clk ---|> |--> ready_n
17 | | |
18 | reset_n -->| |--> status_led_n
19 | | |
20 | sck0 -->| |
21 | sdi0 -->| SPI 0 |
22 | cs0_n -->| |
23 | | |
24 | sck1 -->| |
25 | sdi1 -->| SPI 1 |--> sdo1
26 | cs1_n -->| |
27 | +---------------+
28 | ```
29 |
30 | * `clk` - external core clock input
31 | * `reset_n` - external asynchronous reset input
32 | * `sck0` - serial data clock input (SPI interface 0)
33 | * `sdi0` - serial data input (SPI interface 0)
34 | * `cs0_n` - active-low chip-select input (SPI interface 0)
35 | * `sck1` - serial data clock input (SPI interface 1)
36 | * `sdi1` - serial data input (SPI interface 1)
37 | * `sdo1` - serial data output (SPI interface 1)
38 | * `cs1_n` - active-low chip-select input (SPI interface 1)
39 | * `ready_n` - active-low, open-drain "data ready" output
40 | * `status_led_n` - active-low indicator LED output
41 |
42 | SPI interface 0 is a one-to-many interface which allows the host device load the same job data to all `shapool-core` devices on the SPI bus. Note that this interface does not have a data output.
43 |
44 | SPI interface 1 is a daisy-chained interface which allows the host device to load each `shapool-core` with device-specific data, as well as read device-specific results back.
45 |
46 | Both SPI interfaces are SPI mode 0, 0 and most-significant-bit-first.
47 |
48 | ## Behavioural Description
49 |
50 | `shapool-core` has four main states:
51 |
52 | 1. `RESET` - Reset
53 | 2. `LOAD` - Load device and job data
54 | 3. `EXEC` - Execute job
55 | 4. `DONE` - Done executing, read result
56 |
57 | The device enters the `RESET` state whenever the device's `reset_n` signal is asserted. This state resets execution state but retains job and configuration data.
58 |
59 | Immediately after resetting, the device enters the `LOAD` state, while `reset_n` is still asserted. During the `LOAD` state, both SPI interfaces 0 and 1 are active. Job data and device configuration data can be written to SPI interfaces 0 and 1 respectively.
60 |
61 | After the device is loaded with its job and configuration data, `reset_n` can be de-asserted to put the device into the `EXEC` state.
62 |
63 | The device will work on the provided job until it is done. If and when the device is done its job, the device will enter the `DONE` state.
64 |
65 | Each device who successfully completes its job will assert its `ready_n` signal. The `ready_n` signal tells the host device that work is completed and the result can be read on SPI interface 1. If the host asserts `cs1_n` while devices are in the `EXEC` state, this will force all devices to enter the `DONE` state.
66 |
67 | Once all devices are in the `DONE` state, SPI interface 1 is available to read from. Devices who successfully finished their job will provide the result of their job. Otherwise, the device will provide a result of all zeros.
68 |
69 | After reading the results from the devices, the host can repeat the process by asserting `reset_n` and loading a new job on SPI interface 0.
70 |
71 | ## Device configurations
72 |
73 | Device-specific configuration data can be written to the device using SPI interface 1 while `reset_n` is asserted.
74 |
75 | This typically only needs to be done when the device is initialized, e.g. after a power cycle or reprogramming.
76 |
77 |
78 |
79 | * `nonce start (MSB)`: the most-significant byte of the initial value for the nonce (0-255).
80 |
81 | ## Job configuration
82 |
83 | Job configuration data can be written to the device using SPI interface 0 while `reset_n` is asserted.
84 |
85 | This is done as often as required, e.g. after completed or expired jobs.
86 |
87 |
88 |
89 | * `SHA256 state`: the internal state of the first SHA256 after the first block is hashed but before the second block is hashed.
90 | * `message head`: the start of the second block of the first hash.
91 |
92 | ## Job results
93 |
94 | Job result data can be read using SPI interface 1 when `cs1_n` is asserted, `reset_n` is de-asserted, and all devices have entered the `DONE` state.
95 |
96 | Devices who did not finish their work will provide all zeros as a result.
97 |
98 |
99 |
100 | * `match flags`: bit positions having `1` denote pipelines (cores) that generated a winning hash.
101 | * `winning nonce`: the nonce that caused the winning hash (uncorrected), or zero if no winning nonce found.
102 |
103 | The `winning nonce` provided by devices is "uncorrected." This means that the host is responsible for reconstructing the actual nonce from `match flags` and other knowledge about the devices.
104 |
105 | 1. The nonce value is +2 greater than the actual nonce that caused the match.
106 | 2. Any hard-coded most-significant-bits are zeroed (e.g. in a multi-core configuration.)
107 | 3. `nonce_start_MSB` has not been applied to the returned value.
108 |
109 | So, reconstructing the nonce can be done as follows:
110 |
111 | 1. Subtract 2 from the nonce.
112 |
113 | 2. Correct the most-significant-bits using the value of match flags and the number of hard-coded bits per device.
114 |
115 | For example, if there are 8 cores per device then there are `ceil(log2(8)) = 3` hard-coded bits per core. If match flags is `0x04` (bit position 2), then the most-significant-bits are `b010 = 2**2`.
116 |
117 | 3. Apply `nonce_start_MSB` corresponding to the device that supplied the nonce.
118 |
119 | For example, if `nonce_start_MSB = 0x80` and there are 3 hard-coded bits per core, then XOR the result with `0x80 << (24-3) = 0x01000000`
--------------------------------------------------------------------------------
/helpers/53-lattice-ftdi.rules:
--------------------------------------------------------------------------------
1 | # ICE40HX8K-EVB Development Board (shapool-core)
2 | #ACTION=="add", ATTR{idVendor}=="0403", ATTR{idProduct}=="6010", MODE:="666" # 2018
3 | ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="0660", GROUP="plugdev", TAG+="uaccess"
4 |
--------------------------------------------------------------------------------
/helpers/generate_target_vh.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import sys
4 |
5 | if __name__ == '__main__':
6 | namebase = 'target'
7 | for n in range(0, 14):
8 | difficulty = 2**n
9 | target = 32+n
10 | filename = f'{namebase}-{difficulty}.vh'
11 |
12 | with open(filename, 'w') as f:
13 | print(f'Writing \'{filename}\'', file=sys.stderr)
14 | f.writelines(f'`define TARGET {target}\n')
15 |
16 | print('Done!', file=sys.stderr)
17 |
--------------------------------------------------------------------------------
/helpers/midstate/Makefile:
--------------------------------------------------------------------------------
1 | .phony : all
2 | all : midstate_sha256.so
3 |
4 | midstate_sha256.so : midstate_sha256.c
5 | gcc --std=c99 -Wall -fPIC -shared -o $@ $^
6 |
7 | .phony : test
8 | test : midstate_sha256.so
9 | pytest
10 |
11 | .phony : clean
12 | clean :
13 | rm -f midstate_sha256.so
14 | rm -rf __pycache__/
15 | rm -rf .pytest_cache/
--------------------------------------------------------------------------------
/helpers/midstate/midstate.py:
--------------------------------------------------------------------------------
1 | import argparse
2 | import binascii
3 | import ctypes
4 | from os import path
5 | import sys
6 |
7 | _midstate = ctypes.CDLL(path.abspath(path.join(path.dirname(__file__), "midstate_sha256.so")))
8 |
9 | def _ffi(ffi, function_name, return_type, arg_types):
10 | fn = ffi.__getattr__(function_name)
11 | fn.restype = return_type
12 | fn.argtypes = arg_types
13 | return fn
14 |
15 | class ShaState:
16 | def __init__(self):
17 | self._state = ctypes.create_string_buffer(32)
18 | _init_state = _ffi(_midstate, 'init_state', None, [ctypes.c_char_p,])
19 | _init_state(self._state)
20 |
21 | def __del__(self):
22 | del self._state
23 |
24 | def update(self, block):
25 | _update_state = _ffi(_midstate, 'update_state', None, [ctypes.c_char_p, ctypes.c_char_p,])
26 | _update_state(self._state, block)
27 |
28 | def as_b64(self, byte_swap=False):
29 | return binascii.b2a_base64(self.as_bin(byte_swap)).decode('utf-8')
30 |
31 | def as_hex(self, byte_swap=False):
32 | return binascii.b2a_hex(self.as_bin(byte_swap)).decode('utf-8')
33 |
34 | def as_bin(self, byte_swap=False):
35 | result = bytes(self._state)
36 | if byte_swap:
37 | return result[3::-1] + result[7:3:-1] + \
38 | result[11:7:-1] + result[15:11:-1] + \
39 | result[19:15:-1] + result[23:19:-1] + \
40 | result[27:23:-1] + result[31:27:-1]
41 | else:
42 | return result
43 |
44 | def stream_blocks(stream, block_size=64):
45 | while True:
46 | block_data = stream.read(block_size)
47 |
48 | if not block_data or block_size != len(block_data):
49 | return
50 |
51 | yield block_data
52 |
53 | def get_midstate(stream, last_block=None):
54 |
55 | state = ShaState()
56 |
57 | for n, block_data in enumerate(stream_blocks(stream)):
58 | state.update(block_data)
59 |
60 | if n == last_block:
61 | return state
62 |
63 | if last_block:
64 | raise RuntimeError(f'Stream closed before reaching block {last_block}. Last block was {n}.')
65 |
66 | return state
67 |
68 | if __name__ == '__main__':
69 |
70 | parser = argparse.ArgumentParser(description='Compute intermediate states of a SHA256 hash.')
71 |
72 | parser.add_argument('-i', '--input-file', type=str, help='input file (default: stdin)', default=None)
73 | parser.add_argument('-o', '--output-file', type=str, help='output file (default: stdout)', default=None)
74 | parser.add_argument('-b', '--block', type=int, help='return the state after specified block number (zero-indexed, default: last full block).')
75 |
76 | output_format = parser.add_mutually_exclusive_group(required=False)
77 | output_format.add_argument('--hex', help='Output as hexadecimal.', action='store_true', default=True)
78 | output_format.add_argument('--base64', help='Output as Base64.', action='store_true', default=False)
79 | output_format.add_argument('--bin', help='Output as binary.', action='store_true', default=False)
80 |
81 | args = parser.parse_args()
82 |
83 | if args.block and args.block < 0:
84 | raise ValueError("Block number must be >= 0.")
85 |
86 | if args.input_file is None:
87 | state = get_midstate(sys.stdin.buffer, args.block)
88 | else:
89 | with open(args.input_file, 'rb') as s:
90 | state = get_midstate(s, args.block)
91 |
92 | if args.output_file is None:
93 | s = sys.stdout
94 |
95 | if args.bin:
96 | s.buffer.write(state.as_bin())
97 | elif args.base64:
98 | s.write(state.as_b64())
99 | elif args.hex:
100 | s.write(state.as_hex() + u'\n')
101 |
102 | else:
103 | with open(args.output_file, 'wb') as s:
104 | if args.bin:
105 | s.write(state.as_bin())
106 | elif args.base64:
107 | s.write(state.as_b64().rstrip(u'\n'))
108 | elif args.hex:
109 | s.write(state.as_hex())
110 |
--------------------------------------------------------------------------------
/helpers/midstate/midstate_sha256.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | static const uint32_t SHA256_K[64] = {
6 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
7 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
8 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
9 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
10 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
11 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
12 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
13 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
14 | };
15 |
16 | static const uint32_t SHA256_H0[8] = {
17 | 0x6a09e667, 0xbb67ae85,
18 | 0x3c6ef372, 0xa54ff53a,
19 | 0x510e527f, 0x9b05688c,
20 | 0x1f83d9ab, 0x5be0cd19
21 | };
22 |
23 | static uint32_t ror32(uint32_t x, uint32_t b) {
24 | return (x>>b)|(x<<(32-b));
25 | }
26 |
27 | static uint32_t maj(uint32_t x, uint32_t y, uint32_t z) {
28 | //return (x & y) ^ (x & z) ^ (y & z);
29 | return ((y & z) | (x & (y | z)));
30 | }
31 |
32 | static uint32_t ch(uint32_t x, uint32_t y, uint32_t z) {
33 | //return (x & y) ^ ((~x) & z);
34 | return z ^ (x & (z ^ y));
35 | }
36 |
37 | static uint32_t bsig0(uint32_t x) {
38 | return ror32(x,2) ^ ror32(x,13) ^ ror32(x,22);
39 | }
40 |
41 | static uint32_t bsig1(uint32_t x) {
42 | return ror32(x,6) ^ ror32(x,11) ^ ror32(x,25);
43 | }
44 |
45 | static uint32_t ssig0(uint32_t x) {
46 | return ror32(x,7) ^ ror32(x,18) ^ (x>>3);
47 | }
48 |
49 | static uint32_t ssig1(uint32_t x) {
50 | return ror32(x,17) ^ ror32(x,19) ^ (x>>10);
51 | }
52 |
53 | static uint32_t w_expand(uint32_t w2, uint32_t w7, uint32_t w15, uint32_t w16) {
54 | return ssig1(w2) + w7 + ssig0(w15) + w16;
55 | }
56 |
57 | static uint32_t byte_swap_32(uint32_t x)
58 | {
59 | return ((x & 0x000000ff) << 24) |
60 | ((x & 0x0000ff00) << 8) |
61 | ((x & 0x00ff0000) >> 8) |
62 | ((x & 0xff000000) >> 24);
63 | }
64 |
65 | static void sha256_update(uint32_t* H, const uint32_t* m) {
66 | uint32_t w[64] = {0}; // message schedule
67 |
68 | uint32_t a,b,c,d,e,f,g,h = 0; // working variables
69 | uint32_t t1,t2 = 0; // temporary values
70 |
71 | // Initialize working variables
72 | a = H[0];
73 | b = H[1];
74 | c = H[2];
75 | d = H[3];
76 | e = H[4];
77 | f = H[5];
78 | g = H[6];
79 | h = H[7];
80 |
81 | // Mangle a-h using m
82 | for (uint8_t t = 0; t < 64; t++) {
83 | // Compute w[t]
84 | if (t < 16) {
85 | // 32-bit input is considered big-endian by spec
86 | // whereas x86 is little endian. Swap byte order.
87 | w[t] = byte_swap_32(m[t]);
88 | }
89 | else {
90 | w[t] = w_expand(w[t-2], w[t-7], w[t-15], w[t-16]);
91 | }
92 |
93 | // Compute t1, t2
94 | t1 = h;
95 | t1 += bsig1(e);
96 | t1 += ch(e,f,g);
97 | t1 += SHA256_K[t];
98 | t1 += w[t];
99 |
100 | t2 = bsig0(a);
101 | t2 += maj(a,b,c);
102 |
103 | // Update working variables (order here matters)
104 | h = g;
105 | g = f;
106 | f = e;
107 | e = d+t1;
108 | d = c;
109 | c = b;
110 | b = a;
111 | a = t1+t2;
112 | }
113 |
114 | // Update H
115 | H[0] += a;
116 | H[1] += b;
117 | H[2] += c;
118 | H[3] += d;
119 | H[4] += e;
120 | H[5] += f;
121 | H[6] += g;
122 | H[7] += h;
123 | }
124 |
125 | void init_state(uint32_t* state) {
126 | for (size_t i = 0; i < 8; i++) {
127 | state[i] = SHA256_H0[i];
128 | }
129 | }
130 |
131 | void update_state(uint32_t* state, const uint32_t* block) {
132 | sha256_update(state, block);
133 | }
--------------------------------------------------------------------------------
/helpers/midstate/midstate_test.py:
--------------------------------------------------------------------------------
1 | import binascii
2 | import midstate
3 | import pytest
4 | import struct
5 |
6 | def test_initial_state():
7 | SHA256_H0 = bytes([
8 | # Byte-swap 32-bit words
9 | 0x6a, 0x09, 0xe6, 0x67,
10 | 0xbb, 0x67, 0xae, 0x85,
11 | 0x3c, 0x6e, 0xf3, 0x72,
12 | 0xa5, 0x4f, 0xf5, 0x3a,
13 | 0x51, 0x0e, 0x52, 0x7f,
14 | 0x9b, 0x05, 0x68, 0x8c,
15 | 0x1f, 0x83, 0xd9, 0xab,
16 | 0x5b, 0xe0, 0xcd, 0x19
17 | ])
18 |
19 | s = midstate.ShaState()
20 |
21 | assert s.as_bin(True) == SHA256_H0
22 |
23 | def test_btc_four_zeroes():
24 | expected_state = bytes([
25 | 0xdc, 0x6a, 0x3b, 0x8d, 0x0c, 0x69, 0x42, 0x1a,
26 | 0xcb, 0x1a, 0x54, 0x34, 0xe5, 0x36, 0xf7, 0xd5,
27 | 0xc3, 0xc1, 0xb9, 0xe4, 0x4c, 0xbb, 0x9b, 0x8f,
28 | 0x95, 0xf0, 0x17, 0x2e, 0xfc, 0x48, 0xd2, 0xdf,
29 | ])
30 |
31 | expected_second_block = bytes([
32 | 0xdc, 0x14, 0x17, 0x87,
33 | 0x35, 0x8b, 0x05, 0x53,
34 | 0x53, 0x5f, 0x01, 0x19
35 | ])
36 |
37 | message = struct.pack(" str:
11 | # https://en.bitcoin.it/wiki/Difficulty
12 | exp = bits >> 24
13 | mant = bits & 0xffffff
14 | target_hexstr = '%064x' % (mant * (1<<(8*(exp - 3))))
15 | target_str = target_hexstr.decode('hex')
16 |
17 | @functools.lru_cache
18 | def get_difficulty_bm(size: int) -> bytes:
19 | assert(size >= 0 and size <= 32*8)
20 |
21 | bin_mask = ('1' * size) + ('0' * (32*8-size))
22 |
23 | return bytes(int(bin_mask[i:i+8], 2) for i in range(0, 32*8, 8))
24 |
25 |
26 | def make_header(version: int, previous_block: bytes, merkel_root: bytes, time: int, bits: int) -> bytes:
27 | return struct.pack(" dict:
33 | version = slice(0,4)
34 | previous_block = slice(4,36)
35 | merkel_root = slice(36,68)
36 | time = slice(68,72)
37 | bits = slice(72,76)
38 | nonce = slice(76,80)
39 |
40 | return {
41 | "version": header[version],
42 | "previous_block": header[previous_block],
43 | "merkel_root": header[merkel_root],
44 | "time": header[time],
45 | "bits": header[bits],
46 | "nonce": header[nonce] if has_nonce else None
47 | }
48 |
49 | def test_hash_leading_zeroes(hash: bytes, target_zeroes: int = 64) -> bool:
50 | zero_mask = get_difficulty_bm(target_zeroes)
51 | return all(b & byte_mask == 0 for b, byte_mask in zip(hash, zero_mask))
52 |
53 | def compute_hash(header: bytes) -> bytes:
54 | return hashlib.sha256(hashlib.sha256(header).digest()).digest()
55 |
56 | def compute_nonce(header: bytes, leading_zeroes: int = 64, nonce_gen: Iterator = None) -> int:
57 |
58 | assert(len(header) == 76)
59 |
60 | if nonce_gen is None:
61 | nonce_gen = range(2**32)
62 |
63 | for nonce in nonce_gen:
64 | hash = compute_hash(header + struct.pack(" bytes:
72 | assert(len(header) == 76)
73 |
74 | header = header + struct.pack("] --> compute nonce
86 | # verify [-f ] --> check nonce
87 | # verify [-f ] --> print case in blocks
88 | # verify [-f ] --
89 |
90 | EXAMPLE_TOML = '''# Example TOML
91 | version = 2
92 | previous_block = "000000000000000117c80378b8da0e33559b5997f2ad55e2f7d18ec1975b9717"
93 | merkel_root = "871714dcbae6c8193a2bb9b2a69fe1c0440399f38d94b3a0f1b447275a29978a"
94 | time = 0x53058b35
95 | bits = 0x19015f53
96 | '''
97 |
98 | if __name__ == "__main__":
99 | parser = argparse.ArgumentParser(description="")
100 |
101 | parser.add_argument("difficulty", type=int, help="number of leading zeroes to check hash against")
102 | parser.add_argument("-c", "--case", type=str, required=False, help="path to toml file containing case data (default: stdin)")
103 |
104 | group = parser.add_mutually_exclusive_group()
105 | group.add_argument("-n", "--nonce", type=int, required=False, help="nonce to verify")
106 | group.add_argument("-r", "--range", type=str, required=False, help="set of nonce values to check (comma-separated values or start:end)")
107 |
108 | args = parser.parse_args()
109 |
110 | # Load case
111 | case = None
112 |
113 | if args.case and args.case != '-':
114 | case = toml.load(args.case)
115 | else:
116 | case = toml.load(sys.stdin)
117 |
118 | # TODO validate `case`
119 |
120 | case["previous_block"] = binascii.a2b_hex(case["previous_block"])[::-1]
121 | case["merkel_root"] = binascii.a2b_hex(case["merkel_root"])[::-1]
122 |
123 | header = make_header(**case)
124 |
125 | # Run case
126 | if args.nonce:
127 | # Verify nonce
128 | valid = verify_nonce(header, args.nonce, args.difficulty)
129 |
130 | if not valid:
131 | print(f"Invalid nonce: {args.nonce}", file=sys.stderr)
132 | sys.exit(1)
133 | else:
134 | sys.exit(0)
135 |
136 | else:
137 |
138 | # Interpret nonce range
139 | nonce_gen = None
140 | if args.range:
141 | if ',' in args.range:
142 | nonce_gen = [int(n.strip()) for n in args.range.split(',')]
143 | elif ':' in args.range:
144 | start, end = (int(x) for x in args.range.split(':', 1))
145 | nonce_gen = range(start, end)
146 |
147 | # Compute nonce
148 | nonce = compute_nonce(header, args.difficulty, nonce_gen)
149 |
150 | if nonce is None:
151 | print("No solution found.", file=sys.stderr)
152 | sys.exit(1)
153 | else:
154 | print(nonce)
155 | sys.exit(0)
156 |
--------------------------------------------------------------------------------
/src/Makefile:
--------------------------------------------------------------------------------
1 | DIFFICULTY=1
2 |
3 | # Build all bitstreams
4 |
5 | .phony: all
6 |
7 | all: shapool-ice40hx8k-b-evn.bin shapool-icepool-ice40hx8k.bin # shapool-icepool-ice40up5k.bin
8 |
9 | # Validate verilog code
10 |
11 | .phony: lint
12 |
13 | lint : top.v shapool.v sha_unit.v sha_round.v w_expand.v SHA256_K.v external_io.v
14 | verilator -Wall -cc top.v
15 |
16 | # Clean up
17 |
18 | .phony: clean
19 | clean :
20 | rm -f target.vh
21 | rm -f shapool-*.out \
22 | shapool-*.json \
23 | shapool-*.asc \
24 | shapool-*.bin
25 | rm -rf ./obj_dir
26 |
27 | # Synthesize for device type
28 |
29 | shapool-ice40-hx8k.json : top_hx8k.v top.v shapool.v sha_unit.v sha_round.v w_expand.v SHA256_K.v external_io.v
30 | rm -f target.vh
31 | ln -s targets/target-$(DIFFICULTY).vh target.vh
32 | yosys -p 'synth_ice40 -top top_hx8k -json $@ -abc2 -retime' $^
33 |
34 | shapool-ice40-up5k.json : top_up5k.v top.v shapool.v sha_unit.v sha_round.v w_expand.v SHA256_K.v external_io.v
35 | rm -f target.vh
36 | ln -s targets/target-$(DIFFICULTY).vh target.vh
37 | yosys -p 'synth_ice40 -top top_up5k -json $@ -abc2 -retime' $^
38 |
39 | # Route for target board
40 |
41 | shapool-ice40hx8k-b-evn.asc : shapool-ice40-hx8k.json pinout-ice40hx8k-b-evn.pcf
42 | nextpnr-ice40 --package ct256 --hx8k --json shapool-ice40-hx8k.json --pcf pinout-ice40hx8k-b-evn.pcf --asc $@
43 |
44 | #shapool-icepool-ice40up5k.asc : shapool-ice40-up5k.json pinout-ice40up5k-b-evn.pcf
45 | # nextpnr-ice40 --package sg48 --up5k --json shapool-ice40-up5k.json --pcf pinout-ice40up5k-b-evn.pcf --asc $@
46 |
47 | shapool-icepool-ice40hx8k.asc : shapool-ice40-hx8k.json pinout-icepool-ice40hx8k.pcf
48 | nextpnr-ice40 --package bg121 --hx8k --json shapool-ice40-hx8k.json --pcf pinout-icepool-ice40hx8k.pcf --asc $@
49 |
50 | # Generate bitstream for target board
51 |
52 | shapool-ice40hx8k-b-evn.bin : shapool-ice40hx8k-b-evn.asc
53 | icepack $^ $@
54 |
55 | #shapool-icepool-ice40up5k.bin : shapool-icepool-ice40up5k.asc
56 | # icepack $^ $@
57 |
58 | shapool-icepool-ice40hx8k.bin : shapool-icepool-ice40hx8k.asc
59 | icepack $^ $@
60 |
61 | # Run timing simulations
62 |
63 | .phony: time-ice40hx8k-b-evn
64 | time-ice40hx8k-b-evn : shapool-ice40hx8k-v-evn.asc
65 | icetime -t -m -d hx8k -P ct256 -p pinout-ice40hx8k-b-evn.pcf -o - $^
66 |
67 | #.phony: time-ice40up5k-b-evn
68 | #time-ice40up5k-b-evn : shapool-icepool-ice40up5k.asc
69 | # icetime -t -m -d up5k -P sg48 -p pinout-ice40up5k-b-evn.pcf -o - $^
70 |
71 | .phony: time-icepool-ice40hx8k
72 | time-icepool-ice40hx8k : shapool-icepool-ice40hx8k.asc
73 | #icetime -t -m -d hx8k -P cm121 -p pinout-icepool-ice40hx8k.pcf -o - $^
74 | icetime -t -m -d hx8k -P bg121 -p pinout-icepool-ice40hx8k.pcf -o - $^
75 |
76 | # Make target binary and upload to device
77 |
78 | .phony: flash-ice40hx8k-b-evn
79 | flash-ice40hx8k-b-evn : shapool-ice40-hx8k-ct256.bin
80 | iceprog -v -S $^
81 |
82 | #.phony: flash-ice40up5k-b-evn
83 | #flash-ice40up5k-b-evn : shapool-icepool-ice40up5k.bin
84 | # iceprog -v -S $^
85 |
86 | .phony: flash-icepool-ice40hx8k
87 | flash-icepool-ice40hx8k : shapool-icepool-ice40hx8k.bin
88 | iceprog -v -S $^
89 |
--------------------------------------------------------------------------------
/src/SHA256_K.v:
--------------------------------------------------------------------------------
1 | /*
2 | * Two read-only 256x16 RAM banks for 32-bit word access per clock cycle, addressed by `round`.
3 | */
4 | module SHA256_K (
5 | clk,
6 | round,
7 | Kt
8 | );
9 |
10 | input clk;
11 | input [5:0] round;
12 |
13 | `ifndef VERILATOR
14 |
15 | wire [15:0] data_hi;
16 | wire [15:0] data_lo;
17 |
18 | output wire [31:0] Kt;
19 | assign Kt = { data_hi, data_lo };
20 |
21 | wire [7:0] address;
22 | assign address = { 2'b10, round };
23 |
24 | SB_RAM40_4K ram256x16_hi (
25 | .RDATA(data_hi),
26 | .RADDR(address),
27 | .RCLK(clk),
28 | .RCLKE(1),
29 | .RE(1),
30 | .WADDR(0),
31 | .WCLK(0),
32 | .WCLKE(0),
33 | .WDATA(0),
34 | .WE(0),
35 | .MASK(0)
36 | );
37 |
38 | SB_RAM40_4K ram256x16_lo (
39 | .RDATA(data_lo),
40 | .RADDR(address),
41 | .RCLK(clk),
42 | .RCLKE(1),
43 | .RE(1),
44 | .WADDR(0),
45 | .WCLK(0),
46 | .WCLKE(0),
47 | .WDATA(0),
48 | .WE(0),
49 | .MASK(0)
50 | );
51 |
52 | defparam ram256x16_hi.READ_MODE = 0; // 0 = 256x16
53 | defparam ram256x16_hi.WRITE_MODE = 0; // 0 = 256x16
54 |
55 | defparam ram256x16_lo.READ_MODE = 0; // 0 = 256x16
56 | defparam ram256x16_lo.WRITE_MODE = 0; // 0 = 256x16
57 |
58 | defparam ram256x16_hi.INIT_0 = 0;
59 | defparam ram256x16_hi.INIT_1 = 0;
60 | defparam ram256x16_hi.INIT_2 = 0;
61 | defparam ram256x16_hi.INIT_3 = 0;
62 | defparam ram256x16_hi.INIT_4 = 0;
63 | defparam ram256x16_hi.INIT_5 = 0;
64 | defparam ram256x16_hi.INIT_6 = 0;
65 | defparam ram256x16_hi.INIT_7 = 0;
66 | defparam ram256x16_hi.INIT_8 = 256'hc19b_9bdc_80de_72be_550c_2431_1283_d807_ab1c_923f_59f1_3956_e9b5_b5c0_7137_428a;
67 | defparam ram256x16_hi.INIT_9 = 256'h1429_06ca_d5a7_c6e0_bf59_b003_a831_983e_76f9_5cb0_4a74_2de9_240c_0fc1_efbe_e49b;
68 | defparam ram256x16_hi.INIT_A = 256'h106a_f40e_d699_d192_c76c_c24b_a81a_a2bf_9272_81c2_766a_650a_5338_4d2c_2e1b_27b7;
69 | defparam ram256x16_hi.INIT_B = 256'hc671_bef9_a450_90be_8cc7_84c8_78a5_748f_682e_5b9c_4ed8_391c_34b0_2748_1e37_19a4;
70 | defparam ram256x16_hi.INIT_C = 0;
71 | defparam ram256x16_hi.INIT_D = 0;
72 | defparam ram256x16_hi.INIT_E = 0;
73 | defparam ram256x16_hi.INIT_F = 0;
74 |
75 | defparam ram256x16_lo.INIT_0 = 0;
76 | defparam ram256x16_lo.INIT_1 = 0;
77 | defparam ram256x16_lo.INIT_2 = 0;
78 | defparam ram256x16_lo.INIT_3 = 0;
79 | defparam ram256x16_lo.INIT_4 = 0;
80 | defparam ram256x16_lo.INIT_5 = 0;
81 | defparam ram256x16_lo.INIT_6 = 0;
82 | defparam ram256x16_lo.INIT_7 = 0;
83 | defparam ram256x16_lo.INIT_8 = 256'hf174_06a7_b1fe_5d74_7dc3_85be_5b01_aa98_5ed5_82a4_11f1_c25b_dba5_fbcf_4491_2f98;
84 | defparam ram256x16_lo.INIT_9 = 256'h2967_6351_9147_0bf3_7fc7_27c8_c66d_5152_88da_a9dc_84aa_2c6f_a1cc_9dc6_4786_69c1;
85 | defparam ram256x16_lo.INIT_A = 256'ha070_3585_0624_e819_51a3_8b70_664b_e8a1_2c85_c92e_0abb_7354_0d13_6dfc_2138_0a85;
86 | defparam ram256x16_lo.INIT_B = 256'h78f2_a3f7_6ceb_fffa_0208_7814_636f_82ee_6ff3_ca4f_aa4a_0cb3_bcb5_774c_6c08_c116;
87 | defparam ram256x16_lo.INIT_C = 0;
88 | defparam ram256x16_lo.INIT_D = 0;
89 | defparam ram256x16_lo.INIT_E = 0;
90 | defparam ram256x16_lo.INIT_F = 0;
91 |
92 | `else
93 |
94 | // Simulate RAM lookup for testing
95 |
96 | output reg [31:0] Kt;
97 |
98 | wire [31:0] Ks[0:63];
99 |
100 | always @(posedge clk)
101 | begin
102 | Kt <= Ks[round];
103 | end
104 |
105 | assign Ks[ 0] = 32'h428a2f98;
106 | assign Ks[ 1] = 32'h71374491;
107 | assign Ks[ 2] = 32'hb5c0fbcf;
108 | assign Ks[ 3] = 32'he9b5dba5;
109 | assign Ks[ 4] = 32'h3956c25b;
110 | assign Ks[ 5] = 32'h59f111f1;
111 | assign Ks[ 6] = 32'h923f82a4;
112 | assign Ks[ 7] = 32'hab1c5ed5;
113 | assign Ks[ 8] = 32'hd807aa98;
114 | assign Ks[ 9] = 32'h12835b01;
115 | assign Ks[10] = 32'h243185be;
116 | assign Ks[11] = 32'h550c7dc3;
117 | assign Ks[12] = 32'h72be5d74;
118 | assign Ks[13] = 32'h80deb1fe;
119 | assign Ks[14] = 32'h9bdc06a7;
120 | assign Ks[15] = 32'hc19bf174;
121 | assign Ks[16] = 32'he49b69c1;
122 | assign Ks[17] = 32'hefbe4786;
123 | assign Ks[18] = 32'h0fc19dc6;
124 | assign Ks[19] = 32'h240ca1cc;
125 | assign Ks[20] = 32'h2de92c6f;
126 | assign Ks[21] = 32'h4a7484aa;
127 | assign Ks[22] = 32'h5cb0a9dc;
128 | assign Ks[23] = 32'h76f988da;
129 | assign Ks[24] = 32'h983e5152;
130 | assign Ks[25] = 32'ha831c66d;
131 | assign Ks[26] = 32'hb00327c8;
132 | assign Ks[27] = 32'hbf597fc7;
133 | assign Ks[28] = 32'hc6e00bf3;
134 | assign Ks[29] = 32'hd5a79147;
135 | assign Ks[30] = 32'h06ca6351;
136 | assign Ks[31] = 32'h14292967;
137 | assign Ks[32] = 32'h27b70a85;
138 | assign Ks[33] = 32'h2e1b2138;
139 | assign Ks[34] = 32'h4d2c6dfc;
140 | assign Ks[35] = 32'h53380d13;
141 | assign Ks[36] = 32'h650a7354;
142 | assign Ks[37] = 32'h766a0abb;
143 | assign Ks[38] = 32'h81c2c92e;
144 | assign Ks[39] = 32'h92722c85;
145 | assign Ks[40] = 32'ha2bfe8a1;
146 | assign Ks[41] = 32'ha81a664b;
147 | assign Ks[42] = 32'hc24b8b70;
148 | assign Ks[43] = 32'hc76c51a3;
149 | assign Ks[44] = 32'hd192e819;
150 | assign Ks[45] = 32'hd6990624;
151 | assign Ks[46] = 32'hf40e3585;
152 | assign Ks[47] = 32'h106aa070;
153 | assign Ks[48] = 32'h19a4c116;
154 | assign Ks[49] = 32'h1e376c08;
155 | assign Ks[50] = 32'h2748774c;
156 | assign Ks[51] = 32'h34b0bcb5;
157 | assign Ks[52] = 32'h391c0cb3;
158 | assign Ks[53] = 32'h4ed8aa4a;
159 | assign Ks[54] = 32'h5b9cca4f;
160 | assign Ks[55] = 32'h682e6ff3;
161 | assign Ks[56] = 32'h748f82ee;
162 | assign Ks[57] = 32'h78a5636f;
163 | assign Ks[58] = 32'h84c87814;
164 | assign Ks[59] = 32'h8cc70208;
165 | assign Ks[60] = 32'h90befffa;
166 | assign Ks[61] = 32'ha4506ceb;
167 | assign Ks[62] = 32'hbef9a3f7;
168 | assign Ks[63] = 32'hc67178f2;
169 |
170 | `endif
171 | endmodule
172 |
--------------------------------------------------------------------------------
/src/external_io.v:
--------------------------------------------------------------------------------
1 | /* interface
2 | *
3 | * IO interface for the top level module.
4 | */
5 | module external_io(
6 | clk,
7 | reset_n,
8 | // SPI(0)
9 | sck0,
10 | sdi0,
11 | cs0_n,
12 | // SPI(1)
13 | sck1,
14 | sdi1,
15 | sdo1,
16 | cs1_n,
17 | // Stored data
18 | device_config,
19 | job_config,
20 | // Control signals
21 | core_reset_n,
22 | // From shapool
23 | shapool_success,
24 | shapool_result,
25 | // READY signal
26 | ready
27 | );
28 |
29 | parameter POOL_SIZE = 2;
30 | parameter POOL_SIZE_LOG2 = 1;
31 |
32 | parameter DEVICE_CONFIG_WIDTH = 8; // nonce_start
33 | parameter JOB_CONFIG_WIDTH = 256 + 96; // sha_state + message_head
34 | parameter RESULT_DATA_WIDTH = 32 + 8; // nonce + match flags
35 | // FUTURE scale match_flags?
36 |
37 | // Inputs and outputs
38 |
39 | input wire clk;
40 | input wire reset_n;
41 |
42 | input wire sck0;
43 | input wire sdi0;
44 | input wire cs0_n;
45 |
46 | input wire sck1;
47 | input wire sdi1;
48 | output wire sdo1;
49 | input wire cs1_n;
50 |
51 | // Stored data
52 | output reg [DEVICE_CONFIG_WIDTH-1 : 0] device_config = 0;
53 | output reg [ JOB_CONFIG_WIDTH-1 : 0] job_config = 0;
54 | // output reg [ JOB_CONFIG_WIDTH-1 : 0] job_config = {
55 | // 128'hdc6a3b8d_0c69421a_cb1a5434_e536f7d5, // SHA starting state
56 | // 128'hc3c1b9e4_4cbb9b8f_95f0172e_fc48d2df, // ...
57 | // 96'hdc141787_358b0553_535f0119 // Start of message block
58 | // };
59 |
60 | output reg core_reset_n = 1;
61 |
62 | reg [RESULT_DATA_WIDTH-1 : 0] result_data = 0;
63 |
64 | // From shapool
65 | input wire shapool_success;
66 | input wire [RESULT_DATA_WIDTH-1:0] shapool_result;
67 |
68 | // READY signal
69 | output reg ready;
70 |
71 | // State machine definition
72 | localparam STATE_RESET = 2'b00,
73 | STATE_LOAD = 2'b01,
74 | STATE_EXEC = 2'b10,
75 | STATE_DONE = 2'b11;
76 |
77 | reg [1:0] state = STATE_RESET;
78 |
79 | // Synchronize SPI signals to reference `clk`
80 |
81 | reg [2:0] sck0_sync = 0;
82 | reg [1:0] sdi0_sync = 0;
83 | wire sck0_sync_rising_edge;
84 |
85 | reg [2:0] sck1_sync = 0;
86 | reg [1:0] sdi1_sync = 0;
87 | wire sck1_sync_rising_edge;
88 |
89 | always @(posedge clk)
90 | begin
91 | sck0_sync <= { sck0_sync[1], sck0_sync[0], sck0 };
92 | sck1_sync <= { sck1_sync[1], sck1_sync[0], sck1 };
93 |
94 | sdi0_sync <= { sdi0_sync[0], sdi0 };
95 | sdi1_sync <= { sdi1_sync[0], sdi1 };
96 | end
97 |
98 | assign sck0_sync_rising_edge = ~sck0_sync[2] & sck0_sync[1];
99 | assign sck1_sync_rising_edge = ~sck1_sync[2] & sck1_sync[1];
100 |
101 | // `sdo1` comes from `result_data` when STATE_DONE, otherwise `device_config`
102 | assign sdo1 = (state == STATE_DONE)
103 | ? result_data[RESULT_DATA_WIDTH-1]
104 | : device_config[DEVICE_CONFIG_WIDTH-1];
105 |
106 | // Main state machine process
107 | always @(posedge clk)
108 | begin
109 | case(state)
110 |
111 | STATE_RESET:
112 | begin
113 | ready <= 0; // Deassert READY
114 | core_reset_n <= 0; // Halt core
115 | state <= STATE_LOAD;
116 | end
117 |
118 | STATE_LOAD:
119 | begin
120 |
121 | // Go to STATE_EXEC when `reset_n` is deasserted
122 | if (reset_n)
123 | begin
124 | core_reset_n <= 1;
125 | state <= STATE_EXEC;
126 | end
127 |
128 | // Allow `job_config` and `device_config` to be shifted in while `reset_n` is asserted.
129 | else
130 | begin
131 | // SPI0
132 | if (!cs0_n && sck0_sync_rising_edge)
133 | job_config <= { job_config[JOB_CONFIG_WIDTH-2 : 0], sdi0_sync[1] };
134 |
135 | // SPI1
136 | if (!cs1_n && sck1_sync_rising_edge)
137 | device_config <= { device_config[DEVICE_CONFIG_WIDTH-2 : 0], sdi1_sync[1] };
138 | end
139 | end
140 |
141 | STATE_EXEC:
142 | begin
143 | core_reset_n <= 1;
144 |
145 | // Go to STATE_RESET when `reset_n` is asserted
146 | if (!reset_n)
147 | begin
148 | state <= STATE_RESET;
149 | end
150 | // Go to STATE_DONE when `shapool_success` is asserted
151 | else if (shapool_success)
152 | begin
153 | state <= STATE_DONE;
154 | ready <= 1;
155 | core_reset_n <= 0;
156 |
157 | /* verilator lint_off WIDTHCONCAT */
158 |
159 | // NOTE: The top POOL_SIZE_LOG2 bits are zeroed.
160 | // Host needs to perform check on all possible combination
161 | // of these bits.
162 |
163 | // NOTE: When "success" occurs, the current nonce value is
164 | // one value ahead of the nonce value that caused the success.
165 | // This is because the nonce value feeds the first hash unit,
166 | // whereas success is determined by the result of the
167 | // second.
168 | // In order to save resources, the host is responsible for
169 | // correcting this offset.
170 | result_data <= shapool_result;
171 | /* verilator lint_on WIDTHCONCAT */
172 | end
173 | // Go to STATE_DONE when `cs1_n` is asserted
174 | // FUTURE neighbour READY
175 | else if (!cs1_n)
176 | begin
177 | state <= STATE_DONE;
178 | ready <= 1;
179 | core_reset_n <= 0;
180 | result_data <= 0;
181 | end
182 | end
183 |
184 | STATE_DONE:
185 | begin
186 | if (!reset_n)
187 | state <= STATE_RESET;
188 |
189 | // Shift-in `result_data` (msb-first) on rising edge
190 | if (!cs1_n && sck1_sync_rising_edge)
191 | result_data <= { result_data[RESULT_DATA_WIDTH-2 : 0], sdi1_sync[1] };
192 |
193 | end
194 |
195 | default:
196 | state <= STATE_RESET;
197 |
198 | endcase
199 | end
200 |
201 | endmodule
--------------------------------------------------------------------------------
/src/pinout-ice40hx8k-b-evn.pcf:
--------------------------------------------------------------------------------
1 | # Pinout configuration for the Lattice Semiconductor iCE40HX8K Evaluation Board.
2 | # * http://www.latticesemi.com/en/Products/DevelopmentBoardsAndKits/iCE40HX8KBreakoutBoard.aspx
3 |
4 | # External oscillator (12 MHz)
5 | set_io clk_in J13
6 |
7 | # External asynchronous reset
8 | set_io reset_n_in B15
9 |
10 | # SPI0 (Shared SPI interface)
11 | set_io sck0_in R11
12 | set_io sdi0_in P11
13 | #set_io sdo0_out T11
14 | set_io cs0_n_in R12
15 |
16 | # SPI1 (Daisy-chained SPI interface)
17 | set_io sck1_in B10
18 | set_io sdi1_in B12
19 | set_io sdo1_out B13
20 | set_io cs1_n_in A16
21 |
22 | # READY host open-drain interrupt
23 | set_io ready_n_od_out B14
24 |
25 | # Status/Heartbeat LED
26 | set_io status_led_n_out B5
--------------------------------------------------------------------------------
/src/pinout-icepool-ice40hx8k.pcf:
--------------------------------------------------------------------------------
1 | # Pinout configuration for the `icepool` ice40hx8k-bg121 daughter board.
2 | # * https://github.com/jkiv/icepool-board
3 |
4 | # Pinout for the BG121 variant of the ICE40HX8K.
5 |
6 | # External oscillator (12 MHz)
7 | set_io clk_in F11
8 |
9 | # External asynchronous reset
10 | set_io reset_n_in J1
11 |
12 | # SPI0 (Shared SPI interface)
13 | set_io sck0_in L10
14 | set_io sdi0_in J9
15 | #set_io sdo0_out K9
16 | set_io cs0_n_in K10
17 |
18 | # SPI1 (Daisy-chained SPI interface)
19 | set_io sck1_in G1
20 | set_io sdi1_in F3
21 | set_io sdo1_out K1
22 | set_io cs1_n_in H1
23 |
24 | # READY host open-drain interrupt
25 | set_io ready_n_od_out B1
26 |
27 | # Status/Heartbeat LED
28 | set_io status_led_n_out A11
29 |
--------------------------------------------------------------------------------
/src/pinout-icepool-ice40up5k.pcf:
--------------------------------------------------------------------------------
1 | # Pinout configuration for the `icepool` ice40up5k-sg48 daughter board.
2 | # * https://github.com/jkiv/icepool-board
3 |
4 | # FUTURE
5 |
6 | # External oscillator (12 MHz)
7 | set_io clk_in 35
8 |
9 | # External asynchronous reset
10 | set_io reset_n_in 4
11 |
12 | # SPI0 (Shared SPI interface)
13 | set_io sck0_in 15
14 | set_io sdi0_in 17
15 | #set_io sdo0_out 18
16 | set_io cs0_n_in 16
17 |
18 | # SPI1 (Daisy-chained SPI interface)
19 | set_io sck1_in
20 | set_io sdi1_in
21 | set_io sdo1_out
22 | set_io cs1_n_in
23 |
24 | # READY host open-drain interrupt
25 | set_io ready_n_od_out
26 |
27 | # Status/Heartbeat LED
28 | set_io status_led_n_out 39
29 |
--------------------------------------------------------------------------------
/src/sha_round.v:
--------------------------------------------------------------------------------
1 | /* sha_round
2 | *
3 | * Asynchronously performs a single SHA256 round given an input state and
4 | * values for Kt and Wt for the current round.
5 | *
6 | * For SHA-256,
7 | *
8 | * T1 = h + BSIG1(e) + CH(e,f,g) + Kt + Wt
9 | * T2 = BSIG0(a) + MAJ(a,b,c)
10 | * h' = g
11 | * g' = f
12 | * f' = e
13 | * e' = d + T1
14 | * d' = c
15 | * c' = b
16 | * b' = a
17 | * a' = T1 + T2
18 | *
19 | * where Kt is a constant for loop iteration t
20 | * Wt is the message scheudle value for iteration t
21 | * a -> h are input working words
22 | * a' -> h' are output working words
23 | */
24 | module sha_round(in, Kt, Wt, out);
25 |
26 | `define SHA_ROUND_USE_OPTIMIZED_EXPRESSIONS
27 |
28 | input wire [ 31:0] Kt; // constant word (iteration t)
29 | input wire [ 31:0] Wt; // message schedule word (iteration t)
30 | input wire [255:0] in; // working words, a -> h
31 | output wire [255:0] out; // resultant working words a' -> h'
32 |
33 | wire [31:0] a, b, c, d, e, f, g, h; // working word aliases
34 | wire [31:0] bsig0_a; // result of BSIG0(a)
35 | wire [31:0] bsig1_e; // result of BSIG1(e)
36 | wire [31:0] ch_e_f_g; // result of CH(e,f,g)
37 | wire [31:0] maj_a_b_c; // result of MAJ(a,b,c)
38 | wire [31:0] t1, t2; // temporary values
39 |
40 | // Break up input bus into working variables
41 | assign a = in[255:224];
42 | assign b = in[223:192];
43 | assign c = in[191:160];
44 | assign d = in[159:128];
45 | assign e = in[127: 96];
46 | assign f = in[ 95: 64];
47 | assign g = in[ 63: 32];
48 | assign h = in[ 31: 0];
49 |
50 | // For SHA256, BSIG0(X) = ROTR2(X) XOR ROTR13(X) XOR ROTR22(X)
51 | assign bsig0_a = { a[ 1:0], a[31: 2] }
52 | ^ { a[12:0], a[31:13] }
53 | ^ { a[21:0], a[31:22] };
54 |
55 | // For SHA256, BSIG1(X) = ROTR6(X) XOR ROTR11(X) XOR ROTR25(X)
56 | assign bsig1_e = { e[ 5:0], e[31: 6] }
57 | ^ { e[10:0], e[31:11] }
58 | ^ { e[24:0], e[31:25] };
59 |
60 | // For SHA256, CH(X,Y,Z) = (X AND Y) XOR ((NOT X) AND Z)
61 | `ifdef SHA_ROUND_USE_OPTIMIZED_EXPRESSIONS
62 | assign ch_e_f_g = g ^ (e & (g ^ f));
63 | `else
64 | assign ch_e_f_g = (e & f) ^ ((~e) & g);
65 | `endif
66 |
67 | // For SHA256, MAJ(X,Y,Z) = (X AND Y) XOR (X AND Z) XOR (Y AND Z)
68 | `ifdef SHA_ROUND_USE_OPTIMIZED_EXPRESSIONS
69 | assign maj_a_b_c = ((b & c) | (a & (b | c)));
70 | `else
71 | assign maj_a_b_c = (a & b) ^ (a & c) ^ (b & c);
72 | `endif
73 |
74 | // Update temporary values
75 | assign t1 = h + bsig1_e + ch_e_f_g + Kt + Wt;
76 | assign t2 = bsig0_a + maj_a_b_c;
77 |
78 | // Update working words for next stage/iteration
79 | assign out[255:224] = t1 + t2; // a' = T1 + T2
80 | assign out[223:192] = a; // b' = a
81 | assign out[191:160] = b; // c' = b
82 | assign out[159:128] = c; // d' = c
83 | assign out[127: 96] = d + t1; // e' = d + T1
84 | assign out[ 95: 64] = e; // f' = e
85 | assign out[ 63: 32] = f; // g' = f
86 | assign out[ 31: 0] = g; // h' = g
87 |
88 | endmodule // sha_iter
89 |
--------------------------------------------------------------------------------
/src/sha_unit.v:
--------------------------------------------------------------------------------
1 | module sha_unit(
2 | // Control
3 | clk,
4 | // Externally managed state
5 | round,
6 | Kt,
7 | // SHA256 parameters
8 | M,
9 | H0,
10 | // Result
11 | H1
12 | );
13 |
14 | `define idx32(x) (32*(x+1)-1):(32*(x))
15 |
16 | input wire clk;
17 |
18 | input wire [5:0] round;
19 | input wire [31:0] Kt;
20 |
21 | input wire [511:0] M;
22 | input wire [255:0] H0;
23 | output wire [255:0] H1;
24 |
25 | reg [31:0] Wt = 0;
26 | reg [479:0] W = 0;
27 | wire [31:0] Wxt;
28 |
29 | // Message as 16x 32-bit blocks
30 | // TODO Mt in block RAM, as input
31 | wire [31:0] Mt[0:15];
32 |
33 | reg [255:0] S0;
34 | wire [255:0] S1;
35 |
36 | w_expand wx(
37 | W[`idx32(16-2)],
38 | W[`idx32(16-7)],
39 | W[`idx32(16-15)],
40 | W[`idx32(16-16)],
41 | Wxt
42 | );
43 |
44 | // Concurrent SHA256 round module
45 | sha_round sr(
46 | S0,
47 | Kt,
48 | Wt,
49 | S1
50 | );
51 |
52 | always @(posedge clk)
53 | begin
54 | if (round == 0)
55 | S0 <= H0;
56 | else
57 | S0 <= S1;
58 | end
59 |
60 | always @(posedge clk)
61 | begin
62 | if (round < 16)
63 | Wt <= Mt[round[3:0]];
64 | else
65 | Wt <= Wxt;
66 | end
67 |
68 | always @(posedge clk)
69 | begin
70 | W <= { Wt, W[479:32] };
71 | end
72 |
73 | assign H1[`idx32(7)] = S1[`idx32(7)] + H0[`idx32(7)];
74 | assign H1[`idx32(6)] = S1[`idx32(6)] + H0[`idx32(6)];
75 | assign H1[`idx32(5)] = S1[`idx32(5)] + H0[`idx32(5)];
76 | assign H1[`idx32(4)] = S1[`idx32(4)] + H0[`idx32(4)];
77 | assign H1[`idx32(3)] = S1[`idx32(3)] + H0[`idx32(3)];
78 | assign H1[`idx32(2)] = S1[`idx32(2)] + H0[`idx32(2)];
79 | assign H1[`idx32(1)] = S1[`idx32(1)] + H0[`idx32(1)];
80 | assign H1[`idx32(0)] = S1[`idx32(0)] + H0[`idx32(0)];
81 |
82 | assign Mt[ 0] = M[`idx32(15)];
83 | assign Mt[ 1] = M[`idx32(14)];
84 | assign Mt[ 2] = M[`idx32(13)];
85 | assign Mt[ 3] = M[`idx32(12)];
86 | assign Mt[ 4] = M[`idx32(11)];
87 | assign Mt[ 5] = M[`idx32(10)];
88 | assign Mt[ 6] = M[`idx32( 9)];
89 | assign Mt[ 7] = M[`idx32( 8)];
90 | assign Mt[ 8] = M[`idx32( 7)];
91 | assign Mt[ 9] = M[`idx32( 6)];
92 | assign Mt[10] = M[`idx32( 5)];
93 | assign Mt[11] = M[`idx32( 4)];
94 | assign Mt[12] = M[`idx32( 3)];
95 | assign Mt[13] = M[`idx32( 2)];
96 | assign Mt[14] = M[`idx32( 1)];
97 | assign Mt[15] = M[`idx32( 0)];
98 |
99 | endmodule
100 |
--------------------------------------------------------------------------------
/src/shapool.v:
--------------------------------------------------------------------------------
1 | module shapool
2 | (
3 | // Control
4 | clk,
5 | reset_n,
6 | // Job Params
7 | sha_state,
8 | message_head,
9 | nonce_start_MSB,
10 | // Result
11 | success,
12 | nonce,
13 | match_flags
14 | );
15 | parameter POOL_SIZE = 2;
16 | parameter POOL_SIZE_LOG2 = 1;
17 | parameter BASE_TARGET = 32;
18 |
19 | localparam NONCE_LOWER_WIDTH = 32 - POOL_SIZE_LOG2;
20 |
21 | input wire clk;
22 | input wire reset_n;
23 |
24 | // Job parameters
25 | input wire [255:0] sha_state;
26 | input wire [95:0] message_head;
27 | input wire [7:0] nonce_start_MSB;
28 |
29 | // Job results
30 | output wire success;
31 | output wire [31:0] nonce;
32 | output wire [7:0] match_flags;
33 |
34 | // Shared state
35 | reg [NONCE_LOWER_WIDTH-1:0] nonce_lower = 0;
36 | reg [5:0] round = 0;
37 |
38 | // Supress some logic during first and second hash
39 | // - `first_hash_complete` allows us to supress logic before first hash completes.
40 | // - `second_hash_complete` allows us to supress logic before second hash completes.
41 | reg first_hash_complete = 0;
42 | reg second_hash_complete = 0;
43 |
44 | localparam[255:0] SHA256_H0 = {
45 | 32'h6a09e667, 32'hbb67ae85,
46 | 32'h3c6ef372, 32'ha54ff53a,
47 | 32'h510e527f, 32'h9b05688c,
48 | 32'h1f83d9ab, 32'h5be0cd19
49 | };
50 |
51 | wire [31:0] Kt;
52 |
53 | SHA256_K K (
54 | clk,
55 | round,
56 | Kt
57 | );
58 |
59 | localparam [383:0] M0_tail = {
60 | 128'h80000000_00000000_00000000_00000000,
61 | 128'h00000000_00000000_00000000_00000000,
62 | 128'h00000000_00000000_00000000_00000280
63 | };
64 |
65 | localparam [255:0] M1_tail = {
66 | 128'h80000000_00000000_00000000_00000000,
67 | 128'h00000000_00000000_00000000_00000100
68 | };
69 |
70 | /** Generate "pipelines".
71 |
72 | Each pipeline:
73 | * consists of two chained `sha_unit` hashing units.
74 | * hardcodes unique nonce most-significant bits.
75 | * checks for leading zeros and generates its own `match_flag`.
76 |
77 | */
78 | genvar n;
79 | generate
80 | for (n = 0; n < POOL_SIZE; n = n + 1)
81 | begin : pipelines
82 |
83 | // Hash inputs
84 | wire [511:0] M0;
85 | wire [511:0] M1;
86 |
87 | // Hash outputs
88 | wire [255:0] H_u0;
89 | wire [255:0] H_u1;
90 |
91 | // Saved bits from H_u0 for M1
92 | reg [223:0] M1_H1;
93 |
94 | // Byte-swapped H_u1 for testing
95 | /* verilator lint_off UNUSED */
96 | wire [255:0] H_u1_swap;
97 | /* verilator lint_on UNUSED */
98 |
99 | // Bits to test for `success`
100 | wire [BASE_TARGET-1:0] H_test_bits;
101 |
102 | `ifndef SHAPOOL_NO_NONCE_OFFSET
103 | // Hard-coded unit offset
104 | // -- reduces size of nonce register and increment logic
105 | // -- POOL_SIZE must be a power of 2
106 | // -- POOL_SIZE_LOG2 must be > 0
107 | wire [POOL_SIZE_LOG2-1:0] nonce_upper;
108 | assign nonce_upper = n;
109 | `endif
110 |
111 | // Construct `M_nonce`:
112 | //
113 | // 31 31-POOL_SIZE_LOG2 0
114 | // +-------------+-----------------------------------------+
115 | // | nonce_upper | nonce_lower |
116 | // +-------------+-----------------------------------------+
117 | // XOR
118 | // +-------------------------+-----------------------------+
119 | // | nonce_start_MSB | 0 ... 0 |
120 | // +-------------------------+-----------------------------+
121 | // FUTURE Nonce space segmenting issues arise when not all devices
122 | // have the same `POOL_SIZE`.
123 |
124 | wire [31:0] M_nonce;
125 |
126 | `ifdef SHAPOOL_NO_NONCE_OFFSET
127 | assign M_nonce = nonce_lower ^ { nonce_start_MSB, 24'b0 };
128 | `else
129 | assign M_nonce = { nonce_upper, nonce_lower } ^ { nonce_start_MSB, 24'b0 };
130 | `endif
131 |
132 | assign M0 = {
133 | // Start of M0
134 | message_head,
135 | // Nonce (swapped endianness)
136 | {
137 | M_nonce[ 7: 0],
138 | M_nonce[15: 8],
139 | M_nonce[23:16],
140 | M_nonce[31:24]
141 | },
142 | // End of M0
143 | M0_tail
144 | };
145 |
146 | // SHA256 unit for first hash
147 | sha_unit u0(
148 | clk,
149 | round,
150 | Kt,
151 | M0,
152 | sha_state,
153 | H_u0
154 | );
155 |
156 | // Save `H_u0` (output of first stage) for use in `M1_H1`.
157 | // Bits `H_u0[255:224]` are used by `u1` at the same moment and sent directly to input,
158 | // so we don't need to store them in M1_H1.
159 | //
160 | // `H_u0[255:224]` is needed as soon as it is available, when `round`
161 | // goes from `0` to `1`. At the same instant, the rest of `H_u0` is stored
162 | // in `M1_H1` for use in subsequent rounds.
163 | always @(posedge clk)
164 | begin
165 | if (round == 0)
166 | M1_H1 <= H_u0[223:0];
167 | end
168 |
169 | assign M1 = {
170 | H_u0[255:224],
171 | M1_H1,
172 | M1_tail
173 | };
174 |
175 | // SHA256 unit for second hash
176 | sha_unit u1(
177 | clk,
178 | round,
179 | Kt,
180 | M1,
181 | SHA256_H0,
182 | H_u1
183 | );
184 |
185 | // Endianness-swapped hash result for final comparison.
186 | // -- Depending on target, lower bits may not be used. Hopefully
187 | // logic for generating superfluous bits are optimized out.
188 | assign H_u1_swap = {
189 | H_u1[ 7: 0], H_u1[ 15: 8], H_u1[ 23: 16], H_u1[ 31: 24],
190 | H_u1[ 39: 32], H_u1[ 47: 40], H_u1[ 55: 48], H_u1[ 63: 56],
191 | H_u1[ 71: 64], H_u1[ 79: 72], H_u1[ 87: 80], H_u1[ 95: 88],
192 | H_u1[103: 96], H_u1[111:104], H_u1[119:112], H_u1[127:120],
193 | H_u1[135:128], H_u1[143:136], H_u1[151:144], H_u1[159:152],
194 | H_u1[167:160], H_u1[175:168], H_u1[183:176], H_u1[191:184],
195 | H_u1[199:192], H_u1[207:200], H_u1[215:208], H_u1[223:216],
196 | H_u1[231:224], H_u1[239:232], H_u1[247:240], H_u1[255:248]
197 | };
198 |
199 | // Bits of result we care about
200 | assign H_test_bits = H_u1_swap[255:256-BASE_TARGET];
201 |
202 | // Test bits for zero
203 | assign match_flags[n] = ~(|H_test_bits);
204 |
205 | end
206 | endgenerate
207 |
208 | // Zero out top of `match_flags`
209 | assign match_flags[7:POOL_SIZE] = 0;
210 |
211 | // Generate `success` flag
212 | assign success = (|match_flags[POOL_SIZE-1:0]) & second_hash_complete & (round == 0);
213 |
214 | // Output current nonce
215 | `ifdef SHAPOOL_NO_NONCE_OFFSET
216 | assign nonce = nonce_lower;
217 | `else
218 | assign nonce = {{(POOL_SIZE_LOG2){1'b0}}, nonce_lower};
219 | `endif
220 |
221 | // Control `first_hash_complete` flag
222 | always @(posedge clk)
223 | begin
224 | if (!reset_n)
225 | first_hash_complete <= 0;
226 | else if (round == 63 && !first_hash_complete)
227 | first_hash_complete <= 1;
228 | end
229 |
230 | // Control `second_hash_complete` flag
231 | always @(posedge clk)
232 | begin
233 | if (!reset_n)
234 | second_hash_complete <= 0;
235 | else if (round == 63 && first_hash_complete)
236 | second_hash_complete <= 1;
237 | end
238 |
239 | // Control `round`
240 | always @(posedge clk)
241 | begin
242 | if (!reset_n)
243 | round <= 0;
244 | else
245 | round <= round + 1; // mod 63
246 | end
247 |
248 | // Control `nonce`
249 | always @(posedge clk)
250 | begin
251 | if (!reset_n)
252 | nonce_lower <= 0;
253 | else if (round == 63)
254 | nonce_lower <= nonce_lower + 1;
255 | end
256 |
257 | endmodule
258 |
--------------------------------------------------------------------------------
/src/targets/target-1.vh:
--------------------------------------------------------------------------------
1 | `define TARGET 32
2 |
--------------------------------------------------------------------------------
/src/targets/target-1024.vh:
--------------------------------------------------------------------------------
1 | `define TARGET 42
2 |
--------------------------------------------------------------------------------
/src/targets/target-128.vh:
--------------------------------------------------------------------------------
1 | `define TARGET 39
2 |
--------------------------------------------------------------------------------
/src/targets/target-16.vh:
--------------------------------------------------------------------------------
1 | `define TARGET 36
2 |
--------------------------------------------------------------------------------
/src/targets/target-2.vh:
--------------------------------------------------------------------------------
1 | `define TARGET 33
2 |
--------------------------------------------------------------------------------
/src/targets/target-2048.vh:
--------------------------------------------------------------------------------
1 | `define TARGET 43
2 |
--------------------------------------------------------------------------------
/src/targets/target-256.vh:
--------------------------------------------------------------------------------
1 | `define TARGET 40
2 |
--------------------------------------------------------------------------------
/src/targets/target-32.vh:
--------------------------------------------------------------------------------
1 | `define TARGET 37
2 |
--------------------------------------------------------------------------------
/src/targets/target-4.vh:
--------------------------------------------------------------------------------
1 | `define TARGET 34
2 |
--------------------------------------------------------------------------------
/src/targets/target-4096.vh:
--------------------------------------------------------------------------------
1 | `define TARGET 44
2 |
--------------------------------------------------------------------------------
/src/targets/target-512.vh:
--------------------------------------------------------------------------------
1 | `define TARGET 41
2 |
--------------------------------------------------------------------------------
/src/targets/target-64.vh:
--------------------------------------------------------------------------------
1 | `define TARGET 38
2 |
--------------------------------------------------------------------------------
/src/targets/target-8.vh:
--------------------------------------------------------------------------------
1 | `define TARGET 35
2 |
--------------------------------------------------------------------------------
/src/targets/target-8192.vh:
--------------------------------------------------------------------------------
1 | `define TARGET 45
2 |
--------------------------------------------------------------------------------
/src/tests/Makefile:
--------------------------------------------------------------------------------
1 | .phony : run
2 | run: sha_round_usage_tb sha_unit_usage_tb shapool_usage_tb external_io_usage_tb
3 |
4 | .phony : hardware_tests
5 | hardware_tests : btc_four_zeroes
6 |
7 | .phony : all
8 | all : run hardware_tests
9 |
10 | .phony : clean
11 | clean : clean_test_benches clean_hardware_tests
12 |
13 | .phony : clean_test_benches
14 | clean_test_benches :
15 | rm -f *.out *.vcd
16 |
17 | .phony : clean_hardware_tests
18 | clean_hardware_tests :
19 | make -C ./btc_four_zeroes clean
20 |
21 | # Testbench
22 |
23 | sha_round_usage_tb.out : sha_round_usage_tb.v ../sha_round.v
24 | iverilog -o $@ $^
25 |
26 | sha_round_usage_tb : sha_round_usage_tb.out
27 | vvp $^
28 |
29 | ##
30 |
31 | sha_unit_usage_tb.out : sha_unit_usage_tb.v ../sha_unit.v ../w_expand.v ../sha_round.v
32 | iverilog -o $@ $^
33 |
34 | sha_unit_usage_tb : sha_unit_usage_tb.out
35 | vvp $^
36 |
37 | ##
38 |
39 | shapool_usage_tb.out : shapool_usage_tb.v ../shapool.v ../SHA256_K.v ../sha_unit.v ../w_expand.v ../sha_round.v
40 | iverilog -o $@ $^
41 |
42 | shapool_usage_tb : shapool_usage_tb.out
43 | vvp $^
44 |
45 | ##
46 |
47 | external_io_usage_tb.out : external_io_usage_tb.v ../external_io.v
48 | iverilog -o $@ $^
49 |
50 | external_io_usage_tb : external_io_usage_tb.out
51 | vvp $^
52 |
53 | # Tests requiring hardware
54 |
55 | .phony : btc_four_zeroes
56 | btc_four_zeroes :
57 | make -C ./btc_four_zeroes run
--------------------------------------------------------------------------------
/src/tests/btc_four_zeroes/Makefile:
--------------------------------------------------------------------------------
1 | VENDOR_PATH=../vendor/
2 | MUNIT_C_PATH=../vendor/munit/munit.c
3 | ICEPOOL_PATH=../vendor/icepool-driver/src/
4 | LIBICEPOOL_PATH=../vendor/icepool-driver/src/
5 | FTDI_PATH=/usr/include/ftdi1/
6 | LIBFTDI_PATH=/usr/lib/
7 |
8 | .phony : build
9 | build : btc_four_zeroes gateware
10 |
11 | .phony : run
12 | run : build flash
13 | ./btc_four_zeroes
14 |
15 | btc_four_zeroes : main.c $(MUNIT_C_PATH) libicepool
16 | gcc --std=c99 -g -o $@ -I$(VENDOR_PATH) -I$(ICEPOOL_PATH) -I$(FTDI_PATH) $< $(MUNIT_C_PATH) -L$(LIBICEPOOL_PATH) -licepool-d -L$(LIBFTDI_PATH) -lftdi1
17 |
18 | .phony : libicepool
19 | libicepool :
20 | make -C $(ICEPOOL_PATH) libicepool-d.a
21 |
22 | .phony : gateware
23 | gateware :
24 | make -C ./rtl build
25 |
26 | .phony : flash
27 | flash :
28 | make -C rtl/ flash
29 |
30 | .phony : clean
31 | clean :
32 | make -C ./rtl clean
33 | rm -f ./btc_four_zeroes
--------------------------------------------------------------------------------
/src/tests/btc_four_zeroes/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "munit/munit.h"
4 | #include "icepool.h"
5 |
6 | #define DEVICE_CONFIG_LEN (8/8)
7 | #define DEVICE_RESULT_LEN (40/8)
8 | #define JOB_CONFIG_LEN (352/8)
9 |
10 | void print_buffer(const uint8_t* buffer, size_t buffer_len)
11 | {
12 | for(size_t i = 0; i < buffer_len; )
13 | {
14 | for (size_t j = 0; j < 8 && i < buffer_len; j++, i++)
15 | {
16 | printf("%02x ", buffer[i]);
17 | }
18 | printf("\n");
19 | }
20 | }
21 |
22 | void test_spi_daisy_no_exec(IcepoolContext* ctx)
23 | {
24 | // Set up device data
25 | uint8_t device_config[DEVICE_CONFIG_LEN] = { 0 };
26 |
27 | uint8_t result[DEVICE_CONFIG_LEN] = { 0 };
28 |
29 | // Try immediate read-after-write
30 |
31 | icepool_assert_reset(ctx);
32 |
33 | icepool_spi_assert_daisy(ctx);
34 |
35 | icepool_spi_write_daisy(ctx, device_config, DEVICE_CONFIG_LEN);
36 |
37 | icepool_spi_read_daisy(ctx, result, DEVICE_CONFIG_LEN);
38 |
39 | icepool_spi_deassert_daisy(ctx);
40 |
41 | munit_assert_memory_equal(DEVICE_CONFIG_LEN, device_config, result);
42 | }
43 |
44 | void test_spi_daisy_with_exec(IcepoolContext* ctx)
45 | {
46 | // Set up device data
47 | uint8_t device_config[DEVICE_CONFIG_LEN] = { 0 };
48 |
49 | uint8_t result[DEVICE_CONFIG_LEN] = { 0 };
50 |
51 | // Try EXEC and reset
52 | icepool_assert_reset(ctx);
53 |
54 | icepool_spi_assert_daisy(ctx);
55 |
56 | icepool_spi_write_daisy(ctx, device_config, DEVICE_CONFIG_LEN);
57 |
58 | icepool_spi_deassert_daisy(ctx);
59 |
60 | icepool_deassert_reset(ctx);
61 |
62 | // TODO usleep
63 |
64 | icepool_assert_reset(ctx);
65 |
66 | icepool_spi_assert_daisy(ctx);
67 |
68 | icepool_spi_read_daisy(ctx, result, DEVICE_CONFIG_LEN);
69 |
70 | icepool_spi_deassert_daisy(ctx);
71 |
72 | munit_assert_memory_equal(DEVICE_CONFIG_LEN, device_config, result);
73 | }
74 |
75 | void test_btc_four_zeroes(IcepoolContext *ctx)
76 | {
77 | // Set up device data
78 | uint8_t device_config[DEVICE_CONFIG_LEN] = { 0 };
79 |
80 | // Set up job data
81 | uint8_t job_config[JOB_CONFIG_LEN] = {
82 | // SHA initial state:
83 | 0xdc, 0x6a, 0x3b, 0x8d, 0x0c, 0x69, 0x42, 0x1a,
84 | 0xcb, 0x1a, 0x54, 0x34, 0xe5, 0x36, 0xf7, 0xd5,
85 | 0xc3, 0xc1, 0xb9, 0xe4, 0x4c, 0xbb, 0x9b, 0x8f,
86 | 0x95, 0xf0, 0x17, 0x2e, 0xfc, 0x48, 0xd2, 0xdf,
87 | // Message head:
88 | 0xdc, 0x14, 0x17, 0x87, 0x35, 0x8b, 0x05, 0x53,
89 | 0x53, 0x5f, 0x01, 0x19,
90 | };
91 | // Expected nonce: 39
92 | // Expected hash: c7f3244e501edf780c420f63a4266d30ffe1bdb53f4fde3ccd688604f15ffd03
93 |
94 | // Assert reset_n
95 | icepool_assert_reset(ctx);
96 |
97 | // Send device data
98 | icepool_spi_assert_daisy(ctx);
99 |
100 | icepool_spi_write_daisy(ctx, device_config, DEVICE_CONFIG_LEN);
101 |
102 | icepool_spi_deassert_daisy(ctx);
103 |
104 | // Send job data
105 | icepool_spi_assert_shared(ctx);
106 |
107 | icepool_spi_write_shared(ctx, job_config, JOB_CONFIG_LEN);
108 |
109 | icepool_spi_deassert_shared(ctx);
110 |
111 | // Deassert reset_n (start executing)
112 | icepool_deassert_reset(ctx);
113 |
114 | // Wait for READY
115 | bool ready = false;
116 | for (size_t i = 0; !ready && i < 1e9; i++)
117 | {
118 | ready = icepool_poll_ready(ctx);
119 | }
120 |
121 | munit_assert_true(ready);
122 |
123 | // Get result
124 |
125 | uint8_t expected_result[DEVICE_RESULT_LEN] = { 0x01, 0x00, 0x00, 0x00, 0x29 };
126 | uint8_t result[DEVICE_RESULT_LEN] = { 0xFF };
127 |
128 | icepool_spi_assert_daisy(ctx);
129 |
130 | icepool_spi_read_daisy(ctx, result, DEVICE_RESULT_LEN);
131 |
132 | icepool_spi_assert_daisy(ctx);
133 |
134 | // Assert reset_n
135 | icepool_assert_reset(ctx);
136 |
137 | print_buffer(result, DEVICE_RESULT_LEN);
138 |
139 | munit_assert_memory_equal(DEVICE_RESULT_LEN, result, expected_result);
140 | }
141 |
142 | int main()
143 | {
144 | // Set up icepool context
145 | IcepoolContext* ctx = icepool_new();
146 |
147 | if (!ctx) {
148 | fprintf(stderr, "Could not initialize IcepoolContext. Quitting...\n");
149 | exit(EXIT_FAILURE);
150 | }
151 |
152 | test_spi_daisy_no_exec(ctx);
153 |
154 | test_spi_daisy_with_exec(ctx);
155 |
156 | test_btc_four_zeroes(ctx);
157 |
158 | icepool_free(ctx);
159 |
160 | return EXIT_SUCCESS;
161 | }
--------------------------------------------------------------------------------
/src/tests/btc_four_zeroes/rtl/Makefile:
--------------------------------------------------------------------------------
1 | SHAPOOL_PATH=../../../
2 | SHAPOOL_DEPS=$(SHAPOOL_PATH)top.v \
3 | $(SHAPOOL_PATH)shapool.v \
4 | $(SHAPOOL_PATH)sha_unit.v \
5 | $(SHAPOOL_PATH)sha_round.v \
6 | $(SHAPOOL_PATH)w_expand.v \
7 | $(SHAPOOL_PATH)SHA256_K.v \
8 | $(SHAPOOL_PATH)external_io.v
9 |
10 | TEST_NAME=btc_four_zeroes
11 | SHAPOOL_PCF=$(SHAPOOL_PATH)pinout-icepool-ice40hx8k.pcf
12 |
13 | .phony : build
14 | build : $(TEST_NAME).bin
15 |
16 | .phony: flash
17 | flash : $(TEST_NAME).bin
18 | iceprog -v -S $^
19 |
20 | $(TEST_NAME).bin : $(TEST_NAME).asc
21 | icepack $^ $@
22 |
23 | $(TEST_NAME).asc : $(TEST_NAME).json $(SHAPOOL_PCF)
24 | nextpnr-ice40 --package bg121 --hx8k --json $(TEST_NAME).json --pcf $(SHAPOOL_PCF) --asc $@
25 |
26 | $(TEST_NAME).json : ./top_test.v $(SHAPOOL_DEPS)
27 | yosys -p 'synth_ice40 -top top_test -json $@ -abc2 -retime' $^
28 |
29 | # Clean up
30 | .phony: clean
31 | clean :
32 | rm -f $(TEST_NAME).out \
33 | $(TEST_NAME).json \
34 | $(TEST_NAME).asc \
35 | $(TEST_NAME).bin
--------------------------------------------------------------------------------
/src/tests/btc_four_zeroes/rtl/top_test.v:
--------------------------------------------------------------------------------
1 | module top_test
2 | (
3 | clk_in,
4 | reset_n_in,
5 | // Global data
6 | sck0_in,
7 | sdi0_in,
8 | cs0_n_in,
9 | // Daisy data
10 | sck1_in,
11 | sdi1_in,
12 | sdo1_out,
13 | cs1_n_in,
14 | // READY flags
15 | ready_n_od_out,
16 | // Indicator LED
17 | status_led_n_out
18 | );
19 |
20 | // Making pool smaller to test / fit on HX8K
21 | `define SHAPOOL_NO_NONCE_OFFSET // Required for POOL_SIZE = 1
22 |
23 | parameter POOL_SIZE = 1;
24 | parameter POOL_SIZE_LOG2 = 0;
25 | parameter BASE_TARGET = 4; // Max. ~112 with 2 cores, 256 with 1 core
26 |
27 | // 12 MHz ~ 30 MHz
28 | parameter PLL_DIVR = 4'b0000;
29 | parameter PLL_DIVF = 7'b1001111;
30 | parameter PLL_DIVQ = 3'b101;
31 |
32 | // Multiply input clock signal using SB_PLL40_CORE
33 | wire g_clk;
34 |
35 | SB_PLL40_CORE #(
36 | .FEEDBACK_PATH("SIMPLE"),
37 | .DIVR(PLL_DIVR),
38 | .DIVF(PLL_DIVF),
39 | .DIVQ(PLL_DIVQ),
40 | .FILTER_RANGE(3'b001)
41 | )
42 | pll (
43 | .LOCK(pll_locked),
44 | .RESETB(1'b1),
45 | .BYPASS(1'b0),
46 | .REFERENCECLK(clk_in),
47 | //.PLLOUTCORE(g_clk)
48 | .PLLOUTGLOBAL(g_clk)
49 | );
50 |
51 | // Inputs and Outputs
52 |
53 | input wire clk_in;
54 |
55 | input wire reset_n_in;
56 |
57 | input wire sck0_in;
58 | input wire sdi0_in;
59 | input wire cs0_n_in;
60 |
61 | input wire sck1_in;
62 | input wire sdi1_in;
63 | output wire sdo1_out;
64 | input wire cs1_n_in;
65 |
66 | output wire ready_n_od_out;
67 |
68 | output wire status_led_n_out;
69 |
70 | top #(
71 | .POOL_SIZE(POOL_SIZE),
72 | .POOL_SIZE_LOG2(POOL_SIZE_LOG2),
73 | .BASE_TARGET(BASE_TARGET)
74 | )
75 | u (
76 | g_clk,
77 | reset_n_in,
78 | // Global data
79 | sck0_in,
80 | sdi0_in,
81 | cs0_n_in,
82 | // Daisy data
83 | sck1_in,
84 | sdi1_in,
85 | sdo1_out,
86 | cs1_n_in,
87 | // Success flags
88 | ready_n_od_out,
89 | // Indicators
90 | status_led_n_out
91 | );
92 |
93 | endmodule
94 |
--------------------------------------------------------------------------------
/src/tests/btc_sixteen_zeroes/Makefile:
--------------------------------------------------------------------------------
1 | VENDOR_PATH=../vendor/
2 | MUNIT_C_PATH=../vendor/munit/munit.c
3 | ICEPOOL_PATH=../vendor/icepool-driver/src/
4 | LIBICEPOOL_PATH=../vendor/icepool-driver/src/
5 | FTDI_PATH=/usr/include/ftdi1/
6 | LIBFTDI_PATH=/usr/lib/
7 |
8 | .phony : build
9 | build : btc_sixteen_zeroes gateware
10 |
11 | .phony : run
12 | run : build flash
13 | ./btc_sixteen_zeroes
14 |
15 | btc_sixteen_zeroes : main.c $(MUNIT_C_PATH) libicepool
16 | gcc --std=c99 -g -o $@ -I$(VENDOR_PATH) -I$(ICEPOOL_PATH) -I$(FTDI_PATH) $< $(MUNIT_C_PATH) -L$(LIBICEPOOL_PATH) -licepool-d -L$(LIBFTDI_PATH) -lftdi1
17 |
18 | .phony : libicepool
19 | libicepool :
20 | make -C $(ICEPOOL_PATH) libicepool-d.a
21 |
22 | .phony : gateware
23 | gateware :
24 | make -C ./rtl build
25 |
26 | .phony : flash
27 | flash :
28 | make -C rtl/ flash
29 |
30 | .phony : clean
31 | clean :
32 | make -C ./rtl clean
33 | rm -f ./btc_sixteen_zeroes
--------------------------------------------------------------------------------
/src/tests/btc_sixteen_zeroes/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "munit/munit.h"
4 | #include "icepool.h"
5 |
6 | #define DEVICE_CONFIG_LEN (8/8)
7 | #define DEVICE_RESULT_LEN (40/8)
8 | #define JOB_CONFIG_LEN (352/8)
9 |
10 | void print_buffer(const uint8_t* buffer, size_t buffer_len)
11 | {
12 | for(size_t i = 0; i < buffer_len; )
13 | {
14 | for (size_t j = 0; j < 8 && i < buffer_len; j++, i++)
15 | {
16 | printf("%02x ", buffer[i]);
17 | }
18 | printf("\n");
19 | }
20 | }
21 |
22 | void test_btc_sixteen_zeroes(IcepoolContext *ctx)
23 | {
24 | // Set up device data
25 | uint8_t device_config[DEVICE_CONFIG_LEN] = { 0 };
26 |
27 | // Set up job data
28 | uint8_t job_config[JOB_CONFIG_LEN] = {
29 | // SHA initial state:
30 | 0xdc, 0x6a, 0x3b, 0x8d, 0x0c, 0x69, 0x42, 0x1a,
31 | 0xcb, 0x1a, 0x54, 0x34, 0xe5, 0x36, 0xf7, 0xd5,
32 | 0xc3, 0xc1, 0xb9, 0xe4, 0x4c, 0xbb, 0x9b, 0x8f,
33 | 0x95, 0xf0, 0x17, 0x2e, 0xfc, 0x48, 0xd2, 0xdf,
34 | // Message head:
35 | 0xdc, 0x14, 0x17, 0x87, 0x35, 0x8b, 0x05, 0x53,
36 | 0x53, 0x5f, 0x01, 0x19,
37 | };
38 |
39 | // Assert reset_n
40 | icepool_assert_reset(ctx);
41 |
42 | // Send device data
43 | icepool_spi_assert_daisy(ctx);
44 |
45 | icepool_spi_write_daisy(ctx, device_config, DEVICE_CONFIG_LEN);
46 |
47 | icepool_spi_deassert_daisy(ctx);
48 |
49 | // Send job data
50 | icepool_spi_assert_shared(ctx);
51 |
52 | icepool_spi_write_shared(ctx, job_config, JOB_CONFIG_LEN);
53 |
54 | icepool_spi_deassert_shared(ctx);
55 |
56 | // Deassert reset_n (start executing)
57 | icepool_deassert_reset(ctx);
58 |
59 | // Wait for READY
60 | bool ready = false;
61 | for (size_t i = 0; !ready && i < 1e9; i++)
62 | {
63 | ready = icepool_poll_ready(ctx);
64 | }
65 |
66 | munit_assert_true(ready);
67 |
68 | // Get result
69 |
70 | uint8_t expected_result[DEVICE_RESULT_LEN] = { 0x02, 0x00, 0x00, 0x40, 0xa2 };
71 | uint8_t result[DEVICE_RESULT_LEN] = { 0xFF };
72 |
73 | icepool_spi_assert_daisy(ctx);
74 |
75 | icepool_spi_read_daisy(ctx, result, DEVICE_RESULT_LEN);
76 |
77 | icepool_spi_assert_daisy(ctx);
78 |
79 | // Assert reset_n
80 | icepool_assert_reset(ctx);
81 |
82 | print_buffer(result, DEVICE_RESULT_LEN);
83 |
84 | munit_assert_memory_equal(DEVICE_RESULT_LEN, result, expected_result);
85 | }
86 |
87 | int main()
88 | {
89 | // Set up icepool context
90 | IcepoolContext* ctx = icepool_new();
91 |
92 | if (!ctx) {
93 | fprintf(stderr, "Could not initialize IcepoolContext. Quitting...\n");
94 | exit(EXIT_FAILURE);
95 | }
96 |
97 | test_btc_sixteen_zeroes(ctx);
98 |
99 | icepool_free(ctx);
100 |
101 | return EXIT_SUCCESS;
102 | }
--------------------------------------------------------------------------------
/src/tests/btc_sixteen_zeroes/rtl/Makefile:
--------------------------------------------------------------------------------
1 | SHAPOOL_PATH=../../../
2 | SHAPOOL_DEPS=$(SHAPOOL_PATH)top.v \
3 | $(SHAPOOL_PATH)shapool.v \
4 | $(SHAPOOL_PATH)sha_unit.v \
5 | $(SHAPOOL_PATH)sha_round.v \
6 | $(SHAPOOL_PATH)w_expand.v \
7 | $(SHAPOOL_PATH)SHA256_K.v \
8 | $(SHAPOOL_PATH)external_io.v
9 |
10 | TEST_NAME=btc_sixteen_zeroes
11 | SHAPOOL_PCF=$(SHAPOOL_PATH)pinout-icepool-ice40hx8k.pcf
12 |
13 | .phony : build
14 | build : $(TEST_NAME).bin
15 |
16 | .phony: flash
17 | flash : $(TEST_NAME).bin
18 | iceprog -v -S $^
19 |
20 | $(TEST_NAME).bin : $(TEST_NAME).asc
21 | icepack $^ $@
22 |
23 | $(TEST_NAME).asc : $(TEST_NAME).json $(SHAPOOL_PCF)
24 | nextpnr-ice40 --package bg121 --hx8k --json $(TEST_NAME).json --pcf $(SHAPOOL_PCF) --asc $@
25 |
26 | $(TEST_NAME).json : ./top_test.v $(SHAPOOL_DEPS)
27 | yosys -p 'synth_ice40 -top top_test -json $@ -abc2 -retime' $^
28 |
29 | # Clean up
30 | .phony: clean
31 | clean :
32 | rm -f $(TEST_NAME).out \
33 | $(TEST_NAME).json \
34 | $(TEST_NAME).asc \
35 | $(TEST_NAME).bin
--------------------------------------------------------------------------------
/src/tests/btc_sixteen_zeroes/rtl/top_test.v:
--------------------------------------------------------------------------------
1 | module top_test
2 | (
3 | clk_in,
4 | reset_n_in,
5 | // Global data
6 | sck0_in,
7 | sdi0_in,
8 | cs0_n_in,
9 | // Daisy data
10 | sck1_in,
11 | sdi1_in,
12 | sdo1_out,
13 | cs1_n_in,
14 | // READY flags
15 | ready_n_od_out,
16 | // Indicator LED
17 | status_led_n_out
18 | );
19 | parameter POOL_SIZE = 2;
20 | parameter POOL_SIZE_LOG2 = 1;
21 | parameter BASE_TARGET = 16;
22 |
23 | // 12 MHz ~ 30 MHz
24 | parameter PLL_DIVR = 4'b0000;
25 | parameter PLL_DIVF = 7'b1001111;
26 | parameter PLL_DIVQ = 3'b101;
27 |
28 | // Multiply input clock signal using SB_PLL40_CORE
29 | wire g_clk;
30 |
31 | SB_PLL40_CORE #(
32 | .FEEDBACK_PATH("SIMPLE"),
33 | .DIVR(PLL_DIVR),
34 | .DIVF(PLL_DIVF),
35 | .DIVQ(PLL_DIVQ),
36 | .FILTER_RANGE(3'b001)
37 | )
38 | pll (
39 | .LOCK(pll_locked),
40 | .RESETB(1'b1),
41 | .BYPASS(1'b0),
42 | .REFERENCECLK(clk_in),
43 | //.PLLOUTCORE(g_clk)
44 | .PLLOUTGLOBAL(g_clk)
45 | );
46 |
47 | // Inputs and Outputs
48 |
49 | input wire clk_in;
50 |
51 | input wire reset_n_in;
52 |
53 | input wire sck0_in;
54 | input wire sdi0_in;
55 | input wire cs0_n_in;
56 |
57 | input wire sck1_in;
58 | input wire sdi1_in;
59 | output wire sdo1_out;
60 | input wire cs1_n_in;
61 |
62 | output wire ready_n_od_out;
63 |
64 | output wire status_led_n_out;
65 |
66 | top #(
67 | .POOL_SIZE(POOL_SIZE),
68 | .POOL_SIZE_LOG2(POOL_SIZE_LOG2),
69 | .BASE_TARGET(BASE_TARGET)
70 | )
71 | u (
72 | g_clk,
73 | reset_n_in,
74 | // Global data
75 | sck0_in,
76 | sdi0_in,
77 | cs0_n_in,
78 | // Daisy data
79 | sck1_in,
80 | sdi1_in,
81 | sdo1_out,
82 | cs1_n_in,
83 | // Success flags
84 | ready_n_od_out,
85 | // Indicators
86 | status_led_n_out
87 | );
88 |
89 | endmodule
90 |
--------------------------------------------------------------------------------
/src/tests/external_io_usage_tb.v:
--------------------------------------------------------------------------------
1 | `timescale 10ns/100ps
2 |
3 | module external_io_usage_tb();
4 |
5 | /*
6 | Tests basic usage of `external_io` module.
7 | */
8 |
9 | `define VERILATOR
10 | `define DEBUG_VERBOSE
11 |
12 | localparam spi_bit_half_period = 6; // 3 clock cycles
13 | localparam reset_hold_period = 2; // 1 clock cycle
14 |
15 | localparam JOB_CONFIG_WIDTH = 8;
16 | localparam DEVICE_CONFIG_WIDTH = 8;
17 |
18 | reg clk;
19 | reg reset_n;
20 | // SPI(0)
21 | reg sck0;
22 | reg sdi0;
23 | reg cs0_n;
24 | // SPI(1)
25 | reg sck1;
26 | reg sdi1;
27 | wire sdo1;
28 | reg cs1_n;
29 | // Stored data
30 | wire [DEVICE_CONFIG_WIDTH-1:0] device_config;
31 | wire [JOB_CONFIG_WIDTH-1:0] job_config;
32 | // Control flag
33 | wire core_reset_n;
34 | // From shapool
35 | reg [7:0] shapool_match_flags;
36 | reg [31:0] shapool_result;
37 | reg shapool_success;
38 | // READY signal
39 | wire ready;
40 |
41 | external_io
42 | #(.JOB_CONFIG_WIDTH(DEVICE_CONFIG_WIDTH),
43 | .DEVICE_CONFIG_WIDTH(JOB_CONFIG_WIDTH))
44 | uut (
45 | clk,
46 | reset_n,
47 | // SPI(0)
48 | sck0,
49 | sdi0,
50 | cs0_n,
51 | // SPI(1)
52 | sck1,
53 | sdi1,
54 | sdo1,
55 | cs1_n,
56 | // Stored data
57 | device_config,
58 | job_config,
59 | // Control flags
60 | core_reset_n,
61 | // From shapool
62 | shapool_success,
63 | { shapool_match_flags, shapool_result},
64 | // READY signal
65 | ready
66 | );
67 |
68 | reg [31:0] i;
69 |
70 | localparam [39:0] expected_result = 40'hAA_EEDDCCBB;
71 | localparam [DEVICE_CONFIG_WIDTH-1:0] expected_device_config = 8'b10101010;
72 | localparam [JOB_CONFIG_WIDTH-1:0] expected_job_config = 8'b10101010;
73 |
74 | reg [JOB_CONFIG_WIDTH-1:0] test_job_config = expected_job_config;
75 | reg [DEVICE_CONFIG_WIDTH-1:0] test_device_config = expected_device_config;
76 | reg [39:0] test_result = 0;
77 |
78 | // Generate clock
79 | always
80 | begin
81 | clk <= 0;
82 | #1;
83 | clk <= 1;
84 | #1;
85 | end
86 |
87 | initial
88 | begin
89 |
90 | $dumpfile("external_io_usage_tb.vcd");
91 | $dumpvars;
92 |
93 | // Initial states
94 | reset_n <= 0;
95 | sck0 <= 0;
96 | sdi0 <= 0;
97 | cs0_n <= 1;
98 |
99 | sck1 <= 0;
100 | sdi1 <= 0;
101 | cs1_n <= 1;
102 | shapool_result <= 32'hEEDDCCBB;
103 | shapool_match_flags <= 8'hAA;
104 | shapool_success <= 0;
105 |
106 | #10;
107 |
108 | ////////////////////////////////////////////
109 | // Test SPI0 (clock in job configuration) //
110 | ////////////////////////////////////////////
111 |
112 | if (core_reset_n == 0)
113 | begin
114 | $display("\033\133\063\062\155[PASS]\033\133\060\155 `external_io`: core_reset_n");
115 | end
116 | else
117 | begin
118 | $display("\033\133\063\061\155[FAIL]\033\133\060\155 `external_io`: core_reset_n");
119 | $error("Test case failed: core_reset_n should be low after reset_n goes low and reset_hold_period elapsed.");
120 | end
121 |
122 | // (SPI Mode 0,0)
123 | cs0_n <= 0;
124 | #reset_hold_period;
125 |
126 | for (i = 0; i < JOB_CONFIG_WIDTH; i = i + 1)
127 | begin
128 | // Data out before rising edge
129 | sdi0 <= test_job_config[JOB_CONFIG_WIDTH-1];
130 | test_job_config <= { test_job_config[JOB_CONFIG_WIDTH-2:0], 1'b0 };
131 | #spi_bit_half_period;
132 |
133 | // Rising edge (uut samples)
134 | sck0 <= 1;
135 | #spi_bit_half_period;
136 |
137 | // Falling edge (next bit out)
138 | sck0 <= 0;
139 | end
140 |
141 | cs0_n <= 1;
142 | #10;
143 |
144 | if (uut.job_config == expected_job_config)
145 | begin
146 | $display("\033\133\063\062\155[PASS]\033\133\060\155 `external_io`: shift in job configuration");
147 | end
148 | else
149 | begin
150 | $display("\033\133\063\061\155[FAIL]\033\133\060\155 `external_io`: shift in job configuration");
151 | $display("uut.job_config: %h", uut.job_config);
152 | $error("Test case failed: SPI0 did not properly load uut.job_config.");
153 | end
154 |
155 | ///////////////////////////////////////////////
156 | // Test SPI1 (clock in device configuration) //
157 | ///////////////////////////////////////////////
158 |
159 | // (SPI Mode 0,0)
160 | cs1_n <= 0;
161 |
162 | for (i = 0; i < DEVICE_CONFIG_WIDTH; i = i + 1)
163 | begin
164 | // Data out before rising edge
165 | sdi1 <= test_device_config[DEVICE_CONFIG_WIDTH-1];
166 | test_device_config <= { test_device_config[DEVICE_CONFIG_WIDTH-2:0], 1'b0 };
167 | #spi_bit_half_period;
168 |
169 | // Rising edge (uut samples)
170 | sck1 <= 1;
171 | #spi_bit_half_period;
172 |
173 | // Falling edge (next bit out)
174 | sck1 <= 0;
175 | end
176 |
177 | cs1_n <= 1;
178 | reset_n <= 1;
179 |
180 | if (uut.device_config == expected_device_config)
181 | begin
182 | $display("\033\133\063\062\155[PASS]\033\133\060\155 `external_io`: shift in device configuration");
183 | end
184 | else
185 | begin
186 | $display("\033\133\063\061\155[FAIL]\033\133\060\155 `external_io`: shift in device configuration");
187 | $display("uut.device_config: %h", uut.device_config);
188 | $error("Test case failed: SPI1 did not properly load uut.device_config");
189 | end
190 |
191 | // TODO test shifting out sdo1
192 |
193 | /////////////////////////////////////////////
194 | // Test SPI1 on success (clock out result) //
195 | /////////////////////////////////////////////
196 |
197 | shapool_success <= 1;
198 |
199 | // (SPI Mode 0,0)
200 | cs1_n <= 0;
201 | sdi1 <= 0;
202 |
203 | for (i = 0; i < 40; i = i + 1)
204 | begin
205 | // data out
206 | #spi_bit_half_period;
207 |
208 | // Rising edge (sample)
209 | test_result <= { test_result[38:0], sdo1 };
210 | sck1 <= 1;
211 | #spi_bit_half_period;
212 |
213 | // Falling edge (next bit out)
214 | sck1 <= 0;
215 | end
216 |
217 | cs1_n <= 1;
218 | #reset_hold_period;
219 |
220 | if (test_result == expected_result)
221 | begin
222 | $display("\033\133\063\062\155[PASS]\033\133\060\155 `external_io`: shift out result");
223 | end
224 | else
225 | begin
226 | $display("\033\133\063\061\155[FAIL]\033\133\060\155 `external_io`: shift out result");
227 | $display("test_result: %h", test_result);
228 | $error("Test case failed: SPI1 failed to shift out result properly.");
229 | end
230 |
231 | #100;
232 | $finish;
233 | end
234 |
235 | endmodule
--------------------------------------------------------------------------------
/src/tests/ram_init_test/Makefile:
--------------------------------------------------------------------------------
1 | ICEPOOL_PATH=../vendor/icepool-driver/src/
2 | LIBICEPOOL_PATH=../vendor/icepool-driver/src/
3 | FTDI_PATH=/usr/include/ftdi1/
4 | LIBFTDI_PATH=/usr/lib/
5 |
6 | .phony : build
7 | build : ram_init_test gateware
8 |
9 | .phony : run
10 | run : build flash
11 | ./ram_init_test
12 |
13 | ram_init_test : main.c libicepool
14 | gcc --std=c99 -g -o $@ -I$(ICEPOOL_PATH) -I$(FTDI_PATH) $< -L$(LIBICEPOOL_PATH) -licepool-d -L$(LIBFTDI_PATH) -lftdi1
15 |
16 | .phony : libicepool
17 | libicepool :
18 | make -C $(ICEPOOL_PATH) libicepool-d.a
19 |
20 | .phony : gateware
21 | gateware :
22 | make -C ./rtl build
23 |
24 | .phony : flash
25 | flash :
26 | make -C rtl/ flash
27 |
28 | .phony : clean
29 | clean :
30 | make -C ./rtl clean
31 | rm -f ./ram_init_test
--------------------------------------------------------------------------------
/src/tests/ram_init_test/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "icepool.h"
4 |
5 | #define DEVICE_COUNT 1
6 | #define DUMP_SIZE (64/8)
7 |
8 | void print_buffer(const uint8_t* buffer, size_t buffer_len)
9 | {
10 | for(size_t i = 0; i < buffer_len; )
11 | {
12 | for (size_t j = 0; j < 8 && i < buffer_len; j++, i++)
13 | {
14 | printf("%02x ", buffer[i]);
15 | }
16 | printf("\n");
17 | }
18 | }
19 |
20 | void dump_Kt(IcepoolContext* ctx)
21 | {
22 | uint8_t dump[DUMP_SIZE] = { 0 };
23 |
24 | icepool_assert_reset(ctx);
25 | icepool_deassert_reset(ctx);
26 |
27 | // Wait for READY
28 | while(icepool_poll_ready(ctx) == false) { printf("."); fflush(stdout); }
29 | printf("\n");
30 |
31 | icepool_spi_assert_daisy(ctx);
32 |
33 | icepool_spi_read_daisy(ctx, dump, DUMP_SIZE);
34 |
35 | icepool_spi_assert_daisy(ctx);
36 |
37 | icepool_assert_reset(ctx);
38 |
39 | printf("0x10_000000\t");
40 | print_buffer(&dump[0], 4);
41 |
42 | printf("0x10_111111\t");
43 | print_buffer(&dump[4], 4);
44 | }
45 |
46 | int main()
47 | {
48 | // Set up icepool context
49 | IcepoolContext* ctx = icepool_new();
50 |
51 | if (!ctx) {
52 | fprintf(stderr, "Could not initialize IcepoolContext. Quitting...\n");
53 | exit(EXIT_FAILURE);
54 | }
55 |
56 | dump_Kt(ctx);
57 |
58 | icepool_free(ctx);
59 |
60 | return EXIT_SUCCESS;
61 | }
--------------------------------------------------------------------------------
/src/tests/ram_init_test/rtl/Makefile:
--------------------------------------------------------------------------------
1 | SHAPOOL_PATH=../../../
2 | SHAPOOL_DEPS=$(SHAPOOL_PATH)external_io.v
3 |
4 | TEST_NAME=ram_init_test
5 | SHAPOOL_PCF=$(SHAPOOL_PATH)pinout-icepool-ice40hx8k.pcf
6 |
7 | .phony : build
8 | build : $(TEST_NAME).bin
9 |
10 | .phony: flash
11 | flash : $(TEST_NAME).bin
12 | iceprog -v -S $^
13 |
14 | $(TEST_NAME).bin : $(TEST_NAME).asc
15 | icepack $^ $@
16 |
17 | $(TEST_NAME).asc : $(TEST_NAME).json $(SHAPOOL_PCF)
18 | nextpnr-ice40 --package bg121 --hx8k --json $(TEST_NAME).json --pcf $(SHAPOOL_PCF) --asc $@
19 |
20 | $(TEST_NAME).json : ./top_test.v $(SHAPOOL_DEPS)
21 | yosys -p 'synth_ice40 -top top_test -json $@ -abc2 -retime' $^
22 |
23 | # Clean up
24 | .phony: clean
25 | clean :
26 | rm -f $(TEST_NAME).out \
27 | $(TEST_NAME).json \
28 | $(TEST_NAME).asc \
29 | $(TEST_NAME).bin
--------------------------------------------------------------------------------
/src/tests/ram_init_test/rtl/top_test.v:
--------------------------------------------------------------------------------
1 | module top_test
2 | (
3 | clk_in,
4 | reset_n_in,
5 | // Global data
6 | sck0_in,
7 | sdi0_in,
8 | cs0_n_in,
9 | // Daisy data
10 | sck1_in,
11 | sdi1_in,
12 | sdo1_out,
13 | cs1_n_in,
14 | // READY flags
15 | ready_n_od_out,
16 | // Indicator LED
17 | status_led_n_out
18 | );
19 | // 12 MHz ~ 48 MHz
20 | parameter PLL_DIVR = 4'b0000;
21 | parameter PLL_DIVF = 7'b1111111;
22 | parameter PLL_DIVQ = 3'b100;
23 |
24 | // 12 MHz ~ 56.25 MHz
25 | // parameter PLL_DIVR = 4'b0000;
26 | // parameter PLL_DIVF = 7'b1001010;
27 | // parameter PLL_DIVQ = 3'b100;
28 |
29 | // Multiply input clock signal using SB_PLL40_CORE
30 | wire g_clk;
31 |
32 | SB_PLL40_CORE #(
33 | .FEEDBACK_PATH("SIMPLE"),
34 | .DIVR(PLL_DIVR),
35 | .DIVF(PLL_DIVF),
36 | .DIVQ(PLL_DIVQ),
37 | .FILTER_RANGE(3'b001)
38 | )
39 | pll (
40 | .LOCK(pll_locked),
41 | .RESETB(1'b1),
42 | .BYPASS(1'b0),
43 | .REFERENCECLK(clk_in),
44 | //.PLLOUTCORE(g_clk)
45 | .PLLOUTGLOBAL(g_clk)
46 | );
47 |
48 | // Inputs and Outputs
49 |
50 | input wire clk_in;
51 |
52 | input wire reset_n_in;
53 |
54 | input wire sck0_in;
55 | input wire sdi0_in;
56 | input wire cs0_n_in;
57 |
58 | input wire sck1_in;
59 | input wire sdi1_in;
60 | output wire sdo1_out;
61 | input wire cs1_n_in;
62 |
63 | output wire ready_n_od_out;
64 |
65 | output wire status_led_n_out;
66 |
67 | // Set up dummy external_io
68 |
69 | external_io #(
70 | .POOL_SIZE(1),
71 | .POOL_SIZE_LOG2(0),
72 | .JOB_CONFIG_WIDTH(8), // smallest
73 | .DEVICE_CONFIG_WIDTH(8), // smallest
74 | .RESULT_DATA_WIDTH(64)
75 | )
76 | io (
77 | .clk(g_clk),
78 | .reset_n(reset_n_in),
79 | // SPI(0)
80 | .sck0(sck0_in),
81 | .sdi0(sdi0_in),
82 | .cs0_n(cs0_n_in),
83 | // SPI(1)
84 | .sck1(sck1_in),
85 | .sdi1(sdi1_in),
86 | .sdo1(sdo1_out),
87 | .cs1_n(cs1_n_in),
88 | // Stored data
89 | .device_config(),
90 | .job_config(),
91 | // Control signals
92 | .core_reset_n(),
93 | // From shapool
94 | .shapool_success(done),
95 | .shapool_result(dump),
96 | // READY signal
97 | .ready()
98 | );
99 |
100 | // Read all RAM values into register
101 |
102 | reg [63:0] dump;
103 | reg [5:0] round = 0;
104 |
105 | reg done = 0;
106 |
107 | always @(posedge g_clk)
108 | begin
109 | if (!reset_n_in)
110 | begin
111 | round <= 0;
112 | done <= 0;
113 | end
114 | else if (done == 0)
115 | begin
116 |
117 | round <= round + 1;
118 |
119 | if (round == 0)
120 | begin
121 | dump <= { Kt, dump[63:32] };
122 | end
123 |
124 | if (round == 63)
125 | begin
126 | dump <= { Kt, dump[63:32] };
127 | done <= 1;
128 | end
129 |
130 | end
131 | end
132 |
133 | assign ready_n_od_out = (done == 1) ? 1'b0 : 1'bz;
134 | assign status_led_n_out = !done;
135 |
136 | // RAM setup
137 | wire [15:0] data_hi;
138 | wire [15:0] data_lo;
139 |
140 | wire [31:0] Kt;
141 | assign Kt = { data_hi, data_lo };
142 |
143 | wire [7:0] address;
144 | assign address = { 2'b10, round };
145 |
146 | SB_RAM40_4K ram256x16_hi (
147 | .RDATA(data_hi),
148 | .RADDR(address),
149 | .RCLK(g_clk),
150 | .RCLKE(1),
151 | .RE(1),
152 | .WADDR(0),
153 | .WCLK(0),
154 | .WCLKE(0),
155 | .WDATA(0),
156 | .WE(0),
157 | .MASK(0)
158 | );
159 |
160 | SB_RAM40_4K ram256x16_lo (
161 | .RDATA(data_lo),
162 | .RADDR(address),
163 | .RCLK(g_clk),
164 | .RCLKE(1),
165 | .RE(1),
166 | .WADDR(0),
167 | .WCLK(0),
168 | .WCLKE(0),
169 | .WDATA(0),
170 | .WE(0),
171 | .MASK(0)
172 | );
173 |
174 | defparam ram256x16_hi.READ_MODE = 0; // 0 = 256x16
175 | defparam ram256x16_hi.WRITE_MODE = 0; // 0 = 256x16
176 |
177 | defparam ram256x16_lo.READ_MODE = 0; // 0 = 256x16
178 | defparam ram256x16_lo.WRITE_MODE = 0; // 0 = 256x16
179 |
180 | defparam ram256x16_hi.INIT_0 = 256'h0000_0001_0002_0003_0004_0005_0006_0007_0008_0009_000a_000b_000c_000d_000e_000f;
181 | defparam ram256x16_hi.INIT_1 = 256'h0010_0011_0012_0013_0014_0015_0016_0017_0018_0019_001a_001b_001c_001d_001e_001f;
182 | defparam ram256x16_hi.INIT_2 = 256'h0020_0021_0022_0023_0024_0025_0026_0027_0028_0029_002a_002b_002c_002d_002e_002f;
183 | defparam ram256x16_hi.INIT_3 = 256'h0030_0031_0032_0033_0034_0035_0036_0037_0038_0039_003a_003b_003c_003d_003e_003f;
184 | defparam ram256x16_hi.INIT_4 = 256'h0040_0041_0042_0043_0044_0045_0046_0047_0048_0049_004a_004b_004c_004d_004e_004f;
185 | defparam ram256x16_hi.INIT_5 = 256'h0050_0051_0052_0053_0054_0055_0056_0057_0058_0059_005a_005b_005c_005d_005e_005f;
186 | defparam ram256x16_hi.INIT_6 = 256'h0060_0061_0062_0063_0064_0065_0066_0067_0068_0069_006a_006b_006c_006d_006e_006f;
187 | defparam ram256x16_hi.INIT_7 = 256'h0070_0071_0072_0073_0074_0075_0076_0077_0078_0079_007a_007b_007c_007d_007e_007f;
188 | defparam ram256x16_hi.INIT_8 = 256'h0080_0081_0082_0083_0084_0085_0086_0087_0088_0089_008a_008b_008c_008d_008e_008f;
189 | defparam ram256x16_hi.INIT_9 = 256'h0090_0091_0092_0093_0094_0095_0096_0097_0098_0099_009a_009b_009c_009d_009e_009f;
190 | defparam ram256x16_hi.INIT_A = 256'h00a0_00a1_00a2_00a3_00a4_00a5_00a6_00a7_00a8_00a9_00aa_00ab_00ac_00ad_00ae_00af;
191 | defparam ram256x16_hi.INIT_B = 256'h00b0_00b1_00b2_00b3_00b4_00b5_00b6_00b7_00b8_00b9_00ba_00bb_00bc_00bd_00be_00bf;
192 | defparam ram256x16_hi.INIT_C = 256'h00c0_00c1_00c2_00c3_00c4_00c5_00c6_00c7_00c8_00c9_00ca_00cb_00cc_00cd_00ce_00cf;
193 | defparam ram256x16_hi.INIT_D = 256'h00d0_00d1_00d2_00d3_00d4_00d5_00d6_00d7_00d8_00d9_00da_00db_00dc_00dd_00de_00df;
194 | defparam ram256x16_hi.INIT_E = 256'h00e0_00e1_00e2_00e3_00e4_00e5_00e6_00e7_00e8_00e9_00ea_00eb_00ec_00ed_00ee_00ef;
195 | defparam ram256x16_hi.INIT_F = 256'h00f0_00f1_00f2_00f3_00f4_00f5_00f6_00f7_00f8_00f9_00fa_00fb_00fc_00fd_00fe_00ff;
196 |
197 | defparam ram256x16_lo.INIT_0 = 256'h0100_0101_0102_0103_0104_0105_0106_0107_0108_0109_010a_010b_010c_010d_010e_010f;
198 | defparam ram256x16_lo.INIT_1 = 256'h0110_0111_0112_0113_0114_0115_0116_0117_0118_0119_011a_011b_011c_011d_011e_011f;
199 | defparam ram256x16_lo.INIT_2 = 256'h0120_0121_0122_0123_0124_0125_0126_0127_0128_0129_012a_012b_012c_012d_012e_012f;
200 | defparam ram256x16_lo.INIT_3 = 256'h0130_0131_0132_0133_0134_0135_0136_0137_0138_0139_013a_013b_013c_013d_013e_013f;
201 | defparam ram256x16_lo.INIT_4 = 256'h0140_0141_0142_0143_0144_0145_0146_0147_0148_0149_014a_014b_014c_014d_014e_014f;
202 | defparam ram256x16_lo.INIT_5 = 256'h0150_0151_0152_0153_0154_0155_0156_0157_0158_0159_015a_015b_015c_015d_015e_015f;
203 | defparam ram256x16_lo.INIT_6 = 256'h0160_0161_0162_0163_0164_0165_0166_0167_0168_0169_016a_016b_016c_016d_016e_016f;
204 | defparam ram256x16_lo.INIT_7 = 256'h0170_0171_0172_0173_0174_0175_0176_0177_0178_0179_017a_017b_017c_017d_017e_017f;
205 | defparam ram256x16_lo.INIT_8 = 256'h0180_0181_0182_0183_0184_0185_0186_0187_0188_0189_018a_018b_018c_018d_018e_018f;
206 | defparam ram256x16_lo.INIT_9 = 256'h0190_0191_0192_0193_0194_0195_0196_0197_0198_0199_019a_019b_019c_019d_019e_019f;
207 | defparam ram256x16_lo.INIT_A = 256'h01a0_01a1_01a2_01a3_01a4_01a5_01a6_01a7_01a8_01a9_01aa_01ab_01ac_01ad_01ae_01af;
208 | defparam ram256x16_lo.INIT_B = 256'h01b0_01b1_01b2_01b3_01b4_01b5_01b6_01b7_01b8_01b9_01ba_01bb_01bc_01bd_01be_01bf;
209 | defparam ram256x16_lo.INIT_C = 256'h01c0_01c1_01c2_01c3_01c4_01c5_01c6_01c7_01c8_01c9_01ca_01cb_01cc_01cd_01ce_01cf;
210 | defparam ram256x16_lo.INIT_D = 256'h01d0_01d1_01d2_01d3_01d4_01d5_01d6_01d7_01d8_01d9_01da_01db_01dc_01dd_01de_01df;
211 | defparam ram256x16_lo.INIT_E = 256'h01e0_01e1_01e2_01e3_01e4_01e5_01e6_01e7_01e8_01e9_01ea_01eb_01ec_01ed_01ee_01ef;
212 | defparam ram256x16_lo.INIT_F = 256'h01f0_01f1_01f2_01f3_01f4_01f5_01f6_01f7_01f8_01f9_01fa_01fb_01fc_01fd_01fe_01ff;
213 |
214 | endmodule
215 |
--------------------------------------------------------------------------------
/src/tests/sha_round_usage_tb.v:
--------------------------------------------------------------------------------
1 | `timescale 10ns/100ps
2 |
3 | module sha_round_usage_tb();
4 |
5 | /*
6 | Tests basic usage of `sha_round`.
7 |
8 | * `sha_round` is a concurrent module.
9 | * Testing that the output is correct for known inputs.
10 | */
11 |
12 | `define VERILATOR
13 | `define DEBUG_VERBOSE
14 |
15 | localparam NUMBER_OF_CASES = 3;
16 | reg [255:0] S0_case [0:NUMBER_OF_CASES-1];
17 | reg [31:0] Kt_case [0:NUMBER_OF_CASES-1];
18 | reg [31:0] Wt_case [0:NUMBER_OF_CASES-1];
19 | reg [255:0] S1_expected [0:NUMBER_OF_CASES-1];
20 |
21 | // Set up case data
22 |
23 | // Case 0
24 | initial S0_case[0] = 256'h6a09e667_bb67ae85_3c6ef372_a54ff53a_510e527f_9b05688c_1f83d9ab_5be0cd19;
25 | initial Kt_case[0] = 32'h428a2f98;
26 | initial Wt_case[0] = 32'h61626380;
27 | initial S1_expected[0] = 256'h5d6aebcd_6a09e667_bb67ae85_3c6ef372_fa2a4622_510e527f_9b05688c_1f83d9ab;
28 |
29 | // Case 1
30 | initial S0_case[1] = 256'h04d24d6c_b85e2ce9_b6ae8fff_ffb70472_948d25b6_961f4894_b21bad3d_6d83bfc6;
31 | initial Kt_case[1] = 32'hbef9a3f7;
32 | initial Wt_case[1] = 32'heeaba2cc;
33 | initial S1_expected[1] = 256'hd39a2165_04d24d6c_b85e2ce9_b6ae8fff_fb121210_948d25b6_961f4894_b21bad3d;
34 |
35 | // Case 2
36 | initial S0_case[2] = 256'b0;
37 | initial Kt_case[2] = 256'b0;
38 | initial Wt_case[2] = 256'b0;
39 | initial S1_expected[2] = 256'b0;
40 |
41 | reg [255:0] S0;
42 | reg [31:0] Kt;
43 | reg [31:0] Wt;
44 | wire [255:0] S1;
45 |
46 | sha_round uut (
47 | .in(S0),
48 | .Kt(Kt),
49 | .Wt(Wt),
50 | .out(S1)
51 | );
52 |
53 | reg [1:0] i = 0;
54 |
55 | initial
56 | begin
57 | for (i = 0; i < NUMBER_OF_CASES; i = i + 1)
58 | begin
59 | S0 <= S0_case[i];
60 | Kt <= Kt_case[i];
61 | Wt <= Wt_case[i];
62 | #1;
63 |
64 | if (S1 == S1_expected[i])
65 | begin
66 | $display("\033\133\063\062\155[PASS]\033\133\060\155 `sha_round`: case %0d", i);
67 | end
68 | else
69 | begin
70 | $display("\033\133\063\061\155[FAIL]\033\133\060\155 `sha_round`: case %0d", i);
71 | $display(" S0 = %h", S0[255:128]);
72 | $display(" %h", S0[127: 0]);
73 | $display(" Kt = %h", Kt);
74 | $display(" Wt = %h", Wt);
75 | $display("");
76 | $display(" S1 (actual) = %h", S1[255:128]);
77 | $display(" %h", S1[127: 0]);
78 | $display(" S1 (expected) = %h", S1_expected[i][255:128]);
79 | $display(" %h", S1_expected[i][127: 0]);
80 | $display("");
81 |
82 | $error("Test case failed.");
83 | end
84 |
85 | end
86 |
87 | $finish;
88 | end
89 |
90 | endmodule
91 |
--------------------------------------------------------------------------------
/src/tests/sha_unit_btc_tb.v:
--------------------------------------------------------------------------------
1 | module sha_unit_usage_tb();
2 |
3 | /* Tests basic usage of `sha_unit`.
4 | */
5 |
6 | `define VERILATOR
7 | `define DEBUG_VERBOSE
8 |
9 | `define idx32(x) (32*((x)+1)-1):(32*(x));
10 |
11 | // SHA256 constants
12 | reg [255:0] SHA256_H0 = { 32'h6a09e667, 32'hbb67ae85,
13 | 32'h3c6ef372, 32'ha54ff53a,
14 | 32'h510e527f, 32'h9b05688c,
15 | 32'h1f83d9ab, 32'h5be0cd19 };
16 |
17 | localparam[2047:0] SHA256_K =
18 | { 32'h428a2f98, 32'h71374491, 32'hb5c0fbcf, 32'he9b5dba5,
19 | 32'h3956c25b, 32'h59f111f1, 32'h923f82a4, 32'hab1c5ed5,
20 | 32'hd807aa98, 32'h12835b01, 32'h243185be, 32'h550c7dc3,
21 | 32'h72be5d74, 32'h80deb1fe, 32'h9bdc06a7, 32'hc19bf174,
22 | 32'he49b69c1, 32'hefbe4786, 32'h0fc19dc6, 32'h240ca1cc,
23 | 32'h2de92c6f, 32'h4a7484aa, 32'h5cb0a9dc, 32'h76f988da,
24 | 32'h983e5152, 32'ha831c66d, 32'hb00327c8, 32'hbf597fc7,
25 | 32'hc6e00bf3, 32'hd5a79147, 32'h06ca6351, 32'h14292967,
26 | 32'h27b70a85, 32'h2e1b2138, 32'h4d2c6dfc, 32'h53380d13,
27 | 32'h650a7354, 32'h766a0abb, 32'h81c2c92e, 32'h92722c85,
28 | 32'ha2bfe8a1, 32'ha81a664b, 32'hc24b8b70, 32'hc76c51a3,
29 | 32'hd192e819, 32'hd6990624, 32'hf40e3585, 32'h106aa070,
30 | 32'h19a4c116, 32'h1e376c08, 32'h2748774c, 32'h34b0bcb5,
31 | 32'h391c0cb3, 32'h4ed8aa4a, 32'h5b9cca4f, 32'h682e6ff3,
32 | 32'h748f82ee, 32'h78a5636f, 32'h84c87814, 32'h8cc70208,
33 | 32'h90befffa, 32'ha4506ceb, 32'hbef9a3f7, 32'hc67178f2 };
34 |
35 | wire [31:0] K[0:63];
36 |
37 | assign K[ 0] = SHA256_K[2047:2016];
38 | assign K[ 1] = SHA256_K[2015:1984];
39 | assign K[ 2] = SHA256_K[1983:1952];
40 | assign K[ 3] = SHA256_K[1951:1920];
41 | assign K[ 4] = SHA256_K[1919:1888];
42 | assign K[ 5] = SHA256_K[1887:1856];
43 | assign K[ 6] = SHA256_K[1855:1824];
44 | assign K[ 7] = SHA256_K[1823:1792];
45 | assign K[ 8] = SHA256_K[1791:1760];
46 | assign K[ 9] = SHA256_K[1759:1728];
47 | assign K[10] = SHA256_K[1727:1696];
48 | assign K[11] = SHA256_K[1695:1664];
49 | assign K[12] = SHA256_K[1663:1632];
50 | assign K[13] = SHA256_K[1631:1600];
51 | assign K[14] = SHA256_K[1599:1568];
52 | assign K[15] = SHA256_K[1567:1536];
53 | assign K[16] = SHA256_K[1535:1504];
54 | assign K[17] = SHA256_K[1503:1472];
55 | assign K[18] = SHA256_K[1471:1440];
56 | assign K[19] = SHA256_K[1439:1408];
57 | assign K[20] = SHA256_K[1407:1376];
58 | assign K[21] = SHA256_K[1375:1344];
59 | assign K[22] = SHA256_K[1343:1312];
60 | assign K[23] = SHA256_K[1311:1280];
61 | assign K[24] = SHA256_K[1279:1248];
62 | assign K[25] = SHA256_K[1247:1216];
63 | assign K[26] = SHA256_K[1215:1184];
64 | assign K[27] = SHA256_K[1183:1152];
65 | assign K[28] = SHA256_K[1151:1120];
66 | assign K[29] = SHA256_K[1119:1088];
67 | assign K[30] = SHA256_K[1087:1056];
68 | assign K[31] = SHA256_K[1055:1024];
69 | assign K[32] = SHA256_K[1023: 992];
70 | assign K[33] = SHA256_K[ 991: 960];
71 | assign K[34] = SHA256_K[ 959: 928];
72 | assign K[35] = SHA256_K[ 927: 896];
73 | assign K[36] = SHA256_K[ 895: 864];
74 | assign K[37] = SHA256_K[ 863: 832];
75 | assign K[38] = SHA256_K[ 831: 800];
76 | assign K[39] = SHA256_K[ 799: 768];
77 | assign K[40] = SHA256_K[ 767: 736];
78 | assign K[41] = SHA256_K[ 735: 704];
79 | assign K[42] = SHA256_K[ 703: 672];
80 | assign K[43] = SHA256_K[ 671: 640];
81 | assign K[44] = SHA256_K[ 639: 608];
82 | assign K[45] = SHA256_K[ 607: 576];
83 | assign K[46] = SHA256_K[ 575: 544];
84 | assign K[47] = SHA256_K[ 543: 512];
85 | assign K[48] = SHA256_K[ 511: 480];
86 | assign K[49] = SHA256_K[ 479: 448];
87 | assign K[50] = SHA256_K[ 447: 416];
88 | assign K[51] = SHA256_K[ 415: 384];
89 | assign K[52] = SHA256_K[ 383: 352];
90 | assign K[53] = SHA256_K[ 351: 320];
91 | assign K[54] = SHA256_K[ 319: 288];
92 | assign K[55] = SHA256_K[ 287: 256];
93 | assign K[56] = SHA256_K[ 255: 224];
94 | assign K[57] = SHA256_K[ 223: 192];
95 | assign K[58] = SHA256_K[ 191: 160];
96 | assign K[59] = SHA256_K[ 159: 128];
97 | assign K[60] = SHA256_K[ 127: 96];
98 | assign K[61] = SHA256_K[ 95: 64];
99 | assign K[62] = SHA256_K[ 63: 32];
100 | assign K[63] = SHA256_K[ 31: 0];
101 |
102 | // Test case #1 - FIPS single-block "abc"
103 | reg [511:0] M_fips1 =
104 | { 128'h61626380_00000000_00000000_00000000,
105 | 128'h00000000_00000000_00000000_00000000,
106 | 128'h00000000_00000000_00000000_00000000,
107 | 128'h00000000_00000000_00000000_00000018 };
108 |
109 | reg[255:0] H_fips1 =
110 | { 128'hba7816bf_8f01cfea_414140de_5dae2223,
111 | 128'hb00361a3_96177a9c_b410ff61_f20015ad };
112 |
113 | // Test case #2 - FIPS multi-block "abcdbcdecdefdefgefgh..."
114 | /*
115 | reg [511:0] M_fips2 [0:1];
116 |
117 | initial M_fips2[0] =
118 | { 128'h61626364_62636465_63646566_64656667,
119 | 128'h65666768_66676869_6768696a_68696a6b,
120 | 128'h696a6b6c_6a6b6c6d_6b6c6d6e_6c6d6e6f,
121 | 128'h6d6e6f70_6e6f7071_80000000_00000000 };
122 |
123 | initial M_fips2[1] =
124 | { 128'h00000000_00000000_00000000_00000000,
125 | 128'h00000000_00000000_00000000_00000000,
126 | 128'h00000000_00000000_00000000_00000000,
127 | 128'h00000000_00000000_00000000_000001c0 };
128 |
129 | reg [255:0] H_fips2[0:1];
130 |
131 | initial H_fips2[0] =
132 | { 128'h85e655d6_417a1795_3363376a_624cde5c,
133 | 128'h76e09589_cac5f811_cc4b32c1_f20e533a };
134 |
135 | initial H_fips2[1] =
136 | { 128'h248d6a61_d20638b8_e5c02693_0c3e6039,
137 | 128'ha33ce459_64ff2167_f6ecedd4_19db06c1 };
138 | */
139 |
140 | // Test case #3 - BTC example
141 |
142 | reg [511:0] M_btc[0:1];
143 |
144 | initial M_btc[0] =
145 | { 128'h02000000_17975b97_c18ed1f7_e255adf2, // Start of data
146 | 128'h97599b55_330edab8_7803c817_01000000, // ...
147 | 128'h00000000_8a97295a_2747b4f1_a0b3948d, // ...
148 | 128'hf3990344_c0e19fa6_b2b92b3a_19c8e6ba }; // ...
149 |
150 | initial M_btc[1] =
151 | { 96'hdc141787358b0553535f0119, 32'h00000000, // end of data, nonce
152 | 128'h80000000_00000000_00000000_00000000, // pading
153 | 128'h00000000_00000000_00000000_00000000, // ...
154 | 128'h00000000_00000000_00000000_00000280 }; // ...padding, length
155 |
156 | reg [255:0] H_btc[0:2];
157 |
158 | initial H_btc[0] =
159 | { 128'hdc6a3b8d_0c69421a_cb1a5434_e536f7d5,
160 | 128'hc3c1b9e4_4cbb9b8f_95f0172e_fc48d2df }; // after first block (job parameter)
161 |
162 | initial H_btc[1] =
163 | { 128'h0fc3bf25_9405a32f_d6d78a5e_6de88914,
164 | 128'h8edd4088_cc46a2eb_c604c45a_15fe7d15 }; // intermediate hash
165 |
166 | initial H_btc[2] =
167 | { 128'h766f7950_56dd74d7_03b9173e_8d44223b,
168 | 128'hdbe3e0b2_9fe6a0eb_8ab33534_88c2565c }; // expected result
169 |
170 | reg [255:0] H0 = 0;
171 | reg [255:0] H = 0;
172 | reg [511:0] M = 0;
173 |
174 | reg clk = 0;
175 | reg reset = 0;
176 | reg feedback = 0;
177 |
178 | reg [5:0] round = 0;
179 | reg [31:0] Kt = 0;
180 |
181 | wire [255:0] H_u0;
182 | wire [255:0] H_u1;
183 |
184 | sha_unit u0 (
185 | clk,
186 | round,
187 | Kt,
188 | M,
189 | H0,
190 | H_u0
191 | );
192 |
193 | sha_unit u1 (
194 | clk,
195 | round,
196 | Kt,
197 | { H_u0[255:224], H[223:0], 1'b1, 191'd0, 64'h00000000_00000100 },
198 | SHA256_H0,
199 | H_u1
200 | );
201 |
202 | reg [15:0] i;
203 |
204 | initial
205 | begin
206 | #1 clk = 0;
207 |
208 | // Test case #1
209 |
210 | // Initialize inputs
211 | #1 M = M_fips1;
212 | #1 H0 = SHA256_H0;
213 |
214 | $display("Test #1 - Block #1:");
215 | $display(" M:");
216 | $display(" %h", M[511:384]);
217 | $display(" %h", M[383:256]);
218 | $display(" %h", M[255:128]);
219 | $display(" %h", M[127: 0]);
220 | $display(" H (in):");
221 | $display(" %h", H0[255:128]);
222 | $display(" %h", H0[127: 0]);
223 |
224 | #1 round = 0;
225 | #1 Kt = K[0];
226 |
227 | // Clock 64 times
228 | for (i = 0; i < 64; i = i + 1)
229 | begin
230 |
231 | #1 clk = 1;
232 | #1 clk = 0;
233 |
234 | #1 Kt = K[round];
235 | #1 round = round + 1;
236 |
237 | `ifdef DEBUG_VERBOSE
238 | $display("[%2d] Kt %h, Wt %h", round, Kt, u0.Wt);
239 | $display("[%2d] S0: %h", round, u0.S0);
240 | $display("[%2d] S1: %h", round, u0.S1);
241 | $display("[%2d] H0: %h", round, u0.H0);
242 | $display("[%2d] H1: %h", round, u0.H1);
243 | /*
244 | $display("[%2d] W: %h %h %h %h", round, 32{x}, u.W[`idx32(14)], u.W[`idx32(13)], u.W[`idx32(12)]);
245 | $display("[%2d] %h %h %h %h", round, u.W[`idx32(11)], u.W[`idx32(10)], u.W[`idx32( 9)], u.W[`idx32( 8)]);
246 | $display("[%2d] %h %h %h %h", round, u.W[`idx32( 7)], u.W[`idx32( 6)], u.W[`idx32( 5)], u.W[`idx32( 4)]);
247 | $display("[%2d] %h %h %h %h", round, u.W[`idx32( 3)], u.W[`idx32( 2)], u.W[`idx32( 1)], u.W[`idx32( 0)]);
248 | */
249 | `endif
250 | end
251 |
252 | `ifdef DEBUG_VERBOSE
253 | $display("[%2d] H1: %h", round, u0.H1);
254 | `endif
255 |
256 | $display(" H (out):");
257 | $display(" %h", H_u0[255:128]);
258 | $display(" %h", H_u0[127: 0]);
259 | $display(" H (expected):");
260 | $display(" %h", H_fips1[255:128]);
261 | $display(" %h", H_fips1[127: 0]);
262 | $display("");
263 |
264 | /*
265 | // TEST #2
266 |
267 | // Initialize inputs
268 | M = M_fips2[0];
269 | Hin = SHA256_H0;
270 |
271 | $display("Test #2 - Block #1:");
272 | $display(" M:");
273 | $display(" %h", M[511:384]);
274 | $display(" %h", M[383:256]);
275 | $display(" %h", M[255:128]);
276 | $display(" %h", M[127: 0]);
277 | $display(" H (in):");
278 | $display(" %h", Hin[255:128]);
279 | $display(" %h", Hin[127: 0]);
280 |
281 | // ~> IDLE
282 | #1 reset = 1;
283 | #1 round = 0;
284 | #1 feedback = 0; // Disable feedback for this case
285 |
286 | #1 clk = 1;
287 | #1 clk = 0;
288 | #1 reset = 0;
289 |
290 | // Chew first block
291 | for (i = 0; i < 64; i = i + 1)
292 | begin
293 | // 0) IDLE ~> WORKING
294 | // 1-62) WORKING ~> WORKING
295 | // 63) WORKING ~> DONE
296 | #1 clk = 1;
297 | #1 clk = 0;
298 |
299 | #1 Kt = K[round];
300 | #1 round = round + 1;
301 | end
302 |
303 | // DONE ~> IDLE (required when feedback = 0)
304 | #1 reset = 1;
305 | #1 round = 0;
306 |
307 | #1 clk = 1;
308 | #1 clk = 0;
309 | #1 reset = 0;
310 |
311 | $display(" H (out):");
312 | $display(" %h", Hout[255:128]);
313 | $display(" %h", Hout[127: 0]);
314 | $display(" H (expected):");
315 | $display(" %h", H_fips2[0][255:128]);
316 | $display(" %h", H_fips2[0][127: 0]);
317 | $display("");
318 |
319 | // Prepare for second block
320 | M = M_fips2[1];
321 | Hin = Hout;
322 |
323 | // Chew second block
324 | $display("Test #2 - Block #2:");
325 | $display(" M:");
326 | $display(" %h", M[511:384]);
327 | $display(" %h", M[383:256]);
328 | $display(" %h", M[255:128]);
329 | $display(" %h", M[127: 0]);
330 | $display(" H (in):");
331 | $display(" %h", Hin[255:128]);
332 | $display(" %h", Hin[127: 0]);
333 |
334 | for (i = 0; i < 64; i = i + 1)
335 | begin
336 | // 0) IDLE ~> WORKING
337 | // 1-62) WORKING ~> WORKING
338 | // 63) WORKING ~> DONE
339 | #1 clk = 1;
340 | #1 clk = 0;
341 | #1 Kt = K[round];
342 | round = round + 1;
343 | end
344 |
345 | // Extra clock cycle for updating result
346 | #1 clk = 1;
347 | #1 clk = 0;
348 |
349 | $display(" H (out):");
350 | $display(" %h", Hout[255:128]);
351 | $display(" %h", Hout[127: 0]);
352 | $display(" H (expected):");
353 | $display(" %h", H_fips2[1][255:128]);
354 | $display(" %h", H_fips2[1][127: 0]);
355 | $display("");
356 | */
357 |
358 | // TEST #3
359 |
360 | /*
361 | // Initialize inputs
362 | M = M_btc[0];
363 | Hin = SHA256_H0;
364 |
365 | // This block will be done on host, intermediate state provided as
366 | // parameter.
367 |
368 | $display("Test #3 - Block #1:");
369 | $display(" M:");
370 | $display(" %h", M[511:384]);
371 | $display(" %h", M[383:256]);
372 | $display(" %h", M[255:128]);
373 | $display(" %h", M[127: 0]);
374 | $display(" H (in):");
375 | $display(" %h", Hin[255:128]);
376 | $display(" %h", Hin[127: 0]);
377 |
378 |
379 | // ~> IDLE
380 | #1 reset = 1;
381 | #1 round = 0;
382 | #1 feedback = 0;
383 |
384 | #1 clk = 1;
385 | #1 clk = 0;
386 | #1 reset = 0;
387 |
388 | // Chew first block
389 | for (i = 0; i < 64; i = i + 1)
390 | begin
391 | #1 clk = 1;
392 | #1 clk = 0;
393 | #1 Kt = K[round];
394 | round = round + 1;
395 | end
396 |
397 | // DONE ~> IDLE (required when feedback = 0)
398 | #1 reset = 1;
399 | #1 round = 0;
400 | #1 feedback = 1; // exploit feedback for this case
401 |
402 | #1 clk = 1;
403 | #1 clk = 0;
404 | #1 reset = 0;
405 |
406 | $display(" H (out):");
407 | $display(" %h", Hout[255:128]);
408 | $display(" %h", Hout[127: 0]);
409 | $display(" H (expected):");
410 | $display(" %h", H_btc[0][255:128]);
411 | $display(" %h", H_btc[0][127: 0]);
412 | $display("");
413 | */
414 |
415 | // Prepare for second block -- where we normally start
416 | M = M_btc[1];
417 | H0 = H_btc[0];
418 |
419 | $display("Test #3 - Block #2:");
420 | $display(" M:");
421 | $display(" %h", M[511:384]);
422 | $display(" %h", M[383:256]);
423 | $display(" %h", M[255:128]);
424 | $display(" %h", M[127: 0]);
425 | $display(" H (in):");
426 | $display(" %h", H0[255:128]);
427 | $display(" %h", H0[127: 0]);
428 |
429 | // Chew second block
430 | for (i = 0; i < 64; i = i + 1)
431 | begin
432 | #1 clk = 1;
433 | #1 clk = 0;
434 | #1 Kt = K[round];
435 | #1 round = round + 1;
436 | end
437 |
438 | // Second verse same as the first
439 | $display(" H_u0 (actual):");
440 | $display(" %h", H_u0[255:128]);
441 | $display(" %h", H_u0[127: 0]);
442 | $display(" H_u0 (expected):");
443 | $display(" %h", H_btc[1][255:128]);
444 | $display(" %h", H_btc[1][127: 0]);
445 | $display("");
446 |
447 |
448 | $display(" M1:");
449 | $display(" %h", u1.M[511:384]);
450 | $display(" %h", u1.M[383:256]);
451 | $display(" %h", u1.M[255:128]);
452 | $display(" %h", u1.M[127: 0]);
453 |
454 | // Save H_u0 for use in M for second block
455 | // -- only [223:0] needs to be stored, [255:32] used as wire for use on
456 | // same cycle as round == 0.
457 | H[223:0] = H_u0[223:0];
458 |
459 | for (i = 0; i < 64; i = i + 1)
460 | begin
461 | #1 clk = 1;
462 | #1 clk = 0;
463 | #1 Kt = K[round];
464 | #1 round = round + 1;
465 | end
466 |
467 | $display("Test #3 - Block #3:");
468 | $display(" H_u1 (actual):");
469 | $display(" %h", H_u1[255:128]);
470 | $display(" %h", H_u1[127: 0]);
471 | $display(" H_u1 (expected):");
472 | $display(" %h", H_btc[2][255:128]);
473 | $display(" %h", H_btc[2][127: 0]);
474 | $display("");
475 |
476 | end
477 |
478 |
479 | endmodule
480 |
--------------------------------------------------------------------------------
/src/tests/sha_unit_usage_tb.v:
--------------------------------------------------------------------------------
1 | `timescale 10ns/100ps
2 |
3 | module sha_unit_usage_tb();
4 |
5 | /*
6 | Tests basic usage of `sha_unit`.
7 |
8 | Uses "FIPS single-block" example: "abc".
9 | */
10 |
11 | reg [511:0] M_fips1 =
12 | { 128'h61626380_00000000_00000000_00000000,
13 | 128'h00000000_00000000_00000000_00000000,
14 | 128'h00000000_00000000_00000000_00000000,
15 | 128'h00000000_00000000_00000000_00000018 };
16 |
17 | reg[255:0] H_fips1 =
18 | { 128'hba7816bf_8f01cfea_414140de_5dae2223,
19 | 128'hb00361a3_96177a9c_b410ff61_f20015ad };
20 |
21 | `define VERILATOR
22 | //`define DEBUG_VERBOSE
23 |
24 | // SHA256 constants
25 | // TODO was reg[0:255]
26 | reg [255:0] SHA256_H0 = { 32'h6a09e667, 32'hbb67ae85,
27 | 32'h3c6ef372, 32'ha54ff53a,
28 | 32'h510e527f, 32'h9b05688c,
29 | 32'h1f83d9ab, 32'h5be0cd19 };
30 |
31 | // TODO use SHA256_K.v
32 | localparam[2047:0] SHA256_K =
33 | { 32'h428a2f98, 32'h71374491, 32'hb5c0fbcf, 32'he9b5dba5,
34 | 32'h3956c25b, 32'h59f111f1, 32'h923f82a4, 32'hab1c5ed5,
35 | 32'hd807aa98, 32'h12835b01, 32'h243185be, 32'h550c7dc3,
36 | 32'h72be5d74, 32'h80deb1fe, 32'h9bdc06a7, 32'hc19bf174,
37 | 32'he49b69c1, 32'hefbe4786, 32'h0fc19dc6, 32'h240ca1cc,
38 | 32'h2de92c6f, 32'h4a7484aa, 32'h5cb0a9dc, 32'h76f988da,
39 | 32'h983e5152, 32'ha831c66d, 32'hb00327c8, 32'hbf597fc7,
40 | 32'hc6e00bf3, 32'hd5a79147, 32'h06ca6351, 32'h14292967,
41 | 32'h27b70a85, 32'h2e1b2138, 32'h4d2c6dfc, 32'h53380d13,
42 | 32'h650a7354, 32'h766a0abb, 32'h81c2c92e, 32'h92722c85,
43 | 32'ha2bfe8a1, 32'ha81a664b, 32'hc24b8b70, 32'hc76c51a3,
44 | 32'hd192e819, 32'hd6990624, 32'hf40e3585, 32'h106aa070,
45 | 32'h19a4c116, 32'h1e376c08, 32'h2748774c, 32'h34b0bcb5,
46 | 32'h391c0cb3, 32'h4ed8aa4a, 32'h5b9cca4f, 32'h682e6ff3,
47 | 32'h748f82ee, 32'h78a5636f, 32'h84c87814, 32'h8cc70208,
48 | 32'h90befffa, 32'ha4506ceb, 32'hbef9a3f7, 32'hc67178f2 };
49 |
50 | wire [31:0] K[0:63];
51 |
52 | assign K[ 0] = SHA256_K[2047:2016];
53 | assign K[ 1] = SHA256_K[2015:1984];
54 | assign K[ 2] = SHA256_K[1983:1952];
55 | assign K[ 3] = SHA256_K[1951:1920];
56 | assign K[ 4] = SHA256_K[1919:1888];
57 | assign K[ 5] = SHA256_K[1887:1856];
58 | assign K[ 6] = SHA256_K[1855:1824];
59 | assign K[ 7] = SHA256_K[1823:1792];
60 | assign K[ 8] = SHA256_K[1791:1760];
61 | assign K[ 9] = SHA256_K[1759:1728];
62 | assign K[10] = SHA256_K[1727:1696];
63 | assign K[11] = SHA256_K[1695:1664];
64 | assign K[12] = SHA256_K[1663:1632];
65 | assign K[13] = SHA256_K[1631:1600];
66 | assign K[14] = SHA256_K[1599:1568];
67 | assign K[15] = SHA256_K[1567:1536];
68 | assign K[16] = SHA256_K[1535:1504];
69 | assign K[17] = SHA256_K[1503:1472];
70 | assign K[18] = SHA256_K[1471:1440];
71 | assign K[19] = SHA256_K[1439:1408];
72 | assign K[20] = SHA256_K[1407:1376];
73 | assign K[21] = SHA256_K[1375:1344];
74 | assign K[22] = SHA256_K[1343:1312];
75 | assign K[23] = SHA256_K[1311:1280];
76 | assign K[24] = SHA256_K[1279:1248];
77 | assign K[25] = SHA256_K[1247:1216];
78 | assign K[26] = SHA256_K[1215:1184];
79 | assign K[27] = SHA256_K[1183:1152];
80 | assign K[28] = SHA256_K[1151:1120];
81 | assign K[29] = SHA256_K[1119:1088];
82 | assign K[30] = SHA256_K[1087:1056];
83 | assign K[31] = SHA256_K[1055:1024];
84 | assign K[32] = SHA256_K[1023: 992];
85 | assign K[33] = SHA256_K[ 991: 960];
86 | assign K[34] = SHA256_K[ 959: 928];
87 | assign K[35] = SHA256_K[ 927: 896];
88 | assign K[36] = SHA256_K[ 895: 864];
89 | assign K[37] = SHA256_K[ 863: 832];
90 | assign K[38] = SHA256_K[ 831: 800];
91 | assign K[39] = SHA256_K[ 799: 768];
92 | assign K[40] = SHA256_K[ 767: 736];
93 | assign K[41] = SHA256_K[ 735: 704];
94 | assign K[42] = SHA256_K[ 703: 672];
95 | assign K[43] = SHA256_K[ 671: 640];
96 | assign K[44] = SHA256_K[ 639: 608];
97 | assign K[45] = SHA256_K[ 607: 576];
98 | assign K[46] = SHA256_K[ 575: 544];
99 | assign K[47] = SHA256_K[ 543: 512];
100 | assign K[48] = SHA256_K[ 511: 480];
101 | assign K[49] = SHA256_K[ 479: 448];
102 | assign K[50] = SHA256_K[ 447: 416];
103 | assign K[51] = SHA256_K[ 415: 384];
104 | assign K[52] = SHA256_K[ 383: 352];
105 | assign K[53] = SHA256_K[ 351: 320];
106 | assign K[54] = SHA256_K[ 319: 288];
107 | assign K[55] = SHA256_K[ 287: 256];
108 | assign K[56] = SHA256_K[ 255: 224];
109 | assign K[57] = SHA256_K[ 223: 192];
110 | assign K[58] = SHA256_K[ 191: 160];
111 | assign K[59] = SHA256_K[ 159: 128];
112 | assign K[60] = SHA256_K[ 127: 96];
113 | assign K[61] = SHA256_K[ 95: 64];
114 | assign K[62] = SHA256_K[ 63: 32];
115 | assign K[63] = SHA256_K[ 31: 0];
116 |
117 | reg clk = 0;
118 | reg [5:0] round = 0;
119 | reg [31:0] Kt = SHA256_K[2047:2016];
120 |
121 | wire [255:0] H;
122 |
123 | sha_unit uut (
124 | // Control
125 | .clk(clk),
126 | // Externally managed/shared state
127 | .round(round),
128 | .Kt(Kt),
129 | // SHA256 parameters
130 | .M(M_fips1),
131 | .H0(SHA256_H0),
132 | // Result
133 | .H1(H)
134 | );
135 |
136 | always
137 | begin
138 | #1 clk <= !clk;
139 | end
140 |
141 | always @(posedge clk)
142 | begin
143 | if (round == 63)
144 | round <= 0;
145 | else
146 | round <= round + 1;
147 | end
148 |
149 | always @(posedge clk)
150 | begin
151 | Kt <= K[round];
152 | end
153 |
154 | reg [15:0] i;
155 |
156 | initial
157 | begin
158 |
159 | $dumpfile("sha_unit_usage_tb.vcd");
160 | $dumpvars;
161 |
162 | // Initialize inputs
163 | round <= 0;
164 | Kt <= K[0];
165 | clk <= 0;
166 |
167 | // Clock 64 times
168 | for (i = 0; i < 64; i = i + 1)
169 | begin
170 |
171 | #1; // rising edge
172 |
173 | `ifdef DEBUG_VERBOSE
174 | $display("[%2d] Kt %h, Wt %h", round, Kt, uut.Wt);
175 | $display("[%2d] S0: %h %h %h %h %h %h %h %h", round, uut.S0[255:224], uut.S0[223:192], uut.S0[191:160], uut.S0[159:128], uut.S0[127:96], uut.S0[95:64], uut.S0[63:32], uut.S0[31:0]);
176 | $display("[%2d] S1: %h %h %h %h %h %h %h %h", round, uut.S1[255:224], uut.S1[223:192], uut.S1[191:160], uut.S1[159:128], uut.S1[127:96], uut.S1[95:64], uut.S1[63:32], uut.S1[31:0]);
177 | $display("[%2d] H0: %h %h %h %h %h %h %h %h", round, uut.H0[255:224], uut.H0[223:192], uut.H0[191:160], uut.H0[159:128], uut.H0[127:96], uut.H0[95:64], uut.H0[63:32], uut.H0[31:0]);
178 | $display("[%2d] H1: %h %h %h %h %h %h %h %h", round, uut.H1[255:224], uut.H1[223:192], uut.H1[191:160], uut.H1[159:128], uut.H1[127:96], uut.H1[95:64], uut.H1[63:32], uut.H1[31:0]);
179 | $display("");
180 | `endif
181 |
182 | #1; // falling edge
183 |
184 | end
185 | if (H == H_fips1)
186 | begin
187 | $display("\033\133\063\062\155[PASS]\033\133\060\155 `sha_unit`: FIPS-1 Single block");
188 | end
189 | else
190 | begin
191 | $display("\n\033\133\063\061\155[FAIL]\033\133\060\155 `sha_unit`: FIPS-1 Single block");
192 | $display(" H0 = %h", SHA256_H0[255:128]);
193 | $display(" %h", SHA256_H0[127: 0]);
194 | $display(" M = %h", M_fips1[511:384]);
195 | $display(" %h", M_fips1[383:256]);
196 | $display(" %h", M_fips1[255:128]);
197 | $display(" %h", M_fips1[127: 0]);
198 | $display(" H (actual) = %h", H[255:128]);
199 | $display(" %h", H[127: 0]);
200 | $display(" H (expected) = %h", H_fips1[255:128]);
201 | $display(" %h", H_fips1[127: 0]);
202 |
203 | $error("Test case failed.");
204 | end
205 |
206 | $finish;
207 | end
208 |
209 |
210 | endmodule
211 |
--------------------------------------------------------------------------------
/src/tests/shapool_usage_tb.v:
--------------------------------------------------------------------------------
1 | `timescale 10ns/100ps
2 |
3 | module shapool_test();
4 |
5 | /*
6 | Tests basic usage of `shapool`.
7 |
8 | Uses only one sha_unit (POOL_SIZE = 1).
9 | */
10 |
11 | `define VERILATOR
12 | //`define DEBUG_VERBOSE
13 |
14 | `define SHAPOOL_NO_NONCE_OFFSET // Required for POOL_SIZE = 1
15 |
16 | localparam POOL_SIZE = 1;
17 | localparam POOL_SIZE_LOG2 = 0;
18 | localparam BASE_TARGET = 4;
19 |
20 | localparam [359:0] job_parameters = {
21 | 128'hdc6a3b8d_0c69421a_cb1a5434_e536f7d5, // SHA starting state
22 | 128'hc3c1b9e4_4cbb9b8f_95f0172e_fc48d2df, // ...
23 | 96'hdc141787_358b0553_535f0119 // Start of message block
24 | };
25 |
26 | localparam [7:0] device_parameters = {
27 | 8'h00 // nonce start (MSB)
28 | };
29 |
30 | reg clk = 0;
31 | reg reset_n = 1;
32 |
33 | reg [255:0] sha_state;
34 | reg [95:0] message_head;
35 | reg [7:0] nonce_start_MSB;
36 |
37 | wire success;
38 | wire [31:0] nonce;
39 | wire [7:0] match_flags;
40 |
41 | localparam nonce_expected = 39;
42 | localparam [255:0] H_expected = { 256'hc7f3244e501edf780c420f63a4266d30ffe1bdb53f4fde3ccd688604f15ffd03 };
43 |
44 | reg [255:0] H_btc [0:2];
45 |
46 | // State (a,b,c,...) after first block of first hash
47 | initial H_btc[0] =
48 | { 128'hdc6a3b8d_0c69421a_cb1a5434_e536f7d5,
49 | 128'hc3c1b9e4_4cbb9b8f_95f0172e_fc48d2df };
50 |
51 | // Expected result of first hash
52 | initial H_btc[1] =
53 | { 128'h0fc3bf25_9405a32f_d6d78a5e_6de88914,
54 | 128'h8edd4088_cc46a2eb_c604c45a_15fe7d15 };
55 |
56 | // Expected result of second hash
57 | initial H_btc[2] =
58 | { 128'h766f7950_56dd74d7_03b9173e_8d44223b,
59 | 128'hdbe3e0b2_9fe6a0eb_8ab33534_88c2565c };
60 |
61 | /*
62 | 0 5c56c2883435b38aeba0e69fb2e0e3db3b22448d3e17b903d774dd5650796f76
63 | 1 28902a23a194dee94141d1b70102accd85fc2c1ead0901ba0e41ade90d38a08e
64 | 2 729577af82250aaf9e44f70a72814cf56c16d430a878bf52fdaceeb7b4bd37f4
65 | 3 8491452381016cf80562ff489e492e00331de3553178c73c5169574000f1ed1c
66 | 39 03fd5ff1048668cd3cde4f3fb5bde1ff306d26a4630f420c78df1e504e24f3c7
67 | c7f3244e501edf780c420f63a4266d30ffe1bdb53f4fde3ccd688604f15ffd03 (output of module)
68 | 990 0001e3a4583f4c6d81251e8d9901dbe0df74d7144300d7c03cab15eca04bd4bb
69 | */
70 |
71 | shapool
72 | #(.POOL_SIZE(POOL_SIZE),
73 | .POOL_SIZE_LOG2(POOL_SIZE_LOG2),
74 | .BASE_TARGET(BASE_TARGET))
75 | uut (
76 | // Control
77 | clk,
78 | reset_n,
79 | // Job Params
80 | sha_state,
81 | message_head,
82 | nonce_start_MSB,
83 | // Result
84 | success,
85 | nonce,
86 | match_flags
87 | );
88 |
89 | localparam spi_bit_half_period = 6;
90 | localparam reset_hold_period = 2;
91 |
92 | always
93 | begin
94 | #1 clk = !clk;
95 | end
96 |
97 | reg [31:0] i = 0;
98 | reg [31:0] n = 0;
99 |
100 | initial
101 | begin
102 |
103 | $dumpfile("shapool_usage_tb.vcd");
104 | $dumpvars;
105 |
106 | // Initial values
107 | clk <= 0;
108 | reset_n <= 1;
109 |
110 | // Job parameters
111 | sha_state <= job_parameters[351:96];
112 | message_head <= job_parameters[ 95: 0];
113 |
114 | // Device configuration
115 | nonce_start_MSB <= device_parameters[7:0];
116 |
117 | #10;
118 |
119 | // Reset module
120 | reset_n <= 0;
121 | #reset_hold_period;
122 |
123 | // (Normally job_parameters, device_parameters shifted in here.)
124 |
125 | reset_n <= 1;
126 | #2; // one clock cycle (INIT -> EXEC)
127 |
128 | for (n = 0; n < 50 && !success; n = n)
129 | begin
130 |
131 | for (i = 0; i < 64 && !success; i = i + 1)
132 | begin
133 | #1; // rising edge
134 | #1; // falling edge
135 |
136 | `ifdef DEBUG_VERBOSE
137 | $display(" success: %b", uut.success);
138 | $display(" round: %d", uut.round);
139 | $display(" nonce: %d", nonce);
140 | $display(" u0:");
141 | $display(" M: %h", uut.pipelines[0].u0.M[511:384]);
142 | $display(" %h", uut.pipelines[0].u0.M[383:256]);
143 | $display(" %h", uut.pipelines[0].u0.M[255:128]);
144 | $display(" %h", uut.pipelines[0].u0.M[127: 0]);
145 | $display(" H: %h", uut.pipelines[0].H_u0[255:128]);
146 | $display(" %h", uut.pipelines[0].H_u0[127: 0]);
147 | $display(" u1:");
148 | $display(" M: %h", uut.pipelines[0].u1.M[511:384]);
149 | $display(" %h", uut.pipelines[0].u1.M[383:256]);
150 | $display(" %h", uut.pipelines[0].u1.M[255:128]);
151 | $display(" %h", uut.pipelines[0].u1.M[127: 0]);
152 | $display(" H: %h", uut.pipelines[0].H_u1[255:128]);
153 | $display(" %h", uut.pipelines[0].H_u1[127: 0]);
154 | $display("");
155 | `endif
156 | end
157 |
158 | end
159 |
160 | if (success == 1 && nonce - 2 == nonce_expected && uut.pipelines[0].H_u1 == H_expected)
161 | begin
162 | $display("\033\133\063\062\155[PASS]\033\133\060\155 `shapool`: single track, BTC four-zeroes");
163 | end
164 | else
165 | begin
166 | $display("\033\133\063\061\155[FAIL]\033\133\060\155 `shapool`: single track, BTC four-zeroes");
167 | $display("");
168 | $display(" success = %0d", success);
169 | $display(" nonce = %0d", nonce);
170 | $display(" nonce (adjusted) = %0d", nonce-2);
171 | $display(" H (actual) = %h", uut.pipelines[0].H_u1[255:128]);
172 | $display(" %h", uut.pipelines[0].H_u1[127: 0]);
173 | $display(" H (expected) = %h", H_expected[255:128]);
174 | $display(" %h", H_expected[127: 0]);
175 | $error("Test case failed.");
176 | end
177 |
178 | $finish;
179 | end
180 |
181 | endmodule
--------------------------------------------------------------------------------
/src/tests/top_usage_tb.v:
--------------------------------------------------------------------------------
1 | `timescale 1us/10ns
2 |
3 | module test_top();
4 |
5 | `define VERILATOR
6 |
7 | reg clk_in = 0;
8 |
9 | reg reset_n_in = 0;
10 |
11 | reg sck0_in;
12 | reg sdi0_in;
13 | reg cs0_n_in;
14 |
15 | reg sck1_in;
16 | reg sdi1_in;
17 | wire sdo1_out;
18 | reg cs1_n_in;
19 |
20 | wire ready_n_ts_inout;
21 |
22 | wire status_led_n_out;
23 |
24 | `define SHAPOOL_NO_NONCE_OFFSET // Required for POOL_SIZE = 1:
25 |
26 | localparam POOL_SIZE = 1;
27 | localparam POOL_SIZE_LOG2 = 0;
28 | localparam BASE_TARGET = 3;
29 |
30 | top
31 | #(.POOL_SIZE(POOL_SIZE),
32 | .POOL_SIZE_LOG2(POOL_SIZE_LOG2),
33 | .BASE_TARGET(BASE_TARGET))
34 | uut (
35 | clk_in,
36 | reset_n_in,
37 | // Global data
38 | sck0_in,
39 | sdi0_in,
40 | cs0_n_in,
41 | // Daisy data
42 | sck1_in,
43 | sdi1_in,
44 | sdo1_out,
45 | cs1_n_in,
46 | // Success flags
47 | ready_n_ts_inout,
48 | // Indicators
49 | status_led_n_out
50 | );
51 |
52 | // Test case
53 |
54 | reg [31:0] n = 0;
55 | reg [31:0] i = 0;
56 |
57 | localparam [359:0] test_spi0_data0 = {
58 | 128'hdc6a3b8d_0c69421a_cb1a5434_e536f7d5, // SHA starting state
59 | 128'hc3c1b9e4_4cbb9b8f_95f0172e_fc48d2df, // ...
60 | 96'hdc141787_358b0553_535f0119 // Start of message block
61 | };
62 |
63 | localparam [7:0] test_spi1_data0 = {
64 | 8'h00 // nonce start (MSB)
65 | };
66 |
67 | reg [359:0] test_spi0_data;
68 | reg [7:0] test_spi1_data;
69 | reg [31:0] result;
70 |
71 | initial
72 | begin
73 |
74 | $dumpfile("test_top.vcd");
75 | $dumpvars;
76 |
77 | test_spi0_data = test_spi0_data0;
78 | test_spi1_data = test_spi1_data0;
79 |
80 | // Initial states
81 | clk_in = 0;
82 | reset_n_in = 1;
83 | sck0_in = 0;
84 | cs0_n_in = 1;
85 | sck1_in = 0;
86 | cs1_n_in = 1;
87 |
88 | // Deassert reset_n_in to enter STATE_IDLE
89 | // -- to read in data on SPI
90 | #1 reset_n_in = 0;
91 |
92 | ///////////////////////////////////
93 | // Clock-in device configuration //
94 | ///////////////////////////////////
95 |
96 | // Assert CS1
97 | #1 cs1_n_in = 0;
98 |
99 | for (i = 0; i < 8; i = i + 1)
100 | begin
101 | // Shift-in data msb-first
102 | #1 sdi1_in = test_spi1_data[7];
103 | test_spi1_data <= { test_spi1_data[6:0], 1'b0 };
104 |
105 | #1 sck1_in = 1;
106 |
107 | // Need 3 clock cycles to synchronize sck1_in
108 | #1 clk_in = 1;
109 | #1 clk_in = 0;
110 | #1 clk_in = 1;
111 | #1 clk_in = 0;
112 | #1 clk_in = 1;
113 | #1 clk_in = 0;
114 |
115 | #1 sck1_in = 0;
116 |
117 | // Need 3 clock cycles to synchronize sck1_in
118 | #1 clk_in = 1;
119 | #1 clk_in = 0;
120 | #1 clk_in = 1;
121 | #1 clk_in = 0;
122 | #1 clk_in = 1;
123 | #1 clk_in = 0;
124 | end
125 |
126 | #1 cs1_n_in = 1;
127 |
128 | /////////////////////////////
129 | // Clock-in job parameters //
130 | /////////////////////////////
131 |
132 | #1 cs0_n_in = 0;
133 |
134 | for (i = 0; i < 360; i = i + 1)
135 | begin
136 | // Simulate FIFO into device
137 | #1 sdi0_in = test_spi0_data[351];
138 | test_spi0_data <= { test_spi0_data[350:0], 1'b0 };
139 |
140 | #1 sck0_in = 1;
141 |
142 | // Need 3 clock cycles to synchronize sck1_in
143 | #1 clk_in = 1;
144 | #1 clk_in = 0;
145 | #1 clk_in = 1;
146 | #1 clk_in = 0;
147 | #1 clk_in = 1;
148 | #1 clk_in = 0;
149 |
150 | #1 sck0_in = 0;
151 |
152 | // Need 3 clock cycles to synchronize sck1_in
153 | #1 clk_in = 1;
154 | #1 clk_in = 0;
155 | #1 clk_in = 1;
156 | #1 clk_in = 0;
157 | #1 clk_in = 1;
158 | #1 clk_in = 0;
159 | end
160 |
161 | #1 cs0_n_in = 1;
162 |
163 | $display("Device configuration");
164 | $display(" nonce start MSB: %h", uut.nonce_start);
165 |
166 | $display("Job parameters:");
167 | $display(" SHA256 state: %h", uut.sha_state[255:128]);
168 | $display(" %h", uut.sha_state[127:0]);
169 | $display(" message head: %h", uut.message_head);
170 |
171 | /////////////////////////////////
172 | // Reset and run until success //
173 | /////////////////////////////////
174 |
175 | // Deassert reset_n_in to enter STATE_EXEC
176 | #1 reset_n_in = 1;
177 |
178 | for (n = 0; n < 50 && !ready_n_ts_inout; n = n + 1)
179 | begin
180 |
181 | for (i = 0; i < 64; i = i + 1)
182 | begin
183 | $display("nonce: %d", uut.pool.nonce);
184 | $display("round: %d", uut.pool.round);
185 | $display(" Kt: %h", uut.pool.Kt);
186 | $display(" success: %b", uut.pool.success);
187 | $display(" |match_flags: %b", |uut.pool.match_flags);
188 | $display(" round == 0: %b", uut.pool.round == 0);
189 | $display(" skip_first: %b", uut.pool.skip_first);
190 | $display(" skip_second: %b", uut.pool.skip_second);
191 | $display(" u0.M: %h", uut.pool.tracks[0].u0.M[511:384]);
192 | $display(" u0.M: %h", uut.pool.tracks[0].u0.M[383:256]);
193 | $display(" u0.M: %h", uut.pool.tracks[0].u0.M[255:128]);
194 | $display(" u0.M: %h", uut.pool.tracks[0].u0.M[127:0]);
195 | $display(" u0.Wt: %h", uut.pool.tracks[0].u0.Wt);
196 | $display(" H_u0: %h", uut.pool.tracks[0].H_u0);
197 | $display(" u1.M: %h", uut.pool.tracks[0].u1.M[511:384]);
198 | $display(" u1.M: %h", uut.pool.tracks[0].u1.M[383:256]);
199 | $display(" u1.M: %h", uut.pool.tracks[0].u1.M[255:128]);
200 | $display(" u1.M: %h", uut.pool.tracks[0].u1.M[127:0]);
201 | $display(" u1.Wt: %h", uut.pool.tracks[0].u1.Wt);
202 | $display(" H_u1 (bs): %h", uut.pool.tracks[0].H_bs);
203 | $display(" H: %h", uut.pool.tracks[0].H);
204 | $display(" test bits: %h", { uut.pool.tracks[0].H[BASE_TARGET+16-1:16], uut.pool.tracks[0].H[15:0] & uut.pool.difficulty_bm });
205 | $display("");
206 |
207 | #1 clk_in = 1;
208 | #1 clk_in = 0;
209 | end
210 |
211 | end
212 |
213 | // Extra clock to save output/result
214 | #1 clk_in = 1;
215 | #1 clk_in = 0;
216 |
217 | $display("nonce: %h", uut.nonce);
218 | $display("ext_io.result_data: %h", uut.ext_io.result_data);
219 |
220 | // Extra clock to save result to output buffer
221 | #1 clk_in = 1;
222 | #1 clk_in = 0;
223 |
224 | $display("nonce: %h", uut.nonce);
225 | $display("ext_io.result_data: %h", uut.ext_io.result_data);
226 |
227 | // Shift result out over SPI1
228 | #1 cs1_n_in = 0;
229 |
230 | for (i = 0; i < 32; i = i + 1)
231 | begin
232 | $display("[%d] (%b) %b", i, ready_n_ts_inout, sdo1_out);
233 |
234 | #1 sck1_in = 1;
235 |
236 | // Need 3 clock cycles to synchronize sck1_in
237 | #1 clk_in = 1;
238 | #1 clk_in = 0;
239 | #1 clk_in = 1;
240 | #1 clk_in = 0;
241 | #1 clk_in = 1;
242 | #1 clk_in = 0;
243 |
244 | result <= { result[30:0], sdo1_out };
245 |
246 | #1 sck1_in = 0;
247 |
248 | // Need 3 clock cycles to synchronize sck1_in
249 | #1 clk_in = 1;
250 | #1 clk_in = 0;
251 | #1 clk_in = 1;
252 | #1 clk_in = 0;
253 | #1 clk_in = 1;
254 | #1 clk_in = 0;
255 | end
256 |
257 | #1 cs1_n_in = 1;
258 |
259 | $display("top_test result: %h", result);
260 |
261 | end
262 |
263 | endmodule
264 |
--------------------------------------------------------------------------------
/src/top.v:
--------------------------------------------------------------------------------
1 | /*
2 | * TODO redo documentation
3 | */
4 | module top
5 | (
6 | clk_in,
7 | reset_n_in,
8 | // Global data
9 | sck0_in,
10 | sdi0_in,
11 | cs0_n_in,
12 | // Daisy data
13 | sck1_in,
14 | sdi1_in,
15 | sdo1_out,
16 | cs1_n_in,
17 | // READY flags
18 | ready_n_od_out,
19 | // Indicator LED
20 | status_led_n_out
21 | );
22 |
23 | localparam NONCE_WIDTH = 32 - POOL_SIZE_LOG2;
24 |
25 | parameter POOL_SIZE = 2;
26 | parameter POOL_SIZE_LOG2 = 1;
27 |
28 | // Target range in number of leading zeros:
29 | // * minimum: 32
30 | // * maximum: 224
31 | //
32 | // TARGET example:
33 | //
34 | // Difficulty = 4022059196164
35 | //
36 | // FLOOR(LOG2(0x00000000ffffffff...ffff / 4022059196164))
37 | // = 182
38 | //
39 | // Therefore, 2^182 is nearest power-2 target less than the actual
40 | // target and 74 (=256-182) leading zeros are required to be <= 2^182.
41 |
42 | parameter BASE_TARGET = 32;
43 |
44 | // Inputs and Outputs
45 |
46 | input wire clk_in;
47 |
48 | input wire reset_n_in;
49 |
50 | input wire sck0_in;
51 | input wire sdi0_in;
52 | input wire cs0_n_in;
53 |
54 | input wire sck1_in;
55 | input wire sdi1_in;
56 | output wire sdo1_out;
57 | input wire cs1_n_in;
58 |
59 | output wire ready_n_od_out;
60 |
61 | output wire status_led_n_out;
62 |
63 | // Global reset(s)
64 | wire g_reset_n;
65 |
66 | wire core_reset_n;
67 | wire g_core_reset_n;
68 |
69 | `ifdef VERILATOR
70 | assign g_reset_n = reset_n_in;
71 | assign g_core_reset_n = core_reset_n;
72 | `else
73 | // Buffered external `reset_n`
74 | SB_GB reset_gbuf (
75 | .USER_SIGNAL_TO_GLOBAL_BUFFER(reset_n_in),
76 | .GLOBAL_BUFFER_OUTPUT(g_reset_n)
77 | );
78 |
79 | // Hold the core in a reset state when either the
80 | // external `reset_n` is low or `ready` is high.
81 | SB_GB core_reset_gbuf (
82 | .USER_SIGNAL_TO_GLOBAL_BUFFER(core_reset_n),
83 | .GLOBAL_BUFFER_OUTPUT(g_core_reset_n)
84 | );
85 | `endif
86 |
87 | // Device parameters
88 | // * 8' nonce starting count
89 | wire [7:0] device_config;
90 | wire [7:0] nonce_start;
91 |
92 | assign nonce_start = device_config[7:0];
93 |
94 | // Job parameters
95 | wire [351:0] job_config;
96 | // * 256' initial SHA256 state
97 | // * 96' start of first message block
98 | wire [255:0] sha_state;
99 | wire [95:0] message_head;
100 |
101 | assign sha_state = job_config[351:96];
102 | assign message_head = job_config[ 95: 0];
103 |
104 | // `shapool` results
105 | wire success;
106 | wire [31:0] nonce;
107 | wire [7:0] match_flags;
108 |
109 | // External READY flag (drives open-drain `ready_n_od_out`)
110 | wire ready;
111 |
112 | assign ready_n_od_out = ready ? 1'b0 : 1'bz;
113 |
114 | // External IO interface
115 | external_io #(
116 | .POOL_SIZE(POOL_SIZE),
117 | .POOL_SIZE_LOG2(POOL_SIZE_LOG2)
118 | ) ext_io (
119 | clk_in,
120 | g_reset_n,
121 | // SPI(0)
122 | sck0_in,
123 | sdi0_in,
124 | cs0_n_in,
125 | // SPI(1)
126 | sck1_in,
127 | sdi1_in,
128 | sdo1_out,
129 | cs1_n_in,
130 | // Stored data
131 | device_config,
132 | job_config,
133 | // Control signals
134 | core_reset_n,
135 | // From shapool
136 | success,
137 | { match_flags, nonce },
138 | // READY signal
139 | ready
140 | );
141 |
142 | // Hasher pool
143 | shapool #(
144 | .POOL_SIZE(POOL_SIZE),
145 | .POOL_SIZE_LOG2(POOL_SIZE_LOG2),
146 | .BASE_TARGET(BASE_TARGET)
147 | )
148 | pool (
149 | // Control
150 | .clk(clk_in),
151 | .reset_n(g_core_reset_n),
152 | // Parameters
153 | .sha_state(sha_state),
154 | .message_head(message_head),
155 | .nonce_start_MSB(nonce_start),
156 | // Results
157 | .success(success),
158 | .nonce(nonce),
159 | .match_flags(match_flags)
160 | );
161 |
162 | assign status_led_n_out = g_core_reset_n;
163 |
164 | endmodule
165 |
--------------------------------------------------------------------------------
/src/top_hx8k.v:
--------------------------------------------------------------------------------
1 | `include "target.vh"
2 |
3 | module top_hx8k
4 | (
5 | clk_in,
6 | reset_n_in,
7 | // Global data
8 | sck0_in,
9 | sdi0_in,
10 | cs0_n_in,
11 | // Daisy data
12 | sck1_in,
13 | sdi1_in,
14 | sdo1_out,
15 | cs1_n_in,
16 | // READY flags
17 | ready_n_od_out,
18 | // Indicator LED
19 | status_led_n_out
20 | );
21 | localparam POOL_SIZE = 2;
22 | localparam POOL_SIZE_LOG2 = 1;
23 | localparam BASE_TARGET = `TARGET;
24 |
25 | // 12 MHz ~ 30 MHz
26 | localparam PLL_DIVR = 4'b0000;
27 | localparam PLL_DIVF = 7'b1001111;
28 | localparam PLL_DIVQ = 3'b101;
29 |
30 | // Multiply input clock signal using SB_PLL40_CORE
31 | wire g_clk;
32 |
33 | SB_PLL40_CORE #(
34 | .FEEDBACK_PATH("SIMPLE"),
35 | .DIVR(PLL_DIVR),
36 | .DIVF(PLL_DIVF),
37 | .DIVQ(PLL_DIVQ),
38 | .FILTER_RANGE(3'b001)
39 | )
40 | pll (
41 | .LOCK(),
42 | .RESETB(1'b1),
43 | .BYPASS(1'b0),
44 | .REFERENCECLK(clk_in),
45 | //.PLLOUTCORE(g_clk)
46 | .PLLOUTGLOBAL(g_clk)
47 | );
48 |
49 | // Inputs and Outputs
50 |
51 | input wire clk_in;
52 |
53 | input wire reset_n_in;
54 |
55 | input wire sck0_in;
56 | input wire sdi0_in;
57 | input wire cs0_n_in;
58 |
59 | input wire sck1_in;
60 | input wire sdi1_in;
61 | output wire sdo1_out;
62 | input wire cs1_n_in;
63 |
64 | output wire ready_n_od_out;
65 |
66 | output wire status_led_n_out;
67 |
68 | top #(
69 | .POOL_SIZE(POOL_SIZE),
70 | .POOL_SIZE_LOG2(POOL_SIZE_LOG2),
71 | .BASE_TARGET(BASE_TARGET)
72 | )
73 | u (
74 | g_clk,
75 | reset_n_in,
76 | // Global data
77 | sck0_in,
78 | sdi0_in,
79 | cs0_n_in,
80 | // Daisy data
81 | sck1_in,
82 | sdi1_in,
83 | sdo1_out,
84 | cs1_n_in,
85 | // Success flags
86 | ready_n_od_out,
87 | // Indicators
88 | status_led_n_out
89 | );
90 |
91 | endmodule
92 |
--------------------------------------------------------------------------------
/src/top_up5k.v:
--------------------------------------------------------------------------------
1 | module top_up5k
2 | (
3 | clk_in,
4 | reset_n_in,
5 | // Global data
6 | sck0_in,
7 | sdi0_in,
8 | cs0_n_in,
9 | // Daisy data
10 | sck1_in,
11 | sdi1_in,
12 | sdo1_out,
13 | cs1_n_in,
14 | // Success flags
15 | ready_n_od_out,
16 | // Indicators
17 | status_led_n_out
18 | );
19 |
20 | `define SHAPOOL_NO_NONCE_OFFSET // Required for POOL_SIZE = 1
21 |
22 | parameter POOL_SIZE = 1;
23 | parameter POOL_SIZE_LOG2 = 0;
24 | parameter BASE_DIFFICULTY = 64;
25 |
26 | // 12 MHz ~ 56.25 MHz
27 | parameter PLL_DIVR = 4'b0000;
28 | parameter PLL_DIVF = 7'b1001010;
29 | parameter PLL_DIVQ = 3'b100;
30 |
31 | // Inputs and Outputs
32 |
33 | input wire clk_in;
34 |
35 | input wire reset_n_in;
36 |
37 | input wire sck0_in;
38 | input wire sdi0_in;
39 | input wire cs0_n_in;
40 |
41 | input wire sck1_in;
42 | input wire sdi1_in;
43 | output wire sdo1_out;
44 | input wire cs1_n_in;
45 |
46 | output wire ready_n_od_out;
47 |
48 | output wire status_led_n_out;
49 |
50 | top #(
51 | .POOL_SIZE(POOL_SIZE),
52 | .POOL_SIZE_LOG2(POOL_SIZE_LOG2),
53 | .BASE_DIFFICULTY(BASE_DIFFICULTY),
54 | .PLL_DIVR(PLL_DIVR),
55 | .PLL_DIVF(PLL_DIVF),
56 | .PLL_DIVQ(PLL_DIVQ)
57 | )
58 | u (
59 | clk_in,
60 | reset_n_in,
61 | // Global data
62 | sck0_in,
63 | sdi0_in,
64 | cs0_n_in,
65 | // Daisy data
66 | sck1_in,
67 | sdi1_in,
68 | sdo1_out,
69 | cs1_n_in,
70 | // Success flags
71 | ready_n_od_out,
72 | // Indicators
73 | status_led_n_out
74 | );
75 |
76 | endmodule
--------------------------------------------------------------------------------
/src/w_expand.v:
--------------------------------------------------------------------------------
1 | /* w_expand
2 | *
3 | * Asynchronously performs w_expand function given W[t] values.
4 | *
5 | * For SHA256,
6 | *
7 | * W(t) = SSIG1(W(t-2)) + W(t-7) + SSIG0(W(t-15)) + W(t-16)
8 | *
9 | */
10 | module w_expand(w2, w7, w15, w16, out);
11 |
12 | input wire [31:0] w2; // W[t-2]
13 | input wire [31:0] w7; // W[t-7]
14 | input wire [31:0] w15; // W[t-15]
15 | input wire [31:0] w16; // W[t-16]
16 | output wire [31:0] out;
17 |
18 | wire [31:0] ssig0_w15;
19 | wire [31:0] ssig1_w2;
20 |
21 | // For SHA256, SSIG0(X) = ROTR7(X) XOR ROTR18(X) XOR SHR3(X)
22 | assign ssig0_w15 = { w15[ 6:0], w15[31: 7] }
23 | ^ { w15[17:0], w15[31:18] }
24 | ^ { 3'b0, w15[31: 3] };
25 |
26 | // For SHA256, SSIG1(X) = ROTR17(X) XOR ROTR19(X) XOR SHR10(X)
27 | assign ssig1_w2 = { w2[16:0], w2[31:17] }
28 | ^ { w2[18:0], w2[31:19] }
29 | ^ { 10'b0, w2[31:10] };
30 |
31 | assign out = ssig0_w15 + ssig1_w2 + w7 + w16;
32 |
33 | endmodule // w_expand
34 |
--------------------------------------------------------------------------------