Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Please add examples on how to use this module yowasp openfpgaloader #32

Open
ramalhais opened this issue Feb 13, 2024 · 7 comments
Open

Comments

@ramalhais
Copy link

An example of how to use this would be great! Thanks!

I tried this code:

async function loadModule() {
    try {
        // Dynamically import the module
        const module = await import('https://cdn.jsdelivr.net/npm/@yowasp/yosys/gen/bundle.js');
        
        // Once the module is imported, you can use its exports
        module.runYosys(["--version"]);
    } catch (error) {
        console.error('Error loading module:', error);
    }
}

// Call the function to load the module
loadModule();

but i get this error from the browser:

Uncaught (in promise) RangeError: WebAssembly.Instance is disallowed on the main thread, if the buffer size is larger than 8MB. Use WebAssembly.instantiate, or use the flag `--enable-features=WebAssemblyUnlimitedSyncCompilation`.
    at bundle.js:508:28
    at Application.instantiate (bundle.js:4460:28)
    at Application.execute (bundle.js:504:30)
    at Application.run (bundle.js:534:17)
    at bundle.js:531:46
@whitequark whitequark transferred this issue from YoWASP/openFPGALoader-web Mar 13, 2024
@whitequark
Copy link
Member

For the time being (until bytecodealliance/jco#375 is fixed) you must use a Web Worker to use @yowasp/yosys.

@whitequark
Copy link
Member

I've been working on integrating the jco updates but it's been a bit complex to test.

@ramalhais
Copy link
Author

ramalhais commented Apr 30, 2024

Here's what i did to make it run:

Create index.html:

<!-- Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
These are new security requirements for using SharedArrayBuffer.

You can check in code if cross origin isolation is enabled:

if (crossOriginIsolated) {
    // SharedArrayBuffer is available
} -->

<script type="module" src="main.js"></script>
<script type="text/javascript">
</script>

Create main.js:

// Create a new worker from a JavaScript file
const worker = new Worker('worker.js');

// Handle messages sent from the worker
worker.onmessage = function(event) {
  console.log('Message from worker:', event.data);
};

// Send a message to the worker
worker.postMessage('Hello from the main thread!');

Create worker.js:

async function loadModule() {
    try {
        // Dynamically import the module
        // const module = await import('https://cdn.jsdelivr.net/npm/@yowasp/yosys/gen/bundle.js');
        const module = await import('https://cdn.jsdelivr.net/npm/@yowasp/openfpgaloader@0.3.1-914.18/gen/bundle.js');
        
        // Once the module is imported, you can use its exports
        module.runOpenFPGALoader(["--help"]);
        // module.runYosys(["--version"]);
        // module.runYosys(["-m openFPGALoader"]);
    } catch (error) {
        console.error('Error loading module:', error);
    }
}

// Call the function to load the module
loadModule();

Then serve these files on a webserver:
python3 -m http.server

In chrome, install extension CORS Unblock, open a new tab, and enable CORS Unblock option: "Extra Options" -> "Append Headers to Allow Shared Array Buffer"

Access http://localhost:8000

You can see the output in the JS console.

Not sure how i can now use WebUSB and specify the device to OpenFPGALoader.

Hope this helps

@ramalhais ramalhais changed the title Please add examples on how to use this module Please add examples on how to use this module yowasp openfpgaloader Apr 30, 2024
@ramalhais
Copy link
Author

OK, i figured it out. Just ignore the bad coding :)
The file to be flashed is passed as an argument in filesIn (filename and data) to the module function, and the filename is passed as a normal argument in args.

main.js:

var selectDevice = document.createElement("selectDevice");

// Step 2 (Optional): Set attributes
selectDevice.textContent = "selectDevice"; // Set button text
selectDevice.setAttribute("id", "selectDevice"); // Set button ID

