Origen-SDK / o2

MIT License
4 stars 0 forks source link

Regs #73

Closed ginty closed 4 years ago

ginty commented 4 years ago

There's still a lot to do on regs, but thought I would open a PR to merge the current state into master to allow others access to it. Work will continue to add more functionality on this branch afterwards - I've copied over the reg_spec from O1 and my plan is to now work through that to add whatever is missing.

This PR adds the following:

Here is the latest register definition API:

    # This is the reg description
    with Reg("adc_ctrl", 0x0024, size=16):
        # This is the COCO description
        Field("coco", offset=7, access="ro")
        Field("aien", offset=6)
        Field("diff", offset=5)
        Field("adch", offset=0, width=5, reset=0x1F, enums={
            # A simple enum
            "val1": 3,
            # A more complex enum, all fields except for value are optional, it will probably
            # eventually support assigning the description from this comment
            "val2": { "value": 5, "usage": "w", "description": "The value of something"},
        }

Note that enumerated values as discussed in #31 are partially implemented - any enums defined as above do end up in the database but there is no API to consume them yet (will likely be my_reg.set_data("val1")).

@info-rchitect I commented out your translator tests due to API changes, please feel free to re-instate with the latest API or wait for things to settle down as you see fit. Hopefully the above reg API is stable now though.

In the console, you should soon be able to just do dut.regs to see the list of regs that have been defined as they would have been in O1 without a memory map or address block parent. However, for now you need to do dut.default.default.regs (reflecting that such regs are now physically instantiated in a default (auto-generated) memory map and address block), and you will see something like this:

dut
 └── memory_maps['default']
      └── address_blocks['default']
           ├── register_files []
           └── registers
                ├── reg1
                ├── reg2
                ├── areg0
                └── freg1

And register displays now work, areg0 can be looked up a number of ways:

dut.areg0
dut.reg("areg0")
dut.default.default.areg0
dut.memory_map("default").address_block("default").reg("areg0")

And you get the same reg view from O1:

0x1000 - friendly.path.to.be.implemented.areg0
  ╒═════════════╤═════════════╤═════════════╤═════════════╤═════════════╤═════════════╤═════════════╤═════════════╕
  │     15      │     14      │     13      │     12      │     11      │     10      │      9      │      8      │
  │             │             │             │             │             │             │             │             │
  │             │             │             │             │             │             │             │             │
  ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
  │      7      │      6      │      5      │      4      │      3      │      2      │      1      │      0      │
  │    coco     │    aien     │    diff     │                              adch[4:0]                              │
  │    0(RO)    │      0      │      0      │                                 0x0                                 │
  └─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┘

The data can be get/set on the whole register and individual bit fields:

dut.areg0.get_data()     # => 0
# data() is an alias of get_data()
dut.areg0.data()          
dut.areg0.set_data(0xFFFF)
dut.areg0.get_data()     # => 0x7F   (RO and missing bit behavior is implemented)

# This should work soon:
# dut.areg0.adch.data()
# But for now, the longhand works:
dut.areg0.bits("adch").data()    # => 0x1F
dut.areg0.bits("adch").set_data(5)
info-rchitect commented 4 years ago

@ginty Have you hooked up regs, memory maps and address blocks so this iteration pattern can be used in Python?

for reg in origen.dut.regs:
ginty commented 4 years ago

@info-rchitect, it will definitely work like that eventually, but not sure if it does currently or not

ginty commented 4 years ago

@coreyeng, I haven't made any changes per #71 yet and I'm currently in two minds about whether I should or not. I think for non-model related things (e.g. pattern, flow AST) should not pile in under the existing DUT, but its actually working pretty well for me now as far as model-data and state are concerned.

The RwLock provides (threadsafe) interior mutability to the Bit objects which have a state field which is wrapped by it. So as far as regs go, everything else is essentially immutable, i.e. you declare memory maps, regs, etc. and then these are fixed. The only thing that needs to change during pattern generation is the data stored by the regs and that boils down to the individual bit's state fields.

The way I'm writing it now is that every PyApi entry method grabs an immutable reference to the DUT, and then this is passed down to core functions that require it. Pure Rust entry points (i.e. from the CLI) in future should do the same. Interior functions should be banned from ever grabbing a DUT lock directly (as that can deadlock easily) and instead must look to their caller to provide it.

That has given me pretty minimal bother from the borrow-checker and I think this is following how data is intended to be shared between functions in Rust. The interior mutability aspect of the bits means that I hardly ever need a mutable DUT reference and that certainly helps with borrowing.

An advantage I'm seeing from having everything under DUT now is that it is just one reference I need to pass around. Even though moving to separate REGS, BITS, statics does give finer-grained locking, it would then mean that I would have to deal with passing lots of these references around instead of just one.

coreyeng commented 4 years ago

@ginty, sounds good! I think I've been doing something similar with timing so it should follow your rules above.