[ottool] Add weak/strong gpio support to transports

Currently, only verilator supports modelling detecting weak/strong
inputs.

Signed-off-by: Chris Frantz <cfrantz@google.com>
diff --git a/sw/host/opentitanlib/src/app/config/opentitan_verilator.json b/sw/host/opentitanlib/src/app/config/opentitan_verilator.json
index f6c093b..53eebaf 100644
--- a/sw/host/opentitanlib/src/app/config/opentitan_verilator.json
+++ b/sw/host/opentitanlib/src/app/config/opentitan_verilator.json
@@ -17,6 +17,10 @@
       { "name": "IOR11", "alias_of": "11" },
       { "name": "IOR12", "alias_of": "12" },
       { "name": "IOR13", "alias_of": "13" }
+
+      { "name": "IOC0", "alias_of": "22" }
+      { "name": "IOC1", "alias_of": "23" }
+      { "name": "IOC2", "alias_of": "24" }
   ],
   "uarts": [
     {
diff --git a/sw/host/opentitanlib/src/io/gpio.rs b/sw/host/opentitanlib/src/io/gpio.rs
index 2ad00d6..9eb321a 100644
--- a/sw/host/opentitanlib/src/io/gpio.rs
+++ b/sw/host/opentitanlib/src/io/gpio.rs
@@ -43,6 +43,7 @@
     pub enum PinMode {
         Input,
         PushPull,
+        WeakPushPull,
         OpenDrain,
     }
 }
diff --git a/sw/host/opentitanlib/src/transport/cw310/gpio.rs b/sw/host/opentitanlib/src/transport/cw310/gpio.rs
index cde936a..b1cfc08 100644
--- a/sw/host/opentitanlib/src/transport/cw310/gpio.rs
+++ b/sw/host/opentitanlib/src/transport/cw310/gpio.rs
@@ -42,6 +42,7 @@
             PinMode::Input => usb.pin_set_output(&self.pinname, false)?,
             PinMode::PushPull => usb.pin_set_output(&self.pinname, true)?,
             PinMode::OpenDrain => return Err(GpioError::UnsupportedPinMode(mode).into()),
+            PinMode::WeakPushPull => return Err(GpioError::UnsupportedPinMode(mode).into()),
         }
         Ok(())
     }
diff --git a/sw/host/opentitanlib/src/transport/hyperdebug/gpio.rs b/sw/host/opentitanlib/src/transport/hyperdebug/gpio.rs
index 8d2d1e7..955fe6d 100644
--- a/sw/host/opentitanlib/src/transport/hyperdebug/gpio.rs
+++ b/sw/host/opentitanlib/src/transport/hyperdebug/gpio.rs
@@ -5,7 +5,7 @@
 use anyhow::Result;
 use std::rc::Rc;
 
-use crate::io::gpio::{GpioPin, PinMode, PullMode};
+use crate::io::gpio::{GpioError, GpioPin, PinMode, PullMode};
 use crate::transport::hyperdebug::Inner;
 use crate::transport::TransportError;
 
@@ -53,6 +53,7 @@
                     PinMode::Input => "input",
                     PinMode::OpenDrain => "opendrain",
                     PinMode::PushPull => "pushpull",
+                    PinMode::WeakPushPull => return Err(GpioError::UnsupportedPinMode(mode).into()),
                 }
             ),
             |_| {},