// Step 3: Append the button to an existing DOM element
document.body.appendChild(selectDevice);

        // let filters = [];
        // filters.push({ 'vendorId': 0x0403 });
        // filters.push({ 'serialNumber': serial });
        // navigator.usb.requestDevice({ 'filters': filters }).then(
        //     async selectedDevice => {
        //         await device.open();
        //     }
        // ).catch(error => {
        //         statusDisplay.textContent = error;
        //     }
        // );

let filters = [];
// filters.push({ 'vendorId': 0x0403 });
// filters.push({ 'serialNumber': '123456' });
// filters.push({ 'productId': 0x5678 });
// Each filter object can have the following properties:

// vendorId
// productId
// classCode
// subclassCode
// protocolCode
// serialNumber

selectDevice.addEventListener("click", async () => {

  // navigator.usb
  // .requestDevice({ filters })
  // .then((usbDevice) => {
  //   console.log(`Product name: ${usbDevice.productName}`);
  // })
  // .catch((e) => {
  //   console.error(`There is no device. ${e}`);
  // });

  await navigator.usb.requestDevice({
    filters: filters,
  });

  // const devices = await navigator.usb.getDevices();
  // for (const device of devices) {
  //   console.log("Opening device: " + device);
  //   await device.open();
  // }
});

// Create a new worker from a JavaScript file
const worker = new Worker('worker.js');

// Handle messages sent from the worker
worker.onmessage = function(event) {
  console.log('Message from worker:', event.data);
};

// Send a message to the worker
worker.postMessage('Hello from the main thread!');

worker.js:

async function loadModule() {
    try {
        // Dynamically import the module
        // const module = await import('https://cdn.jsdelivr.net/npm/@yowasp/yosys/gen/bundle.js');
        const module = await import('https://cdn.jsdelivr.net/npm/@yowasp/openfpgaloader@0.3.1-914.18/gen/bundle.js');
        
        console.log("Listing USB devices");
        const devices = await navigator.usb.getDevices();
        for (const device of devices) {
            console.log("Device: %o", device);
            // try {
            //     await device.open();
            // } catch (error) {
            //     console.log("ERROR:", error);
            // }
            
        }

        // console.log("runOpenFPGALoader: %o", module.runOpenFPGALoader);
        // module.runOpenFPGALoader(["--help"]);

        // Once the module is imported, you can use its exports
        // console.log("OpenFPGALoader Scanning USB devices");
        // module.runOpenFPGALoader(["--scan-usb"]);


        const fileUrl = 'next_kms.fs';
        var fileContent;

        await fetch(fileUrl)
            .then(response => {
                // Check if the request was successful
                if (!response.ok) {
                    throw new Error('Network response was not ok');
                }
                // Read the response body as ArrayBuffer (binary data)
                return response.arrayBuffer();
            })
            .then(arrayBuffer => {
                // Create a Uint8Array from the ArrayBuffer
                const uint8Array = new Uint8Array(arrayBuffer);
                fileContent = uint8Array;
                // Do something with the Uint8Array, for example, log its length
                console.log('Length of Uint8Array:', uint8Array.length);
                // You can perform any processing with the Uint8Array here
            })
            .catch(error => {
                console.error('There was a problem fetching the file:', error);
            });

        var filesData = { "data.fs": fileContent };
        // console.log("filesData: %o",filesData);
        const moduleArgs = ["-b", "tangnano9k", "-v", "-f", "data.fs"];

        console.log("OpenFPGALoader Flashing");
        module.runOpenFPGALoader(moduleArgs, filesData);

        // module.runYosys(["--version"]);
        // module.runYosys(["-m openFPGALoader"]);
    } catch (error) {
        console.error('Error loading module:', error);
    }
}

// Call the function to load the module
loadModule();

@ramalhais
Copy link
Author

You can check working example at https://ramalhais.github.io/openfpgaloader-webflash/

@whitequark
Copy link
Member

Hm, I feel like there should be a way to do it without SAB.

@whitequark
Copy link
Member

For the time being (until bytecodealliance/jco#375 is fixed) you must use a Web Worker to use @yowasp/yosys.

Good news: I've tested the changes there so you should be able to use @yowasp/yosys without a Worker soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants