rigless 0.1.0

Virtual hardware-in-the-loop runtime: run unmodified firmware on an emulated MCU with every peripheral, chip model and unit of virtual time in Rust, and a CPU core of its own that translates the firmware's instructions to host code
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
68
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
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
// Copyright (c) 2026 Rigless Labs.
// SPDX-License-Identifier: MIT OR Apache-2.0
//! The inter-integrated circuit interface of RM0090 rev 22 chapter 27, written against the `i2c3`
//! layout. One layout serves all three instances: I2C1, I2C2 and I2C3 carry the same ten registers
//! at the same offsets.
//!
//! **Controller mode only.** By default the interface "operates in target mode", 27.3.1, and
//! switches to controller mode the moment software generates a start. This model never receives a
//! start from the wire, so it is always the controller and never a target: OAR1, OAR2, and the
//! target-only flags are stored and inert, in the second table. A firmware that runs the part as a
//! target, answering another controller, gets nothing here yet.
//!
//! **Addressing is read from the byte, because the register file carries no bit that says how many
//! address bytes a controller is about to send.** A byte matching `11110xxx` after `START` is a
//! 10-bit header, and its own bit 0 says whether this is the two-byte write-direction sequence of
//! 27.3.3 (header, then a plain second byte, `ADD10` between them) or the one-byte header a repeated
//! start resends to turn the same transfer around into a read, page 843's "To enter Receiver mode"
//! case. Every other byte is a 7-bit address. This is the same distinction the ChibiOS `I2Cv1`
//! driver constructs on `EV5` (`hal_i2c_lld.c` line 392, `0xF0 | (0x6 & (addr >> 8)) | (0x1 & addr)`)
//! and a target recognises on the wire. Nothing here invents a rate or a delay to reach it.
//!
//! **A byte takes nine SCL periods**, eight data bits and the acknowledge bit, at the rate `CCR`,
//! `DUTY` and `F/S` give against the peripheral clock the part's tree feeds this instance, 27.6.8.
//! The start and stop conditions themselves carry no register-configurable duration RM0090
//! gives a number for, so they take none here: `SB` and the effect of `STOP` land at the instant of
//! the write that asks for them, except where a byte is already on the wire, which section 27.3.3
//! itself defers to that byte's end.
//!
//! **`START` and `STOP` read back set until they are carried out.** Deferred behind a byte, or a
//! `START` held by a `BUSY` this transaction does not own, the bit stays exactly as software wrote
//! it, and the CR1 note above 27.6.2 warns against a second write while that is true, precisely because
//! hardware has not cleared it yet. Both can be pending together, carried out start-to-finish in the
//! order they were written, never one replacing the other.
//!
//! | Register or section | Behaviour | Source | Test |
//! |---|---|---|---|
//! | Reset state | Every register at zero but `TRISE`, which resets to `0x0002` | 27.6.1 to 27.6.10 | `reset_leaves_every_register_at_the_manuals_values` |
//! | `START`, `SB` | Sets `SB`, `MSL` and `BUSY` and clears `TxE`, `BTF` and `TRA` at the write, unless a byte is already on the wire, which defers all of it to that byte's end, 27.3.3's note on a restart | 27.3.3 | `setting_start_on_an_idle_bus_sets_sb_and_raises_msl_and_busy`, `a_repeated_start_mid_byte_waits_for_the_byte_to_finish`, `a_repeated_start_after_a_write_leaves_the_status_chibios_checks_for_ev5` |
//! | `SR1` read, paired two ways | Arms the `SB`/`ADD10` pairing, completed only by the next write of `DR`, and the `ADDR` pairing, completed only by the next read of `SR2`, apart from each other: whichever access the register file currently supports consumes it, so neither a `CR1` write between them nor the other pairing's own access wrongly uses it up | 27.6.7's note on the clearing sequence | `a_cr1_write_between_sr1_and_sr2_does_not_stop_sr2_from_clearing_addr`, `a_one_byte_read_that_clears_ack_between_sr1_and_sr2_as_ev6_says` |
//! | 7-bit addressing | One byte, its LSB the direction, always taken as the transfer's own direction from here. Acknowledged: `ADDR` sets. Not acknowledged: `AF` sets and nothing is started | 27.3.3 | `a_seven_bit_address_that_is_acknowledged_sets_addr_and_tra_and_addr_clears_by_sr1_then_sr2`, `a_nacked_address_sets_af_and_the_peer_is_never_started`, `a_ten_bit_write_after_a_seven_bit_read_turns_the_transfer_around` |
//! | 10-bit addressing, the header | `11110xx0` sets `ADD10`, cleared by a read of `SR1` then a write of `DR` with the second byte, which then sets `ADDR` | 27.3.3 | `a_ten_bit_address_sends_the_header_then_the_second_byte_before_addr` |
//! | 10-bit addressing, a repeated start to read | `11110xx1` alone sets `ADDR`, with no second byte: page 843's worked case | 27.3.3 | `a_repeated_start_in_ten_bit_mode_resends_only_the_header_with_the_read_bit` |
//! | `ADDR` cleared, `TRA` | A read of `SR1` then of `SR2` clears `ADDR` once both have happened, in that order, whichever flag was standing when the second lands. `TRA` is the address byte's direction | 27.3.3, 27.6.7 | `a_seven_bit_address_that_is_acknowledged_sets_addr_and_tra_and_addr_clears_by_sr1_then_sr2` |
//! | Controller transmitter, `TxE`, `BTF` | `TxE` sets the instant the address phase hands the transmitter an empty buffer, `EV8_1`, and a write that finds the shift register idle never actually clears it, since the byte flows onto the wire at once: 27.6.6 bit 7's own exception for the first byte and for one written while `BTF` stands. A write that instead finds a byte already on the wire fills `DR` and does clear it. `BTF` sets once an acknowledged byte's shift register empties with nothing queued behind it, and clears on either a read or a write of `DR` | 27.3.3, 27.6.6 bits 2 and 7 | `txe_stands_once_addressed_to_write_before_any_byte_is_written`, `a_byte_written_goes_out_and_txe_and_btf_both_follow_it_when_nothing_queues_behind`, `a_second_byte_written_before_the_first_acknowledges_keeps_txe_low_until_it_reaches_the_wire`, `a_dummy_read_of_dr_clears_btf_the_way_chibios_ev8_2_does` |
//! | Controller receiver, one byte | `ACK` cleared during `EV6`, read at the byte's own end rather than when it was scheduled, NACKs the only byte | 27.3.3, 27.6.1 bit 11 | `the_one_byte_receive_procedure_nacks_the_only_byte` |
//! | Controller receiver, two bytes, `POS` | `ACK` cleared and `POS` set before `ADDR` clears delays the acknowledge bit one byte, so the first byte is acknowledged and the second is not | 27.3.3, 27.6.1 bit 11 | `the_two_byte_receive_procedure_uses_pos_to_delay_the_nack_one_byte` |
//! | Controller receiver, more than two bytes | The controller free-runs a byte at a time. A byte landing with `DR` still unread by the last one sets `BTF` and holds there until `DR` is read, which is the manual's own `N-2` procedure. `ACK` governs whichever byte is on the wire at the instant its own period ends, so clearing it while that byte is already shifting still lands on it | 27.3.3, 27.6.1 bit 11 | `the_more_than_two_byte_receive_procedure_stalls_on_btf_until_dr_is_read`, `clearing_ack_mid_byte_still_nacks_the_byte_already_shifting` |
//! | `STOP` | Ends the transaction at the write, unless a byte is on the wire, deferred to its end, releases the peer and clears `MSL`, `BUSY` and `TRA`. Nothing is scheduled once a `STOP` or `START` is pending or the transaction is already closed, so no byte, transmitted or received, is clocked after it. A byte still buffered in `DR`, or held behind it, reads back afterwards exactly as 27.3.3's `N > 2` procedure needs it to | 27.3.3, 27.6.1 bit 9, 27.6.7 bit 1 | `a_write_ends_with_stop_and_releases_the_peer`, `stop_set_mid_procedure_leaves_the_still_buffered_bytes_readable`, `nothing_is_clocked_after_a_stop_closes_the_more_than_two_byte_procedure`, `a_byte_queued_behind_a_deferred_stop_does_not_go_out` |
//! | `AF` | A NACK on the address or on a data byte in transmission sets it, and drops whatever was queued in `DR` behind the `NACKed` byte, since that byte does not survive the repeated start 27.3.4 assumes follows. Cleared by a written zero, which the vendor's file needs correcting for, or by `PE=0` | 27.3.4, 27.6.6 bit 10 | `a_nacked_address_sets_af_and_the_peer_is_never_started`, `a_nacked_data_byte_sets_af_mid_transfer`, `a_written_zero_clears_af_and_a_written_one_leaves_it`, `a_queued_byte_does_not_survive_a_nack_and_a_repeated_start` |
//! | `ITEVTEN`, `ITBUFEN` | The event line rises for `SB`, `ADDR`, `ADD10` and `BTF` under `ITEVTEN` alone, and for bare `TxE` or `RxNE` only with `ITBUFEN` set too | 27.4, table 124 | `itevten_raises_the_event_line_for_sb_addr_add10_and_btf_without_itbufen`, `itbufen_is_needed_only_for_bare_txe_and_rxne` |
//! | `ITERREN` | The error line rises for `AF`, the one error condition this controller-only model can raise | 27.4 | `iterren_raises_the_error_line_for_af` |
//! | `DMAEN` | Drives the receive request off `RxNE` and the transmit request off `TxE`, on the streams table 43 gives each instance | 27.3.8, table 43 | `dmaen_drives_the_two_requests_off_rxne_and_txe` |
//! | `CCR`, `DUTY`, `F/S` | The byte period, standard mode `2 x CCR`, fast mode `3 x CCR` or, under `DUTY`, `25 x CCR`, SCL periods of the peripheral clock | 27.6.8 | `a_byte_takes_nine_scl_periods_at_the_ccr_rate`, `fast_mode_changes_the_periods_the_formula_gives`, `fast_mode_duty_changes_the_periods_the_formula_gives`, `a_run_of_bytes_does_not_drift` |
//! | `fPCLK1` | The peripheral clock the tree feeds this instance, followed as it changes: the byte already on the wire keeps the rate it began at, and the next one's carry is dropped with the rate it was a fraction of | 27.3.2, 6.2 | `a_change_of_clock_applies_from_the_next_byte`, `a_change_of_clock_times_the_next_byte_at_the_new_rate` |
//! | `SWRST` | Puts the interface "under reset state": the peer released and every register of the instance, `BUSY` among them, back to its reset value, which is also the manual's own way out of a `BUSY` a glitch left locked. The bit is software's to clear, and until it does the instance stays there, `SWRST` reading back set and every other write landing nothing | 27.6.1 bit 15 | `swrst_resets_every_register_and_releases_the_peer`, `swrst_is_the_only_way_out_of_a_busy_a_pending_start_left_locked` |
//! | `PE` cleared mid-communication | 27.6.1 bit 0 defers the disable to the end of the communication and then says a controller "must not" clear it before then, giving that case no outcome. The model's own: the communication ends at the write, the peer released as by `STOP`, and every bit `PE=0` resets is reset there, `START`, `ACK` and `POS` among them. `BUSY` is the one flag the manual keeps "still updated" through it and is left alone | 27.6.1 bits 0, 8, 10, 11, 27.6.7 bit 1 | `clearing_pe_aborts_the_transaction_but_leaves_busy_as_hardware_would` |
//! | `PE` cleared, held clear | `START`, `ACK` and `POS` read back clear for as long as `PE` is clear, whatever was last written to them, 27.6.1 bits 8, 10 and 11's own hardware-clear-at-`PE=0` note | 27.6.1 bit 0 | `start_written_with_pe_clear_stays_in_cr1` |
//! | `START` against a set `BUSY` | Taken at once when this transaction already holds the bus, the ordinary repeated start. Held pending, not taken, when `BUSY` is set and `MSL` is not, which is what `PE=0` mid-transaction can leave behind. Only `SWRST` gets out of that | 27.3.3, 27.6.1 bit 15's note | `swrst_is_the_only_way_out_of_a_busy_a_pending_start_left_locked` |
//! | The driver's own sequence | `SWRST`, the clock and filter setup, `PE`, `ITEVTEN`, `START`, and the NACK an empty bus answers with, replayed at the values a run of `ArduCopter` recorded | 27.3.3, 27.3.4 | `the_chibios_driver_probes_an_empty_bus_and_gets_its_nack` |
//! | A silent chip | A chip the board has silenced, a board condition, isn't on the wire: it never acknowledges its address, so the controller sets `AF` as it does with nobody at that address. A silence the board asks for while the chip is in the open transaction waits for the `STOP`, `SWRST` or `PE` cleared that ends it, and a part reset | 27.3.3 | `a_silent_chip_is_not_acknowledged_and_answers_again_after`, `a_silence_waits_for_the_stop` |
//!
//! **What the model leaves out, and why.**
//!
//! | Behaviour | Source | Reason |
//! |---|---|---|
//! | Target mode entire: address matching against `OAR1`/`OAR2`, `ENGC`, `NOSTRETCH`, `ENDUAL`, the `SMBus` address types, `GENCALL`/`SMBHOST`/`SMBDEFAULT`/`DUALF` | 27.3.2, 27.3.7 | The runtime has no seam for it: [`Peer`] is the far end a controller addresses, and nothing on a board's side is a second controller that addresses the part. The registers are stored |
//! | `STOPF` | 27.3.2 | Target-mode only, "Stop detection (target mode)." Never set |
//! | `OVR` | 27.3.4 | Target mode with `NOSTRETCH` set. Never set |
//! | `BERR` | 27.3.4 | "Detects an external Stop or Start condition" from a second controller or a glitch on the wire. This model is the bus's only controller and drives every transition itself, so the condition cannot arise |
//! | `ARLO` | 27.3.4 | Multi-controller arbitration. The same reason as `BERR` |
//! | `TIMEOUT`, the `SMBus` clock-low timeout | 27.3.7 | Times a target's own clock-stretching, and [`Peer`]'s calls answer synchronously: nothing on this bus can hold `SCL` for a duration to time out on |
//! | Debug mode: "The `SMBUS` timeout either continues to work normally or stops" under the `DBG` module's own configuration bits while the core is halted | 27.5 | The timeout it freezes isn't modelled either, the row above |
//! | `SMBALERT`, the `SMBA` pin | 27.3.7 | No pin carries it |
//! | A peer holding `SDA` or `SCL` low | 27.3.4, 27.3.6 | Looks, on the wire, like a lost arbitration with `BUSY` never clearing, but [`Peer`]'s three calls answer synchronously in the call that makes them: nothing lets a peer hold a line down for a stretch of virtual time, the same gap that leaves clock stretching out below |
//! | PEC | 27.3.9 | A CRC-8 over every address and data byte, workable the way `spi.rs`'s CRC is. Left for a pass of its own rather than folded into an already wide chapter |
//! | `TRISE` | 27.6.9 | Stored. Section 27.6.8's own frequency formula, the only timing this chapter gives a number for, never reads it. Its job is compensating a measured rise time against the controller's own loopback delay, which a deterministic model with no analogue edge has nothing to compensate |
//! | `FLTR`, `DNF`, `ANOFF` | 27.6.10, 27.3.5 | Stored. There is no noise to filter, the same reason `usart.rs` gives its own noise flags. The hold-time extension the section states is a sub-bit margin, not a term in the byte period |
//! | DMA's anticipatory NACK, `LAST` acted on | 27.3.8 | The controller must NACK the byte before the last one a DMA stream will take, on a signal the DMA controller alone can compute from its own count. Every join this part has runs a peripheral's flag into the DMA controller. None yet runs the other way, from the controller into a peripheral, which is what this needs. `LAST` is stored and the two request lines are driven. The early NACK is not: a real driver's three-byte DMA read, ChibiOS's own `EV6_MASTER_REC_MODE_SELECTED`, leaves `ACK` set for that count, so this model ACKs the third byte like any other and a fourth is already on the wire when DMA stops asking for one, rather than the transfer ending in `STOP` on its own. `ardupilots_own_dma_read_of_three_bytes_never_nacks_the_last_one` pins exactly that |
//! | Clock stretching by a peer | 27.3.6 | [`Peer::start`], `write` and `read` answer in the call that makes them: nothing lets a peer hold `SCL` down for a stretch of virtual time. The controller's own wait for software, holding a byte off the wire until `DR` is written, is real and modelled, since it falls out of nothing being scheduled until then |
//! | Word and half-word access: "The peripheral registers have to be accessed by half-words (16 bits) or words (32 bits)." | 27.6 | The manual names the widths a write must use and not the effect of a narrower one, so a narrower access lands in its lane on the bus rather than in this model. The same shape as the timer's own access-width row |
//! | Two peers acknowledging the same address | 27.3.3 | Unlike a chip select's push-pull line, an acknowledge is open-drain: two peers pulling it low at once is indistinguishable on the wire from one, so there is no SPI-shaped contention to invent. The first peer in attachment order that acknowledges is the one addressed |
//! | ES0206 rev 24, 2.10.1: bus error detected spuriously in controller mode | ES0206 rev 24 | Not modelled: the sheet names no condition that triggers it, only that it "can be detected spuriously" and that "any such transfer continues normally." Its workaround, "the `BERR` flag must be cleared by software. No other action is required," is already satisfied, since this model never sets `BERR` for the workaround to act on |
//! | ES0206 rev 24, 2.10.2: `SMBus` not fully `SMBus` 2.0 compliant | ES0206 rev 24 | Not modelled, for the reason PEC and the `SMBus` address types above are not |
//! | ES0206 rev 24, 2.10.3: start not generated after a misplaced stop | ES0206 rev 24 | Unreachable here, though Table 3 marks it on every revision. The misplaced stop it answers needs a second controller, the same reason as 2.10.1's own register condition, `BERR` |
//! | ES0206 rev 24, 2.10.4: repeated-start setup time violated near 100 kHz | ES0206 rev 24 | An analogue AC timing margin in nanoseconds on the physical wire, not a register behaviour, the same shape as `rcc.rs`'s PC13-disturbs-the-LSE entry |
//! | ES0206 rev 24, 2.10.5: data valid time violated without `OVR` | ES0206 rev 24 | Unreachable here, though Table 3 marks it on every revision. It's target-mode only, "in Target transmit mode." |
//! | ES0206 rev 24, 2.10.6: SDA/SCL rise time violated above a bus voltage | ES0206 rev 24 | A board-level electrical condition between `VDD_I2C` and the rail, not a register behaviour |
//! | ES0206 rev 24, 2.2.7: a delay between an `RCC` clock enable and the peripheral answering | ES0206 rev 24 | Recorded once in `rcc.rs`, for the same reason: a gate opens at the write. I2C sits on APB1, so the sheet's own number for it is "1 + (AHB/APB prescaler) cycles," not the two AHB cycles an AHB peripheral gets |
//! | Being held at reset by `RCC_APB1RSTR` | 6.3.8 | The gate is the part's. Being held at reset is a third behaviour the runtime has no verb for, the same note every other peripheral's table carries |
//!
//! **Where this model departs from the vendor's file.** Section 27.6.6 types `SR1`'s error flags,
//! `BERR` through `SMBALERT`, `rc_w0`: a written zero clears the bit and a written one leaves it.
//! ST's file gives every one of them plain read-write with no write rule, which would let a written
//! one set a flag no condition raised. `memory_map.rs` corrects the register's write rule. The seven
//! bits below it, `SB` through `TxE`, are already read-only in ST's file and need no correction, since
//! this model clears them itself through the sequences above.

use std::any::Any;

use crate::chip::Place;
use crate::chip::i2c::Peer;
use crate::device::{Device, DeviceContext, Level, RegisterFile};
use crate::snapshot::store;
use crate::soc::stm32f427::generated::i2c3::{Register, ccr, cr1, cr2, sr1, sr2};
use crate::time::{EventId, VirtualNanos};

/// The event line, position zero of the instance's table: `I2C1_EV` at RM0090 rev 22 table 63's
/// line 31 for `I2C1`, and the instance's own pair for `I2C2` and `I2C3`.
const EVENT: usize = 0;
/// The error line, position one: `I2C1_ER`.
const ERROR: usize = 1;

/// The request `DMAEN` drives off `RxNE`, this instance's request output zero, RM0090 rev 22
/// section 27.3.8.
pub const RECEIVE_REQUEST: usize = 0;
/// The request `DMAEN` drives off `TxE`, request output one.
pub const TRANSMIT_REQUEST: usize = 1;

/// A 10-bit header's fixed top bits, RM0090 rev 22 section 27.3.2's note: `11110xx0`, masked to the
/// five bits no address chooses.
const TEN_BIT_HEADER: u8 = 0xF0;
const TEN_BIT_MASK: u8 = 0xF8;

/// A peer that answers one address, holds a known sequence, repeats its last byte once that drains,
/// and records every byte it was sent, the same job `spi::Pattern` and `usart::Pattern` do for their
/// own buses: what it answers is known and different from what it was given, so a controller reading
/// its own write back is caught, and what it records is the far end's own evidence the bytes crossed.
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct Pattern {
    address: u8,
    answers: std::collections::VecDeque<u8>,
    held: u8,
    received: Vec<u8>,
    /// Every acknowledge this peer was asked to give a read byte, oldest first, so a check can tell
    /// the controller actually `NACKed` the last one of a bounded read rather than merely stopped
    /// asking for more.
    lasts: Vec<bool>,
}

