Skip to content

qubic.soc_rpc_server

Functions for running an RPC server on the ZCU216 to allow users to submit remote jobs/circuits. See the Getting Started Guide for details on how to configure.

ServerConfig

Source code in qubic/soc_rpc_server.py
17
18
19
20
21
22
23
24
25
26
27
28
29
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
@define
class ServerConfig:
    xsa_commit: str
    ip: str
    port: int
    log_level: str
    jobserver_mode: bool = False
    dac_current_values: Dict = field(default=None)
    dac_nyquist_zone: Dict = field(default=None)
    adc_nyquist_zone: int = 1
    lmk_freq: float = 500.18
    platform: str = 'rfsoc'

    """
    Class for configuring/initializing ZCU216 RPC server. Wraps
    server_config.yaml

    Attributes
    ----------
    xsa_commit: str
        commit hash of gateware build (directory w/ XSA/configs)
    ip: str
        server IP
    port: int
        server port
    log_level: str
    enable_batching: bool 
        if True, allow clients to submit batched jobs, otherwise
        an intermediate job server (job_rpc_server.py) is 
        required.
    dac_current_values: Dict[Tuple, int]
        dictionary of DAC channels to modify current. Format 
        is (block, tile): <current in uA>
    dac_nyquist_zone: int
    adc_nyquist_zone: int
    lmk_freq: float
    """

    def __attrs_post_init__(self):
        if self.dac_current_values is not None:
            self.dac_current_values = {
                    tuple(int(i) for i in key.split(',')): value for key, value in self.dac_current_values.items()}
        if self.dac_nyquist_zone is not None:
            dac_nyquist_zone_dict = {}
            for key, value in self.dac_nyquist_zone.items():
                if key.lower() == 'default':
                    dac_nyquist_zone_dict['default'] = value
                else:
                    dac_nyquist_zone_dict[tuple(int(i) for i in key.split(','))] = value

            self.dac_nyquist_zone = dac_nyquist_zone_dict

platform = 'rfsoc' class-attribute instance-attribute

Class for configuring/initializing ZCU216 RPC server. Wraps server_config.yaml

Attributes:

Name Type Description
xsa_commit str

commit hash of gateware build (directory w/ XSA/configs)

ip str

server IP

port int

server port

log_level str
enable_batching bool

if True, allow clients to submit batched jobs, otherwise an intermediate job server (job_rpc_server.py) is required.

dac_current_values Dict[Tuple, int]

dictionary of DAC channels to modify current. Format is (block, tile):

dac_nyquist_zone int
adc_nyquist_zone int
lmk_freq float

run_soc_server(server_config)

Start an xmlrpc server that exposes an instance of CircuitRunner over a network. Intended to be run from the RFSoC ARM core python (pynq) environment. IP should only be accessible locally!

Parameters:

Name Type Description Default
server_config ServerConfig
required
Source code in qubic/soc_rpc_server.py
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 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
def run_soc_server(server_config: ServerConfig):
    """
    Start an xmlrpc server that exposes an instance of CircuitRunner over a 
    network. Intended to be run from the RFSoC ARM core python (pynq) 
    environment. IP should only be accessible locally!

    Parameters
    ----------
    server_config: ServerConfig
    """
    if server_config.log_level is not None:
        if server_config.log_level.lower() == 'info':
            logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s: %(message)s')

        elif server_config.log_level == 'debug':
            logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s: %(message)s')

        else:
            raise Exception(f'log level: {server_config.log_level} not supported')

    if server_config.platform == 'rfsoc':
        pl_driver = pl.PLInterface(commit_hash=server_config.xsa_commit,
                                   dac_current_values=server_config.dac_current_values,
                                   dac_nyquist_zone=server_config.dac_nyquist_zone,
                                   adc_nyquist_zone=server_config.adc_nyquist_zone,
                                   lmk_freq=server_config.lmk_freq,
                                   load_xsa=True)

    elif server_config.platform == 'rfsoc_multiboard':
        pl_driver = pl.PLInterfaceSync(commit_hash=server_config.xsa_commit,
                                       dac_current_values=server_config.dac_current_values,
                                       dac_nyquist_zone=server_config.dac_nyquist_zone,
                                       adc_nyquist_zone=server_config.adc_nyquist_zone,
                                       lmk_freq=server_config.lmk_freq,
                                       load_xsa=True)

    elif server_config.platform == 'sim':
        pl_driver = SimInterface()

    else:
        raise Exception(f'unsupported platform: {server_config.platform}')

    runner = CircuitRunner(pl_driver)
    server = xmlrpc.server.SimpleXMLRPCServer((server_config.ip, server_config.port), 
                                              logRequests=True, allow_none=True)


    if server_config.jobserver_mode:
        sync_interface = SyncInteface(pl_driver)
        server.register_function(runner.load_executable)
        server.register_function(runner.start_program)
        server.register_function(partial(runner.run_circuit, from_server=True), name='run_circuit')
        server.register_function(partial(runner.wait_and_readback, from_server=True), name='wait_and_readback')
        server.register_function(partial(runner.load_and_run_acq, from_server=True), name='load_and_run_acq')
        server.register_function(runner.ddr_batch_prepare, name='ddr_batch_prepare')
        server.register_function(sync_interface.read_ptp_corrval)
        server.register_function(sync_interface.write_ptp_corrval)
        server.register_function(sync_interface.ptp_enable_tx)
        server.register_function(sync_interface.ptp_disable_tx)
        server.register_function(sync_interface.ptp_read_tx_clockcount)
        server.register_function(sync_interface.ptp_read_rx_clockcount)
        server.register_function(sync_interface.ptp_read_dsp_clockcount)


    else:
        server.register_function(partial(runner.run_circuit_batch, from_server=True), name='run_circuit_batch')
        server.register_function(runner.ddr_start_circuit, name='ddr_start_circuit')
        server.register_function(runner.ddr_batch_prepare, name='ddr_batch_prepare')
        server.register_function(partial(runner.load_and_run_acq, from_server=True), name='load_and_run_acq')

    print('RPC server running on {}:{}'.format(server_config.ip, server_config.port))

    server.serve_forever()