Skip to content

Commit c932e74

Browse files
authored
Merge pull request #104 from StanfordVLSI/fpga_merge2
Get loopback emulation test working with mixed-signal emulation models
2 parents fb4d493 + 3eac8dd commit c932e74

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1807
-752
lines changed

.buildkite/pipeline.yml

+8
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,18 @@ steps:
7171
- "tests/fpga_system_tests/*/build/*/prj/prj.runs/*/*.log"
7272
- "tests/fpga_system_tests/*/build/*/prj/prj.runs/*/*.bit"
7373
- "tests/fpga_system_tests/*/build/*/prj/prj.runs/*/*.ltx"
74+
- "tests/fpga_system_tests/*/build/*/prj/prj.runs/*/*.xsa"
75+
- "tests/fpga_system_tests/*/build/*/prj/prj.runs/*/ps7_init.tcl"
76+
- "tests/fpga_system_tests/*/build/*/prj/prj.runs/*/*.hwdef"
77+
- "tests/fpga_system_tests/*/build/*/prj/prj.runs/*/*.sysdef"
78+
- "tests/fpga_system_tests/*/build/*/prj/prj.sdk/*/*/*.elf"
7479
- "tests/fpga_system_tests/*/build/*/prj/prj.sim/*/behav/xsim/*.log"
7580
- "tests/fpga_system_tests/*/build/*/prj/prj.sim/*/behav/xsim/*.sh"
7681
- "tests/fpga_system_tests/*/prj.yaml"
7782
- "tests/fpga_system_tests/*/source.yaml"
83+
- "build/all/jtag/reg_list.json"
84+
- "build/cpu_models/jtag/jtag_reg_pack.sv"
85+
- "build/tb/jtag_drv_pack.sv"
7886
timeout_in_minutes: 60
7987
agents:
8088
fpga_verif: "true"

config/fpga/clk_delay.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
dt: 0.1e-6
2-
n_bits: 8
3-
t_per: 1.0e-9
2+
n_bits: 9
3+
t_per: 250.0e-12

config/fpga/osc_model.yml

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1 @@
1-
dt: 0.1e-6
2-
tlo: 0.5e-9
3-
thi: 0.5e-9
4-
tdel: 0.5e-9
1+
dt: 0.1e-6

config/fpga/rx_adc.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
dt: 0.1e-6
2-
vp: 1.0
3-
vn: -1.0
2+
vref: 0.4
43
n: 8

config/fpga/system_fpga.yml

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
parameter_list:
2+
- &channel_width 16
3+
- &code_precision 8
4+
- &output_precision 10
5+
- &ffe_length 4
6+
- &ffe_weight_precision 10
7+
- &estimate_depth 4
8+
- &estimate_precision 8
9+
- &sequence_length 3
10+
- &decision_shift_precision 4
11+
- &ffe_shift_precision 5
12+
- &mlsd_bit_length 1
13+
- &mlsd_est_cursor_pos 0
14+
15+
generate:
16+
channel:
17+
class: "PulseChannel"
18+
type: "dielectric1"
19+
file_name: "impulse_response.txt"
20+
parameters:
21+
baud_rate: 1
22+
sampling_pos: 0
23+
channel_depth: 125
24+
tau: 0.0087
25+
sample_rate: 100
26+
baud_rate: 1
27+
cursor_pos: *mlsd_est_cursor_pos
28+
29+
30+
generic:
31+
parameters:
32+
channel_width: *channel_width
33+
code_precision : *code_precision
34+
ffe_length: *ffe_length
35+
ffe_weight_precision: *ffe_weight_precision
36+
ffe_shift: 8
37+
mlsd_shift: 8
38+
ffe:
39+
parameters:
40+
length : *ffe_length
41+
width : *channel_width
42+
input_precision : *code_precision
43+
output_precision: *output_precision
44+
weight_precision: *ffe_weight_precision
45+
shift_precision: *ffe_shift_precision
46+
adaptation:
47+
type: 'wiener'
48+
args: { mu : 0.1 }
49+
comp:
50+
parameters:
51+
width : *channel_width
52+
input_precision : *output_precision
53+
conf_precision : 8
54+
thresh_precision : *output_precision
55+
threshold:
56+
value: 0
57+
mlsd:
58+
parameters:
59+
width: *channel_width
60+
length: *sequence_length
61+
code_precision : *code_precision
62+
estimate_precision: *estimate_precision
63+
estimate_depth: *estimate_depth
64+
shift_precision: *decision_shift_precision
65+
bit_length: *mlsd_bit_length
66+
est_center: *mlsd_est_cursor_pos
67+

config/fpga/tx.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
dt: 0.1e-6
2-
vp: 1.0
3-
vn: -1.0
2+
vp: 0.4
3+
vn: -0.4

conftest.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,23 @@ def pytest_addoption(parser):
44
parser.addoption(
55
'--dump_waveforms', action='store_true', help='Dump waveforms from test.'
66
)
7+
78
parser.addoption(
89
'--board_name', default='ZC702', type=str, help='Name of the FPGA board.'
910
)
1011

12+
parser.addoption(
13+
'--ser_port', default='/dev/ttyUSB2', type=str, help='USB serial path.'
14+
)
15+
1116
@pytest.fixture
1217
def dump_waveforms(request):
1318
return request.config.getoption('--dump_waveforms')
1419

1520
@pytest.fixture
1621
def board_name(request):
17-
return request.config.getoption('--board_name')
22+
return request.config.getoption('--board_name')
23+
24+
@pytest.fixture
25+
def ser_port(request):
26+
return request.config.getoption('--ser_port')

dragonphy/adapt_fir.py

+7-65
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import numpy as np
21
from pathlib import Path
32

4-
from dragonphy import Channel, Wiener, Quantizer, Packager
3+
from dragonphy import Channel, Packager
54

65
class AdaptFir:
76
def __init__(self, filename=None, **system_values):
@@ -10,52 +9,18 @@ def __init__(self, filename=None, **system_values):
109
ffe_config = system_values['generic']['ffe']
1110
constant_config = system_values['generic']
1211
mlsd_config = system_values['generic']['mlsd']
13-
comp_config = system_values['generic']['comp']
12+
comp_config = system_values['generic']['comp']
13+
1414
# create channel model
1515
kwargs = dict(
16-
channel_type='arctan',
17-
tau=0.25e-9,
18-
t_delay=4e-9,
19-
sampl_rate=10e9,
16+
channel_type='exponent',
17+
tau=25e-12,
18+
t_delay=31.25e-12,
19+
sampl_rate=160e9,
2020
resp_depth=500
2121
)
2222
chan = Channel(**kwargs)
2323

24-
# create a channel model delayed such that the optimal
25-
# cursor position is an integer
26-
# TODO: clean this up
27-
kwargs_d = kwargs.copy()
28-
kwargs_d['t_delay'] += 0.5e-9
29-
chan_d = Channel(**kwargs_d)
30-
31-
# compute response of channel to codes
32-
iterations = 200000
33-
ideal_codes = np.random.randint(2, size=iterations) * 2 - 1
34-
chan_out = chan_d.compute_output(ideal_codes)
35-
36-
# Adapt to the channel
37-
cursor_pos = 5
38-
adapt = Wiener(
39-
step_size=ffe_config['adaptation']['args']['mu'],
40-
num_taps=ffe_config['parameters']['length'],
41-
cursor_pos=cursor_pos
42-
)
43-
for i in range(iterations - cursor_pos):
44-
adapt.find_weights_pulse(ideal_codes[i - cursor_pos], chan_out[i])
45-
weights = adapt.weights
46-
47-
# Uncomment this line for debugging purposes to
48-
# use weights corresponding to a perfect channel
49-
# weights = np.array([1.0, 0, 0])
50-
51-
# Normalize weights
52-
weights = weights * (100.0 / np.sum(np.abs(weights)))
53-
54-
# Quantize the weights
55-
# TODO: why isn't "quantized_weights" used?
56-
qw = Quantizer(width=ffe_config['parameters']['weight_precision'], signed=True)
57-
quantized_weights = qw.quantize_2s_comp(weights)
58-
5924
# create constants package
6025
Packager(
6126
package_name='constant_gpack',
@@ -84,29 +49,6 @@ def __init__(self, filename=None, **system_values):
8449
dir=build_dir
8550
).create_package()
8651

87-
# Write impulse response to package
88-
step_dt = 0.1e-9
89-
_, v_step = chan.get_step_resp(f_sig=1 / step_dt, resp_depth=500)
90-
Packager(
91-
package_name='step_resp_pack',
92-
parameters={
93-
'step_len': len(v_step),
94-
'step_dt': step_dt,
95-
'v_step': v_step
96-
},
97-
dir=build_dir
98-
).create_package()
99-
100-
# Write weights to package
101-
# TODO: why is "weights" used here instead of "quantized_weights"?
102-
Packager(
103-
package_name='weights_pack',
104-
parameters={
105-
'read_weights': [int(elem) for elem in weights]
106-
},
107-
dir=build_dir
108-
).create_package()
109-
11052
# Write the step response data to a YAML file
11153
chan.to_file(build_dir / 'chan.npy')
11254
print(build_dir / 'chan.npy')

dragonphy/anasymod.py

+23-2
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,34 @@
22
import yaml
33

44
class AnasymodProjectConfig:
5-
def __init__(self):
5+
def __init__(self, fpga_sim_ctrl='UART_ZYNQ'):
66
self.config = {
77
'PROJECT': {
88
'dt': 50e-9,
99
'board_name': 'ZC702',
1010
'plugins': ['msdsl'],
11-
'emu_clk_freq': 20e6
11+
'emu_clk_freq': 5e6,
12+
'cpu_debug_mode': 0,
13+
'cpu_debug_hierarchies': [],
14+
'flatten_hierarchy': 'none'
15+
},
16+
'FPGA_TARGET': {
17+
'fpga': {
18+
'fpga_sim_ctrl': fpga_sim_ctrl
19+
}
1220
}
1321
}
1422