diff --git a/sw/host/opentitanlib/src/transport/ti50emulator/gpio.rs b/sw/host/opentitanlib/src/transport/ti50emulator/gpio.rs
index f131df8..552d9f1 100644
--- a/sw/host/opentitanlib/src/transport/ti50emulator/gpio.rs
+++ b/sw/host/opentitanlib/src/transport/ti50emulator/gpio.rs
@@ -134,6 +134,8 @@
         match (state.pin_mode, state.pull_mode, state.value) {
             (Some(PinMode::PushPull), _, false) => Logic::StrongZero,
             (Some(PinMode::PushPull), _, true) => Logic::StrongOne,
+            (Some(PinMode::WeakPushPull), _, false) => Logic::WeakZero,
+            (Some(PinMode::WeakPushPull), _, true) => Logic::WeakOne,
             (Some(PinMode::OpenDrain), _, false) => Logic::StrongZero,
             (Some(PinMode::OpenDrain), PullMode::PullUp, true) => Logic::WeakOne,
             (Some(PinMode::OpenDrain), PullMode::PullDown, true) => Logic::WeakZero,
diff --git a/sw/host/opentitanlib/src/transport/ultradebug/gpio.rs b/sw/host/opentitanlib/src/transport/ultradebug/gpio.rs
index f36848a..c3fdaf1 100644
--- a/sw/host/opentitanlib/src/transport/ultradebug/gpio.rs
+++ b/sw/host/opentitanlib/src/transport/ultradebug/gpio.rs
@@ -91,6 +91,7 @@
         let direction = match mode {
             PinMode::Input => false,
             PinMode::PushPull => true,
+            PinMode::WeakPushPull => return Err(GpioError::UnsupportedPinMode(mode).into()),
             PinMode::OpenDrain => return Err(GpioError::UnsupportedPinMode(mode).into()),
         };
         self.device
diff --git a/sw/host/opentitanlib/src/transport/verilator/gpio.rs b/sw/host/opentitanlib/src/transport/verilator/gpio.rs
index 630c8f3..6f42840 100644
--- a/sw/host/opentitanlib/src/transport/verilator/gpio.rs
+++ b/sw/host/opentitanlib/src/transport/verilator/gpio.rs
@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: Apache-2.0
 
 use anyhow::{ensure, Context, Result};
-use std::cell::RefCell;
+use std::cell::{Cell, RefCell};
 use std::collections::HashMap;
 use std::fs::{File, OpenOptions};
 use std::io::{self, ErrorKind, Read, Write};
@@ -17,11 +17,16 @@
 pub struct VerilatorGpioPin {
     inner: Rc<RefCell<Inner>>,
     pinname: u8,
+    pinmode: Cell<PinMode>,
 }
 
 impl VerilatorGpioPin {
     pub(crate) fn new(inner: Rc<RefCell<Inner>>, pinname: u8) -> Rc<Self> {
-        Rc::new(VerilatorGpioPin { inner, pinname })
+        Rc::new(VerilatorGpioPin {
+            inner,
+            pinname,
+            pinmode: Cell::new(PinMode::PushPull),
+        })
     }
 }
 
@@ -33,11 +38,19 @@
 
     fn write(&self, value: bool) -> Result<()> {
         let mut inner = self.inner.borrow_mut();
-        inner.gpio.set(self.pinname, value)
+        inner.gpio.set(
+            self.pinname,
+            value,
+            self.pinmode.get() == PinMode::WeakPushPull,
+        )
     }
 
-    fn set_mode(&self, _mode: PinMode) -> Result<()> {
-        log::warn!("set_mode not implemented");
+    fn set_mode(&self, mode: PinMode) -> Result<()> {
+        ensure!(
+            mode != PinMode::OpenDrain,
+            GpioError::UnsupportedPinMode(mode)
+        );
+        self.pinmode.set(mode);
         Ok(())
     }
 
@@ -81,8 +94,8 @@
                     );
                     for (i, val) in buf.iter().enumerate() {
                         self.rval = match val {
-                            b'0' => self.rval & !(1 << 31 - i),
-                            b'1' => self.rval | 1 << 31 - i,
+                            b'0' => self.rval & !(1 << (31 - i)),
+                            b'1' => self.rval | 1 << (31 - i),
                             b'\n' | b'X' => self.rval,
                             _ => {
                                 return Err(GpioError::Generic(format!(
@@ -112,11 +125,12 @@
         Ok(self.rval & (1 << index) != 0)
     }
 
-    fn set(&mut self, index: u8, val: bool) -> Result<()> {
+    fn set(&mut self, index: u8, val: bool, weak: bool) -> Result<()> {
+        let weak = if weak { "w" } else { "" };
         let command = if val {
-            format!("h{}\n", index)
+            format!("{}h{}\n", weak, index)
         } else {
-            format!("l{}\n", index)
+            format!("{}l{}\n", weak, index)
         };
         self.write
             .write(command.as_bytes())
diff --git a/sw/host/opentitanlib/src/transport/verilator/transport.rs b/sw/host/opentitanlib/src/transport/verilator/transport.rs
index 0e318dc..fea4f0c 100644
--- a/sw/host/opentitanlib/src/transport/verilator/transport.rs
+++ b/sw/host/opentitanlib/src/transport/verilator/transport.rs
@@ -67,10 +67,7 @@
             spi_file: spi,
             gpio_read_file: gpio_rd,
             gpio_write_file: gpio_wr,
-            inner: Rc::new(RefCell::new(Inner {
-                uart: None,
-                gpio: gpio,
-            })),
+            inner: Rc::new(RefCell::new(Inner { uart: None, gpio })),
         })
     }