Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Q1ASM parse and generation #868

Open
wants to merge 50 commits into
base: main
Choose a base branch
from
Open

Q1ASM parse and generation #868

wants to merge 50 commits into from

Conversation

alecandido
Copy link
Member

@alecandido alecandido commented Apr 4, 2024

Attempting a complete parser and reconstructor for Q1ASM.

  • grammar to parse Q1ASM
  • transform to native classes
  • reconstruct Q1ASM
  • add instructions documentation
  • add Q1 execution time
    • the case of conditional jumps can't be fully worked out statically
    • not useful right now, postponed for later
  • parse & dump register to int
    • remove/add initial R
  • add references (parse & dump)
    • as special immediates
    • remove/add initial @
  • format with labels
  • format comments
  • test all features

Copy link

codecov bot commented Apr 4, 2024

Codecov Report

Attention: Patch coverage is 92.93286% with 20 lines in your changes missing coverage. Please review.

Project coverage is 54.36%. Comparing base (e8df7f5) to head (5c73d4f).

Files with missing lines Patch % Lines
src/qibolab/_core/instruments/qblox/ast_.py 92.39% 20 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #868      +/-   ##
==========================================
+ Coverage   50.74%   54.36%   +3.61%     
==========================================
  Files          63       65       +2     
  Lines        3019     3302     +283     
