bittide / bittide-hardware

17 stars 1 forks source link

Add haskell function to program soft-core with openOCD and GDB #648

Closed lmbollen closed 1 week ago

lmbollen commented 1 month ago

We currently have some functionality to start gdb and run a script that is located outside of the Haskell code. But it would be nice to at least have a reusable function to load a binary onto the FPGA. This could simply be a function that starts openocd, starts gdb, programs the soft-core connected via JTAG and starts execution.

Currently the adapter usb location is hardcoded to 1-5.1:1, in the sipeed.tcl script. We need to be able to control this via haskell.

The location itself is a static USB path that points to the JTAG interface. These paths can be shown using lsbusb -t where 1-5.1:1 means:

/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/16p, 480M
    |__ Port 5: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
        |__ Port 3: Dev 20, If 0, Class=Vendor Specific Class, Driver=, 12M
        |__ Port 3: Dev 20, If 1, Class=Vendor Specific Class, Driver=ftdi_sio, 12M
        |__ Port 1: Dev 4, If 0, Class=Vendor Specific Class, Driver=, 12M
        |__ Port 1: Dev 4, If 1, Class=Vendor Specific Class, Driver=ftdi_sio, 12M
        |__ Port 4: Dev 9, If 0, Class=Hub, Driver=hub/4p, 480M
            |__ Port 4: Dev 13, If 0, Class=Hub, Driver=hub/4p, 480M
                |__ Port 1: Dev 14, If 1, Class=Vendor Specific Class, Driver=ftdi_sio, 12M
                |__ Port 1: Dev 14, If 0, Class=Vendor Specific Class, Driver=, 12M
                |__ Port 2: Dev 15, If 0, Class=Vendor Specific Class, Driver=ftdi_sio, 12M
                |__ Port 2: Dev 15, If 1, Class=Vendor Specific Class, Driver=ftdi_sio, 12M
            |__ Port 2: Dev 11, If 0, Class=Vendor Specific Class, Driver=, 12M
            |__ Port 2: Dev 11, If 1, Class=Vendor Specific Class, Driver=ftdi_sio, 12M
            |__ Port 3: Dev 12, If 1, Class=Vendor Specific Class, Driver=ftdi_sio, 12M
            |__ Port 3: Dev 12, If 0, Class=Vendor Specific Class, Driver=, 12M
            |__ Port 1: Dev 10, If 0, Class=Vendor Specific Class, Driver=, 12M
            |__ Port 1: Dev 10, If 1, Class=Vendor Specific Class, Driver=ftdi_sio, 12M
        |__ Port 2: Dev 17, If 1, Class=Vendor Specific Class, Driver=ftdi_sio, 12M
        |__ Port 2: Dev 17, If 0, Class=Vendor Specific Class, Driver=, 12M
    |__ Port 7: Dev 3, If 2, Class=Mass Storage, Driver=usb-storage, 480M
    |__ Port 7: Dev 3, If 0, Class=Human Interface Device, Driver=usbhid, 480M
    |__ Port 7: Dev 3, If 1, Class=Human Interface Device, Driver=usbhid, 480M
    |__ Port 9: Dev 5, If 0, Class=Hub, Driver=hub/4p, 480M
    |__ Port 11: Dev 7, If 0, Class=Human Interface Device, Driver=usbhid, 12M
martijnbastiaan commented 2 weeks ago

Perhaps we could pass these in using environment variables? I.e., something like:

USB_DEVICE="1-5.1:1" gdb the_script.tcl

The TCL could then do something like:

set usb_device [env USB_DEVICE]

if { $usb_device == "" } {
    error "Required environment variable 'USB_DEVICE' is not set."
}
lmbollen commented 2 weeks ago

@martijnbastiaan How would we then open multiple jtag devices at once?

martijnbastiaan commented 2 weeks ago

We're currently using withCreateProcess, which takes a CreateProcess. Each CreateProcess can pass its own environment variables (env). I.e., you would start OpenOCD multiple times, each with its own environment variable.

lmbollen commented 2 weeks ago

Ah interesting. Currently @hiddemoll has a working implementation, but that seems like a way simpler approach. You'll see the PR soon I think