Closed jmdevy closed 2 years ago
The file system is not initialized by the emulator. If you want to have a file system, you'd need to create it yourself and make it available in a specific location in the simulated flash memory.
For MicroPython on the Raspberry Pi Pico, that'd be littlefs at flash offset 0xa0000, with a block size of 4k and 352 blocks.
What project are you working on?
OK,
So I can use littlefs to create a filesystem starting at 0xa0000 for 352 blocks at 4kB per block.
I have been able to successfully write files that MicroPython can see using the code you provided before: https://github.com/wokwi/rp2040js/issues/81#issuecomment-932823793; however, I still get Errno 19
when creating files in MicroPython (step 5).
Here are the steps I use that allows MicroPython see files but still fails on MP file creation:
flash
using littlefs.wasmflash
to emulator flashHere's the code for step 2:
console.log("Flash FS copy started");
littlefs._lfs_unmount(lfs);
littlefs._free(lfs);
littlefs._free(config);
rp2040.flash.set(flash, 0xa0000);
console.log("Flash FS copy ended");
I thought your name was familiar :)
For proper writing to flash, you'd need to implement the SSI peripheral (see section 4.10 of the datasheet)
A workaround would be to patch the flash_range_program
function from the bootrom. MicroPython uses that function to write to the Flash.
The details of that function are available in section 2.8.2.1.3.
You could also compile your own version of the bootrom, and replace this function with your own implementation.
How did the wokwi simulator do it? I'm guessing the bootrom workaround? I noticed that files can be created without the error.
Yes, the bootrom workaround. I was too lazy to implement the SSI peripheral (thought that's obviously the better solution)
Does that edited bootrom code live anywhere? Still not clear exactly what's wrong with flash_range_program
link (sorry if it's apparent, not as advanced as you).
Don't worry about many asking questions. It's not an easy stuff, took me a while to figure it out too.
Nothing is wrong with flash_range_program
. But instead of implementing the SSI peripheral so I could properly "talk" with this code, I replaced this function with a breakpoint instruction (asm("bkpt 27");
). Then, the simulator catches this breakpoint instruction, and does the writing to flash.
When hitting that breakpoint, you'll find the parameters of the function in the r0, r1, r2 registers. They'll tell you where to write the data in the flash (addr
), how many bytes to write (count
), and where to find the data in the RAM (addr
).
At that point, all you have to do is to read the data from the RAM, write it to the flash, and return to the caller (by copying the value of the LR register to the PC register).
Looking at the bootrom's code, it seems like implementing the relevant part of the SSI peripheral should be too hard as well. It might be even easier than my workaround. If you want to try that and need some pointers, please let me know.
Clever.
I replaced flash_range_program
in the bootrom with asm("bkpt 27")
then complied and verified it works with the emulator.
How do I figure out what opcode to look for? It should be the last one executed in here, right?
This one: https://github.com/wokwi/rp2040js/blob/f0eabd0b1c7c71fb9a053e7cd75dcbe5dfb81f4f/src/rp2040.ts#L965
Note that it calls onBreak()
with the argument for you, so you can just override onBreak with your own implementation that checks if the argument is 27
Is this about what you meant?
this.onBreak = (code) => {
// TODO: raise HardFault exception
// console.error('Breakpoint!', code);
// console.log(code);
if(code == 27){
const flashAddr = this.registers[0];
const ramAddr = this.registers[1] - RAM_START_ADDRESS;
const count = this.registers[2];
this.flash.set(this.sram.slice(ramAddr, ramAddr+count), flashAddr);
// Copy LR to PC register
this.registers[15] = this.registers[14];
}else{
this.stopped = true;
}
};
File creation works through MicroPython now but only if I don't set the stop flag. Does this have to do with how I copy LR to PC? Should it be done in the bootrom? I'm not sure it matters if I copy LR to PC if I just don't stop the emulator, but I guess this means I get rid of the potential to use breakpoints in some cases?
That sounds right. You can probably rewrite the last line before the else
as this.PC = this.LR
for clarity, but it'd still function the same. It will probably even if you don't copy PC to LR, I haven't tried but I see no reason why it wouldn't.
I wouldn't worry too much about the potential use of breakpoint. You still have 254 available "codes" for breakpoints. If I remember correctly, GDB always uses 0, so breakpoints in GDB still work.
Do you know if the littlefs.wasm package you made exposes directory functions?
For example, lfs_write_file
can be called from JS through
writeFile = littlefs.cwrap(
'lfs_write_file',
['number'],
['number', 'string', 'string', 'number']
);
Which I assume relates to this in littlefs
Does that mean I can do something similar for making directories based on this? I assume the way you compiled littlefs with emscripten needs to include some export flag for the function?
I made the source code public, so you can have a look: https://github.com/wokwi/littlefs-wasm.
Most of the API is exported, and you can play around with test.js to experiment with different functions.
One day I may even get around to adding a REAMDE file there :)
Thanks, I'll take a look!
rp2040js: 0.14.6 MicroPython: 1.17 OS: Windows 10
Steps to reproduce:
git clone https://github.com/wokwi/rp2040js.git
cd rp2040js
npm install
npm run start:micropython
f = open('test.txt', 'w')
Corresponds to filesystem not mounted: https://forum.micropython.org/viewtopic.php?t=1855#p10444