 Okay, let's see if we can get this loader working. I have found an emulator, which is this, with the rather stupid window that doesn't want to drag very well. That wasn't doing that before, maybe it's my screen recorder. Well, it does seem to work. It's a Windows program running in wine. It provides a GDB interface that I've got hooked up over here so that I can actually debug things. And miraculously, yeah, let's not touch that again, I think, miraculously I can even point it at the symbol table for our program here. So if I run the program, it immediately breaks into it over here in the debugger and we can step through and see why it's not working. So we can watch it, okay, that's weird. So we can watch it start enumerating the volumes, then it tries to actually open the file itself. Unfortunately, the way I've compiled it means that we don't get to see any of the error numbers, but we can see that it's immediately stopped working, hang on, it wasn't doing that before. Well, as far as I'm aware, it's going straight from here to here and exiting. So I believe that means that it is failing to load the file. So that's probably to do with the path. Let's just try putting a forward slash on and I will turn off optimization, which should generate better code. We should be able to build it. You'll also copy the proc file into the simulated SD card. Luckily, this has this nice system where you can pretend that one of the SD cards is actually in a directory on the disk, which is really useful, okay. So now I believe I need to reset the emulator. This should, okay, the debugger's died. Let's just kill that and restart it, I think. So we need to point it at the binary, point it at the source files and tell it that we're using the palm pilot as the target, okay. So we go to applications, data run, and then it immediately breaks into the program. So that's not single stepping properly. That is indeed not single stepping properly. Well, that's annoying, okay. So I think we do need, let's try OG, OG applies basic optimizations that don't interfere with debugging. Maybe I need A minus G here. No, apparently I don't. Okay, so now I've rebuilt it. This, the debugger should spot that the binary's changed. Okay, so that's reset the emulator. Yes, we do want to load the new symbol table. Continue. Okay, that is not working very well at all. Let's see if I can reconnect. Okay. Right, now we hit the program. Can we single step? No, we can't. Typical, okay. Dear target, okay. Well it's here to be able to single step with instructions. We are at least stepping now. So we've got to, we've done the enumerate. We should be around here now. I'm not sure why it's suddenly gone to, it's showing me line 51, which is down here. I assume that's spurious. And then it exits. Yes, I do not believe the debugger is doing a particularly good job of mapping the, the source it can see here with the actual program. So we're going to have to go to the machine code view. Right, so we're actually, so this is the comparator here. Actually, you know what? I'm actually, I'm going to start again from the beginning of the program. So this, right. So we are up here. This trap 15 is going to be the call to volume enumerate. I assume. So we're expecting to get to D6. It's going to try to enumerate the volume, retract over the parameters, compare the, compare the result to zero, which is a none. If it is not zero, then jump to the end. Otherwise, we go down this code path. So we want to go to D6. Right. We're at D6. We're here. We are now calling file open. So let's just do some more disassembly. The terminal is not working right. If I just do disass that will disassemble the entire function that we're in. So, okay, here is our comparison. Here is where we call file open. So we expect to get to F8 if it's correctly opened the file. Right. It's jumped ahead, which means it's gone to error here. No, it hasn't. It's gone to here because this comparison has failed, which means it has not found the file. So we're now at 1CA, which is here. And we are going to, right, we're at the bottom of the while. It's going to compare VI with VFS iterator stop and either jump back to the beginning or terminate. So 1D0 is where the comparison is, which is there. And it hasn't taken the branch, which means it has not found any more volumes. Okay. So it has tried to look for the file and hasn't spotted it. The file is in here and it's called kernel.image. So this path is incorrect. I don't know how Palmos paths work, to be honest. I'm going to have to go look that up. So I found here in the Palmos program as companion and a discussion of file names. And it says all paths are volume relative and absolute within that volume. And the root directory is a forward slash. So I would have thought that this would work. However, given the way that this loop is only going once through the... This loop is only going around once. This implies it's only finding a single volume. And there should be at least two volumes on this system. I got a file manager, files. So if we run that, we can see that there are two volumes internal and pose slot one. And there is our file. So that's a little interesting. Why isn't it finding both volumes? So let me go look up VFS volume enumerate again in the reference. VFS volume enumerate. This is the volume... FileOpen wants the volume reference number, which is the first parameter. And here is the sample code. So we're starting with VFS iterator start. We loop until it's VFS iterator stop. Yeah, this code looks correct. So that's peculiar. I would like to know what this value is. So build and... Oh, G is not supported. I didn't spot that last time. I think we're going to have to do OS. OS means small as possible code. Okay, reset the emulator. Load new symbol table. Okay, waiting. Run. So this is our function disassembly. We want to run to... This is where we're calling enumerate. So this is file open. So if we want to stop there. Okay. Hey, and we even have the right line number. Can we print E? No, we can't. Can we print D0? 2A0E. So now I need to find out what error that is. So I'd expect it to return one of these values. I think they are hash defined. So they won't have symbol values. BFS error, bad name. No. Okay. Oh dear, they're constructed error numbers with complicated definitions. So VFS error class. It's that 2A. Yes, it is. Okay. So 2A0E is error 0E or 14. In the VFS set. So VFS error, bad name, invalid file name, path, volume, label or something. Looks okay to me. Maybe it doesn't want the slash after all. Okay. Great. Now the debugger's crashed. Yeah, there's something not right about the debugger. I seem to have to press return twice after each command. I don't think it's buffering properly. Target. And you also want to set the directory. Okay. Home run. So again, we want to run until this is volume enumerate. This is file open. So we want to run till there. Do we have an E? We don't have an E. Do we have a D0? Same thing again. It just doesn't like the file name. Right. So let's do something different. Data. We don't want to read data. What I want to do is... Here we go. What I want to do is to enumerate the root directory and see what files are actually there. So it looks like we have to open the root directory with VFS file open. And then we can enumerate it. Okay. So that should be the name of the root directory and read. We then want to enumerate. Should be an example. Oh yes, that's useful. Name pointer is a buffer. Name buff len is the size of the buffer. This is the directory iterator which starts at VFS iterator start. While DI is not equal to VFS iterator end. VFS file. VFS dear entry enumerate directory file reference pointer to the iterator. Pointer to the file info. We're just going to call printf here. There isn't anywhere for it to go but it will force the buffer to not be optimised away. Okay. So that compiles. Reload the binary. Restart the emulator. That error always shows up. Okay. Apps. And it's not breaking into the debugger. Let's just restart it. File. Dear. Target. It's not breaking. That's somewhat peculiar. Okay. Let's just quit everything. Start it all up again. Dear. Target. Intriguing. Well now it has broken. It's failed from file open. You have a nice back trace. It's failed to open the root directory of our volume. Which is odd. File ref num must be defined. File ref yes. VFS mode read yes. File name is a slash. I mean it hasn't even failed an error. It's just like died. I still would like it if it would stop here and I could step through. And now of course it's not breaking at all. Fabulous. So something is different and I don't know what. VFS iterator start and stop yes. I wonder if it's the printf. It's possible that linking in the printf is going to make it try to. Create a studio program which. Is sort of supported although I don't know how to make it actually work. Dear. Target. Okay. Or not. Trap one should be a breakpoint. It should force the debugger to be entered. I don't know whether it does. But. File. Dear. Target. Apparently it doesn't. This emulator is ridiculously old. It's supposed to be open source except no one's been able to build it for years. All right then. I am going to look in to see whether I can get the studio model to work. Because if we can't debug it we're going to have to get information out of it somehow. And printf is preferable anyway. So apparently loading binaries via the emulated SD card isn't very reliable. So I have luckily found another way to do it. I did look into the studio stuff and it looks horrifying. So what I'm doing now is instead of copying the proc file into the emulated SD card. I should actually get rid of that copy. I am in fact just installing it via the debugger view. Debugger simulator menu. That gives me a built in application and I can run it. And I found this useful function called sys fatal alert that produces a dialog. So we can now re-enable all this stuff. sys fatal alert file buffer. Okay make. Install. Run. Okay. It has found something called palm. I expected that. That is in. Down here is the contents of the SD card. So it's found that. It's found hello.tex which is that. And it's found colonel.image. Okay it should be finding the, it should be finding our file. So let us lose all this. And then here. Still not C99. Install. Run. So it is not opening our file. Even though we can see our file names. Let's try that again with the forward slash. Aha aha. It has now successfully opened the file and then it crashes. That's good. Now one useful thing is there's this debug option. Actually you know I will just reset. Because I bet the debugger is now going to behave rather better. So that's built. File. Dear. Target. Install. Dana run. Yep. And it drops into the debugger. Good. Excellent. And now we're even debugging properly. So it's, we've opened the file. We figured out how big it is. This will fit into seven memory blocks. So we start creating them. Here are our pointers and they are not in numerical order. So we run Qsort. Did that actually run Qsort? Don't think it did. Does still seem to be out of order. They are indeed out of order. But we do appear to be now loading all our data. Yeah. And now we copy the bootloader into the last block. Yes. And now we're inside the bootloader. Right. So this has not sorted. Yeah. Because this doesn't give us the contents of each block. The contents of the array slot is giving us a pointer to the array slot. So we actually want to do this to dereference them. Okay. So now we build dereferencing. Yeah. These should both be like that. Unfortunately, we can't change the type of the comparator because otherwise we'll have an error when we call this Qsort. Okay. Right. Run. We allocate our blocks. Here they are out of order. Sort. Here they are in order. Good. So now we load everything into them. Set up the bootloader and we're in it. Okay. So now we can watch this and see how things go. So interrupt off. Why doesn't it like us turning interrupts off? Please don't tell me that the debugger in the debugger stub in the emulator is actually done in software. Because if that's the case, then turning interrupts off will make everything die. 74706. Yes. Turning interrupts off has meant that the debugger isn't working anymore. So we have in fact crashed here. Okay. We don't actually, we don't need to turn interrupts off here. We only need to turn interrupts off when we actually start doing the copying. Let's just put that over here. Okay. So if I set the program counter to 746F8 and set. Okay. We're now here. So D0 is the number of blocks. Step I, root D0. That's not a decent number of blocks. It's possible that the crash has in fact upset the stack pointer. Though I do slightly doubt it. So if I disassemble this, disassemble our program. And here is where we have called into the bootloader. We can see that the two parameters being pushed onto the stack, one of them is a long and one of them is a word, which was not what I wanted. I did define this as being, these was both being, but this is a pointer and is therefore a long. And this is a UN32. So that should not have produced this code. But here's another JSR. Okay. Am I doing it the wrong thing? I think. Yeah. That's irrelevant. That's fine. Okay. Here's pilot main. Here's our function here. So if we simply scroll down, there it's calling mem copy. Here is our, the code which is actually calling the bootloader. So we can see that it has pushed two, two longs onto the stack. And then we call our bootloader function. So we should see the second parameter here. Hang on. What order of these parameters being pushed in? Well, this is the number of blocks. And then it's pushing the address. So, right. In memory order, they are this way around. Okay. So if we then just step again to the next one, look at a zero. Yeah. It's got these the wrong way around. So that there are seven blocks. And the block array is at this address. Okay. Let's rebuild this. Let this fall over. Dear target. Okay. Reinstall run copy the bootloader that writes and we're there. Okay. So the first parameter is the address which is there. The second parameter is the number of blocks, which is there. So first we copy the block list down in here into safe memory. So we copy the address of the safe memory block. And then we start copying two, four, six, two, four, six, two, four, six. Right. We are here. We then write the terminating zero. We are now here. We are going to set up to actually concatenate the blocks together and go. However, we can't step past here. Let's just try continuing and see what happens. Okay. Right. That was a debugging feature of the emulator. It's spotted this application is writing to a place as it shouldn't. However, that is useful for us because it shows us that we just hit this. So if we continue, we can see it writing one word at a time. The emulator is very unhappy with this. Now it's just trying to read from zero. That's not right. Okay. Seven, four, seven, two, eight. We're here. So A2 is the source. That is zero. That's not correct. All right. I know what has happened. We've just done this. We've read the last block, but the loading the zero hasn't set the zero flag. Let me double check that. There's a useful reference to the instruction set here. So it's probably done a move A, which does not set the condition code. A normal move does. So plus 20, we are here. That's a move AL. Okay. So we're actually going to have to do a test LA2, I believe. Okay. However, we now know that we've finished doing the concatenation. So let's just set the program counter to here, which is seven, four, seven, two, eight. So we've now read the address of the first block to A0, which is there. So we jumped to here. Now this should be our emutos ROM ready to go. I believe that is. That looks right. It starts out with a branch. So let's just bring this up and continue and see what happens. I doubt very much whether this ROM, this simulator will run emutos. Yeah. Four E7B. Yes. That's a privileged instruction. It does occur to me that maybe we're not in supervisor mode. And maybe we do need to be in supervisor mode. If so, that's easy enough to sort out. This needs to be a little bit trickier here. But we should be doable. But I think that is now working. So let's just save this. I think I did change this. So I think we may have run out of stuff to do with the simulator. I am going to put this into supervisor mode. So what we need to do for this, the only way to get into supervisor mode from user mode is via a system trap. So what we're going to have to do is remember where I put my datasheet. We want to find the memory map, I believe. Here we go. Here are all the traps. No, wait. These are the addresses of the control registers. We want this one. Here we go. Here are all the startup vectors. All we're going to do is we write to address 080, which is the trap0 address. And a trap n uses vector number 32 plus n decimal. Yeah, trap0. So what we're going to do is instead of jumping to the address, we're actually going to write the address to trap0 and then do a trap0. So that will switch to supervisor mode and then jump to the address we first thought of. All right. So I will actually just, this needs resetting. We've just scribbled all over memory, so it's probably going to get upset. I wonder if our host FS is still there. No, it still seems to be intact. It's probably horribly corrupted, but reinstall our program and run is and we watch it scribble over memory. Probably turn these off actually. It will be watching the headers and footers of each heap block for memory corruption. Okay. Here we've just written to the trap vector. Continue. Trap0 machine language instruction. Yeah, the simulator doesn't know what to do with this. All right. Let's just go away. We're going to have to do a hard reset because we've just mangled everything. Our storage heap does seem to be intact. All right. I am going to get the real thing set up and put this thing on an SD card and then we'll see if it works. Here we are. I'm using the keyboard because of course the pen hasn't calibrated. We find Dana run and we press the return key and it immediately crashes. Yes. That's not helpful. Why would it be doing that? Or more accurately, why would it be doing this in the real hardware but working on the emulator? It's possible that there's some level of memory protection that the real hardware has that the emulator doesn't. That would certainly be annoying. It's possible that it's crashing before it actually even enters this code because something is different. Let's just put some sys alert things in and we'll see how this behaves. Let's just get rid of the emulator. We don't need that anymore. Sys fatal alert, not sys alert. Okay. Copy. Okay. Run. Right. I think that sys fatal alert is only working in the debug environment and isn't working on the real thing. That's annoying. But at least we know it didn't crash before that point. So that is, I think that on the real thing sys fatal alert is causing the application to immediately terminate. That's good because we can now try it like this. Because if it crashes now, then we know the crash is here. If it exits immediately, then it's hitting this line and not going any further. Oh, that's interesting. So that suggests, where did I put that? Yeah. That suggests that something's going wrong up here. So there should be room for nine blocks. We know the file's been opened, otherwise we wouldn't be getting this far. There must be an alert routine that exists. I'm going to go have another look through the docs. Okay. If all else fails, let's just draw stuff on the screen the hard way. So let's see how this works. We get the, we don't see anything. Maybe it's possible that stuff is that it doesn't have an immediate mode renderer. And that the graphics only appear on the screen after when the event loop is hit. If so, we'll have to do a bit more work. Yeah, I would expect to see at least something. So I think we need to handle some events. So we want to keep processing events until there are none left, I believe. And we should end up with a nil event. So we now need to look to see what kind of event this is. Okay. So hopefully that something in there will cause the graphics to appear. And I'll actually just put that there as well. And nothing. Great. There's a possibility that the, the fatal error dialogue is causing the text to go away. Let's see just removing some things. Goodness, this is faster than doing a serial upload, even if it is still pretty annoying. Interesting. So does the program actually work at all? Right. Apparently it doesn't. Now, I did actually see crashes like this in the simulator. Actually, I can probably demonstrate for it to start up. That was not what I wanted. Yeah, I think the state here is somewhat corrupt at this point. So install Dana run.brook. Okay. Run it. Okay. Well, I did see crashes. I think it doesn't really like dropping off the end. I put this in because I thought it needed it. I wonder if it in fact doesn't. So I can't quite tell whether anything actually is appearing on the screen. But this should, this should touch the SD card. And so it should take a little bit of time. Okay. That is actually now printing stuff. Install allocating blocks, which is here. So we now know that this program runs on the simulator. So let's get rid of the simulator. Try it on the real thing again. And we get an exception and nothing on the screen. So my suspicion is that this is not actually starting up correctly. And I may have to actually write a real program. Okay. So I am going to go away and put together a simple but minimal program that just displays something on the screen and waits for a button press using like the actual event loop. And see if I can persuade it to work on this. So I think I figured out what's going on. And it's the same problem we were seeing with the emulator. So Parmos doesn't actually support running applications of disk. You have to copy them into internal memory into what it calls the storage heap before they can be executed. And this means that when you run an application of the SD card, what it's actually doing is copying the binary into the storage heap and running it there. And I think it's caching old versions of the executable and isn't updating it when a new version shows up on the card. So the solution is to do the same thing that we were doing with the emulator. And rather than running Dana run of the card, we install it into the internal memory, which luckily we can do with USB and the PilotX for Linux program. So I run this, press the button and it's done. And now I can go and find the actual program, run it, and now we get our tracing. And it's actually getting all the way up to starting the bootloader before it crashes. So the next stage is to try and figure out where it's crashing. And there's a simple debugging trick we can do here, which is to simply jump to the current address. That will cause a hang. So fire up HotSync again. Okay. So now when we run it, what happens? Okay. So it hasn't hung, it's actually crashed. This means it hasn't got this far. It must be crashing somewhere else. So let me think I know where it's crashing. Let's put it there. You have to reset this. So I think that this block of memory is read only. So attempting to copy the list of blocks into our address base down here is failing. No, of course it's not read only memory. We actually, this is running of memory we've allocated off the heap. So it is read write memory. Like we've just copied this bootstrap loader into it. Let's try this anyway. Find the wrong one. So I still can't quite see the screen. Why does it keep doing that HotSync and run it? Okay. It's hung. This means it's reached this point. So why is it... So it's failing to do this copy. Right. I bet that means that it's trying to do something with read only memory. Because the very simple memory system in this thing can be set up like that. So what would the solution be? The solution would be to disable the memory protection. Okay. Let's figure out how to do that. So we want the chip select logic. Actually, let's try the minimum possible. Let's first let's try the minimum possible code to reproduce the crash. So let's just put our branch here just in case this turning interrupts off is causing problems. Build. Okay. And that hangs. That means that we've reached here. So the thing that's actually failing is this code, which is trying to actually do the copy. So it's you it clearly is using some kind of memory protection trick to ensure that you don't overwrite resources that are supposed to be read only. Okay. Okay. So we've got our chip select groups. Sorry, our chip select registers. Now there are read only bits here we go. And we did see lots of code in the disassembled ROM to do with making memory writable. So yeah, let's take a look at that. Shall we? I'll I haven't fired up Gidry yet. We'll just go and do that. Well, here it is enabled data rights and it is not complicated. All we are doing is fiddling with chip select D, which is the one that the RAM is on the DRAM is on. And let me see if that bit is not set to 0010 R op read only for protected memory block. Yeah, that is. Yes, you can either specify that the entire block that the chip select register is referring to is read only. Or there is an area which is which is read only. And what this is doing is checking to see whether it's in that particular configuration. And if it is, it masks out. Let me see D is 1101. Right. It turns that bit off. Okay. Now, before I actually do anything involving hardware registers, I think that we can actually just call this function directly to do it from here. So that will be we want to call this particular trap. There should be a function for it. Here we are. Hardware enable data rights. That should allow us to know apparently there isn't don't see anything that looks like a header for that unless it's this. Right, you see this is it's found the it has found the prototype, but it's failed to link it, presumably because I need some kind of library, which could be any of these. So let's just not bother. Go into here and just do the trap directly. And you do need to figure out what trap it is. I'm constant a 24 a if we it is trapped 15. Okay. So and we've put our branch here. So this should hang up. Well, that wasn't quite what I was expecting to see. Let's try putting the whole there just to make sure that it is calling. This trap hardware enable data rights correctly. I got the screen almost calibrated. I'm having to touch to the left of where everything is to make it work. Okay. So that's worked. So the question is now why is it crashing the same code on the simulator quote worked unquote. So we could be passing in something wrong here. I don't think we are something could be going wrong here. So this is the number of word transfers. This is then doing the transfer. I remember something about some kind of long operation not working on the base 668,000. Don't think that's relevant at this point. I think that's a. Yeah, I think that's a different thing. I think that's got to do with indexed addressing. Well, that was an adventure. That jump cut happened to contain several days worth of work. I did go and investigate the debugger and I have figured out how to start the debugger interface on the Dana. Unfortunately, it doesn't seem to talk to anything in the outside world. I suspect that the Dana's emulation of a USB keyboard is interfering with that. So I can't actually use the debugger to debug anything on the Dana, which is annoying. However, after way too long, I remembered that we do actually have a serial port. It's like on the debug board. So by initializing the serial port, I can write out tracing from within my bootloader. This is the serial terminal here. It has printed this, which is the address of my safe memory that's appeared here. No, it's not. It's the address of the entry in the block list. Then it's printed a Q, but it hasn't printed a W or a Z. And this tract has isolated the problem to this instruction. And if I go and look at the test instruction, I see that it supports nearly all addressing modes except address registers. So that is producing exception. It's an unimplemented instruction error. Turns out the stock 68000 does not support this. And as I forgot to tell the assembler that I'm using a stock 68000, which I believe is this, yep, I didn't get an error. So runtime crash it is. Yay. Okay, so let's get rid of some of this tracing. This is going to be, I presume I compare. Yeah, compare works. So I can do compare long zero against 82. That will do the same thing except it won't crash. Let's lose that. Let's lose that. And let's lose that. So, yeah, comma. Okay. And I also discovered a much easier way of doing hot syncing to upload the new program, which is that there is a hot sync button on sync. It's this one here. So you function that and it does go straight into the thing. Okay, so backlight, backlight on. Press the button. Not that one. Intriguing. Well, this is actually good news because it means that it's done something. What probably happened is emutos has splurged data all over the Parmos frame buffer. However, emutos is supposed to have, is supposed to have reset its screen. So that looks like it's crashed somewhere. So let's just stick some more stuff in here. So actually let's, we can do some decent tracing here. Let's put some of this stuff back. So we're going to print the source address, which is an A2, and the destination address, which is an A1 for each block. And then once we've finished, we will print a Z. So sync. Okay, that's interesting. That looks right. Six blocks. Yep, because remember that we haven't copied the first block. So this is actually seven blocks. One D7E2 is the end of the first block. So that should work. And then at the end we get zero, which we then go from here to finished. And then this should actually start the code. We don't get the garbage on the screen that we did last time. So let's do that. That will then dump the address of the address that we're calling. That's the sync mode. So this is the address that it's actually called. That is wrong. The address should be looking at the pattern here, one five A7E. So that's why it hasn't done anything. Are we using D0 for anything? No, we're not. So we can simplify this like this. So this is then copying D0 number of block addresses into the array at A1, which starts at blocks. So what's wrong with this code? All right, what's wrong with that code is that my tracing is incorrect. It should be that. I was printing the address of the block array rather than the address of the first block. So that is the right address. I believe that it is called the right thing, but nothing's actually happened on the data. And we have got no further tracing out here. One five FEC is quite low. Our ROM is compressed. If it is decompressing, it decompresses to, well, dressing to 240, I believe, 240. And it's the compressed ROM is that big. However, the, wait a minute. I'm copying the wrong ROM onto the SD card. I've copied the uncompressed ROM that is supposed to load at 240 rather than the compressed ROM that relocates itself to the right address. So let's just fix that. You just double check. emutostdainer.rom is the one I want. emutostdainer.rom. Okay. Okay. So it's mounted the SD card. That's what the beep was. So turn on the backlight to make it more visible and it crashes. Okay. Now, so this is the point we were at before. The start address of the code is here, and our ROM is actually this long. So as we decompress and relocate the ROM, it's possible that it's overwriting the decompressed data itself, which will cause horrible things to happen. And the simplest way to do this is to not decompress, is to not compress the ROM. That means that as it gets copied, no, that's annoying. So this is our ROM header, which contains the code needed to do the decompression. So I think what we need to do is this. So what we've done is, okay, what I was trying to do is to move the relocation code to the end of the ROM after the relocation data. We probably then want to change this to be the non-compressed version. That means that no matter how big the ROM was, we would never overwrite the relocation code. But it's hard to jump from the beginning of the ROM to the end of the ROM using position-independent code. We would probably need to... So this would need to be program-counter-relative. I'm trying to remember how to do that in this assembler. I think it's this. No, it's not. Okay, that actually did it. The program-counter-relative addressing is done automatically for you. So what that does is this word contains the offset between entry and relocate. So we fetch the address of entry, which is a program-counter-relative thing. We then add on the value here, and that gives us the address we want to jump to. However, we probably don't want to use this code as it inflates the code. It will get bigger, so there's more of a chance of overwriting the version of the ROM that Parmos has created. So what we're actually going to do is just this. We don't need inflate anymore. And all this code is going to be is... DAC pointer... That should be a 4. Hopefully that will be small enough. I want to copy from the source to the destination. pf d0,1 back... Okay, is that working? I think it could be. Let me just... Yes, that fits. So the issue here is that, as we're copying a word at a time and using dbf, if the ROM is bigger than... the size has to be in a word rather than a long. So if this is too big, then this loop won't work. Okay, so Dana boot now depends on the non-deplated version. We don't need Zopfli anymore. The ROM is now bigger. Well, it's the same size as the ROM we were mistakenly using before. So now we're not transferring via serial port. It's much easier to work with. So copy, backlight. There we go. And it still crashes. So it's possible that our ROM code is wrong. Luckily, there's an easy way to diagnose this. All we need to do is let's just cut and paste all of this into here. We also need our registers. So we do want to set up the stack. We do anything. And now we can do... We can't do a BSR. We can't do a BSR for the same reason that we couldn't before. We're having to jump over the very large ROM. But we can work around that for the time being by putting these routines before the ROM. So now we can do putCNL. So now we should get a queue. And I'm actually going to do modelA0.E7. Put x32.NL. So that will then print the address that we're jumping to. Because that's the most likely thing that is wrong. Now let's try it. And what did we get? We got a queue and we got a 4CEDA. So this is the beginning of the ROM that is entry. That's where we've jumped to. And this jump is trying to go to relocate which is here. So was that correct? Well, relocate is at 369C. 369C minus the start address of the ROM is at 163E. And put that in hex. Hang on. Hang on. Want this one? 4CEDA. Right. It has jumped to the right place. So let us verify that we've actually done this. By taking out that code and then moving all our serial port stuff back underneath relocate so that we can call it with a BSR. Okay. So we should get a P before the copy and a Q after. However, we do not get a P. That suggests that we are in fact either jumping to the wrong place or there is something wrong with that address. Okay. Let's put things back the way they were. Like that. So that's going to print the address that we're jumping to and then read a word from that address and print that. So we should then be able to look at the disassembly and verify that the address we're jumping to contains the bytes we think it does. It does in fact contain zeros, which is wrong. So relocate is 36DA8. 36DE8, was it? Plus 0x1613ED8. 36DA8 is 4CEE6. That is the address that things have jumped to. So this suggests that we are not assembling our ROM correctly in memory, which puts us back to this code here. It's possible that my use of dbf here is incorrect. dbf doesn't... dbf jumps if the result is zero, not less than zero. So let me just double check this. Right. No, it doesn't. It jumps if... It does the decrement and then jumps if negative. So that means each time round it loops one extra time than you would expect. So you have to subtract one from the count. But honestly, I'm not particularly happy with that. So let's just turn that into a normal loop to be sure. So that's part of Dana Run. So we transfer it using hot sync and we got this. Well, that's definitely not the code we expected. That looks like an address in the bottom three bytes and something else in the top. Something is still wrong. Well, if all else fails, we can do this. We are going to copy the destination address and print it. Then print the byte being copied. So that now when we run it, it's going to dump the entire ROM that is going to dump the entire set of data that it's copying. So we can look to see what's different. And there is quite a lot of it and it's going to dump quite slowly. So I am going to cut until that's finished. Well, that took forever but here we are. Here is the copied file. And it's important to remember that the... Where is it? That this code that shuffles all the blocks together is always working in terms of 32k chunks. So as the last chunk is incomplete because it's the end of the file, we do have garbage after it. So this is the load address. So let's find... We have 36dbc. 36dbc plus the load address is 15fbc. Which means 4cd88 is the last byte... Well, the byte just... Yeah, that is the last byte of the ROM. And this is in fact not correct. So what we're going to have to do, this is try and find where the last byte of real code is. So 4c200... Let's use this as a... So x4c200 minus 15fbc is at 36214. So x000045... Okay, 4578... 4578, that looks correct. So where are we? 4578 is... Okay. So if we now go to 4c302, it's 69 and we now go to 36316. Or the closest we can get to... Variable length instructions, yay. 6973, 6973, that is correct. So again, 4c402 is here. 36412, 7065, that does not look right. I wonder... It'd be nice to be able to convert this left-hand column into the source addresses. How do I do hex in... Okay, stir it into the leading. Yep, okay. So stir to num0x like that. Okay. Minus 0x1fivc, printf08x0x0x... Actually, these three want to be strings. Okay. Yep, I should have done that. Considerably previously. So the left-hand column is now the offset into the image destination address, source address and value. So 36dbc, 36dbc is incorrect. 36007374 is correct. 7636a205b is correct. 3708b is not participating in this file. 36b63 is 672036c004eb9, yes. 36d002foa, yes. 36da2o1 is not correct. D9642078bf4c, no. D50226f, no. D30... We checked that D00 was correct. That's 2foa. Doa487a, ffc... Hang on, d002foa493, okay. 36d20 is incorrect. 36d18487a is incorrect. 36d10493, okay, that is correct. So, tracking it down. 508f4a406630, here. This is where it starts to go wrong. At 4cd04, which is at offset 36d18. What is magic about this address? So it looks like the file image is all present. Or is it? Okay, this is the... No, that's not it. This is the function we're using to actually read data. This contains a number of bytes that are actually read. So if it's not reading the entire file for some reason, then... Why would it not be? Well, the last block, of course, is incomplete. That's not correct. So size is the number of bytes. Okay, so once we've finished reading all the blocks, we look to see whether the file pointer is at the end of the file. And if it's not, we give up. Okay, so we run it. And what do we get? Right, it looks like it is successfully loading the entire image. It's now starting, it's dump again. So... So just thinking of things that might be corrupting that. There's... Overflowing the stack. But the stack is here. And we're doing very little. It's only used by the serial code. Our blocks are all 32k. We've allocated what I believe to be the right number. We seem to be reading the entire file. This is setting up the bootloader in the last 32k block. So that is kind of weird. Now, the obvious thing to do to verify that we've read the image correctly is to just write it out again to disk, and then look to see whether the data is the same. But let's have a... Look at this. So we have destination, source and the byte. You can see that by this point the source is now almost 256 bytes in advance of the source. Because we've just allocated a whole bunch of big blocks in a row, it's a pretty fair guess that our seven blocks are one immediately after the other. So we expect the difference between... the gap between them to be just the size of a block header. In fact, we can see that here. So down at the end we have source here and destination here. While at the top there are only less than... there are eight bytes apart actually. That means there's an eight byte header between blocks, which is reasonably small. This is copying bytes. Yeah, because we told it to. Okay, this will now list the actual... the addresses of each block being copied rather than every byte, which should be a bit clearer. So again, it is source, comma, destination. So A80 is in advance of A70, A96 in advance of yes, yes, yes. And then the last one, this is zero. We see that the source block is zero and we jump to finished and we're done. So I do not know... as we pass in the correct block count there. Okay, let's dump the blocks to a file. If the fs file opens, yeah. Out of the image. fs mode... fs mode truncate. fs mode write. That is not as less than or equal to block count because we want to write out the boot block as well. fs file write. fs file block size. blocks a null. close a far. Okay, so that should have done the right. So let's take a look at it on the SD card and see what there is. We have a file that looks to be about the right kind of size. 224536 is the same size as kernel.image. So out.image contains all the data of kernel.image plus some stuff at the end. That's the emutos code. I expect this to be the beginning of the boot block code which looks about the right kind of size. So that makes... there's some very suspicious looking strings in here. Where is our... what address is our relocate? 3688. 3688 is not executable code. So we should see 4FFAFFE. Yes, that looks interesting. It's possible that this is just... I need to recompile this. My source code doesn't match anymore because I've changed stuff. I know what is the... I can never remember the object copy syntaxes. minus target object format. And I also need 6,000. Yeah, here we go. So according to this, the last byte of the ROM is at 36dbc in this 4FFAFFE. So 36dbc... 36dbc is text. Well, those are different. Okay. So what was the thing I was using to actually copy the ROM? That looks plausible enough. Okay. Right, it still crashes. So 36dbc... 36dbc... Yeah, okay, 4EF821F0, 2140. That is the right instruction. So it looks like our ROM is being read into memory correctly. Oh, and in fact, if we look at this, that is indeed the right instruction. That's weird. I've seen this before a few times. I think something's not quite right with the way the file systems are hooked up. But that does actually look like it's called into the right place. 4CEE6 does not look like the right address, though. This is... We can get rid of some of this. No, that is correct. That has done the right thing. It just hasn't worked. I believe that we're now getting as far as entering the emutos kernel at 2140. So let me just double check my relocation code. So load A1 with 2140, which is our destination address. Load A2 with source. There's a relocation. We can't do that. That's why it's not working. Fabulous. So what we're going to do is... Actually, there's a much simpler way to do it. I was just going to do the relocation thing again. But we can do... You can do push effective address of data start. Here we just want to move A1SP into A0. Move A0 into A1. No, we don't. We want to put that into a... This is the source. So in fact, we want to put that straight into there. So we now have no more relocations. While at the beginning of the file, we also have no relocations. Right. I think that's better. So what was happening is that the relocation entry wasn't being relocated. So instead of loading the source register with the address of data start, it was actually loading it with some random piece of garbage. So it was copying... It was relocating the ROM into the wrong place. But then jumping to the right address, which that was never going to work. Okay. Let's see what this does now. Fantastic, and it still doesn't work. That will be because this should be that for a pop. The 68000 doesn't have normal push and pop instructions. Instead, it uses these addressing modes. So that is a push and... Sorry, that is a push and that is a pop. The only instruction it's got for pushing is PEA there, which is special. Okay. Fantastic. It works. It only works. That's brilliant. And we even have the serial console here. But let's just... Okay. We do actually now need to change disks. I will see if I can make this work with both cards in. That is still not working. Interesting. So I have a suspicion that the ROM... I have a suspicion that Emutos is setting up the system clock incorrectly, or rather not setting it up at all. We're just using the default values from boot. And I think it may be running at 16 MHz rather than 32. But PalmOS will be setting it up to run at 32 MHz. So all our timings are likely to be wrong. The serial terminal here is using the right board rate because we actually calculated the right board rate based on the PLL values. But the SD card may not be. So I think this could be running at 16 MHz. And it's possible that this is too fast and the card is not initializing. Let's just try changing that. Okay. That still looks unhappy to be honest. Okay. I actually think this is going to be more difficult to fix than I think. We've finally managed to get the PalmOS loader working, which is good. We can now start Emutos without needing a serial port. So that is like critical for anyone other than me to be able to use this thing. So as this video is actually incorporated multiple days worth of work rather than just the one evening session they usually are, I am going to call it here and do the rest of the debugging in a different video because this is long enough as it is and trying to edit this down to a reasonable length is going to be nightmarish. So I hope you enjoyed this video. Please let me know what you think in the comments.