23+
def set_cpu_debug_mode(self, value):
24+
self.config['PROJECT']['cpu_debug_mode'] = value
25+
26+
def set_flatten_hierarchy(self, value):
27+
assert value in {'none', 'full', 'rebuilt'}, 'Invalid setting.'
28+
self.config['PROJECT']['flatten_hierarchy'] = value
29+
30+
def add_debug_probe(self, depth, path):
31+
self.config['PROJECT']['cpu_debug_hierarchies'].append([depth, path])
32+
1533
def set_board_name(self, value):
1634
self.config['PROJECT']['board_name'] = value
1735

@@ -61,6 +79,9 @@ def add_verilog_sources(self, file_list, fileset=None):
6179
def add_verilog_headers(self, header_list, fileset=None):
6280
self.add_generic_sources('verilog_headers', header_list, fileset)
6381

82+
def add_firmware_files(self, file_list, fileset=None):
83+
self.add_generic_sources('firmware_files', file_list, fileset)
84+
6485
def add_defines(self, defines, fileset=None):
6586
if 'defines' not in self.sources:
6687
self.sources['defines'] = {}

dragonphy/fpga_models/chan_core.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212

1313
class ChannelCore:
1414
def __init__(self, filename=None, **system_values):
15+
# set a fixed random seed for repeatability
16+
np.random.seed(0)
17+
1518
module_name = Path(filename).stem
1619
build_dir = Path(filename).parent
1720

@@ -30,7 +33,7 @@ def __init__(self, filename=None, **system_values):
3033
view = system_values['view']
3134

3235
# read in the channel data
33-
chan = Filter.from_file(get_file('build/' + view + '/adapt_fir/chan.npy'))
36+
chan = Filter.from_file(get_file('build/fpga_models/adapt_fir/chan.npy'))
3437

3538
# create a function
3639
domain = [chan.t_vec[0], chan.t_vec[-1]]

dragonphy/fpga_models/clk_delay_core.py

+4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
from pathlib import Path
2+
import numpy as np
23
from msdsl import MixedSignalModel, VerilogGenerator, min_op
34
from msdsl.expr.expr import array, concatenate
45
from msdsl.expr.extras import if_
56

67
class ClkDelayCore:
78
def __init__(self, filename=None, **system_values):
9+
# set a fixed random seed for repeatability
10+
np.random.seed(1)
11+
812
module_name = Path(filename).stem
913
build_dir = Path(filename).parent
1014

dragonphy/fpga_models/osc_model_core.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
from pathlib import Path
22
from copy import deepcopy
3+
import numpy as np
34
from msdsl import MixedSignalModel, VerilogGenerator
45
from msdsl.expr.expr import array
56
from msdsl.expr.extras import if_
67

78
class OscModelCore:
89
def __init__(self, filename=None, **system_values):
10+
# set a fixed random seed for repeatability
11+
np.random.seed(2)
12+
913
module_name = Path(filename).stem
1014
build_dir = Path(filename).parent
1115

@@ -14,15 +18,14 @@ def __init__(self, filename=None, **system_values):
1418
f'Cannot build {module_name}, Missing parameter in config file'
1519

1620
m = MixedSignalModel(module_name, dt=system_values['dt'], build_dir=build_dir)
17-
m.add_real_param('t_lo', default=system_values['tlo'])
18-
m.add_real_param('t_hi', default=system_values['thi'])
21+
m.add_real_param('t_del', 0)
1922
m.add_digital_input('emu_rst')
2023
m.add_digital_input('emu_clk')
24+
m.add_analog_input('t_lo')
25+
m.add_analog_input('t_hi')
2126
m.add_analog_input('emu_dt')
22-
m.add_analog_output('dt_req', init=system_values['tdel'])
27+
m.add_analog_output('dt_req', init='t_del')
2328
m.add_digital_output('clk_val')
24-
m.add_digital_input('clk_i')
25-
m.add_digital_output('clk_o')
2629

2730
# determine if the request was granted
2831
m.bind_name('req_grant', m.dt_req == m.emu_dt)
@@ -55,15 +58,12 @@ def __init__(self, filename=None, **system_values):
5558
m.bind_name('dt_req_imm', dt_req_imm_array, **dt_fmt_kwargs)
5659
m.set_next_cycle(m.dt_req, m.dt_req_imm, clk=m.emu_clk, rst=m.emu_rst)
5760

58-
# pass through clock input to clock output
59-
m.set_this_cycle(m.clk_o, m.clk_i)
60-
6161
# generate the model
6262
m.compile_to_file(VerilogGenerator())
6363

6464
self.generated_files = [filename]
6565

6666
@staticmethod
6767
def required_values():
68-
return ['dt', 'tlo', 'thi', 'tdel']
68+
return ['dt']
6969

0 commit comments

Comments
 (0)