Miscellaneous Tool/Command Line Suggestions


Miscellaneous Tool/Command Line Suggestions

This was originally written as an Ed post intended for the students of Stanford’s Winter 2024 140E offering (which I TA’d).

I’ll periodically go through and update this more—you don’t need to read any/all of it, but hopefully it will contain something you find useful in working for this class. I unfortunately lost all of my progress when my laptop died., so I’ll be updating this version a little more this lab.

Keyboard shortcuts (note that these use emacs bindings by default, see the terminal subheading under vim if you’d prefer to use those):

  • CTRL+U delete to the beginning of the line

  • CTRL+K delete to the end of the line

  • META+B go back a word (meta will be dependent on your terminal emulator settings, escape should always work, alt may or may not work)

  • META+F go forward a word (can be prefixed by a META+number for a count)

  • CTRL+R to search for a particular command (can keep searching backward using CTRL+R or can go forward again using CTRL+S)

  • CTRL+X CTRL+E open $EDITOR (maybe $VISUAL) and execute the resulting commands from whatever file you save

Useful commands:

  • cd -—change directory to the last directory you were in.

  • pushd/popd—used for keeping track of a stack of working directories (worth looking at other options, e.g., +1 which you can use to rotate the directory stack)

You can set up some aliases like Dawson talked about.

alias 140="cd $CS140E_2024_PATH/"
alias 140pi="cd $CS140E_2024_PATH/libpi"
alias 140l1="cd $CS140E_2024_PATH/labs/1-compile"
alias 140l2="cd $CS140E_2024_PATH/labs/2-trusting-trust"
alias 140l3="cd $CS140E_2024_PATH/labs/3-gpio"
alias 140l4="cd $CS140E_2024_PATH/labs/4-cross-checking"
alias 140l5="cd $CS140E_2024_PATH/labs/5-interrupts"
alias 140l6="cd $CS140E_2024_PATH/labs/6-threads"
alias 140l7="cd $CS140E_2024_PATH/labs/7-bootloader"
alias 140l8="cd $CS140E_2024_PATH/labs/8-uart"
alias 140l9="cd $CS140E_2024_PATH/labs/9-device-int"
alias 140l10="cd $CS140E_2024_PATH/labs/10-debug-hw"
alias 140l11="cd $CS140E_2024_PATH/labs/11-imu-i2c"
alias 140l12="cd $CS140E_2024_PATH/labs/12-i2c+mailboxes"
alias 140l13="cd $CS140E_2024_PATH/labs/13-ss-equiv"
alias 140l14="cd $CS140E_2024_PATH/labs/14-ss-equiv-deux"
alias 140l15="cd $CS140E_2024_PATH/labs/15-pinned-vm"

I like using fzf to quickly navigate between directories. In my ~/.zshrc, I have

