 So, it's day 13 and after the staggering display of an aptitude, last time trying to make random access writing work, let's try and make random access reading work. This should not actually be as difficult as for writing because I don't believe we have any nasty low-level bugs that need fixing, which is honestly what took most time, and also we can reuse a lot of the code. So, the stuff we need is basically all of this. This is the code that computes the module extent record number from the random access pointer and switches to the new extent. That is all perfectly common. So, we're going to do a... we already have some seeks. So, seek to random location, let's use point to the random access location, shifting the extents as necessary. So, that is this code. So, we're just gonna go and paste it like so. So, we do actually need to cope with errors because, well, to honestly, this can... this can fail. So, we're just gonna put in the exit. Clear carry here. If carry is set, stop. Actually, there is a error code for this. I actually went through and collected all the CPM error codes. Error reporting in CPM is kind of hit and miss. Actually, I will put these in here. So, this is a enum, CPM errors, and enum. Just for the namespacing, in case these should all be dollar signs, no commas, these should all be semicolons. Okay. So, if we... if we're doing random access operation, we can't write the old extent back to disk. It actually returns with a specific error. So, this is gonna be LDA. CPME can't close. PCS exit. This one is going to be CPME are no dear full directory full. No, it's not. It is dearful. And this becomes exit. I am just wondering, can we rely on the error code being returned by these? Probably not. Also, I need to go through and do a pass and fix all the error handling, which is just basically bogus, secot2, random location, PCS exit. Okay. So, this is only for writes. Okay. So, for a read, we do entry read random, convert user FCB, seek to random location. We are gonna want to copy this code and then modify it. So, if current record is greater than RC, then we need to return an error code. So, we take out the add1. So, if current record is greater than the record count, then instead of updating the record count, we set this to no data, I think it's called. No block, no block. And return. Then we want to do the read. I'm not sure that's right. Seek to block here. I believe this is going to try and allocate a new block, which is not what we want. And wait a minute. Read sequential here. This is the code that we want. Seek to block we want to rename. Seek to block actually is only used on the code path that creates a block. So, we're going to rename seek to block to seek to block and create. Okay. So, our read sequential code here, no here. We are going to copy this code. I'm going to copy all this code. We do not want to move the FCB on. So, we get the disk block in XA. If it is zero, then we fail with a no data error. This is not necessarily right. So, the issue is this create file down here. On a read, we don't want to create a new extent. We only want to do that on the right path. So, on a read, we actually want to do the open file. And then, if it fails, return an error code. So, we want all of this code except for create file here. Okay. So, if we fail open file, then we're going to return no extent. In our write random code, then we do seek to random location. We are going to test for carry set. Is this a failure? So, test for no extent. If so, make a new one. And in fact, if I'm going to change the logic round, if it's not, if it's not no extent, fail with an error, otherwise, create the new one. So, write random should still work. Read random will correctly fail with an error. So, if there is no extent, we'll get a no extent error returned, which is correct. Let me find the documentation. This is John Elliott CPM reference page, which is enormously useful. So, read random. This is our no extent error code. I do not know when record number can be out of range. No, I don't. This is the no block error we're returning. Okay. So, we also need to add this to our jump table. Okay. So, fire up our emulator. We still have our RAND routine. So, let's just do a quick test. That looks like it's worked. We have a file containing one block. I've also, I've rearranged the file system. This is now, I think, almost as big as will fit on an ACON DFS floppy disk, which is about 200K. So, there's a bit of space left over for the MOS file system, which is half a K. And the BIOS and BDoS, both of which live in the MOS file system. So, our CPM fastest occupies what remains. But I will also change the block size to 1K. So, that works fine. So, yeah. I believe that to be working. So, let's change our RAND program. So, we are going to change this test reads. So, we are going to create the output file. Open. Now, hang on. We don't want to create the output. Okay. That is the output file. We are going to open the input file. Okay. We are, first we are going to, so, first we are going to parse the parameter that is in the second parameter. This will be overwritten when we try and open the input file. So, we preserve it in a variable. So, we set the record of the input file. We read the input file. We then write the output file and close it. It wants a char star. That is going to be a return 0. And that is going to be a semicolon. Okay. So, what this should do is read one record out of the input file and write it to do that. Possibly printing the error. Okay. So, six whole records. So, let us read test dot sub record 0. I am not sure that worked. We did create a doubt file which is empty. So, the fact that it didn't print anything suggests it bailed here. That is because OXFF is an error code. Okay. And test dot sub 0. Right. Well, it tried to read sector 1192, which is wrong. This parsing code is not working. And then we read the random record. That failed. We ignored the error. So, it should have created our dat, which is one record. So, we can dump it. And what we are seeing is the default DMA buffer which overlaps with the input parameters. So, that is why we are seeing test dot su here. Not sure what happened to the rest of it. This should be one record from the file. Interesting. Well, let us just do a inside record here. Because at this point, this should be valid. I print I is a machine code routine I made to print 16 bit numbers. This is not necessarily very good. That is not a 16 bit number. I forgot to put a CRLF in. So, it is actually printed 7, 8, 1, twice. So, this is not worked. And test dot sub 0. We have a dot and a 4. So, two parameters. These should have gone into CPM FCB and CPM FCB 2. So, our programs are loading at 1.900 on this BBC master. 7, I think it was. Okay. So, this is the 6502 startup code for C programs. We then do initialization, which I believe we can skip. And then we go into main, which is here. So, here, yeah. Here is where we are allocating stuff off the soft stack. When we save parameters, it is all a bit wordy. I do not know what that is doing. Well, here is a JSR, where we are calling probably A to I, which suggests that it has put our, I bet that 1BBC might be our P block. It is here. 1BBC is not the P block. 1BBC is the command line buffer. So, here you can see the test sort of sub is there and our 0 is there. Have I missed a bit? Has it inlined A to I? It could well have. Is CPM FCB 2 actually pointing at the right place? I think it might not be. Let us just take a look at our MOS 65 code. So, it should be here. Yes, it is in fact pointing at the wrong place. CPM FCB 2 is after CPM FCB in this code, which is not right, because they should overlap. So, we just add 16 on. So, I am going to have to rebuild. Rebuild MOS LVM. Clean. Build. Okay, power up the emulator. Right. Rand test.sub0. I believe that is more correct. So, it has created that. We dump it. And yes, this is the first record of our test.sub, which of course is only one record. So, we can do rand.com0. We now get the first record of rand.com. We can do rand.rand.com5. This test gets the last record. That is the record number and that is the error code. So, here is the tail end of the constant data in rand. That will be this FCB followed by the relocation data and there it is terminating. Now, let us try to get the next record and that fails. It does not print the error code because the bindings I have got around the these routines actually return a simple pass fail code and stash the error code off into another variable. So, I can actually I can do that. So, we are going to do rand test.sub1. This will fail and this is reported error code one, no block. Correct. So, it is worth noting that firstly that name is not quite correct. That should be no data. There is actually a block for record one but we are after the end of the file therefore it is still refusing to return data and we are going to do a no data here. No data. So, this then becomes now if we do if we try and get a record that is not in the current block that will produce the same error but this time it is because it actually hasn't found a block there. If however I ask for a record that is in the next extent we get error code four meaning that it is tried to seek to an extent that doesn't exist. But this should all be absolutely fine. I think this is working. So, we are going to call that done. We don't have any files that are more than one extent but I imagine that will work because it is all the same code as for write random. Okay, good. That's what's changed. Reading from random records works. Platform. SDK commit platform. I only want to commit the pblock file to in the right place. Okay. So, we only have a few more things to do. Let's take a break from random access and do set file attributes. This is actually very simple. It's basically the same code as rename. So, we are just going to so cpm stores file attribute bits in the high bit of the file name. These are defined down here. So, in the extension, which is three characters, we have the read only bit, the system bit and the archive bit set if the file has not been changed since it was last copied. This suggests that we need to make sure that that bit gets cleared when we modify a file. But I think I'm not going to worry about that just yet. The rest of the file name has got other bits that are as for our reserved for the BDOS for our undefined user attributes. So, all set file address does is it scans the directory looking for any file which matches the file name, and then it effectively just renames the file to the file name in the FCB, thus updating the bit. So, we are going to copy the file name from the FCB to the DRN, which means that we only need one index. So, we can put that in Y. So, we read, we write, we increment, and we keep going till we're done. And then we write that back to disk, and we are finished. Okay. So, observant viewers will notice that there is no ccp.sys here because I made it a system file, which is why it is displayed in parentheses here. Now, try to remember the syntax. I think we can do this. Hasn't done anything. Let me go look up how stat works. Okay. Here is the original stat documentation, and actually adding $s is supposed to make it display size information in bytes. Hang on, in bytes. The size field lists the virtual size in records, while the rec field sums the number of virtual records in each extents. Okay. I think that's a stat bug. I think we are just, I think recs here is supposed to display the number of allocated records, and size is supposed to return the virtual size of the file. And I think I'm reporting size as rec. So, I'll go and fix the size code later. The code for actually changing attributes is $sys. So, that is a system file, hence the parentheses. dir is the opposite of sys, so we should be able to do dir. And it hangs. Well, that's nice. How about we put that into a cpy so it doesn't spin constantly overwriting all of memory. Okay, let's try that one again. ccp.sys dir. ccp.sys set to dir. And there it is. We can do that. And it's gone again. Read only. We haven't implemented this. The read only status is recorded with the file, blah, blah, blah, blah. And file is marked read only, subsequent attempt to erase or write to the file because the following message on your screen. So, that's a hard error and we haven't done those in the BDOS yet. But, I mean, we can still set the files. So, we can change set this to read only. Is it displayed here? It is not. Oh, there it is. Read only. Okay. So, setting file attributes works. Let's get back to random access. So, we've got these two compute file size and compute random pointer. Let's do compute random pointer because it's easy. And it sets the random access pointer to wherever the FCB is currently pointing. So, this is so that you can read sequentially through a file and then you can convert the sequential pointer in the FCB to a random access pointer so you can seek back again later. So, all this is is the opposite of this code here. So, I was thinking the best way to do this. We are going to start in the middle with the extent number. Now, this needs to be shifted right by one. The top bit goes into the, so the top, the top four bits of the extent number go into the high byte of the random access pointer. The bottom bit of the extent number goes into the top of the low byte. So, SRA, shift right, bottom bit goes into C, store the top into temp. And so, this gives us that part. We now want to or in the record count. No, the current record which goes from 0 to 7f. So, rather than storing it, we can actually just do that. We are now done with the low byte. Okay, we now need to finish the computation for the high byte by shifting this, shifting that left by four. Hang on, I need to load it, don't I? Owing in the four bits from the extent which we put in temp plus one. And we are now finished with the high byte. So, that should be all there is to it. Should be a logic shift right. Okay, how do we do this? So, we're going to get a number from the second parameter. We're then going to open the input file. We are then going to keep reading that many times. Then we are going to print the record count and stop. Okay, so if I do a zero then, I can't remember what I called that now. There doesn't really seem to be defined names for all the entry points. Everybody uses different ones. The original documentation which I've got here doesn't actually give them names at all. It just defines what they do, which is not in this file. So, oh yeah, LLVM Moss SDK, Moss Platform, CPM 65, CPM.h, what did I call it? Seek to sequential position, which is actually more descriptive of what it actually does. Seek to sequential position of CPM FCB. So, rand, rand.com, zero. Good, that is what we wanted. Okay, rand.com, one, good. Five, yes, good. This is actually what we wanted. We are now reading 20 records from the file, but it's only six long. So, it stops and produces an error after the sixth. So, our sequential pointer hasn't advanced. So, what's our biggest file? Probably the CCP. I know what the biggest file is. It's stat. We know it's 55 records long. Yes, good. And if we put this to like 200, it's still doing the right thing. So, it's not really a very robust test because we don't have files bigger than that. Let's actually put one in. We're using those three, BDOS to asm, put that in there. Okay, so, there is our big file that is now four extents long, 64k, 512 records. So, we can do BDOS to asm 200, which should be in the second extent, and we're getting the right number. 400. That pause is because it is actually reading the disc. 600. Interesting. It's 512 records long. That should... Okay, that's wrong. Why is that wrong? Has it tried to advance to the next extent? It's possible. It shouldn't have because right sequential shouldn't move on to the next extent once it hits the rest of the file. It should stay at that record. I mean, these numbers are correct. The maths is working. And you know what that means. So, we are of read the extent number, which is four. That's what we expect for the end of the file. Is it five extents long? Four extents? I don't remember now. Oh, it's almost exactly 64k. So, yes, it's four extents long. Oh, right. We have read the last block of the last extent, and we've advanced to the beginning of the next extent, which is empty. So, we have that might be what's confusing it. So, 1b2b. Here is the fcb. That's interesting. Why is that a four, not a three? It's much more likely I've misremembered how long it is that the number's wrong. So, we've actually just computed the high byte as two, which is four shifted left by one, and carry is clear because the high bit of the low byte is not set. So, we now draw that to prepare the low byte, zero. Our current record is five seven. Okay. Again, that number seems wrong. So, we are in the record count. We write it. So, there. We haven't written the four four yet. We're about to do that. So, we get s2, which has the top bit set. Okay. And we shift it. We don't need to remove that because we're shifting it left, which means that the top bit gets shifted away into nothingness. So, there are no modules. We're on module zero. So, when we write back, this is our record count, which is 0257. How long is this file? 64k, 512 records. These numbers are wrong. Okay. Just check this. Here we go. Os3bdostasm is three records of four, four dear ends, four extents. The last one of which is numbered three and is full. So, yes, we have a problem. That'll be here. Close extents. And I believe that what's happening is, yeah, what's happening is that we've tried to read off the end of the file. And the BDOS is not robust for that. So, because we didn't put any error checking in our program. So, this has closed the last extent. It's advanced the pointer to the beginning of extent four correctly. We then try to open it. We don't find it. We just see what read sequential is supposed to return. Yes, end of file. So, we return CPME, no data. We then do our test program, then tries to read again. But it doesn't, this code doesn't know that the file has been closed and the FCB is no longer valid. So, it assumes that the data it has in the FCB, where this value here has been updated to four, is valid. So, it starts reading through the file until it reaches the end. And the reason why the record count was just a couple lower than a full extent is because the only time when, I was about to say, the only time when we don't actually advance the pointer is at the end of the file. But that's not true. We do still advance the pointer. I think, I think that what we need to do here is to clear the record count. The zero record count means that we will always fail here at the beginning of the next extent. Because it means that the current record, which is going to be zero because it's reset here, is equal to the new record count of the unopened deer ant, which is zero. So, we will always go through the end of file logic. We will see that the record count is not 128. Therefore, we are not at the end of the extent. Therefore, there is always going to be no data available. So, we just immediately bail out. Let's try this. So, rand, os3, you don't have to add some 600. Did I take my hangout? I did not. Good. 512. We reached the end of the file and stopped. So, we now know this works. Of course, we don't know it with modules because we don't have any files that are big because disk isn't big enough. We could put a sparse file in. Honestly, the module stuff is easy. So, if this works, I trust the rest of it, at least for now. Okay. So, we have two more to do. And they are actually both going to be annoying. So, compute file size or, as I called it in the other naming system, seek to end, will actually determine the virtual size of the file and seek to one past the last record. So, this is going to be here. And I just want to double check exactly what this does. Random access read, write, compute file size. Set the random record count byte, the FCP is the random access pointer to the number of 128 byte records in the file. Yes. So, that will be one past the length of the file. So, you can then start writing and you won't overwrite any existing data. So, the way this works is we are going to have to iterate through the directory, looking for all the dear ends with this file name and tracking the maximum extent module and record count that we see. That will give us the data we need. Can't use temp here. So, this is basically more directory scanning. Do we have some code I can steal? We are actually going to call find first. Oh, we can steal from open. It's more complicated than that, but that's fine. Compute file size. So, we prepare the FCP. We want to match just the file name. We call find first. If there is at least one matching dear end, we do stuff, keep going until the carry is set. And then we do our computation. So, where are we going to track this information? Honestly, I think we have to track it in the FCP, because we have got three bytes there and our zero, our one and our two. Okay. So, we need to start at the top and work down. So, we read S2. We then compare with the value in R2. And then we go over here to my second favorite 6502 lookup table. We want to know if current dear end, if current dear end dot S2 is greater than FCP dot R2. So, it's greater than or equal to BCS. No, it is more complicated than that. So, the greater than or equal to, if it's not equal to, it must be greater than. So, if it is equal to, then we'd need to, if it is equal, then we need to compare EX, which was going into R1. If this is equal to, then we need to compare against RC. Okay. So, if the carry is set and is not equal, then we know that we have reached a strictly greater than situation when comparing these three bytes. So, that we then update the values in R0, R1, R2. I do not like this. I think there's a better way. The thing is, so, I don't think compute file size is supposed to update the sequential position. I want to find the programming manual. It's not this file, but it's nearby. This is the one I've actually been looking at. I need to go system interface. I want to see what the original text said. Compute file size. The deregister pair, addresses. FCP in random mode format. Well, like they always are. It just means that these three bytes are about to be overwritten, so you better be sure they're there. It's an unambiguous file name. Upon return, the random record bytes containing the virtual file size does not update the sequential position. Okay. I know what I am going to do. We are going to save our sequential position onto the stack. We are going to... Okay. What I was going to do here is, in this code, copy the deregister idea of where the of the sequential position into the FCP so that I can then call compute pointer to actually update the random access bytes because, of course, this is expecting the value to be in param, but then I will run out of storage because I need to be able to store the old random access position, which I've just overwritten. Do I need some more storage? And I will actually go and check to see where the find first and friends are using a temp so far. It would be nice if they didn't. See, I know that doing anything with blocks uses temp. This is using temp B, which is an extra temporary byte that I had forgotten about. Why are we doing that? Okay. Let's try this using temp because that will make life way easier. So, we are going to... We are going to save the param pointer because we are going to want to update param to point at the current dear end so that we can then use compute pointer to calculate the position. We are then going to use this as the file size accumulator. So, this starts at zero. Right. We now iterate through the directory. This will... It will overwrite the three bytes after the current directory entry, which is in the directory buffer owned by the bios. We can't do that. Okay. I am going to need to break up this code. I think... Seek to sequential position. No. Calculate sequential position. So, we are finished with the low bytes. We want that to go into A. So, this is then working on the high byte. High byte goes into X. And then we return it. Now, overflow. I completely forgot about overflow. The reason why the record count is three bytes, even though we only ever used two, is because there is a single situation when you need three bytes, which is when the file is the maximum length, because then you will run out of bits. The maximum length file is eight megabytes. So, that is a 128 records. So, 65536 records, which is this many extents. Now, hang on. No, that's not right. There are 128 records in an extents. So, it's this many extents. That is also too big, because the extent number... Oh, yeah. Okay. That's right. It's this many extents. The extent byte goes up to 32, which means the module number, the S2 byte, can go up to 16. But this is the file length. So, this is pointing at the last extents. So, this will only ever go up to 15. So, what this is going to return is the record number of the record that we're currently looking at. This wants to return one plus that. So, right. Okay. We do not need to worry about overflow here. So, compute, calculate sequential position. Okay. And then we want to write it into param. And we're done. So, down here we are going to call calculate sequential position. And we are going to compare the value that we just returned with what's in the file size accumulator. So, first we want the high byte. So, if the value in the register that we got back from here is greater than or equal to this carrier set. Now, we want to compare the low byte. Why am I doing plus three? That is because plus three is what I want. Then I compare the low byte. If it's greater than or equal to, then we want to update it. So, sdx, 10 plus 3. End if. So, end if. And go around again. Okay. So, this will give us the record count of the largest possible record. Okay. So, now we are going to, first we are going to put param back the way it was. So, we're going to increment the file size counter. So, increment the low byte. If it rolled over, increment the high byte. If it rolled over, then the value must have been ff, ff. Therefore, r2 must be one. So, now we load 10 plus 3 and store it and return. So, this can return, put an error. This, not that one. This one. That one can't return an error, but let's just put a clc just to be sure. Okay. So, this should now calculate the virtual length of a file. Let's just go and adjust this. So, this is called seek to end. Okay. So, randtest.com has reported garbage. We don't want this anymore. That's very much not the right answer. So, the first time through, we find a d'adirrent. Copy the pointer to param so that we can then use calculate sequential position, which returns the value in xa. Check x with the high byte of the accumulator. Check a with the low byte of the accumulator. If they are both, if the second is greater than or equal to, then the result must be greater than or equal to. So, we update the file size accumulator. Keep going until we run out of d'adirrents. 502, 345. So, we call new user fcb. We save the param pointer in a handy temp, because this is where we discover whether the temps are actually preserved. So, it's 10, 11, 12 and 13. So, there is our param pointer. There is our accumulator. Find first. Yep, they've been overwritten. Fantastic. Okay, I clearly need some more storage somewhere. We don't need those anymore. Why don't we copy the dph at one point? Because I thought we had some unused locations in the dph. So, we've got cdarm max and scratch1, scratch2, which is four bytes. I don't really want to because then I can't use ink. It's not so much of a problem here because I can use yindexing, but it does kind of make a difference here. I'm just going to allocate some more space. I think we can do two bytes worth. I'll need to check to see whether two and three are in use. That looks more plausible, but no, it's still wrong. It's three records, not one. Or it's the maths are wrong. Anyway, let's try this. Break. That's not going to work. Anyway, we've got the address we wanted. So, break1505, reset continue, grandtest.com, and we've broken. Okay, so we save our values in temp4 and 5. Hang on a second. Oh no, no, I'm all right. Yes, here are our values. So, we've allocated an extra three here for param. So, we've got the accumulator here and param here. So, let's do find first, and we still see the right value there. Okay. So, carry is clear. Copy pointers. Why is that using absolute addressing there? That's not right. I've noticed this with the CC65 assembler. I'm actually going to change it all to use the LLVM assembler at some point because I don't want to mix two different tool chains. Anyway, calculate the sequential position, which is zero. That's wrong. So, if I look at 0614, this is the deer end we're looking at. So, it has returned a sequential position of zero from this data. Well, we've got because this code's using the current record, which is here. We want to use the record count, which is here. I think I'm going to have to duplicate all that code. Well, let's just put this back here then. Here we can do this to get a param from a wife. Finish with low byte. I even forgot to take away that LDY. Finish with low byte. Finish with high byte. Great. So, this goes away. No, it doesn't because we're going to use the code completely with the shifts. But of course, we're now working off this byte, which is the record count, not the current record. So, that is one more than it should be. So, now this code can overflow. Okay, size of the file. You can still make this work. So, we're done with the low byte. Put the high byte here and the low byte here. If this last ASL has got the carry set, no, because that value won't overflow at all. It's this one that can overflow. So, if this is set to 128 and EX is the maximum possible, which is 31, and S2 is the maximum possible, which is 15, then we've overflowed. Okay, so if the record count is 128, if the extent is 1F, if S2 is OF, then we know that there cannot be any files bigger than this. So, we can just write 0 to R0, 0 to R1, 1 to R2, and stop. We have to put param back. Also, we don't actually need our two extra temp spaces because we can push them. So, we need to restore param to the high byte. Okay, so these then do become param. Okay, so the total file size cannot overflow, but record count here can still be 128. So, we are going to have to allow for that. So, we have our low byte in A. Therefore, we actually need to add in the record count. This, if EX was, if the bottom bit of EX was 1, then this will now overflow. The carry will be set. So, we are now going to save the carry, we fetch S2 and shift it, restore the carry, add on the previously saved high byte, and the carry, put it into X to give us our value in AX. Okay, well, let's fix this code. So, temp23 now contains the record, now contains the record count of the file. So, all we need to do now is to write 0 to R2 and copy the record count into R. Okay, let's try this now. So, RAND test.com gives us 3, which is the right number. Test.sub should give us 1, yeah. Okay, let's try our big file, which is actually a good example because it's got completely full extents. 384, that's the wrong number. Also, the wrong number. I actually think I can rework this code to be quite a lot clearer. By simply working from the top down, we will always have a valid 16-bit value. So, let's try that. So, we're actually going to start with S2. So, this then goes into the high byte. We need to keep all this stuff in registers. Otherwise, we will need yet more storage, of course. I think I'm going to try this anyway just to see whether I can use the stack instead because I am not pleased with this stuff. So, we can use temp b. Okay, so we now load the extent byte, put that in temp b. We now have carry in the top byte. So, we get the carry value that was saved. I do not believe ORA will set the carry. It does not. Okay, so that carry is preserved to here. So, this now gives us the low byte. We want to add in RC. Instead of putting that back into temp b, we can stash it in X because that then allows us to fetch the record count, add it to this value. This may set carry. So, if carry is set, then we wish to increment X. And this will then leave us with in AX, which then allows us to do this computation here. Okay, still the wrong number. Anyway, I am happier with this code. It's shorter and faster. There is actually a trick you can do that makes doing 6.02 arithmetic so much easier. And that is to create a lookup table, which is just all the numbers from 0 to 255 in order, because this will allow you to do arithmetic with values in X. We could have done like this. So, it will add X on to lookup table, read it. That will return a value that is the same as X. But this involves wasting a complete page of memory. So, I am not doing that. It's possible that temp2 and temp3 are being used by findNext. In fact, that's moderately plausible. I'm going to have to step through this again. So, randstat.com, break, 9, reset, randstat.com. Okay, we are here. So, we push. We reset the accumulator. We call find first. We see that our accumulator is still 0, which is what we expect. Why are we saving param? We don't need to anymore. We were saving param so we could use the other piece of computation code which expects the value in param. But we're not doing that. So, let's just get rid of all of that, and that makes the code smaller. Okay. So, we're here. We're checking for the maximum possible by 4. Here is our drentstat.com with these numbers. Record count of 37. Extent an s2 of 0. So, we zip through this code. We want to get rid of that. So, we save drent which we don't need to do anymore. We are now calculating the size of the files we get if s2, which is 0, shift it, stash, fetch x, which is 0. Shift it right by 1 and or it into the high byte. Put it into x. Okay, x is 0. Load the high bit of the low byte which is 0. Load the record count and add it in 37. Let's carry set no. Is this bigger than the value in our accumulator at 12? Should be. Right. So, we now update our accumulator 3700. We now get the next item and it hasn't been overwritten. So, this we should have carry set because there are no more records. Carry is clear because I overwrote param. That's why I should have put it back before calling fine next. We don't need to do this anymore because I've taken out the code to stash param. So, randstat.com is the right value. Okay, randos3b.s.asm is the wrong value. I think this means my maths need a bit of work. Let's try it on the right value. Okay, so where were we? 1, 4, f, 9. Okay, randos3b.s.asm. Right, we're here. Test step. Find first. Is this the maximum possible length? No. Wait a minute. Ah, the record count is 128 because the the record that we've, the drent that we've just seen, it does have the maximum possible length. It means it's full. So, we now check ex and that is not 1f. Right, we now calculate the size of the file based on this drent. So, s2 is 0. So, we can skip through this. We get ex. This will be 0 because the extents are created in order. 0. Okay, now we have the low byte of, yeah, okay, we haven't added on the thing yet. So, you'll see ADC, you may see that we have a low byte of 80. Carry is clear because it didn't roll over. So, we now update the thing. Done. Find the next drent. Carry is clear. Back to the top. So, this one is also full. So, we compare the extents, not maximum. So, we go to here. s2 is still 0. It will always be 0. Fetch the extents. Extent number is 0 because we were looking at the FCB. This one was right. That's why the record count was being updated. The other values were all wrong. Still wrong. That's the right number. Okay, so find first. We are here. We fetch s2. Yeah. Okay, I'm going to assume this works. Okay, second time through. Fetch s2 which is 0. Fetch ex which is 1. Okay, we're now looking at the right thing. Yeah. So, we shift that right. Carry is set and a is 0. We are in the s2 value which of course will do nothing and put it into x. We now compute the low byte number from the extent by using the carry which we now see is 128. We now want to add in the record count which we've done which has gone to 0. Carry is set. That means that it's rolled over so we increment x. So, our file size now is 256. We've seen two full DRNs, therefore 256. So, now we compare x. Wait a minute. Wait a minute. This code is wrong. That's what's happening. So, this is greater than or equal to. If it's greater than, then we always want to do the update. If it's equal to, then we need to compare the low byte. So, that may be if not equal, then we update the file size. Okay, I think that is better. That was the wrong command. Continue. 512, 16, 55. Okay, I think this is now working finally. 1. I haven't tried it with a zero length file but I think that I can be confident that will work. That's an annoying piece of code. I'm sure there's stuff here that can be commened out and cleaned up. Okay, let's call that one done. Right, well we are getting somewhere. It's now I see it's 11 o'clock my time. I was kind of hoping to get this done but this one is going to be a pig. The reason why it's a pig is because it's a layer violation. So, we go to write random. It's basically the same code. However, seek to block and create down here calls this and inside this, well actually here, we are going to want to decide to clear the block. This will involve writing a certain number of zero records to the entire block to zero it. Now, I can, this is calling seek to block to create here. I could set a global flag that causes it to happen inside. I could duplicate this. Yes, I don't want to do that now. I think what I will probably end up doing is having a global flag that tells this to clear blocks then write filled will just set the flag and then fall through into this code that will do all the work. That actually doesn't sound too bad but I don't want to do that now. Okay, well this is very nearly done apart from all the bugs and I should probably do something about error purporting. We do need hard errors because that will let us do write protect stuff and so on. I can probably clean up a whole bunch of the error handling. For example, inside the entry code, which is up here, I should be saving the stack pointer so that I can have a generic error return call that I can call from anywhere that will reset the stack that is unwind from wherever we've got to so that we can call it inside subroutines and places where we've put stuff onto the stack and leave a error value in the result. Again, not particularly difficult but it just needs doing. Okay, good. That's the wrong button. Next time then.