impl Pattern {
    /// A peer at `address` answering `bytes`, oldest first, then repeating the last one.
    #[must_use]
    pub fn answering(address: u8, bytes: impl IntoIterator<Item = u8>) -> Self {
        Self {
            address,
            answers: bytes.into_iter().collect(),
            held: 0,
            received: Vec::new(),
            lasts: Vec::new(),
        }
    }

    /// Every acknowledge the controller gave a byte this peer answered, oldest first.
    #[must_use]
    pub fn lasts(&self) -> &[bool] {
        &self.lasts
    }
}

store!(Pattern);

impl Peer for Pattern {
    fn start(&mut self, address: u8, _read: bool, _context: &DeviceContext<'_>) -> bool {
        address == self.address
    }

    fn write(&mut self, byte: u8, _context: &DeviceContext<'_>) -> bool {
        self.received.push(byte);
        true
    }

    fn read(&mut self, last: bool, _context: &DeviceContext<'_>) -> u8 {
        self.lasts.push(last);
        if let Some(byte) = self.answers.pop_front() {
            self.held = byte;
        }
        self.held
    }

    fn received(&self) -> &[u8] {
        &self.received
    }

    fn stop(&mut self, _context: &DeviceContext<'_>) {}
}

/// A 10-bit-addressed stand-in for a bench with no 10-bit chip model yet, RM0090 rev 22 section
/// 27.3.2's note: it acknowledges the header carrying its own top two bits, then its own second
/// byte, and a repeated header with the read bit turns it around with no second byte at all.
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct TenBit {
    address: u16,
    expecting_second_byte: bool,
    received: Vec<u8>,
    answers: std::collections::VecDeque<u8>,
    held: u8,
}

impl TenBit {
    /// A peer at the 10-bit `address` answering `bytes`, oldest first, then repeating the last one.
    #[must_use]
    pub fn answering(address: u16, bytes: impl IntoIterator<Item = u8>) -> Self {
        Self {
            address,
            expecting_second_byte: false,
            received: Vec::new(),
            answers: bytes.into_iter().collect(),
            held: 0,
        }
    }
}

store!(TenBit);

impl Peer for TenBit {
    fn start(&mut self, header: u8, read: bool, _context: &DeviceContext<'_>) -> bool {
        let top = u8::try_from((self.address >> 8) & 0x3).unwrap_or(0);
        if header != TEN_BIT_HEADER >> 1 | top {
            return false;
        }
        self.expecting_second_byte = !read;
        true
    }

    fn write(&mut self, byte: u8, _context: &DeviceContext<'_>) -> bool {
        if self.expecting_second_byte {
            self.expecting_second_byte = false;
            return byte == u8::try_from(self.address & 0xFF).unwrap_or(0);
        }
        self.received.push(byte);
        true
    }

    fn read(&mut self, _last: bool, _context: &DeviceContext<'_>) -> u8 {
        if let Some(byte) = self.answers.pop_front() {
            self.held = byte;
        }
        self.held
    }

    fn received(&self) -> &[u8] {
        &self.received
    }

    fn stop(&mut self, _context: &DeviceContext<'_>) {}
}

/// What the byte-period event ends.
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
enum Phase {
    /// The address phase's one byte: a 7-bit address, a 10-bit header, or a 10-bit sequence's second
    /// byte.
    Address { byte: u8, second: bool },
    /// A data byte going out.
    Write(u8),
    /// A data byte coming in. Its acknowledge is decided when it ends, not when it was scheduled,
    /// since `ACK` governs whichever byte is on the wire at that instant, RM0090 rev 22 section
    /// 27.6.1 bit 11.
    Read,
}

/// A byte-period elapsing, RM0090 rev 22 section 27.6.8: nine SCL periods, ending at `event`.
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
struct Shift {
    event: EventId,
    phase: Phase,
}

/// The open transaction's direction, the address byte's LSB, RM0090 rev 22 section 27.3.3.
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
enum Direction {
    Write,
    Read,
}

impl Direction {
    fn of(read: bool) -> Self {
        if read { Self::Read } else { Self::Write }
    }