alias cf.='cd "$(find . -type d | fzf)"'
alias cf='cd "$(find . -wholename '\''./*.*'\'' -prune -o -type d -print | fzf)"'
alias ve='vi "$(find . -type f | fzf)"'

cf gives you a fuzzy finding prompt with directories below your current value, cf. does the same thing but not ignoring hidden directories, and ve lets you edit a file with a fuzzy finder (e.g., so you can do ve and then type lab/1/1.c to edit the part one code.

Useful Utilities

  • You can use grep -r to recursively search for a term. Other common flags I use include -l (print the file name only), and -A and -B (for printing context). This can be useful when you want to know where something is called (e.g., where does some_fn appear->grep -r some_fn or grep some_fn *.S *.c. I like using ripgrep (rg, https://github.com/BurntSushi/ripgrep) for this purpose, which is a multithreaded equivalent written in rust.

  • bear (https://github.com/rizsotto/Bear) is useful for use with the clangd language server (if you’re using vim/nvim, I assume you know whether or not you’re using it—if you’re using vscode, I think it’s the default). If you just run bear -- make, it will generate compile_commands.json such that your lsp can find definitions (works better than e.g., ctags since it can figure out functions made with the MK_FN macro).

Vim/Neovim Config

I use vim/neovim, so I can’t give as much commentary to how to use vscode effectively. I use neovim preferentially over vim since I think the integration with lua as a scripting language leads to a richer plugin ecosystem, and I like that it has builtin lsp integration (although I miss my :term using a pseudo terminal). Some plugins I find useful are

  • lazy.nvim (https://github.com/folke/lazy.nvim) as my plugin manager—I think the plugin manager you pick is relatively arbitrary (in vim, I still use Vundle). It lazily loads plugins which can be nice.

  • VonHeikemen/lsp-zero.nvim—nice utility for handling lsp things so I just kind of do’t think about them, especially with williamboman/mason.nvim and williamboman/mason-lspconfig.nvim which make it so I can :LspInstall when I open a new file type where I haven’t downloaded the lsp yet.

Separately, I like using junnegunn/fzf and junnegun/fzf.vim which make it convenient to switch between files/buffers/etc… I have the following lines

nnoremap <c-f>f :Files
nnoremap <c-f>b :Buffers
nnoremap <c-f>L :Lines
nnoremap <c-f>l :BLines
nnoremap <c-f>r :Rg
nnoremap <c-f>w :Windows
nnoremap <c-f>t :Tags
nnoremap <c-f>m :Marks
nnoremap <c-f><c-f> :Files<cr>
nnoremap <c-f><c-b> :Buffers<cr>
nnoremap <c-f><c-L> :Lines<cr>
nnoremap <c-f><c-l> :BLines<cr>
nnoremap <c-f><c-r> :Rg<cr>
nnoremap <c-f><c-w> :Windows<cr>
nnoremap <c-f><c-t> :Tags<cr>
nnoremap <c-f><c-m> :Marks<cr>

Splits

I like using splits and having my terminal in my vim instance; the relevant commands and keystrokes include :term (open a terminal), :split, :vsplit, and <C-W> prefixed commands (<c-w>n split the current buffer horizontally, <c-w>v split the current buffer vertically, <c-w>[hjkl] move to the pane to the direction specified in the normal vim way, <c-w><c-w> alternate between buffers, <c-w>[HJKL] move the current pane in the direction specified by the letter, <c-w>r rotate the list of panes, <c-w>_ maximize the current pane vertically, <c-w>| maximize the current pane horizontally, <c-w>+ increase height (takes an optional count), <c-w>- decrease height, <c-w>< decrease width, <c-w>> increase width, <c-w>= equalize splits). I’ll sometimes use tabs as well, normally using :tabe and gt, gT to navigate between them.

Terminal

As mentioned under the main terminal navigation subheading, while the default terminal emulator settings probably use emacs key bindings, you can easily switch this to using vim keybindings. In bash or zsh the 1-second fix is to run set -o vi (you might want to throw that in your .bashrc or .zshrc). In bash, the equivalent to C-X C-E is <ESC>v, in zsh, it’s a little more complicated (https://unix.stackexchange.com/questions/6620/how-to-edit-command-line-in-full-screen-editor-in-zsh). In bash and other programs that use gnu readline (python is the other obvious one off the top of my head, although also gdb, sadly not node), you can modify your .inputrc to achieve a similar effect just throw in the lines

set editing-mode vi
set keymap vi-command

140E Stuff

debugging asm

You can just b to a function you’ve defined in C, where you’re likely more comfortable (I’ll normally just define a function like void tmp_debug(uint32_t reg1) that calls clean_reboot at the end (since normally we clobber registers in a way that makes the rest hard to interpret). If you get a linker error since you’re branching to something that doesn’t exist in a given test case, you can either change your Makefile so you’re only looking at the failing test case, or you can add a .weak symbol in the asm file with the name you’re using.

When to read-modify-write

The basic idea is we read modify write when we want to keep some of the old state. There are some heuristics you can use for this: “can I give sensible values to every bit/byte?” (yes->probably write whole thing, no->probably rmw).