embassy-rs / chiptool

Apache License 2.0
37 stars 21 forks source link

Support discontinuous field #22

Closed eZioPan closed 4 months ago

eZioPan commented 4 months ago

I found some "discontinuous field" when I make timer_v2. eg. MMS of TIMx_CR2 from Page1567 of Section38 AdvTim of H573 RM0481; TS of TIMx_SMCR from the same page.

I try add support for this situation.


yaml file will support

fieldset/CR2_2CH_CMP:
  extends: CR2_1CH_CMP
  description: control register 2
  fields:
  - name: MMS
    description: Master mode selection
    bit_offset:
      - start: 4
        end: 6
      - start: 25
        end: 25
    bit_size: 4
    enum: MMS

new syntax, and chiptool do properly check when parse source file.

It will generate PAC like this:

#[doc = "Master mode selection"]
#[inline(always)]
pub const fn mms(&self) -> super::vals::Mms {
    let mut val = 0;
    val += (((self.0 >> 4usize) & 0x07) << 0usize);
    val += (((self.0 >> 25usize) & 0x01) << 3usize);
    super::vals::Mms::from_bits(val as u8)
}
#[doc = "Master mode selection"]
#[inline(always)]
pub fn set_mms(&mut self, val: super::vals::Mms) {
    self.0 = (self.0 & !(0x07 << 4usize)) | (((val.to_bits() as u32 >> 0usize) & 0x07) << 4usize);
    self.0 = (self.0 & !(0x01 << 25usize)) | (((val.to_bits() as u32 >> 3usize) & 0x01) << 25usize);
}

And for fields array:

  - name: OCM
    description: Output compare y mode
    bit_offset:
      - start: 4
        end: 6
      - start: 16
        end: 16
    bit_size: 4
    array:
      len: 2
      stride: 8
    enum: OCM

it will generate:

#[doc = "Output compare y mode"]
#[inline(always)]
pub const fn ocm(&self, n: usize) -> super::vals::Ocm {
    assert!(n < 1usize);
    let mut val = 0;
    let offs = 4usize + n * 8usize;
    val += (((self.0 >> offs) & 0x07) << 0usize);
    let offs = 16usize + n * 8usize;
    val += (((self.0 >> offs) & 0x01) << 3usize);
    super::vals::Ocm::from_bits(val as u8)
}
#[doc = "Output compare y mode"]
#[inline(always)]
pub fn set_ocm(&mut self, n: usize, val: super::vals::Ocm) {
    assert!(n < 1usize);
    let offs = 4usize + n * 8usize;
    self.0 = (self.0 & !(0x07 << offs)) | (((val.to_bits() as u32 >> 0usize) & 0x07) << offs);
    let offs = 16usize + n * 8usize;
    self.0 = (self.0 & !(0x01 << offs)) | (((val.to_bits() as u32 >> 3usize) & 0x01) << offs);
}

I didn't touch the output of regular bit_offset (though regluar bit_offset can also be write as 1-range bit_offset), I think we should keep as simple as possible, since access registers can be "hot paths".