    fn is_read(self) -> bool {
        self == Self::Read
    }
}

/// A `START` or a `STOP` written while a byte was on the wire, RM0090 rev 22 section 27.3.3: both
/// wait for that byte to finish rather than land at the write. Both can be waiting at once, carried
/// out in the order they were written.
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
enum Pending {
    Start,
    Stop,
}

/// One inter-integrated circuit interface of an STM32F42xxx, RM0090 rev 22 chapter 27, in controller
/// mode.
#[derive(Debug)]
pub struct I2c {
    clock_hz: u64,
    peers: Vec<Place<dyn Peer>>,
    /// The peer that acknowledged the open transaction's address, if one did.
    active: Option<usize>,
    reading: Direction,
    /// `SR1` was read and nothing has consumed the pairing yet: the next write of `DR` that finds
    /// `SB` or `ADD10` standing, or the next read of `SR2` that finds `ADDR` standing, completes
    /// whichever sequence it belongs to and consumes this. Neither consumes it on the other's behalf.
    sr1_read: bool,
    shifting: Option<Shift>,
    /// `DR`'s buffer half in the transmit direction, filled only once a byte is already shifting,
    /// RM0090 rev 22 section 27.6.6 bit 7's exception for an idle shift register.
    transmit: Option<u8>,
    /// `DR`'s buffer half in the receive direction.
    holding: Option<u8>,
    /// A second received byte, landed while `holding` was still full: `BTF`'s condition.
    stuck: Option<u8>,
    /// The acknowledge bit as it stood one byte back, for `POS`'s "the next byte" reading of it.
    delayed_ack: bool,
    /// The nanosecond a byte period's division drops, carried into the next byte of the same
    /// transaction.
    carry: u128,
    /// `START` and `STOP` requests waiting behind a byte on the wire, carried out in this order once
    /// it ends.
    pending: Vec<Pending>,
    interrupt: [Level; 2],
    requests: [Level; 2],
    control: u64,
}

store!(I2c {
    values: [
        clock_hz,
        active,
        reading,
        sr1_read,
        shifting,
        transmit,
        holding,
        stuck,
        delayed_ack,
        carry,
        pending,
        interrupt,
        requests,
        control,
    ],
    parts: [peers],
    built: [],
});

impl I2c {
    /// The interface of an instance whose peripheral bus runs at `clock_hz`, which `CCR` divides,
    /// until the part's tree drives it otherwise.
    #[must_use]
    pub fn with_clock(clock_hz: u64) -> Self {
        Self {
            clock_hz,
            peers: Vec::new(),
            active: None,
            reading: Direction::Write,
            sr1_read: false,
            shifting: None,
            transmit: None,
            holding: None,
            stuck: None,
            delayed_ack: true,
            carry: 0,
            pending: Vec::new(),
            interrupt: [Level::Low; 2],
            requests: [Level::Low; 2],
            control: 0,
        }
    }

    /// Hangs a chip on this bus's wires, behind whatever address it answers to.
    pub fn attach(&mut self, peer: impl Peer + 'static) {
        let peer: Box<dyn Peer> = Box::new(peer);
        // ceiling: a trigger never counts or faults a chip here; upgrade when a board names an I2C chip to one
        self.peers.push(Place::new(peer));
    }

    /// Takes the chips off `from`'s wires and hangs them on these, silent if they were. A part reset
    /// ends the open transaction, so a silence that was waiting for it has had it.
    pub fn inherit(&mut self, from: &mut Self) {
        self.peers = std::mem::take(&mut from.peers);
        self.peers.iter_mut().for_each(Place::release);
    }

    /// Stops the nth chip on these wires answering, or lets it answer again: a board condition,
    /// [`Place::silence`]. A chip in the open transaction keeps answering until it ends, so a
    /// transfer is never cut in half. Answers whether a chip hangs there.
    #[must_use]
    pub fn silence(&mut self, nth: usize, silent: bool) -> bool {
        let Some(place) = self.peers.get_mut(nth) else {
            return false;
        };
        if self.active == Some(nth) {
            place.silence_at_release(silent);
        } else {
            place.silence(silent);
        }
        true
    }

    /// The first chip on this bus, to ask what it saw, or `None` where nothing is hung.
    #[must_use]
    pub fn peer(&self) -> Option<&dyn Peer> {
        self.peers.first().map(Place::chip)
    }

    /// The nth chip on this bus as the type it was hung as, or `None` where nothing hangs there or
    /// another chip does.
    pub fn chip_mut<P: Peer>(&mut self, nth: usize) -> Option<&mut P> {
        let peer: &mut dyn Any = self.peers.get_mut(nth)?.chip_mut();
        peer.downcast_mut()
    }

    /// The chip the open transaction addressed, if it acknowledged and still answers.
    fn active_peer(&mut self) -> Option<&mut dyn Peer> {
        self.peers.get_mut(self.active?)?.answering()
    }

    /// Ends the open transaction with the chip it addressed, which then takes a silence that was
    /// waiting for it.
    fn release(&mut self, context: &DeviceContext<'_>) {
        if let Some(peer) = self.active_peer() {
            peer.stop(context);
        }
        if let Some(place) = self
            .active
            .take()
            .and_then(|index| self.peers.get_mut(index))
        {
            place.release();
        }
    }

    /// A byte's nine SCL periods as a fraction of a nanosecond, RM0090 rev 22 section 27.6.8:
    /// standard mode `2 x CCR`, fast mode `3 x CCR`, or `25 x CCR` under `DUTY`. `None` where `CCR`
    /// or the peripheral clock is zero: nothing to divide by, nothing to schedule.
    fn byte_period(&self, registers: &RegisterFile) -> Option<(u128, u128)> {
        let value = registers.get(Register::Ccr);
        let count = ccr::CCR.get(value);
        if count == 0 || self.clock_hz == 0 {
            return None;
        }
        let periods: u128 = if !ccr::F_S.is_set(value) {
            2
        } else if ccr::DUTY.is_set(value) {
            25
        } else {
            3
        };
        let numerator = 9 * periods * u128::from(count) * 1_000_000_000;
        Some((numerator, u128::from(self.clock_hz)))
    }

    /// Schedules `phase` to end a byte period from `context.now()`, carrying the remainder a
    /// division drops into the next byte of the same transaction so a run of them does not drift.
    fn schedule(
        &mut self,
        phase: Phase,
        registers: &RegisterFile,
        context: &mut DeviceContext<'_>,
    ) {
        let Some((numerator, denominator)) = self.byte_period(registers) else {
            return;
        };
        let total = numerator + self.carry;
        let nanos = u64::try_from(total / denominator).unwrap_or(u64::MAX);
        self.carry = total % denominator;
        let at = VirtualNanos(context.now().0 + nanos);
        self.shifting = Some(Shift {
            event: context.schedule(at),
            phase,
        });
    }

    /// `START` carried out, RM0090 rev 22 section 27.3.3: `SB`, `MSL` and `BUSY` set, `TxE`, `BTF`
    /// and `TRA` cleared, at the instant nothing is on the wire to defer it behind, which ChibiOS's
    /// own `I2C_EV5_MASTER_MODE_SELECT` reads as `SR1` and `SR2` holding nothing else. A new
    /// transaction starts the byte-period carry over, drops a byte still queued behind the last one,
    /// and starts the next address phase fresh, 27.3.4: neither survives into it.
    fn start_transaction(&mut self, registers: &mut RegisterFile) {
        self.carry = 0;
        self.transmit = None;
        let sr1 = registers.get(Register::Sr1);
        registers.set(
            Register::Sr1,
            sr1::TXE.set(sr1::BTF.set(sr1::SB.set(sr1, 1), 0), 0),
        );
        let sr2 = registers.get(Register::Sr2);
        registers.set(
            Register::Sr2,
            sr2::TRA.set(sr2::MSL.set(sr2::BUSY.set(sr2, 1), 1), 0),
        );
    }

    /// `START` requested with `PE` set. Deferred behind a byte already on the wire, RM0090 rev 22
    /// section 27.3.3, or behind a `BUSY` this transaction does not hold, which is what
    /// [`I2c::abort`] can leave standing. Only `SWRST` gets out of that, 27.6.1 bit 15's own note. A
    /// repeated start, `BUSY` and `MSL` both already this transaction's own, is taken at once.
    fn request_start(&mut self, registers: &mut RegisterFile) {
        if self.shifting.is_some() {
            self.pending.push(Pending::Start);
            return;
        }
        let sr2 = registers.get(Register::Sr2);
        if sr2::BUSY.is_set(sr2) && !sr2::MSL.is_set(sr2) {
            return;
        }
        let cr1 = cr1::START.set(registers.get(Register::Cr1), 0);
        registers.set(Register::Cr1, cr1);
        self.start_transaction(registers);
    }

    /// `STOP` requested with `PE` set. Deferred behind a byte already on the wire the same way a
    /// `START` is, RM0090 rev 22 sections 27.3.3 and 27.6.1 bit 9.
    fn request_stop(&mut self, registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
        if self.shifting.is_some() {
            self.pending.push(Pending::Stop);
            return;
        }
        let cr1 = cr1::STOP.set(registers.get(Register::Cr1), 0);
        registers.set(Register::Cr1, cr1);
        self.close(registers, context);
    }

    /// Searches every peer for one that acknowledges `address`, RM0090 rev 22 section 27.3.3: the
    /// controller learns nothing about a peer that does not, and a silent one never does.
    fn address(&mut self, address: u8, read: bool, context: &DeviceContext<'_>) -> bool {
        for (index, place) in self.peers.iter_mut().enumerate() {
            if place
                .answering()
                .is_some_and(|peer| peer.start(address, read, context))
            {
                self.active = Some(index);
                return true;
            }
        }
        false
    }

    /// The address phase's byte has crossed. `second` is a 10-bit sequence's own second byte, sent
    /// as a plain byte to the peer the header already selected.
    fn finish_address(
        &mut self,
        byte: u8,
        second: bool,
        registers: &mut RegisterFile,
        context: &mut DeviceContext<'_>,
    ) {
        // A repeated start's 10-bit header carries the read bit and completes the address phase by
        // itself, section 27.3.3's "10-bit addressing mode" case. Only the write-direction header
        // waits for a second byte, so the mask alone cannot tell the two apart.
        let read = byte & 1 != 0;
        let ten_bit_header = !second && byte & TEN_BIT_MASK == TEN_BIT_HEADER;
        let acked = if second {
            self.active_peer()
                .is_some_and(|peer| peer.write(byte, context))
        } else {
            // Every first address byte sets the transfer's direction from its own LSB: a 10-bit
            // write header is as definite about it as a 7-bit address is.
            self.reading = Direction::of(read);
            // `mpu9250.rs`'s internal master strips the direction bit the same way before calling
            // `Peer::start`, which takes it as its own argument.
            self.address(byte >> 1, read, context)
        };
        if !acked {
            registers.set(Register::Sr1, sr1::AF.set(registers.get(Register::Sr1), 1));
            return;
        }
        if ten_bit_header && !read {
            registers.set(
                Register::Sr1,
                sr1::ADD10.set(registers.get(Register::Sr1), 1),
            );
            return;
        }
        let sr1 = registers.get(Register::Sr1);
        // RM0090 rev 22 section 27.3.3, `EV8_1`.
        let sr1 = if self.reading.is_read() {
            sr1::ADDR.set(sr1, 1)
        } else {
            sr1::TXE.set(sr1::ADDR.set(sr1, 1), 1)
        };
        registers.set(Register::Sr1, sr1);
        let sr2 = registers.get(Register::Sr2);
        registers.set(
            Register::Sr2,
            sr2::TRA.set(sr2, u64::from(!self.reading.is_read())),
        );
    }

    /// A transmitted byte's acknowledge has crossed, RM0090 rev 22 section 27.6.6 bits 2 and 7. A
    /// NACK sets `AF` and drops whatever was queued behind it, 27.3.4: it does not survive into the
    /// repeated start that section assumes follows. An ACK with a byte queued moves it onto the wire
    /// at once, `TxE` standing throughout. With nothing queued, `BTF` sets, unless a `STOP` or
    /// `START` is already waiting, which carries out its own final state instead.
    fn finish_write(
        &mut self,
        byte: u8,
        registers: &mut RegisterFile,
        context: &mut DeviceContext<'_>,
    ) {
        let acked = self
            .active_peer()
            .is_some_and(|peer| peer.write(byte, context));
        if !acked {
            registers.set(Register::Sr1, sr1::AF.set(registers.get(Register::Sr1), 1));
            self.transmit = None;
        } else if self.active.is_some() && self.pending.is_empty() {
            if let Some(next) = self.transmit.take() {
                // 27.3.3: the acknowledge moves the queued byte into the shift register, which
                // leaves `DR` empty for the next one, `EV8`.
                registers.set(Register::Sr1, sr1::TXE.set(registers.get(Register::Sr1), 1));
                self.schedule(Phase::Write(next), registers, context);
            } else {
                let sr1 = registers.get(Register::Sr1);
                registers.set(Register::Sr1, sr1::TXE.set(sr1::BTF.set(sr1, 1), 1));
            }
        }
    }

    /// A received byte's period has ended: RM0090 rev 22 section 27.6.1 bit 11 reads `ACK` now,
    /// against the byte that was actually in the shift register for it, rather than at the instant
    /// the byte was scheduled, since 27.3.3's closing sequence clears `ACK` while that byte is still
    /// on the wire. `POS` set reads back one byte, banking today's value for the one after.
    fn finish_read(&mut self, registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
        let cr1_value = registers.get(Register::Cr1);
        let live = cr1::ACK.is_set(cr1_value);
        let acked = if cr1::POS.is_set(cr1_value) {
            self.delayed_ack
        } else {
            live
        };
        self.delayed_ack = live;
        let last = !acked;
        let byte = self
            .active_peer()
            .map_or(0, |peer| peer.read(last, context));
        if self.holding.is_none() {
            self.holding = Some(byte);
            registers.set(
                Register::Sr1,
                sr1::RXNE.set(registers.get(Register::Sr1), 1),
            );
            if !last {
                self.schedule_read(registers, context);
            }
        } else {
            self.stuck = Some(byte);
            registers.set(Register::Sr1, sr1::BTF.set(registers.get(Register::Sr1), 1));
        }
    }

    /// The manual's controller-receiver free run, RM0090 rev 22 section 27.3.3: one byte every
    /// period. Nothing is scheduled once a `STOP` or `START` is waiting, or the peer has already
    /// been released, so no byte lands after the transaction has ended.
    fn schedule_read(&mut self, registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
        if self.stuck.is_some()
            || self.shifting.is_some()
            || self.active.is_none()
            || !self.pending.is_empty()
        {
            return;
        }
        self.schedule(Phase::Read, registers, context);
    }

    /// The controller enters receiver mode once `ADDR` clears in the read direction, RM0090 rev 22
    /// section 27.3.3.
    fn begin_receiving(&mut self, registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
        self.delayed_ack = true;
        self.schedule_read(registers, context);
    }

    /// `STOP`'s effect: the peer released, the transaction's flags cleared, RM0090 rev 22 sections
    /// 27.6.6 and 27.6.7, `BUSY` among them, its own rule rather than a side effect of the others.
    fn close(&mut self, registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
        self.release(context);
        let sr2 = registers.get(Register::Sr2);
        // 27.6.7 bit 1: `BUSY` clears "on detection of a Stop condition", which is this, and no
        // other bit's rule: [`I2c::abort`] leaves it exactly as it found it.
        let sr2 = sr2::BUSY.set(sr2::MSL.set(sr2::TRA.set(sr2, 0), 0), 0);
        registers.set(Register::Sr2, sr2);
        let sr1 = registers.get(Register::Sr1);
        let sr1 = sr1::TXE.set(sr1, 0);
        // RM0090 rev 22 section 27.6.6 bit 2: a stop condition clears `BTF` in transmission alone.
        // In reception, `data N-1 and N` are still to be read after it, section 27.3.3.
        let sr1 = if self.reading.is_read() {
            sr1
        } else {
            sr1::BTF.set(sr1, 0)
        };
        registers.set(Register::Sr1, sr1);
        self.transmit = None;
        self.pending.clear();
    }

    /// `SWRST` set, RM0090 rev 22 section 27.6.1 bit 15: the interface "under reset state," and its
    /// own note gives this bit as the way out of a `BUSY` a glitch left locked. The reset reaches the
    /// whole register file, not only the flags a transaction touches, since nothing short of that
    /// promise recovers the locked case: [`I2c::abort`], `PE=0`, keeps `BUSY` standing on purpose.
    fn swrst(&mut self, registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
        self.release(context);
        registers.reset();
        self.shifting = None;
        self.transmit = None;
        self.holding = None;
        self.stuck = None;
        self.pending.clear();
        self.reading = Direction::Write;
        self.sr1_read = false;
        self.delayed_ack = true;
        self.carry = 0;
    }

    /// 27.6.1 bit 15: set and cleared by software, and the interface stays under reset state for as
    /// long as it stands, so nothing written anywhere lands but the bit itself.
    fn hold_in_reset(registers: &mut RegisterFile) {
        registers.reset();
        registers.set(Register::Cr1, cr1::SWRST.mask());
    }

    /// `PE` cleared while a transaction was open, RM0090 rev 22 section 27.6.1 bit 0: releases a peer
    /// mid-transaction and drops what was on the wire. [`I2c::close`] clears `BUSY`, its own rule
    /// from a stop condition, 27.6.7 bit 1. Here it is put back, since that section's own note keeps
    /// it "still updated" through `PE=0`. `AF`, the one error this model can raise, names its own
    /// hardware clear at `PE=0` in 27.6.6 bit 10, on top of the written zero [`I2c::write`] already
    /// gives it.
    fn abort(&mut self, registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
        let busy = sr2::BUSY.is_set(registers.get(Register::Sr2));
        self.close(registers, context);
        registers.set(
            Register::Sr2,
            sr2::BUSY.set(registers.get(Register::Sr2), u64::from(busy)),
        );
        self.shifting = None;
        self.holding = None;
        self.stuck = None;
        self.reading = Direction::Write;
        let sr1 = registers.get(Register::Sr1);
        registers.set(
            Register::Sr1,
            sr1::SB.set(
                sr1::BTF.set(
                    sr1::ADDR.set(sr1::ADD10.set(sr1::RXNE.set(sr1::AF.set(sr1, 0), 0), 0), 0),
                    0,
                ),
                0,
            ),
        );
    }

    fn write_cr1(
        &mut self,
        value: u64,
        registers: &mut RegisterFile,
        context: &mut DeviceContext<'_>,
    ) {
        let was = self.control;
        if cr1::SWRST.is_set(value) {
            if !cr1::SWRST.is_set(was) {
                self.swrst(registers, context);
            }
            Self::hold_in_reset(registers);
        } else if !cr1::PE.is_set(value) && cr1::PE.is_set(was) {
            self.abort(registers, context);
            let cleared = cr1::POS.set(cr1::ACK.set(cr1::START.set(value, 0), 0), 0);
            registers.set(Register::Cr1, cleared);
        } else if cr1::PE.is_set(value) {
            if cr1::START.is_set(value) && !cr1::START.is_set(was) {
                self.request_start(registers);
            }
            if cr1::STOP.is_set(value) && !cr1::STOP.is_set(was) {
                self.request_stop(registers, context);
            }
        } else {
            // 27.6.1 bit 0: `PE=0` holds `START`, `ACK` and `POS` clear regardless of what is
            // written, bits 8, 10 and 11's own hardware-clear note.
            let cleared = cr1::POS.set(cr1::ACK.set(cr1::START.set(value, 0), 0), 0);
            registers.set(Register::Cr1, cleared);
        }
        self.control = registers.get(Register::Cr1);
    }

    /// `DR` written: the address phase's byte while `SB` or `ADD10` stands and `SR1` was just read,
    /// or an outgoing data byte otherwise.
    fn write_dr(
        &mut self,
        byte: u8,
        registers: &mut RegisterFile,
        context: &mut DeviceContext<'_>,
    ) {
        let sr1_now = registers.get(Register::Sr1);
        if self.sr1_read && sr1::SB.is_set(sr1_now) {
            self.sr1_read = false;
            registers.set(Register::Sr1, sr1::SB.set(sr1_now, 0));
            self.schedule(
                Phase::Address {
                    byte,
                    second: false,
                },
                registers,
                context,
            );
            return;
        }
        if self.sr1_read && sr1::ADD10.is_set(sr1_now) {
            self.sr1_read = false;
            registers.set(Register::Sr1, sr1::ADD10.set(sr1_now, 0));
            self.schedule(Phase::Address { byte, second: true }, registers, context);
            return;
        }
        if self.reading.is_read() || self.active.is_none() {
            return;
        }
        if self.shifting.is_some() {
            // 27.6.6 bit 7: `DR` really is full now, waiting behind the byte already on the wire.
            registers.set(Register::Sr1, sr1::TXE.set(sr1_now, 0));
            self.transmit = Some(byte);
        } else {
            // 27.6.6 bit 7's exception: the shift register was idle, so the byte flows straight
            // through and `TxE` is never actually cleared by this write.
            registers.set(Register::Sr1, sr1::BTF.set(sr1_now, 0));
            self.schedule(Phase::Write(byte), registers, context);
        }
    }

    /// The line of table 124: `SB`, `ADDR`, `ADD10` and `BTF` raise it under `ITEVTEN` alone, and
    /// bare `TxE` or `RxNE` need `ITBUFEN` as well. `AF`, the one error this model raises, needs
    /// `ITERREN`. The two requests of section 27.3.8 follow `RxNE` and `TxE` under `DMAEN`.
    fn refresh_signals(&mut self, registers: &RegisterFile, context: &mut DeviceContext<'_>) {
        let sr1 = registers.get(Register::Sr1);
        let cr2 = registers.get(Register::Cr2);
        for (output, level) in [
            (
                RECEIVE_REQUEST,
                cr2::DMAEN.is_set(cr2) && sr1::RXNE.is_set(sr1),
            ),
            (
                TRANSMIT_REQUEST,
                cr2::DMAEN.is_set(cr2) && sr1::TXE.is_set(sr1),
            ),
        ] {
            let wanted = Level::from(level);
            if wanted != self.requests[output] {
                self.requests[output] = wanted;
                context.request(output, wanted);
            }
        }
        let event = cr2::ITEVTEN.is_set(cr2)
            && (sr1::SB.is_set(sr1)
                || sr1::ADDR.is_set(sr1)
                || sr1::ADD10.is_set(sr1)
                || sr1::BTF.is_set(sr1)
                || (cr2::ITBUFEN.is_set(cr2) && (sr1::TXE.is_set(sr1) || sr1::RXNE.is_set(sr1))));
        let error = cr2::ITERREN.is_set(cr2) && sr1::AF.is_set(sr1);
        for (position, wanted) in [(EVENT, event), (ERROR, error)] {
            let wanted = Level::from(wanted);
            if wanted != self.interrupt[position] {
                self.interrupt[position] = wanted;
                context.interrupt(position, wanted);
            }
        }
    }
}

impl Device for I2c {
    type Register = Register;

    /// The peripheral clock has changed. A byte on the wire keeps the rate it began at: nothing here
    /// re-times a period already scheduled. `carry` is a remainder in the old clock's units, so it is
    /// dropped with the rate it was a fraction of, the way `usart.rs` and `spi.rs` drop theirs.
    fn on_clock(
        &mut self,
        hz: u64,
        _registers: &mut RegisterFile,
        _context: &mut DeviceContext<'_>,
    ) {
        self.clock_hz = hz;
        self.carry = 0;
    }

    fn read(
        &mut self,
        register: Register,
        registers: &mut RegisterFile,
        context: &mut DeviceContext<'_>,
    ) -> Option<u64> {
        match register {
            Register::Sr1 => {
                self.sr1_read = true;
                None
            }
            Register::Sr2 => {
                let value = registers.get(Register::Sr2);
                let sr1 = registers.get(Register::Sr1);
                if self.sr1_read && sr1::ADDR.is_set(sr1) {
                    self.sr1_read = false;
                    registers.set(Register::Sr1, sr1::ADDR.set(sr1, 0));
                    if self.reading.is_read() {
                        self.begin_receiving(registers, context);
                    }
                    self.refresh_signals(registers, context);
                }
                Some(value)
            }
            Register::Dr => {
                if self.reading.is_read() {
                    let byte = self.holding.take();
                    let sr1 = registers.get(Register::Sr1);
                    registers.set(Register::Sr1, sr1::RXNE.set(sr1, 0));
                    if let Some(stuck) = self.stuck.take() {
                        self.holding = Some(stuck);
                        let sr1 = registers.get(Register::Sr1);
                        registers.set(Register::Sr1, sr1::RXNE.set(sr1::BTF.set(sr1, 0), 1));
                        self.schedule_read(registers, context);
                    }
                    self.refresh_signals(registers, context);
                    return Some(u64::from(byte.unwrap_or(0)));
                }
                // 27.6.6 bit 2: `BTF` clears on a read of `DR` as well as a write, ChibiOS's own
                // `EV8_2` dummy read.
                let sr1 = registers.get(Register::Sr1);
                if sr1::BTF.is_set(sr1) {
                    registers.set(Register::Sr1, sr1::BTF.set(sr1, 0));
                    self.refresh_signals(registers, context);
                }
                None
            }
            _ => None,
        }
    }

    /// `DR` receiving is the byte a read would take. `SR1` and `SR2` read as they stand.
    fn peek(
        &self,
        register: Register,
        _registers: &RegisterFile,
        _now: VirtualNanos,
    ) -> Option<u64> {
        (register == Register::Dr && self.reading.is_read())
            .then(|| u64::from(self.holding.unwrap_or(0)))
    }

    fn write(
        &mut self,
        register: Register,
        value: u64,
        registers: &mut RegisterFile,
        context: &mut DeviceContext<'_>,
    ) {
        if cr1::SWRST.is_set(self.control) && !matches!(register, Register::Cr1) {
            Self::hold_in_reset(registers);
            return;
        }
        match register {
            Register::Cr1 => self.write_cr1(value, registers, context),
            Register::Dr => {
                let byte = u8::try_from(value & 0xFF).expect("masked to eight bits");
                self.write_dr(byte, registers, context);
            }
            _ => {}
        }
        self.refresh_signals(registers, context);
    }

    fn on_event(
        &mut self,
        event: EventId,
        registers: &mut RegisterFile,
        context: &mut DeviceContext<'_>,
    ) {
        let Some(shift) = self.shifting.filter(|shift| shift.event == event) else {
            return;
        };
        self.shifting = None;
        match shift.phase {
            Phase::Address { byte, second } => {
                self.finish_address(byte, second, registers, context);
            }
            Phase::Write(byte) => self.finish_write(byte, registers, context),
            Phase::Read => self.finish_read(registers, context),
        }
        for pending in std::mem::take(&mut self.pending) {
            match pending {
                Pending::Stop => {
                    let cr1 = cr1::STOP.set(registers.get(Register::Cr1), 0);
                    registers.set(Register::Cr1, cr1);
                    self.close(registers, context);
                }
                Pending::Start => {
                    let cr1 = cr1::START.set(registers.get(Register::Cr1), 0);
                    registers.set(Register::Cr1, cr1);
                    self.start_transaction(registers);
                }
            }
        }
        self.refresh_signals(registers, context);
    }
}