Skip to content

hbc_fsm

Contains HyperBus_FSM class for the State Machine in hyperbus protocol.

Classes:

HyperBus_FSM

HyperBus_FSM()

State machine class for hyperbus.

Methods:

  • ca_words

    Splits the 48bit CA into 6 bytes for transmission.

  • fsm

    FSM for states IDLE, CAs, WR_LATENCY, WRITE, READ, DONE.

  • fsm_reset

    Resets the fsm to IDLE state.

  • generate_random_data

    Generate random num number of byte.

  • get_time

    Get simulation time.

  • is_rwdsvalid

    Samples the RWDS input signal every 5ns and stores it in rwds_d.

  • log

    Logs a message value with prefixed simulation time.

  • rwds_valid

    Returns True if RWDS is valid.

  • rx_data

    Returns hex string of a 32 bit number.

  • swap_halves

    Swaps the upper and lower 16 bits of a 32-bit value used for word alignment, endianess conversion into little endian.

  • update_ca

    Builds the 48-bit command/address word using write strobe, config access, and memory address fields.

  • wdata_words

    Splits the 32 bit write data into bytes, with special arrangement if CA[46]=1.

  • wstrb_words

    Splits Write strobe into bits for each byte lane.

Source code in src/cocotbext/hyperbus/hbc_fsm.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
def __init__(self) -> None:
    """Initialization of signals in testbench and dut."""
    self.i_clk = 0
    self.i_rstn = 1
    self.i_cfg_access = 0
    self.i_mem_valid = 0
    self.o_mem_ready = 0
    self.i_mem_wstrb = 0
    self.i_mem_addr = 0
    self.i_mem_wdata = 0
    self.o_mem_rdata = 0
    self.o_csn0 = 1
    self.o_csn1 = 1
    self.o_clk = 0
    self.o_clkn = 1
    self.o_dq = 0
    self.i_dq = 0
    self.o_dq_de = 0
    self.o_rwds = 0
    self.i_rwds = 0
    self.o_rwds_de = 0
    self.o_resetn = 1
    self.io_dq: Union[int, str] = 0
    self.io_rwds = 0
    self.dq_z_en = 0
    # Internal Variables
    self.state = self.IDLE
    self.ca = 0
    self.wdata = 0
    self.wstrb = 0
    self.counter = 0
    self.mem_ready = 0
    self.mem_rdata = 0
    self.rwds_d = 0
    self.bus_clk = 0

    # High-z values
    self.highimp_8 = "z"
    for _i in range(7):
        self.highimp_8 += "z"
    self.highimp_1 = "z"

ca_words

ca_words() -> List[int]

Splits the 48bit CA into 6 bytes for transmission.

Source code in src/cocotbext/hyperbus/hbc_fsm.py
176
177
178
def ca_words(self) -> List[int]:
    """Splits the 48bit CA into 6 bytes for transmission."""
    return [(self.ca >> (8 * i)) & 0xFF for i in range(6)]

fsm async

fsm(dut: SimHandleBase) -> None

FSM for states IDLE, CAs, WR_LATENCY, WRITE, READ, DONE.

Source code in src/cocotbext/hyperbus/hbc_fsm.py
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
async def fsm(self, dut: SimHandleBase) -> None:
    """FSM for states IDLE, CAs, WR_LATENCY, WRITE, READ, DONE."""
    await Timer(5, "ns")
    while True:
        if not self.i_rstn:
            self.fsm_reset()

        elif self.state == self.IDLE:
            self.mem_ready = 0
            if self.i_mem_valid and not self.mem_ready:
                self.ca = self.update_ca(self.i_mem_wstrb, self.i_cfg_access, self.i_mem_addr)
                self.wdata = self.i_mem_wdata
                self.wstrb = self.i_mem_wstrb
                self.counter = 5
                self.state = self.CAs

        elif self.state == self.CAs:
            if self.counter:
                self.counter -= 1
            elif self.ca >> 47:
                self.counter = 3
                self.state = self.READ
            elif self.ca >> 46 & 1:
                self.counter = 1
                self.state = self.WRITE
            else:
                self.counter = self.WRITE_LATENCY
                self.state = self.WR_LATENCY

        elif self.state == self.WR_LATENCY:
            if self.counter:
                self.counter -= 1
            else:
                self.counter = 3
                self.state = self.WRITE

        elif self.state == self.WRITE:

            if self.counter:
                self.counter -= 1
            else:
                self.state = self.DONE

        elif self.state == self.READ:

            if self.rwds_valid():
                if self.counter == self.RBYTE_3:
                    self.mem_rdata = (self.i_dq << 8) | (
                        self.mem_rdata & 0xFFFF00FF
                    )
                elif self.counter == self.RBYTE_2:
                    self.mem_rdata = (self.i_dq) | (self.mem_rdata & 0xFFFFFF00)
                elif self.counter == self.RBYTE_1:
                    self.mem_rdata = (self.i_dq << 24) | (
                        self.mem_rdata & 0x00FFFFFF
                    )
                elif self.counter == self.RBYTE_0:
                    self.mem_rdata = (self.i_dq << 16) | (
                        self.mem_rdata & 0xFF00FFFF
                    )
                if self.counter:
                    self.counter -= 1
                else:
                    self.state = self.DONE

        elif self.state == self.DONE:
            self.mem_ready = 1
            self.state = self.IDLE

        self.o_csn0 = self.state in [self.IDLE, self.DONE]
        self.o_resetn = self.i_rstn
        self.o_dq = (
            self.ca_words()[self.counter]
            if self.state == self.CAs
            else (
                self.wdata_words()[self.counter] if self.state == self.WRITE else 0
            )
        )
        self.o_rwds = (
            not self.wstrb_words()[self.counter] if self.state == self.WRITE else 0
        )
        self.o_dq_de = self.state in [self.CAs, self.WRITE]
        self.o_rwds_de = self.state == self.WRITE and not (self.ca >> 46 & 1)
        self.o_mem_ready = self.mem_ready
        self.o_mem_rdata = self.mem_rdata
        self.io_dq = self.o_dq if self.o_dq_de else self.highimp_8
        self.io_rwds = (self.o_rwds if self.o_rwds_de else BinaryValue(self.highimp_1))
        await Timer(10, "ns")

fsm_reset

fsm_reset() -> None

Resets the fsm to IDLE state.

Source code in src/cocotbext/hyperbus/hbc_fsm.py
72
73
74
75
76
77
78
def fsm_reset(self) -> None:
    """Resets the fsm to IDLE state."""
    self.ca = 0
    self.state = self.IDLE
    self.mem_ready = 0
    self.mem_rdata = 0
    self.counter = 0

generate_random_data

generate_random_data(num: int) -> bytes

Generate random num number of byte.

Source code in src/cocotbext/hyperbus/hbc_fsm.py
235
236
237
238
239
240
241
242
def generate_random_data(self, num: int) -> bytes:
    """Generate random num number of byte."""
    int_list = []
    for _ in range(num):
        # Generate a random integer within the specified range
        random_int = random.randint(0, 2**8 - 1)
        int_list.append(random_int)
    return bytes(int_list)

get_time

get_time() -> int

Get simulation time.

Source code in src/cocotbext/hyperbus/hbc_fsm.py
197
198
199
def get_time(self) -> int:
    """Get simulation time."""
    return get_sim_time("ns")

is_rwdsvalid async

is_rwdsvalid() -> None

Samples the RWDS input signal every 5ns and stores it in rwds_d.

Source code in src/cocotbext/hyperbus/hbc_fsm.py
191
192
193
194
195
async def is_rwdsvalid(self) -> None:
    """Samples the RWDS input signal every 5ns and stores it in rwds_d."""
    while True:
        await Timer(5, "ns")
        self.rwds_d = self.i_rwds

log

log(msg: str) -> None

Logs a message value with prefixed simulation time.

Source code in src/cocotbext/hyperbus/hbc_fsm.py
201
202
203
def log(self, msg: str) -> None:
    """Logs a message value with prefixed simulation time."""
    cocotb.log.info(f"[{self.get_time()}]  {msg}")

rwds_valid

rwds_valid() -> int

Returns True if RWDS is valid.

Used for data sampling.

Source code in src/cocotbext/hyperbus/hbc_fsm.py
169
170
171
172
173
174
def rwds_valid(self) -> int:
    """Returns True if RWDS is valid.

    Used for data sampling.
    """
    return self.rwds_d or self.i_rwds

rx_data

rx_data(num: int, size: int)

Returns hex string of a 32 bit number.

Source code in src/cocotbext/hyperbus/hbc_fsm.py
205
206
207
208
209
210
def rx_data(self, num: int, size: int):
    """Returns hex string of a 32 bit number."""
    binary_str = format(num, "032b")
    shrinked_binary_str = binary_str[-size:]
    shrinked_num = int(shrinked_binary_str, 2)
    return hex(shrinked_num)

swap_halves

swap_halves(hex_num: int) -> int

Swaps the upper and lower 16 bits of a 32-bit value used for word alignment, endianess conversion into little endian.

Source code in src/cocotbext/hyperbus/hbc_fsm.py
227
228
229
230
231
232
233
def swap_halves(self, hex_num: int) -> int:
    """Swaps the upper and lower 16 bits of a 32-bit value used for word alignment, endianess conversion into little endian."""
    hex_str = f"{hex_num:08x}"
    first_half = hex_str[:4]
    second_half = hex_str[4:]
    swapped_hex_str = second_half + first_half
    return int(swapped_hex_str, 16)

update_ca

update_ca(
    i_mem_wstrb: int, i_cfg_access: int, i_mem_addr: int
) -> int

Builds the 48-bit command/address word using write strobe, config access, and memory address fields.

Source code in src/cocotbext/hyperbus/hbc_fsm.py
212
213
214
215
216
217
218
219
220
221
222
223
224
225
def update_ca(self, i_mem_wstrb: int, i_cfg_access: int, i_mem_addr: int) -> int:
    """Builds the 48-bit command/address word using write strobe, config access, and memory address fields."""
    or_i_mem_wstrb = int(i_mem_wstrb != 0)
    not_or_i_mem_wstrb = int(not or_i_mem_wstrb)
    _ca = 0
    _ca |= not_or_i_mem_wstrb << 47
    _ca |= int(i_cfg_access) << 46
    _ca |= (or_i_mem_wstrb & int(i_cfg_access)) << 45
    _ca &= ~((1 << 45) - (1 << 16))
    _ca |= (i_mem_addr & 0xFFFFFFF8) << 13
    _ca &= ~0x7
    _ca |= i_mem_addr & 0x7
    _ca &= (1 << 48) - 1
    return _ca

wdata_words

wdata_words() -> List[int]

Splits the 32 bit write data into bytes, with special arrangement if CA[46]=1.

Source code in src/cocotbext/hyperbus/hbc_fsm.py
180
181
182
183
184
185
def wdata_words(self) -> List[int]:
    """Splits the 32 bit write data into bytes, with special arrangement if CA[46]=1."""
    if self.ca >> 46 & 1:
        return [(self.wdata >> 16) & 0xFF, (self.wdata >> 24) & 0xFF]

    return [(self.wdata >> (8 * i)) & 0xFF for i in range(4)]

wstrb_words

wstrb_words() -> List[int]

Splits Write strobe into bits for each byte lane.

Source code in src/cocotbext/hyperbus/hbc_fsm.py
187
188
189
def wstrb_words(self) -> List[int]:
    """Splits Write strobe into bits for each byte lane."""
    return [(self.wstrb >> 1) & 1, self.wstrb & 1, (self.wstrb >> 3) & 1, (self.wstrb >> 2) & 1]