[opentitantool] Refactor bitstream USR_ACCESS code to a separate module

Signed-off-by: Alphan Ulusoy <alphan@google.com>
diff --git a/sw/host/opentitanlib/BUILD b/sw/host/opentitanlib/BUILD
index b12fa57..499a018 100644
--- a/sw/host/opentitanlib/BUILD
+++ b/sw/host/opentitanlib/BUILD
@@ -119,6 +119,7 @@
         "src/util/rom_detect.rs",
         "src/util/unknown.rs",
         "src/util/usb.rs",
+        "src/util/usr_access.rs",
         "src/util/voltage.rs",
     ],
     compile_data = [
diff --git a/sw/host/opentitanlib/src/util/mod.rs b/sw/host/opentitanlib/src/util/mod.rs
index 292cf3a..fa8200d 100644
--- a/sw/host/opentitanlib/src/util/mod.rs
+++ b/sw/host/opentitanlib/src/util/mod.rs
@@ -11,6 +11,7 @@
 pub mod rom_detect;
 pub mod unknown;
 pub mod usb;
+pub mod usr_access;
 pub mod voltage;
 
 /// The `collection` macro provides syntax for hash and set literals.
diff --git a/sw/host/opentitanlib/src/util/rom_detect.rs b/sw/host/opentitanlib/src/util/rom_detect.rs
index 3475752..00d87ae 100644
--- a/sw/host/opentitanlib/src/util/rom_detect.rs
+++ b/sw/host/opentitanlib/src/util/rom_detect.rs
@@ -5,23 +5,14 @@
 use anyhow::Result;
 use regex::Regex;
 use serde::{Deserialize, Serialize};
-use std::convert::TryInto;
 use std::str::FromStr;
 use std::time::Duration;
 use std::time::Instant;
 use structopt::clap::arg_enum;
-use thiserror::Error;
 
 use crate::io::uart::Uart;
 use crate::uart::console::{ExitStatus, UartConsole};
-
-const REG_USR_ACCESS: [u8; 4] = [0x30, 0x01, 0xa0, 0x01];
-
-#[derive(Error, Debug, Serialize, Deserialize)]
-pub enum Error {
-    #[error("USR_ACCESS value not found in bitstream")]
-    UsrAccessNotFound,
-}
+use crate::util::usr_access::usr_access_get;
 
 arg_enum! {
     #[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)]
@@ -41,7 +32,7 @@
     pub fn new(kind: RomKind, bitstream: &[u8], timeout: Option<Duration>) -> Result<RomDetect> {
         Ok(RomDetect {
             kind: kind,
-            usr_access: Self::scan_usr_access(bitstream)?,
+            usr_access: usr_access_get(bitstream)?,
             console: UartConsole {
                 timeout: timeout,
                 exit_success: Some(Regex::new(r"(\w*ROM):([^\r\n]+)[\r\n]").unwrap()),
@@ -50,17 +41,6 @@
         })
     }
 
-    fn scan_usr_access(bitstream: &[u8]) -> Result<u32> {
-        let operand = bitstream
-            .chunks(4)
-            .skip_while(|op| **op != REG_USR_ACCESS)
-            .nth(1)
-            .ok_or(Error::UsrAccessNotFound)?;
-        let usr_access = u32::from_be_bytes(operand.try_into()?);
-        log::info!("Bitstream file USR_ACCESS value: {:#x}", usr_access);
-        Ok(usr_access)
-    }
-
     pub fn detect(&mut self, uart: &dyn Uart) -> Result<bool> {
         let t0 = Instant::now();
         let rc = self.console.interact(uart, None, None)?;
diff --git a/sw/host/opentitanlib/src/util/usr_access.rs b/sw/host/opentitanlib/src/util/usr_access.rs
new file mode 100644
index 0000000..c1a2c8a
--- /dev/null
+++ b/sw/host/opentitanlib/src/util/usr_access.rs
@@ -0,0 +1,39 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+use anyhow::Result;
+use serde::{Deserialize, Serialize};
+use std::convert::TryInto;
+use thiserror::Error;
+
+const WRITE_USR_ACCESS: [u8; 4] = [0x30, 0x01, 0xa0, 0x01];
+
+#[derive(Error, Debug, Serialize, Deserialize)]
+pub enum Error {
+    #[error("Command {0:#x?} not found in bitstream")]
+    CommandNotFound(u32),
+}
+
+fn find_cmd(bitstream: &[u8], cmd: &[u8; 4]) -> Result<usize> {
+    Ok(bitstream
+        .chunks(4)
+        .enumerate()
+        .find(|(_, op)| *op == cmd)
+        .ok_or(Error::CommandNotFound(u32::from_be_bytes(*cmd)))?
+        .0
+        * 4)
+}
+
+
+pub fn usr_access_get(bitstream: &[u8]) -> Result<u32> {
+    let i = find_cmd(&bitstream, &WRITE_USR_ACCESS)?;
+    if (i + 8) > bitstream.len() {
+        return Err(Error::CommandNotFound(u32::from_be_bytes(WRITE_USR_ACCESS)).into());
+    }
+    let operand = &bitstream[i + 4..i + 8];
+    let usr_access = u32::from_be_bytes(operand.try_into()?);
+    log::info!("Bitstream file USR_ACCESS value: {:#x}", usr_access);
+    Ok(usr_access)
+}
+