How to Print Part of a Binary Number

This may be trivial, but how do you print only part of a binary number? I'm reading a densely-packed, 32-bit register and I want to print it 8 bits per line. bits 0-7, then bits 8-15, and so on. Is there a std::fmt to print like this with some type of indexing, or should I mask and bit shift to get what I want? I looked through the docs but didn't see what I needed.

Mask and bitshift it manually.

1 Like

You can use to_be_bytes or similar instead of masking and shifting:

fn print_bits(x: i32) {
    for byte in x.to_be_bytes().iter() {
        println!("{:08b}", byte);
    }
}

Playground

2 Likes

I didn't get what I expected with this code @mbrubeck . I did have to change the parameter to usize instead of i32. Should I cast it to i32 to make it work?
output

10
0
1
111
0
1
11
11

Did you keep the 08 in the format? That specifies 0-padding to width 8.

1 Like

Yes I did,

#![no_std]
#![no_main]

extern crate panic_halt;

use riscv_rt::entry;
use hifive1::hal::prelude::*;
use hifive1::hal::DeviceResources;
use hifive1::{sprintln, pin};
use riscv::register::{pmpaddr0,pmpaddr1,pmpaddr2,pmpaddr3,pmpaddr4,pmpaddr5,pmpaddr6,pmpaddr7,
                      pmpcfg0,pmpcfg1};


fn print_register_by_byte(x:usize){
    for byte in x.to_be_bytes().iter(){
        sprintln!("{:08b}",byte);
    }
}

#[entry]
fn main() -> ! {
    let dr = DeviceResources::take().unwrap();
    let p = dr.peripherals;
    let pins = dr.pins;

    // Configure clocks
    let clocks = hifive1::clock::configure(p.PRCI, p.AONCLK, 320.mhz().into());

    // Configure UART for stdout
    hifive1::stdout::configure(p.UART0, pin!(pins, uart0_tx), pin!(pins, uart0_rx), 115_200.bps(), clocks);

    sprintln!("Preparing to read PMP registers");

    // Read the pmp registers
    let _pmp0 = pmpaddr0::read();
    let _pmp1 = pmpaddr1::read();
    let _pmp2 = pmpaddr2::read();
    let _pmp3 = pmpaddr3::read();
    let _pmp4 = pmpaddr4::read();
    let _pmp5 = pmpaddr5::read();
    let _pmp6 = pmpaddr6::read();
    let _pmp7 = pmpaddr7::read();

    let _pmp_cfg0 = pmpcfg0::read();
    let _pmp_cfg1 = pmpcfg1::read();

    // Print the PMP address registers in hex
    sprintln!("pmpaddr0: {:#X}", _pmp0);
    sprintln!("pmpaddr1: {:#X}", _pmp1);
    sprintln!("pmpaddr2: {:#X}", _pmp2);
    sprintln!("pmpaddr3: {:#X}", _pmp3);
    sprintln!("pmpaddr4: {:#X}", _pmp4);
    sprintln!("pmpaddr5: {:#X}", _pmp5);
    sprintln!("pmpaddr6: {:#X}", _pmp6);
    sprintln!("pmpaddr7: {:#X}", _pmp7);

    // Print the PMP configuration registers 8 bits, or byte, at a time
    print_register_by_byte(_pmp_cfg0);
    print_register_by_byte(_pmp_cfg1);


    loop {}
}

Ah crap, nope I'm going blind. The 8 got left out.

1 Like

defmt has some magic which lets you specify different bit ranges of the same argument to print as separate chunks of text in your output. I don't know how it works -- I didn't even look at the code -- but it can be cool if that behaviour can be ported to core::fmt.

Hmm, is there any use for fill/padding formats without a width? I feel like this deserves a warning.

2 Likes

I saw that Ferrous Systems released defmt as part of their knurling project. I read a little about it, but haven't really looked at it hard yet. If I'm not mistaken, it uses probe-rs and has support for RISC-V, which is what my board is using. I'm going to check it out at some point.

I somehow missed that it is for an embedded platform. I had something like core::fmt backporting the nice bitwise formatting from defmt in mind. If you're using embedded and your platform is supported I'd say you must definitely give it a shot. It looks really nice to use and helpful.

1 Like

I've generated their template for testing. Using probe-run --list-chips I get

Generic Riscv
    Variants:
        riscv

I'm going to give it a shot, but one part I can't figure out is the .cargo/config.toml part. I can't find this file to modify it.

You can create the file if it doesn’t exist. For details, see:

https://doc.rust-lang.org/cargo/reference/config.html

Thanks, I found it. For some reason it is hidden in the directory but I can cd into the .cargo folder then modify the config.toml from there.

Turns out the defmt app template does not support RISC-V linking. I opened an issue on Github here, they said they would keep it open as a possible enhancement. I guess it is sprintln! until then.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.