==========================================
+ Hits         1532     1795     +263     
- Misses       1487     1507      +20     
Flag Coverage Δ
unittests 54.36% <92.93%> (+3.61%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@alecandido
Copy link
Member Author

This is the current state:

[ins] In [1]: from qibolab._core.instruments.qblox.parse import parse
         ...: from pathlib import Path
         ...: from rich import print
         ...: basic = Path("tests/qblox/q1asm/basic.q1asm")
         ...: prog = parse(basic.read_text())
         ...: print(prog)
Program(
    elements=[
        'Basic example from docs\nhttps://qblox-qblox-instruments.readthedocs-hosted.com/en/main/tutorials/q1asm_tutorials/basic/baseband/basic_sequencing.html#Create-Q1ASM-program',
        Line(Move(source='100', destination='R0'), comment='Loop iterator.'),
        Line(Move(source='20', destination='R1'), comment='Initial wait period in ns.'),
        Line(WaitSync(duration='4'), comment='Wait for sequencers to synchronize and then wait another 4 ns.'),
        Line(SetMrk(mask='1'), label='loop', comment='Set marker output 1.'),
        Line(Play(wave_0='0', wave_1='1', duration=4), comment='Play a gaussian and a block on output path 0 and 1 respectively and wait 4 ns.'),
        Line(SetMrk(mask='0'), comment='Reset marker output 1.'),
        Line(UpdParam(duration=18), comment='Update parameters and wait the remaining 18 ns of the waveforms.'),
        Line(Wait(duration='R1'), comment='Wait period.'),
        Line(Play(wave_0='1', wave_1='0', duration=22), comment='Play a block and a gaussian on output path 0 and 1 respectively and wait 22 ns.'),
        Line(Wait(duration='1000'), comment='Wait a 1us in between iterations.'),
        Line(Add(a='R1', b='20', destination='R1'), comment='Increase wait period by 20 ns.'),
        Line(Loop(a='R0', address='@loop'), comment='Subtract one from loop iterator.'),
        Line(Stop(), comment='Stop the sequence after the last iteration.')
    ]
)

[ins] In [2]: print(prog.asm(60))
# Basic example from docs
# https://qblox-qblox-instruments.readthedocs-hosted.com/en/main/tutorials/q1asm_tutorials/basic/baseband/basic_sequencing.html#Create-Q1ASM-program

     move 100 R0   # Loop iterator.
     move 20 R1    # Initial wait period in ns.
     wait_sync 4   # Wait for sequencers to synchronize and
                   # then wait another 4 ns.
loop set_mrk 1     # Set marker output 1.
     play 0 1 4    # Play a gaussian and a block on output
                   # path 0 and 1 respectively and wait 4
                   # ns.
     set_mrk 0     # Reset marker output 1.
     upd_param 18  # Update parameters and wait the
                   # remaining 18 ns of the waveforms.
     wait R1       # Wait period.
     play 1 0 22   # Play a block and a gaussian on output
                   # path 0 and 1 respectively and wait 22
                   # ns.
     wait 1000     # Wait a 1us in between iterations.
     add R1 20 R1  # Increase wait period by 20 ns.
     loop R0 @loop # Subtract one from loop iterator.
     stop          # Stop the sequence after the last
                   # iteration.

[ins] In [3]: print(prog.asm(60, comments=False))
     move 100 R0
     move 20 R1
     wait_sync 4
loop set_mrk 1
     play 0 1 4
     set_mrk 0
     upd_param 18
     wait R1
     play 1 0 22
     wait 1000
     add R1 20 R1
     loop R0 @loop
     stop

@alecandido alecandido requested a review from stavros11 October 27, 2024 14:23
@alecandido alecandido marked this pull request as ready for review October 27, 2024 14:23
@alecandido
Copy link
Member Author

@stavros11 this module is missing documentation at all, and it is only tested globally in practical use cases, but there is no unit test at all.

It is not my intention to fully skip these relevant parts, but the idea is that the assembly generation is fully internal, and not much useful as it is.
Thus, I will try to focus on pushing forward another bit, to have something resembling an actual driver (also because that could be immediately useful), and then come back to docs and unit tests of the more internal modules (in the spirit to preserve more internal knowledge for further devs).

In any case, I don't really want to merge, at least until I won't have something, even extremely tiny, built on top of this.
But it's already a good time to start having a review, and I'm not planning any further feature for this PR. If useful, I may provide some docs as part of the review process.

@alecandido
Copy link
Member Author

alecandido commented Oct 27, 2024

Showcase once more the current results

[ins] In [1]: from pathlib import Path
[ins] In [2]: asm = Path("basic.q1asm").read_text()
[ins] In [3]: from qibolab._core.instruments.qblox.parse import parse
[ins] In [4]: print(parse(asm).asm())
# Basic example from docs
# https://qblox-qblox-instruments.readthedocs-hosted.com/en/main/tutorials/q1asm_tutorials/basic/baseband/basic_sequencing.html#Create-Q1ASM-program

      move      100,R0   # Loop iterator.
      move      20,R1    # Initial wait period in ns.
      wait_sync 4        # Wait for sequencers to synchronize and then wait another 4 ns.
loop: set_mrk   1        # Set marker output 1.
      play      0,1,4    # Play a gaussian and a block on output path 0 and 1 respectively and wait 4 ns.
      set_mrk   0        # Reset marker output 1.
      upd_param 18       # Update parameters and wait the remaining 18 ns of the waveforms.
      wait      R1       # Wait period.
      play      1,0,22   # Play a block and a gaussian on output path 0 and 1 respectively and wait 22 ns.
      wait      1000     # Wait a 1us in between iterations.
      add       R1,20,R1 # Increase wait period by 20 ns.
      loop      R0,@loop # Subtract one from loop iterator.
      stop               # Stop the sequence after the last iteration.

[ins] In [5]: print(parse(asm).asm(width=80))
# Basic example from docs
# https://qblox-qblox-instruments.readthedocs-hosted.com/en/main/tutorials/q1asm_tutorials/basic/baseband/basic_sequencing.html#Create-Q1ASM-program

      move      100,R0   # Loop iterator.
      move      20,R1    # Initial wait period in ns.
      wait_sync 4        # Wait for sequencers to synchronize and then wait
                         # another 4 ns.
loop: set_mrk   1        # Set marker output 1.
      play      0,1,4    # Play a gaussian and a block on output path 0 and 1
                         # respectively and wait 4 ns.
      set_mrk   0        # Reset marker output 1.
      upd_param 18       # Update parameters and wait the remaining 18 ns of the
                         # waveforms.
      wait      R1       # Wait period.
      play      1,0,22   # Play a block and a gaussian on output path 0 and 1
                         # respectively and wait 22 ns.
      wait      1000     # Wait a 1us in between iterations.
      add       R1,20,R1 # Increase wait period by 20 ns.
      loop      R0,@loop # Subtract one from loop iterator.
      stop               # Stop the sequence after the last iteration.

[ins] In [6]: print(parse(asm).asm(width=80, comments=False))
      move      100,R0
      move      20,R1
      wait_sync 4
loop: set_mrk   1
      play      0,1,4
      set_mrk   0
      upd_param 18
      wait      R1
      play      1,0,22
      wait      1000
      add       R1,20,R1
      loop      R0,@loop
      stop

[ins] In [7]: print(parse(asm).asm(width=60))
# Basic example from docs
# https://qblox-qblox-instruments.readthedocs-hosted.com/en/main/tutorials/q1asm_tutorials/basic/baseband/basic_sequencing.html#Create-Q1ASM-program

      move      100,R0   # Loop iterator.
      move      20,R1    # Initial wait period in ns.
      wait_sync 4        # Wait for sequencers to
                         # synchronize and then wait another
                         # 4 ns.
loop: set_mrk   1        # Set marker output 1.
      play      0,1,4    # Play a gaussian and a block on
                         # output path 0 and 1 respectively
                         # and wait 4 ns.
      set_mrk   0        # Reset marker output 1.
      upd_param 18       # Update parameters and wait the
                         # remaining 18 ns of the waveforms.
      wait      R1       # Wait period.
      play      1,0,22   # Play a block and a gaussian on
                         # output path 0 and 1 respectively
                         # and wait 22 ns.
      wait      1000     # Wait a 1us in between iterations.
      add       R1,20,R1 # Increase wait period by 20 ns.
      loop      R0,@loop # Subtract one from loop iterator.
      stop               # Stop the sequence after the last
                         # iteration.

@alecandido alecandido mentioned this pull request Nov 1, 2024
22 tasks
@alecandido alecandido self-assigned this Nov 1, 2024
@alecandido alecandido mentioned this pull request Nov 2, 2024
6 tasks
Since it is a more accurate description: that is actually a reference to a label set somewhere else
There is no reason in saving the specific encodings of integers, or
similar information, thus it can't be reproduced. Parsing will be a
function, but not a bijective one, as there is no apparent advantage in
making it such
More or less in the spirit of cross-validation: since the existing
examples have been heavily used for development, let's check this is
also working on something previously unobserved
Horrible patch. Some code should be refactored...
Fix linter's warning
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant