day five Let's try and make the ctp do stuff, but first let's fix a bug so During the off-time I put in the jump table for all the VDOS entry points because that's just boring cut and pasting and not particularly interesting and An interesting thing well the only interesting thing about it the table is uninteresting the consequences of the table are interesting Anyway, when I run it it crashes It has Printed a couple of numbers and stopped as you can see that's not an error It's just got confused and died and the reason for that is dead simple. So our ccp Does nothing other than exit What does the exit entry point to do? well It's here and it loads the ccp So why hasn't it reloaded it correctly? Well, the answer is because The the FCB we're using to refer to the ccp Has its various fields set up from reading the last ccp So open file does work. It opens the file We then try to read a sector from it But it's already at the end of the file So it terminates immediately We patch it. We relocate it again This mangles all the fix-ups in the ccp and then we try to run it. It does a hyperspace jump into nowhere So we need to be resetting the relevant fields in the ccp Which Honestly, I think that the open call should be doing this. I think it should reset Well, we have to reset the extent the current record and s to but It doesn't so there you go FCB comma hang on a second Ccp FCB is a 16 bit value. So there's no point doing any of our indexing. We can just do whoops Do that again, but pressing the right keys this time. You just do early zero plus FCB extent byte s to By S to the module number should be a document here on the disk formats This one contains the description of what the various fields in the FCB do you go s to the one we want? Yep and Current record Okay, so now when we run it it should Not do that extent counter extent counter It's also going to mangle the drive number whoops, and that should be a one Okay, I am confused now So let's use the debugger. So we are going to one nine oh four continue Run Okay reset the disk system. We're here clear the relevant bytes in the FCB Load the address of the FCB into one E one C So when we dump that we can see drive one file name everything else is zeros and We're now about to open the file. So let's dash another break point there And continue and it crashes immediately So it's trying to print an error intriguing Okay, open the file Carry is clear that means the file is correctly opened Yeah, I can't step over that bcc Do that again And we get already open Actually, I will do something about that right now so the reason why The file is already open Is because it's referring to the cpmfs file that we've opened here a soft reset hitting break It's not close all files, which doesn't make any sense, but That's mos for you. It's a decent 8-bit operating system, but it does have holes in it And this is one of them Uh, so all we have to do is call The system core to close all open files mos api It's os find doing this There we go close the file specified by the handle Uh, if function is zero handle is in y and x is ignored so Like so so now we hit break we hit shift break And it actually runs. We haven't done a hard reset On the bbc micro you do a hard reset with control break and that resets a whole bunch more stuff Open the file Yeah, carry clear Get the tpa address into user dma e49 Which is 001f Our bdos is bigger now. So we've it's claimed another page Start reading The file. So if you now look at 1f. Oh, oh, we see The wrong file. I know what's gone wrong Some of the stuff I did offline was In the bios here. I wrote this huge terrifying macro To alec to compute the dph and dpd So You give it the disk parameters. So 40 by 32 Sectors 2k blocks 64 Directory entries no reserve sectors And I bet that this Is Yep This is configured for a block size of 24. This is cpm tools definition of the disk I'm using this to create the file system And he's using a block size of 1024 So we just go up here and change this back to 1024 which I must have left in for debugging And now it should work Okay, it should now be spinning loading the ccp over and over again So let's actually make the ccp do something So here is our system call table twice low byte and high byte the same as we did for the bidos And we're going to put in console Well one console routine con in No con out entry con out So what this does is I just don't want to check to make sure that I put Bios con out that's in lower case That should be an upper case and Bios set tpa Likewise be Get tpa Okay, so all this will do is on entry So we should theoretically just be able to do jump bios con out Or even just put bios con out directly here but Uh, I don't think we can because console output Send the character to the screen tabs are expanded to spaces I think it may also turn Carriage returns to new lines So con out ends up actually being quite Big Right the character What's this doing? You can also you it'll also It does X or X off Uh pausing Not sure Yeah, this is Wait a minute. This is the That's not the user typing on the keyboard. That's the the character being sent from the program to the console So i'm not sure how that's actually supposed to work Comp call is true if we're computing the column position because we have to keep track of that to expand tabs Okay, well, let's Let's define a byte to put the column position in Uh, it will also potentially copy to the printer, but we have no printer in cpm 65 so This is the Column stuff it also handles backspaces Sends the character in e to the screen Taps expanded spaces up can be paused with ctrl s and restarted with ctrl q That sounds like it's the user typing on the keyboard. I'm going to find the original documentation So here's the original cpm 2 interface guide. Yes ctrl s and ctrl q are Typed on the keyboard and this is checking for Starting stopping the scrolling the thing is that There is no way for the bdos to buffer Incoming text So I would expect that It's more on receipt of a ctrl s on the on the keyboard Then we would end up blocking in the console input routine Rather than console output So what does con brook do? Here we go Check for character ready Okay, so this actually seems to be doing the blocking in con out rather than con in Which is weird Anyway, so the input character isn't a So on this info to you can use the bit instruction to test flags So we're going to say bit output paused What that will do is it will read the value Set the n and v flags Based on the value It then sets the zero flag to that value anded with the accumulator We don't care about that and we're going to be using the top bit So that when we're paused It'll be negative So now we want to compute the column position so if a is A backspace Which is ASCII 8 or ASCII 127 We want to Decrement Column position If it is negative zero it if it is a Tab Wait a minute Comp cold is true if we are computing the column position. Why would we not be computing the column position? This is the code That prints the character Yeah, why would comp cold be false? This is the buffered read routine I was expecting these routines to be dead simple actually, but they really aren't True if computing column position So the only place it seems to be being set is in the read routine so This is the buffered read routine. It reads a line from the keyboard with simple line editing Really simple line editing So we have Carriage return line feed backspace This is all the backspace code Comp cold greater than zero marks repeat as length compute whatever that means Yes, I don't know what that does So let's ignore it for now I think it has to do with being able to set this to zero And then you can write lots of stuff with con out and it will compute the column that it will have been at I don't know why anyway So this is actually going to print the character first Are we going to Are we relying on the terminal to do tab expansion? Well, here are the comparison routines in this and there's backspace space It's doing that to check for control characters And Backspace Again a different backspace no column change if nulls These comments are not terribly helpful. Okay. Well, so we print the character and now we compute the uh Column position which we're going to do the easy way It's actually cheaper to do it like this than it is to um And I just want to check to see I think decrement absolute Yeah, all the decrements set the negative and zero bits so we can do if negative lda zero sda Column position reset column position to zero and exit so branch if equal to backspace Branch if equal to Backspace Is it a tab? If yes, then we want to Advance to the next eight character boundary so They carry and one Okay And if it's a control code That is smaller than space then I think as a simplifying assumption I think it's a simplifying assumption for all control codes which includes new lines We are just going to Uh zero the column position. So what should this be? so if So we are subtracting position minus 32 so if Char minus 32 so if the character is 31 We will get a A result of minus one carry will be set if Char is 32 then we forget as a result of zero and as we discovered last time the carry will be set So we're going to set that to 31 one less And do a branch if carry set to zero column in all other cases We are going to increment the column position and exit And there is actually one other thing we want to do Which is up here somewhere Well, I can't find it, but it's something we have to do Which is to Mask off the top bit because cpm is not 8 bit safe Although given that we're not actually going to be running any real cpm code Let's make it 8 bit safe All right And I actually I think I can do slightly better than this Load the column position into x Then this means that Because this is three bytes So you want to increase the column position inks and it with not seven and store and exit Here we just want to increase the column position store and exit In fact, we're going to want to do a lot of storing and exiting So decrease the column position is dex Zero column is a simple ldx zero And here we actually want to store x and exit Which means that we can't actually put a jump exit in there. We do want to store a We could put it back into x and jump down here, but that's four bytes, which is what this costs So it's all the same Okay, so basically it will do a cheap and easy a Count of what what column we're at Assuming that the terminal is going to expand to tabs, which I think it does on the bbc micro um And whenever there's a control code normally the user has Done a return Then it'll reset the column position to zero and here We are going to Check to see if the user has restarted output So to do that we are going to Push the character as it's dash the character that the user's trying to Let's do that here actually We want to Read a character that the user has typed This is This is calling console status Return if no char ready Check for character ready Oh, I see what it's doing I see what it's doing It's checking the status on the output so that if the user is typing while text is going out It will process the key. I did not know it did that Huh Okay So stash the character being read um Check to see if there is a character ready our bios is Where's const We're turning zero or non zero for no ordinary boolean value So I'm in Check for stop screen function. That's control s found control s Yeah So we're going to compare with control s is x off which Is not on this List n o p q r s 19 um If the user's typed to control c Then we immediately reboot the system That is restart the bedos and the ccp Thus exiting the current program So if you if we are pausing If we are pausing then we just block for another key discard it And then continue on So we don't need that anymore right 294 minus eight why okay Zero column is defined inside a scope so we can't actually Do that okay, so we need to do branch if positive to exit pause is undefined eq Right now we want bios con in and const And we're putting our bios calls down here con in con out cons Data's This is too far. We can't we can't Jump this far I could probably do it if I put the console stuff above the jump table So let's just do that 6502 short branches have a eight-bit displacement Now this is just too big Okay, well, let's put that back where it was And this has to turn into if equal jump to Exit Okay, so this should run but nothing will actually happen because we're not doing anything in it here So let's just do a as if on here LDA q Y dos All output jsr b dos In loop Right, and let's see what it does Okay, we successfully print a q and then we stop and I know why we stop that halt message was coming from Here because we aren't returning from the from after our system call So we could just put a rts in and then it should work There we go Our ccp is now printing lots of cues and Because of the magic of moss I can switch to a high res screen mode And everything should still work And you can see the speed at which is actually doing The things which isn't brilliant. So there's quite a lot of overhead But anyway, that's the way it is Okay, so we now have our console working. Oh, yes, there was actually one other thing I wanted to try Okay, it's running I said control c Nope control s Nope Am I using the right control key? Yes, I believe I am Okay inki is wrong Uh inki is the system call we're using to actually do the console status Stuff just wondering how to step this Actually, one thing I can do is Do that Okay, that is actually typing the word key So we know we've reached this point So we read the key And then we test it I bet con in is not working right So con in If There is no pending key called read char. Oh, this is this code is broken Well, that should be a jump for a start So if there is no key pending called uh osrudge And then exit immediately. That's why that's a jump otherwise Return the pending key. We've read the pending key into a so we clear the flag here and exit So here If there is a pending Key Then Say yes Otherwise Check to see if there are any keys pending from the operating system By trying to read one with the timeout If there are none Then no Otherwise Store the key And exit Yeah, let's try that Okay, not a control s. That's still not working in control c Yes, I can't actually tell if that's doing anything. I don't think it is I think it's just printing the word key in stopping So we're going to have to debug this and we are loading at 40 o If you want to debug the bios we continue Okay, it's loaded That is the table we're looking at here This garbage is ascii text and here Is where we're going for a one Okay So let's press a key and hopefully const will have done its work And we should get a break We got a break So read the key And it was eight one. That's not a valid key Osbyte Osbyte eight one returns the key in X I bet Read key with time limits on exit X is the character So that should be sdx pending key But anyway, it thinks there's a key pending So We skip the call to rudge And we try to return the key Yeah And return now we're back in The bedos and of course that key is not any of the values here because it's garbage So it's not a return So it's not a control s It's not a through it's not a control c So we just continue on Okay, let's try that again control s Oh It's not working control c No So we are trying to get two for a one So let's type a control s Okay Is there a key pending? Yes, there is And it's eight one again On exit X is the character Did I remember to save this? Okay control s Right Right, okay. Yeah, I forgot to save it. That was what the problem was So we now have a control s character in a So reset yeah, yeah is a Uh, it is a control s. So now we Pause waiting for a key like press the key Oh, we're still broken press the key I said Press the key Okay, so it's the second time we're in we've gone through con in So this should now be blocked waiting for the user to type something So we look for the key press the key press is zero. There is no pending key and of course Osrudge I bet Returns It's key in I thought I was going to return it in x again control s continue once Okay, so this is the operating system doing its thing. It's checking all its various Bits you don't want that one Yeah, I think that it's now blocked waiting for a key press I'm going to change this to this Because this will allow me to Step over This First time Second time step over Press key Oh The operating system is not picking up So why is it doing that? Our operating system call is not returning I don't know why FFE zero is the right address. Yeah intriguing Well, I did make it work. So I can do control s And it stops typing and I can do any other key and it continues typing and I can do control c And it reboots You can't actually see anything happening when it reboots except if you go up here into the memory view This noise here Is the bios and the bedos being loaded And what I did was I changed the call to osrudge to a call to osbyte 81 the same one that we're using to Test for a key press I just gave it a high time out And this works and I don't know why this works and osrudge doesn't But anyway So we should now have a console more or less working We've got con out we don't have con in But Let's just skip ahead slightly and do This one as this is a useful routine Oh, yeah, I also want to move these down into Our transient state table because we want it all to be zero initialized When the bedos really starts So what this does is it writes the parameter So the first thing we need to do is get the parameter into a pointer and This brings up another point All our entry points so far well except for con out And exit like a sum of our entry points open file and read sequential They take a 16 bit parameter which is a pointer to the fcb Now all the bedos entry points take 16 bit parameters So rather than stick the code to copy this into a pointer Because they're nearly all always pointers in the entry point itself We are going to do it here So our fcb Uh Variable this is just going to be a general purpose Parameter variable we didn't want to do that just trying to remember what the vim end of word Escape is Angle brackets fcb becomes Param Okay, and we didn't want to change these or that We did want to change that Just line up to these spaces I'll fix the rest of the alignment later. Can't be bothered to do it now. Wow. I did use that fcb name space a lot Okay so We're using these are old user fcb and new user fcb routines to actually store the parameter so we are Not in fact This that routine goes away completely and this becomes a fall through it's for read sequential Okay, we want to leave it our old user fcb has gone away. So this becomes select fcb Drive we're actually going to turn this tune to select fcb drive convert user fcb okay, so this actually wants to store The ccp fcb value in param so that will be low bytes sdp param plus zero high bytes param plus one And now we can use indexing cheaply here Actually, is it cheap if we use indexing it would be two bytes to load y two bytes to do the store and These are three bytes. So it's not actually cheaper. So let's just Shump this down here Open file, okay and param remain set Here okay, so now we come down to the BIOS entry point So the first thing we want to do is to stash the parameter which got passed in in registers So we now no longer care about the value of a so we don't need to push and pop around there We just need to find our console routine Uh, again We don't need to push and pop here So that is just going to be a load the low byte of the parameter Uh reset ignores the parameter open file uses it new, uh Read sequential uses it And I believe that's all we've got so it does this work. No, it doesn't okay. It loads And it reboots And it stops and I also remember now that there is a thing. We're missing which is if the if the user actually typed a control c We want to reboot so that Is going to take this out of line Put it down here Or can we be clever? I think we can No, we still have to I was just thinking there was a way to get rid of that jump, but there isn't Okay So the reason this comes up is because now on entry to write string param is set to the appropriate parameter So all we need to do is Do a loop load The value And And I don't think we want to do that with indexing The reason for not using indexing is indexing would limit us to to 256 bytes in the string And I don't want to do that So it's a handful more bytes So we can do load param comma y Okay Is it a dollar sign? If yes, stop Is it zero? This is an extension used by our uh dialect because in c zero length strings are so much more common And because we just want to check zero bit and that is set by the load we can put that there So and all we do is bios con out increment param plus zero if rolled over in param plus one like so And now in our ccp We're going to add our first utility function, which is bedos right string right string jump bedos And instead of Instead of just printing a queue We are going to ld a is the low byte ld x is the high byte jsrb dos right string Okay, and when we run it We get hello world and control s Should work Don't think it did anything Control c should work That does not look right to be honest Here is our ccp code so 1f07 is where our loop goes so break there continue Okay, it does actually seem to be working Yeah If you look at the memory view Because this shows zero at the top and ff at the bottom Uh this line The red represents right. This is the video memory Uh this Blue means execute green is read I bet this is the string and these are The that that will be the bit of the bios that we're currently running from to print the message And this will be these two blue lines here. This will be the bedos entry point code and the actual Um Printing loop so Good that works So this gives us the ability to print Things let's just do con in So con in should actually be simpler which should just be Yes read keyboard character to a It does actually seem to be buffering One character Oh interesting That's the character red elsewhere That's this character This is so that if you press a key that's not a control s or a control c It gets buffered ready to read later So we're going to have to put that in So this is actually the same code we're using in the bios Load buffered key If it is zero read it otherwise Clear it and here If it's not a reboot Then we actually want to store the key in Buffered key So what if you type two characters while something is being Listed Then You'll lose the first one. I think that's good enough Okay, so let's go to our ccp con in So input Beados Beados con out all output jump Beados So let us print Then oh that didn't work What's this complaining about A local scope was not closed I didn't put an n proc in better Okay, let's try that And run Type something Good good good control s Yeah, that eats That eats several characters. Why is it eaten several characters? Oh, I know what's happening. We are printing the control s and it's being interpreted as a bbc micro Uh escape sequence Okay, let's try control c Is that working? That's not working Uh Because control c is not interpreted in con in it's only interpreting con out Okay, anyway, let's change to higher s text mode Manually with the star key gone Manually run the thing. So if I type control s control a a Then three more a's Yep I remember that from times past vdu 19 The control code 19 otherwise known as control s Is the the code for redefining the palette. So I turned uh Logical color one which this mode is monochrome. So that's white Into Physical color one which is red Anyway, that was a thing That works good So If I look at con in it's Not parsing the character Wait a minute. There's actually a lot more to this. This is a fall through Right it gets the character and then it prints it No, there's a jump. It does not print it But it doesn't parse it either Uh There's two entry points one does not print it One does print it Which one Are we looking at here? console output console input Uh, it reads the next console character to register a Graphic characters along with character turn line feedback says our ecode Yeah, so con in here is actually con ec In the in the original code con in is used elsewhere There's the error handling routine It's used by con ecco And it's used by The live the buffered read routine So this is actually going to Not fall through to print the character Uh, we want to Hmm We want to print it, but we also want to return it in a or do we want to return it in a So this entry code on entry we are putting the value into Param zero and one I think we should do the same thing on exit. So we return the input parameter so that exiting from The actual entry point We are then going to want to reload These and return So the only thing we've got so far that returns anything Other than the carry flag on error, which is important is this See now this will just work Open file can return an error. It should return an error code Uh, I think find first is doing it This is read sequential. This is returning an error. I think we now need to put this in param plus zero And set the carry flag Not there. This is also No, this is an internal So that's fine And I don't think we're doing this anywhere else Yeah, okay So We should be good We also want to change our ccp Let's just Just increment a Okay run So if I press an a That's not what I wanted Interesting I am pressing the same k key the same key each time that should be an a So I'm guessing that these values are not being read in and out correctly That will be a Entry point thing so we are storing The thing in a x in the parameter And once we've done that we are loading the thing from the parameter into a x So con in this wants to be a Jump exit We go press a There we go So we get the a that's echoed From the first key And the b that's comes from the ccp after it returns the value so Good and if I do a control c it should restart ccp Of course it didn't Why did it not do that? because This has I think Yes Because this has put the wrong value into x into param zero I don't even know why that worked to be honest con in Returns its value in a so we want to put that into x That's that's not great code So that's working control c Did I say this was supposed to be easy This is just a Frigging console it should be straightforward transfer a to x jump to exit This dx param plus zero Jumped entry con out. She's here check the console status. Yeah, yeah interesting So the key being pressed by con in Is put straight into the parameter But this is not reading from that this is reading directly from the console and of course there is nothing pending So read character with echo call con in call echo c To echo the character which does this bit So if it's a If it's a control character we know about Ignore it If it's any other graphic character ignore it I'm not sure why this needs to be that ret here is wrong No, it's not wrong. That is just setting the carry flag on exit This isn't falling through even though it kind of looks like it is So carry set if not graphic So return if carry is set. So if it graphics then We do this Character must be echoed before return. So we only echo graphic characters If this logic is weird So that calls tab out to do the work Which expands tabs? Uh But con out Does not expand tabs control out expand Does con out call control out? No Does tab out call con out? Yes So if the user calls console out Tabs are not expanded But it says here that tabs are expanded. So again, is it relying on the terminal to expand the tabs? I'm very confused at the semantics of the logic here and also console input graphic characters Echoed tab characters are expanded Check is made for start stop and start stop printer Okay, this is weird I don't quite follow the logic of what's going on. So let's simplify for now So we read a key. I do think I want to check for control c in the input path that's the Hmm No, actually, I don't think I will Uh, so let's just simplify con in so it actually makes sense Yeah, I think that will do uh honestly Let's just if we compare x with minus one and if Carrie is set It's a graphic character So carry clear meaning it's not a graphic character. So print it Otherwise just exit So we only echo Non graphic characters So control c won't work, but I actually I think that's not going to be a problem. So if I do control g That beeps. Why is that beeping?  I'm getting myself incredibly muddled So here is our jump table Therefore we want the first thing after it which will be here At four five six seven eight nine a b c d e f one eight two f Which is there Break one eight two f continue Okay It wants us to type something step step Con in We're blocked type of control g Okay so A contains seven that's the what that's the the beep character control g So step we put it in x Jump to here We're putting it in the parameter Is it less than one f? I have the sense of this Wrong, that's why okay control g Good it didn't beep, but it did move the cursor back left. That's because uh This is receiving a seven not echoing it returning it to the ccp The ccp is adding one to seven to get an eight which is the backspace character and calling con out Good, that is what we want right Next one this one's going to be moderately exciting We're doing read a line This is the the line Editor This finger quotes around editor there. Uh, this is the thing that Reads a line of text from the keyboard with the ability to Uh, do basic editing So read a line from the keyboard Buffer is at param Size at param Plus zero so Go to the ccp We want a buffer and it's going to Start with the size of the buffer which is going to be 128 for us And then we're going to reserve some bytes for it Here We Here we Set the size. Let me just check to see whether this is whether the size byte includes The maximum number of characters the buffer will hold So I think that does not include The size byte itself So this is going to need to be a one two seven Store it in buffer Okay So on entry we already have the buffer set up with the length in param plus zero so This is the description of the various control codes Certain functions which return the carriage to the leftmost position Do so only to the column position where the prompt ended So this is one of the reasons we need the column position Starting column position is a byte so lda Column position sda Start column position And this is basically A big loop we want to Start with The length And we're going to store that at 10 plus zero Actually, we can do So essentially what this will be is Reading a character Then we type Then we echo the character So it's using con in Ah, yes, that's why we that's why this is using this rather than The bios because we want to honor the existing buffered key Okay, well So read a key without echo easy to graphic character And we know from up here That we want character set so If we are already at The last Position in the buffer or then do nothing So If it's not equal to that then We want to You want to write that to the buffer and increment the buffer position and Echo Which we are going to do using the bios Like so Have not done said continue Yeah, I don't like using a jump there But that will at least work In fact, we've just fall through there Okay, so let's see what this does Type something good Let's actually just change the ccp to make that buffer a lot smaller And see if that reaches the end of the buffer No, it doesn't there we go so Our buffer is eight bytes wide Our pointer starts at one two three four five six seven So we can actually enter that last one Console input is terminated. Oh when either the input buffer overflows When either the input buffer overflows, there should be an or presumably when someone presses return so Mx is the number of characters which the buffer can hold So our buffer is ostensibly eight wides. That's zero to seven So mx should be seven. So we should be able to store one extra character So this should not be a not equals This should be a carry Clear carry set It must be carry clear But I think we're doing this comparison the wrong way around Yeah um We actually want to compare with one plus The easiest thing to do is to swap max and pause, but of course that won't put the value in y that we need for here No, well, there we go seven characters Terminate with either a new line or a return So on exit We want to store the buffer length in the parameter buffer And exit with other things which are Which we can do are control h for backspace But we are also going To support 127 Because otherwise life gets so annoying so this Will be Just thinking how can I do an ore here in a reasonably sane way? The scoping is not making my life easier. I have to say I mean these structured macros are making my life a lot easier But trying to jump into one is tricky so if If the buffer position is not one The buffer position is set to the The next character That we're going to write So yes, if the buffer position is not one Then x is the maximum number of characters in the buffer and sees the number of characters read So that's actually going to be one less than the buffer position Uh, we want to make uh, we want to have y be the buffer position Because we want to index into param and we want to skip that first byte So if it's not one Then we are clear to Delete one character So that will be deck buffer pause Print the The delete character Which will move left one and arrays and loop Otherwise do nothing. Uh, it's not what I wanted. Right Uh, that I believe was deleting back to the beginning of the line, but then buffer position was one So it was skipping this and going through and It was that was a graphic character. Therefore, it shouldn't have been printed That's better And if I press return Then we turn back to the ccp and it loops So what else can we do? Reboot If we're at the beginning of the line boot Otherwise abandon the character. In fact A z continue turns up a jump. So it's actually much cheaper to just uh Load a with a value that's a graphic character and let it fall through the rest of this conditional Well much cheaper being two bytes So If I press ctrl c here Nothing happens. If I backspace to here and press ctrl c It reboots good ctrl r is No, I can do this the easy way. Uh, and r is Is 82 82 minus 64 is 18 So if it's a retight then We want to print a new line We then want to print spaces Until we reach the column position that we started at Uh, we can do better than this We now want to print the string It'd be nice if we could just call the print string function, but we can't so So we compare with buffer max break if it is Equal have we run out of temp that we haven't So the problem here is we're about to call Um Bios con out which will corrupt Why we start that with zero Increment it here and save ourselves a little bit of Pain And what does this do so I type a ctrl r Well, that wasn't right. Okay debug time and we want to break out one out of four Start it We didn't want to break it one effort for but never mind Uh So that is con in This looks Like I think we're here No, we're not Here we are. Uh, this is this piece of code here. Okay, so Delete Reboot The next one here Is retype 1b o 1 So print a new line Okay Load the column position Which is zero because we've just printed a new line Wait We printed a new line with The bios We're doing all this with the bios. We're not updating the Column position So in fact the column position should be z should be Set from the end of the string Wait a second This is using the Blasted Um Bios we want to call here So we are going to put our pha in pla back there And we're going to put A We're going to put an internal con out here So that here we can call Internal con out and it will type it using this code But we don't want to do that here because we don't want these things to be interpreted So in fact Whenever we call con out we want to also increment Column Position or in this case we want to decrement column position to make sure the column position is still kept current so retype line increment column position and Likewise here we want to increment the column position And the count and here we want to increment the column position Apparently we've just used another another page a controller Well, that's still not working, but it's now at least breaking differently. So this looks like Compared with 12 that is 16 17 18 retype line. So break 4 print a new line And you see the cursor has just moved down to there Load the column position, which is 6 Is that correct very much Not correct. I don't believe that right string here Has incremented the column position. It should have but I don't think it has Well, anyway, let's just see where we Let's see it Pipe more I'm going to have to give up on this session soon. I'm tired and going a little bit horse 10 What's at 10 10 as I start in column position is zero yet. So in fact, this should do nothing. This should break immediately Which it did not The column position is bigger than start column position Start column position is zero Yes calling new line should have reset the column position column position is in one f 8 2 Which is seven that's the the characters I've typed So we call new line back. Let's Just put that right here if we need another new line. I can In fact, we do need another new line But that's going to go here because it's part of the console stuff And I'm just thinking that the other place we want it is actually up here to In void No, it's not it's In It's here Yeah, so there we get our extra new line. I'll take out the extra one in the bios in a moment. So control r But now where did we put the bios? Banner, um, I managed to save a byte by reversing the string Okay, well I go on 1b o 9 is where you want to be Okay, so we're here We need to the column position Which is seven. Yeah, it's still wrong. It's at 10 10 is zero start column position is Yeah, I I'm losing it It's late. Okay, so New line. Yes, we're on a new line Load the column position Which is nine. Why is that nine? This should be this is calling internal con out Which is hitting This code is this wrong. I think this is wrong. So if Uh, if the character is 32, then we get zero and the carry is set if the character is 31 minus 32 that's negative and the carry is Set Yes, this should be B bcs that is correct probably Okay, so we go into the new line we print a 13 We are here and in fact, I don't think you want to go through this code at all Not from the editor So we test the key Nothing is pressed. So we go to here PLAA is a 13 print it Read the column position to x x is seven Was the character an eight? No. Was it a backspace? No Was it a tab? No Compare with 31 carry is clear 13 minus 31 Is negative So why isn't the carry set? Well, that's just going to increment the counter Yeah, we we do not want To call con out here and that code was wasn't working anyway um We do want to call it from right string hmm So when in doubt look it up and this does say that if Uh, a is less than operand Carry is clear So Anyway And now we have problems Here because that we have too much code Um, we are actually going to need to put something else in so Uh Let's just bail out to a function. This will cost us three bytes four bytes rather Because we've got the three bytes for the call and one byte for the Return here But it does make the code easier to read which is more important. It still doesn't work Okay bugger 1b34 we want to go to Okay run type control r Okay print A carriage return using the bios clear The column position and let's just look see what the column position is The column position is zero still load column position back in Compare it with the value at 10 which is 16 That was where we started zero one two three four five six seven eight nine ten 11 12 13 14 15 16 Okay Start column position is correct. Something we've done is reset column position in here I don't know what I'll be probably calling uh The wrong thing Actually we want to leave that because that's used by the startup code. Anyway, um Okay, so we should now print spaces So we print a space There we go cursor has moved on one increment the column count and continue and the column count is Yeah, I think this is actually going to print the right number of spaces So let's break at five and continue Right, where's the cursor cursor is in the right place Okay So now we are We are going to print seven characters. I hope but We actually want to start at one not zero Because so this is going to actually print garbage at the beginning But it should at least print some characters. So let's give this a try So a is seven that's the length of our buffer We're going to print this and it's incorrect So we increment the column position and the count Go back to the loop And continue So this should be our first character It's a 10. Why is it a 10? oh a 2047 Does not look like a valid Buffer pointer Um, I know what's happening We are not writing Yeah, we've done the same thing here We have not Um We're not actually writing anything to the buffer. So the buffer is still full of relocation bytes Or no If a is less If a is greater than or equal to The parameter if it's greater than equal to 32 Okay. Yeah, we are actually printing it here. Therefore, we must be advancing Column position and buffer pos But that's buffer max. We're always writing to the end of the buffer Which is presumably where this eight down here comes from And this should also be buffer pos Buffer pos because we want to only print up to where the cursor is Wow, this is garbage Okay, control r It did it it beeps, but it did it That's because I didn't advance this So we're printing the seven at the beginning of the line There we go So control r retypes It's if the terminal gets garbled Okay, anyway, uh, we've got one more to do which should be fairly straightforward Which is control u and u is 85 64 is 21 Yeah, really we should just be jumping to the To the relevant code and then jumping back again to the loop Rather than doing a call That would save us uh That would save us one byte because You would still this would be a jump that would be three bytes still Uh We would get rid of this three bytes But we would gain three bytes here instead of the rts So nothing there. So the only thing we're doing is losing the rts, which is one byte So it's really not worth it. Anyway, delete line. Delete line is actually similar to retype Code wise in that we print a new line We print spaces However We actually want to print one fewer space Do we Just trying to remember how cpm actually does it removes current line after new line They're just thinking what happens if we're at the beginning of the Uh Beginning of the line. It's not going to work. Sorry. Let me say that more clearly Uh, what I've seen cpm do when you do a control u is it new lines it indents One fewer character than retype did and it types a backslash indicates that you've cleared the line Uh, of course, if you're at the beginning of the line, that's not going to work anyway, um so column position Is in a if column position is less than starting column position Continue so if it's if column position is greater than or equal to no, no See, I'm hoping I can get my one different here somehow But I don't think I can because I want to I want to break if greater than or equal to For which I need to test two bits rather than one So actually I might as well just just Might as well just do it like this Uh If the column position is not zero print the backspace then print the backslash And then we lose all this code instead Resetting buffer paths back to one where it was originally One of those. Okay run that Control you Yes, that worked And the reason why it's type is printing a half sign here rather than Anything that we would that's a control r That's the control you the reason for the half is because in the bbc micros mode seven text mode you actually get the Uh, the teletext character set which has got interesting symbols like Uh You see Arrows half quarter and so on if I go back into mode three And I run cpm And now I do control you Now we get the backslash In fact, I now Oh, yeah and return works, which is nice I'm now actually unconvinced that backslash is the right character So I'll have to check that up But I believe the line editor works. There is actually one thing I need to do Which is? I want to print the um Print the string Which is more annoying than it sounds. Uh, let's this has to go up here so lda So this should be the length of the string and compare with The maximum length of the buffer Break if they're equal load the um Load the byte print it increment the count and New line so Now I type something and press return That beep means that we have done this wrong once again And in fact, we don't want to check for equality here Because we do want to print the last one. We only want to break We only want to break out if count is greater than the buffer length. So we want to We want carry set but z not set So we do it Yeah, that will do This is just test code. I can't be bothered making it small Okay, that wasn't right So this should be Loading the value Yeah, this should be correct Then we increment Let me go around again Sadly our bedos entry points due to the way they work cannot preserve registers The moss entry points do preserve registers. It's so much easier to work with Are we correctly setting the value After a loop buffer pause Decrement by one Stick it in the first byte Looks okay. Okay, break one f o four So this should break In the bedos except it didn't Presumably because we want to break at two oh oh four There we go We've just used another page so No, I wanted to break at two Oh seven That's better Two oh four is the wrong address. That was where the bedos entry point was So low print the banner done our buffer is in two zero seven zero So Read a line Okay So let's see what we got Two zero seven zero And we see There are indeed seven bytes And a seven at the beginning of the line So yeah, that is doing everything just right So print a new line Now we start counting Oh, interesting. There isn't a zero page form of ldy That makes some of my code rather less efficient And there isn't there is one for Wait, there is one for ldy and it knows it's in zero page. Why is that not done the right thing? odd odd Anyway, um, okay, you get the first byte. Why is now one? Load it There we go five three print it increment count I stepped when I should have nexted Okay Yes, I have completely completely mangled that step, but at least we can go through it again Okay Type something There should be four New line That's a character print increment jump Go through again for the next one increment load character it is print increment Jump did I type x twice? I did xxdv increment load a character 4 4 print Jump Last one we got a 4 4 again That's wrong xxdv it should be Oh, I haven't loaded it yet. That's why there we go. Okay print jump load So this comparison should fail carry is set uh wait Zero is not set So what is in one nine one nine contains a four 2070 contains a four Okay, good right that works Took long enough, but that works So Okay, well that is kind of where I expected to get this time though. I was hoping to do a little bit of actual ccp stuff uh next time we will print a prompt and start parsing the command line Which is annoying It's the ccp's job to parse file names into fcb's Which is kind of grim, but this was kind of grim too. So I suppose Now I'm used to it. Let's just take a quick look how big my bios is My vdos is rather 2k Hmm There are some strings Just see how much relocation there is Quite a lot of relocation actually We are eight five Six no seven minus Probably here Call that 63 Yeah, we have a nearly a nearly 400 bytes of relocation So it's not quite as bad as it looks still quite bad that line editor was a surprising amount of code um When I'm not talking on the microphone I might try and Clean it up a little Yeah Okay So that's that then see you next time


Hello, all hope everyone is doing good. My name is Shraddha and I'm currently working for the system software team in Samsung Foundry Business at Samsung Semiconductor India R&D panel. On behalf of my teammates, Padman Abhin and Pankaj, I welcome you all to the presentation titled non-invasive PCI RAS desk framework for automotive SOCs. This presentation is going to introduce you to the need of a software framework to detect and recover from any kind of PCI related errors which can lead to an unstable system. So let us quickly move to the agenda. First comes the introduction section, whereas the name suggests we will introduce you to this presentation and explain the motivation behind it. Next, we will cover how the RAS feature is integrated in the PCI base specification to provide link level reliability. Then we are going to take the example of design where PCI controller and talk about how its DES or desk features help in extending and enhancing the RAS features so that errors can be quickly detected reported and corrected. Next comes the very important part which explains what really is the need of a software framework and why what we already have isn't enough. Then I'll be explaining a bit of where does this framework exactly fit in our Linux PCI subsystem and how the implemented debug FS structure will look like in the user space. We will then move on to the different use cases where I will show you experiments and results and how sniffing hardware data and passing it to the application level helped us in easier and faster debugging. So let's begin. As you all know PCI is the industry standard IO interconnect. It is one of the high performance complex serial interface providing IO connectivity across multiple platforms like mobile, desktop and automotive. Transistors are getting smaller and smaller and SOCs are becoming subject to higher risk of failures due to external conditions like temperature, EMI, power surges. The transition to faster PCI speeds like PCI 5.0 and now 6.0 is augmenting the risk of errors due to time and budgets to incorporate shorter channel length inside the SOC or electrical issues like attenuation, jitter outside the SOC. As PCI Express is further being deployed into mission critical applications in the automotive, AI, enterprise markets, the need for higher level of reliability, availability and service ability is increasing. Due to this, SOC designers and users are looking for advanced mechanism to help in creating a more reliable, stable and robust product. Some PCI vendors and IPs do provide such features, but unfortunately they are not being used up to its potential due to the absence of a software system to support it. The framework implementation that we are going to present will decrease the debugging time of these fatal issues and provide mechanisms to detect, recover and prevent potential hazards without the use of any expensive hardware based PCI analyzers. Before diving into details of the develop framework, let us understand in a nutshell how reliability, availability and service ability features are available in PCI and how they make sure that underlying hardware failures do not cause interruption in the overall system operation. So let us begin with reliability. Features in PCI protocol like parity or ECC data protection and mechanisms like link CRC and end to end CRC error detection help in ensuring data integrity. An acknowledgement or not acknowledged, which is like the ACNAC mechanism handles seamless retransmission of error in a spacket and includes timeouts to ensure broken links do not go unnoticed. Basically any mechanism that allows the PCI interface to be more tolerant to external or internal conditions is considered a reliability feature and as we just understood PCI has many of them. Next is availability. Availability provides active information on whether the system is working as expected over a certain period of time. The implementation of event counters in the system, which can point out the number of times the system has entered into any error state or any LTS system state can be a good example of ensuring availability. Service ability explains how device can recover from any fatal error without disturbing the operation of the system. For example, hot plug ability is a feature of the PCI which ensures that we can restart PCI interface by unplugging and replugging the device without affecting the working system. Error injection can be really, really important to analyze the PCI response to errors and make sure that the service ability is high. So now before putting any product into production, if we have enough of error injections and we check how a system behaves or responds to those errors, it is going to be a real benefit. Quick and easy identification of PCI runtime issues or bugs is considered a service ability feature which the framework can provide. So now we are going to take the example of Synopsys Designware Controller and I'm going to explain in the next three slides of how much data can be captured, analyzed and used in PCI controllers to enhance the reliability, availability and service ability mechanisms. So DES stands for Debug Error Injection and Statistics. Now the debug feature that we are seeing here, so the D of the DES provides status of the current PCI system. So in case of any failure, these status registers can be read and the underlying software can understand where exactly the failure has happened and implement the respective fix. So if you see the different kind of debug features can be the data link layer up and down indicator. So it's going to indicate when the link suddenly goes down. So this is really important to understand the reliability of the link. The AXI slave and non-DBI transfer pending status, the DMA transfer pending status, the receive request pending status. There's a pulse that indicates that the receive queues have overflowed. This kind of data can be read in the debug registers. Now the state of the current link, like the, what is the LDSSM state where exactly is the RC or the EP in which LDSSM state are these and the EQ status, what kind of equalization has happened until now, what phases of equalization the link has gone through. All this kind of data details of enter and exit latencies of different ASPM link states. So in ASPM low power link states, there are different to enter and to exit some amount of latency is required. What were those latencies? This data can be used to analyze and further retune the five parameters to make this a more reliable and better system. All these are like the debugging features which can be used to understand the current system in detail and debug in a much faster and efficient way. Next we move on to the E, which is the error injection. The design where PCI controller provides support for the application to inject the following errors. CRC error, sequence number error, DLLP error, sync header error, FC credit update error, TLP duplicate error, specific TLP error. With the help of such kind of error mechanisms, we can inject common errors like ECRC, LCRC, unsupported requests, completed award, and we can check the error detection, error logging and error handling mechanism. So basically any sort of error injection is going to test the system on how fast or how efficiently the error is detected, how properly the error is logged, and how well is the error handled. So validating the system's error response mechanisms at an early stage is going to help reduce the risk and increase the robustness of the system. Next we move on to the S, which is statistics. One, the statistics feature keeps track of the various event counters that are happening throughout the system. And two, it keeps track of the time the controller spends in doing each of these various events. The following counters for time-based analysis are present. The time PCI spends in each LTSSM state. For example, the time it spends in L0, which is the common working state of the PCI, the time it spends in L0, STX, RX, which is the first power saving stage, and the time it spends in L1 and its substates, which have further stricter power saving mechanisms. It also calculates the time the link spends in recovery or in configuration. This feature also captures the amount of data processed by measuring PCI TX TLP header plus TLP payload. It does the same for PCI RX TLPs. So basically these debug counters help to understand the performance of the system by measuring the percent of time the controller spends in each LTSSM state and also obtain information regarding the TX and RX data throughput of the PCI in the system. Next is statistic event counters, which is clubbed into different kind of events. So one is the error events. Statistics stores the different kinds of errors that are happening in the system. These include errors like overflow of the buffer, buffer underrun, decode error, disparity error, receiver error, FTS timeout error, framing error, bad TLP error, ECRC errors. Basically any error that you can think of. Second is the straight state transition events. These count the entry and the exit for each LTSSM state, which means the number of times the PCI link entered L0, L0, AS, L1, etc. It also counts the speed change and the width change counter, the number of times the link downgraded its speed or its width or upgraded its speed or its width. Third is the response events. So basically it contains or records the number of times TX, RX, ACT, DLLP was sent, nullified TLP was sent, NAC, DLLP was sent, etc. Transaction events. So this will be counting the number of TX, RX memory read write, TX, RX config read write, IO read write, etc. that PCI is doing. So as we can see the controller keeps track of almost all events that are happening in the PCI system and this counter can be read by the application at any time to help in better debugging, understanding and maintaining of the system. Now we move to the need for the proposed RASDES framework. The Linux kernel being used by the application has generic frameworks to log some of the RAS or the AR events. We all have heard of the AR driver present in the current Linux subsystem, right? Errors are reported on the RC, but one, there is no support present for errors being reported on the EP side. Two, lot of errors that are part of this RASDES feature is not a part of the AR handling. Three, features like error injection and statistical monitoring is not present. Another commonly used user space utility is known as RASDEMI. This monitors the RAS events from the kernel trace log and reports it on the system log. But since PCI IP supported by multiple vendors, the usage of extended capabilities of the PCI RAS or usage of the more advanced RAS features turns out to be cumbersome and not so useful. In short, the generic RAS features on the Linux is not capable of providing complete debug and statistical information for debug. Our framework is going to dig this important data and bring it up to the application level in an easy and readable form. Associated designers are looking for mechanisms that provide better visibility into the PCI interface behavior and better control over its operation. For suppose implementing programmable timers and timeouts inside the PCI interface logic as well as mechanisms for generating errors without side effects will improve the reliability of the system. The RAS features gives us a way or an opportunity to tweak the timeouts for various events. Also having dedicated monitoring status and control interfaces for each PCI interface functional layer like the file layer or the MAC layer will allow associate designers to flag specific events and errors and improve the overall serviceability and availability of the system. So currently most of the protocol errors are captured and interpreted to a usable readable form by a hardware PCI analyzers. These analyzers are connected between the root complex and the endpoint of the PCI subsystem. They capture the PCI traffic but some applications use PCI chip to chip communication where the communication is achieved through PCB tracks. So it does not use any external hardware connections. In these cases connecting a hardware PCI analyzers is going to turn out to be impossible. Moreover hardware analyzers are really expensive and hard to maintain. Our framework will to some extent replace this hardware analyzers which will be a lifesaver. So let us now move on to the proposed framework implementation. This figure shows the software stack of the RC and of the EP. So like you can see the existing structure goes down from the virtual file system or the VFS in the user space down to the PCI file via which the PCI transactions will finally take place. In this flow we have added two modules that will help us achieve all that we have spoken about in the previous slides. The PCI RAS framework will be sitting with other PCI device drivers. This driver will basically pluck out the data by reading hardware registers and passing this information to the user space where a debug FS system will display this data in an understandable form. Some RAS features also allow us to tweak hardware parameters for debugging. Example we can increase the ASPM entry or exit latencies or hold LTS7 in a particular state. In this case debug FS will accept input from the user and pass it down to the RAS framework which will finally take care of implementing it in the hardware. So what is debug FS and why did we use it? Debug FS entries as we all know is a special file system available in the Linux kernel. It is a simple to use RAM based file system specially designed for debugging purposes. It exists as a simple way for kernel developers to make information available to the user space. Unlike PROC which is only meant for information about a process or CIS FS which has a strict one value per file rule debug FS has no rules at all. So since there is no one value per file rule you can also dump like a full buffer in debug FS entries. Developers can put any information they want there. To compile a Linux kernel with a debug FS facility the config debug FS option must be set to yes. Once we boot the system it is typically mounted onto slash CIS slash kernel slash debug. A lot of interfaces like the clock, Ethernet and GPIO use the debug FS in some form or the other. So this is how we have split our debug FS entries into multiple files and organize them in a hierarchical directory structure. The goal was to make it as simple for the first time users to understand. So move down from CIS to kernel to debug. This is where our debug FS entry will be mounted. Suppose we have five PCI controllers in the system. Each of these controller is going to have a separate directory in the debug FS folder. Depending on which controller RAS data we want to read or understand we can enter the respective directory. Inside each controller there will be three sub subfolders each for debug error injection as statistics as you can see here. Inside the debug there are n number of files each having a specific debug value that the user or developer can read to explore the current state of the PCI system. Suppose we want to read the debug feature and know whether the RC has detected EPs lanes. For this there is a debug value called lane detection. So if we cat on this file we will be able to see the value 0x0 for lane not detected and a value 1 for lane detected. So suppose there are four lanes in the PCI connection. We can write onto the file to indicate which lanes value we are looking for because a feature like lane detection is dependent on the lane per lane. So in this case the lane which we want the information for should be echoed onto this particular file. So echo 1 to this file will read back detection status of lane 1 when the cat is done. Similarly inside error injection there are n number of files each having different errors that can be injected. Suppose we want to inject the TX LCRC error. Here writing to the file is going to tell the driver how many LCRC errors we want to inject. If we write 5 here for the next 5 PCI transactions that will be initiated it will have LCRC error injected into it. On reading back this file it indicates how many errors are left to be injected. So after making two transactions if you read or do a cat on this particular file it will show the value 3 meaning 3 error injections are left. Now let's move to the statistics directory. Instead of directly having files to read we have sub-directories for each type of event that we had seen in the previous slide. So the counter can be error count or an entry count. Now within this sub directory 3 files will be seen. Counter enable file whereas the name suggests it is to enable or disable the counter. Writing 0 will disable this counter and writing 1 to it will enable the counter. The next file is the counter value and this is exactly what we need. Reading this file will give the count of the number of times the specific event has occurred. Another file is the lane select. So this file only comes into picture where the event is lane specific. Suppose receiver error this is something which is lane specific event. And for each of the lanes present in the PCI subsystem the error count can be different. In that case we need to specify the lane that we want to read the counter for. Now we are going to move on to one use case each from D, E and S which is the debug, error injection and statistic feature. Where I will first show you a glimpse on the implementation and then try to narrate an experiment that we did with the feature and how it helped us in our daily debug game. So let me give you an idea that the current implementation is done keeping in mind the design where controller. Since the RASDES features implemented by different vendors are vendor specific. In future these features can be a part of the PCI protocol like AERs today and then all PCI vendors can implement these hooks that the general framework provides. Currently it's written only for the design where PCI controller but it can easily be ported to other vendors as well. Our patches are currently under review in the kernel mainline and I have provided the link for the same. Now let's move to the implementation. This is how a basic debug FS read or write function will be written. The read function is going to read data from the hardware registers and copy this data from kernel buffer to user buffer. So as we can see a simple read from buffer function does this copying of data. The write function copies data from user buffer and does the respective programming to the hardware registers. So here you can see that we are reading this SD lane status register. It provides information like whether the RX is valid, whether lane is detected, if TX and RX lanes are electrical idle. Other debug registers provide options to disable transition to recovery in case of framing error or it can hold LTSSM in a particular state manually. Or it also gives an option to jump to a particular LTSSM state directly by skipping some of the states. It can also dump the internal PM state of the master as well as that of the slave interface. All of these debug options are extracted from registers and displayed in different files as shown in the previous slide. This is then the experiment that we had conducted to make use of the debug feature. So the problem statement that we were facing here is when we were trying to link up between the RC and the EP, the LTSSM state was stuck in detect quiet and it was not moving forward and the link up was failing. So first I'd like to show you when you do a CD to CIS kernel debug you will be able to see the platform, the folder for your PCI platform present there. Inside that you can see the RAS disk debug registers which is inside which there can be different features like the force detection, lane detection, RX valid. So now we echo one to the RX valid which means I am trying to read the RX valid value for lane one. Now when I cat the same it's showing a zero. Similarly I do that for the lane detection and I read back zero. Now these values zero show that neither has the lane been detected nor is the RX valid. Currently at this time this is expected as we have not yet enabled the LTSSM state and the state transition has not begun yet. So currently the values zero are expected. Then I ran the link up script which initiated the link up to begin between the RC and the EP. But what we received was a file link never came up message which indicated that the link did not happen properly. Post this the first thing that we had to do was read the current LTSSM state and realize that the state was still stuck at detect choir. Now I wanted to check whether the lanes are valid and whether the lane has been detected. So when we did an echo one to the RX valid which is for lane one and I read the RX valid. I found the value to be one, which means the RX valid had been detected. Now RX valid is something that can detect that can tell you about whether a lane is broken or not. So if the value would have been zero it would have indicated that there's physical broken lanes on your PCI system. But in our case it was one indicating that there were no broken lanes. Next we I went on to read the lane detection value. Here the lane detection value was still zero. So this indicated that there was something wrong with the lane detection and it made us curious to know why this was happening. So on further debugging it was identified that due to a five parameter issue the lane was not detected in time even though it was present there. So each LTSSM state has a timeout and somehow a five parameter wasn't detecting the lane in that particular time frame. So here we tried to force lane detection, which is another debug feature. And the lane can lane detection can be forced from software. So when I wrote 0xf which means force detection for all lane 0123 and then try to link up we could finally see the link was up and done successfully. So this is how the various debug features like lane detection, RX valid, whether your RX is idling, forcing LTSSM states, holding LTSSM states can be useful in debugging a link up scenario or a width downfall scenario, speed downfall scenario, etc. So now moving to the error injection implementation. Here we have not created separate functions for each error injection as the offsets are in order. So when we do cat on a file and the read function is called we have extracted the error number from the file name. So depending on whichever file name is there, the error number is extracted. And according to that the offset is set. Then we read the register of that particular error to indicate the number of errors that are left to be injected. Similarly, in case of write we copy the value from user buffer and program the respective register to enable error injection and update the count of errors to be injected. This again extracts the error injection number based on the file name. There are overall around 35 errors and all of them use the same read and write function. The error response can be checked by clubbing debug and statistic features after injection. So for example, when a framing error is injected and it occurs, the PCI system is supposed to move to a recovery state. So after injecting the error, we can read debug registers to note the current state is in recovery. We can read the framing error pointer and also check if the count of framing error has increased. Or suppose after an LCRC error, the system is supposed to retransmit the PLPs and recover on its own. So we can check the PLP retransmission count and make sure the data was transferred properly. Now here we can see the experiment that we did to inject errors to test system response. I'm going to take the example of LCRC error injection. So again, we need to go to says kernel debug, but this time instead of going into the debug folder, we go into the error injection folder. Inside the error injection folder, you can see immense amount of errors that can be injected. For example, here we can see RxECRC, RxLCRC, TxECRC and TxLCRC. So suppose we want to inject LCRC error. So now we are going to echo one in the LCRC error counter-enable. So before injecting any error, I am enabling the LCRC counter so that post injection we can check whether the error was actually injected. So here I am just echoing one to counter-enable to enable the error and then I'm reading the counter value to make sure that it's zero before injecting any errors. Next, I'm going to inject the LCRC Rx error. So for that, I'm going to write one. Let us just inject one error. So I'll just write one. When I read back, it shows me one, which means that one error is left to be injected. The counter value is still zero because the injection has not yet been done. As I mentioned before, the injection will only be done when you initiate any transaction. So now we are initiating a transaction using a custom script that we have. So here as you can see the test came as OK, which means the test did not fail and the data was transmitted successfully. This is because LCRC is a correctable error. So by this, we made sure that the system response to this error is correct. Now, when we read the LCRC counter value, it is one indicating that the error injection actually happened and the system was able to detect this error. When we now read the RASDS error injection value, it is showing zero indicating that zero errors are left to be injected and the one error has been injected. Next is the software implementation for statistics. Here again, we have created a single read and write function for counter enable and disable and extract the event number using file name. The counter value is a read only function where we are reading the corresponding hardware register and inform the user of the number of times the event has occurred. Similarly for lane select, we have a write and read function which will copy required data from the user buffer and set the lanes in the hardware. As discussed before, it can dump data regarding fatal errors, non-fatal errors, correctable errors, non-correctable errors and so on. However, it is different from AER in the form that this debug FS is also available to be read on the EP side. As we know, AER only has support to inform about the errors on the RC side. And of course it has much, much more information when we compare to what is tapped by the AER. Now, if anyone has used a hardware PCI analyzer, we know that it generates a report that contains a pictorial representation of how much time the link has spent in each state. Each LTSM state may be recovery, config, L0 or L1. Now in this case, we can do that by simply reading a debug FS entry. This is how the framework is helping in efficient debugging. Let's try to understand one of the experiments that we conducted regarding the statistical feature. So we were facing a problem with extra power consumption in one of our test suits. So to debug this, what we did was we tried to read the L1 entry counter just to understand how many times the link enters L1, how much time it spends in the L1 and so on. So now again, first I'll explain you the directory hierarchy. So we'll go to CIS kernel debug and this time instead of debug or error injection, we'll go to the RAS desk counter directory. So inside that there are various statistical folders having different event counters like you can see computer timeout error, abort error, decode error, L1 entry, what is the speed, how many times the speed has changed, how many times the width has changed, unsupported request error and so on. Now when we go inside any particular event folder, for suppose L1 entry, we can see the three different files, counter enable, counter value and lane select. When reading the counter enable, it shows disabled as by default all the counters are disabled. The counter value is zero because yet nothing has happened and the counter is not enabled. So then firstly, we enable the counter. So I just enable the L1 entry counter and on reading it back, I could see that the counter is enabled. The value on reading is still zero because the link has never entered L1 yet. Now we're going to run a script to enable L1. The read value shows 14 which shows that the LTSM state is in L1. Now we're going to cat the counter value and I saw that the value was 6A, even though the value should have been one because we initiated the L1 entry only a single time. On further reading the counter value after a few seconds, I could see that the number or the counter value to L1 entry was increasing. This was more than one despite no active transactions to cause L1 exit and reentry. On every read after delay, the counter was increasing. So this led us to discover about the ZR XTC compliance in Phi. The non-ZR XTC compliant Phi exits L1 state after every 100 milliseconds. So this is why we were facing excessive power consumption because even though the link was in L1, it kept exiting back to L0 which included the latency to exit. So we do have a MAC register which can flag this and skip this multiple exit and entries. So we can inform our MAC that our Phi is ZR XTC compliant and in that case it will skip the entry and exit multiple times. So we try to do the same experiment again after making the controller as ZR XTC compliant. We wrote 0 to counter enabled which will disable the counter and also reset the counter value back to 0. So on reading back the counter enabled register, I could see that the counter is disabled. Next we also read the counter value and it shows 0 as expected. Now we performed various PCI workload which would cause the L1 exit and reentry. The counter remains 0 as the counter is currently disabled. So after a point we enable the counter and then run a PCI load. In this case the exit has happened to L0 and the reentry to L1 happened. Hence on reading the counter value I could see the value is 1. We waited for some time and read the counter value again which was still 1 indicating that now multiple exits and reentries are not happening. On another transaction the exit was re-initiated and hence on reading the counter value we could see the value is 1. So this gives us an idea of how this feature can be used to detect and debug various kind of issues. Coming to the conclusion and future scope to conclude that the current implementation has a great advantage for the critical automotive applications is that the automotive solution mandates a need for reliable and easily repairable solution. Also the error report are handled by corrective mechanism which will reduce human intervention. The error information projected to the user helps in understanding the nature of the error thereby increasing the robustness of the system. The future scope of this development involves implementing a unique mechanism to automatically detect the RAS errors and resolve the errors without taking it to the user level. So we hope that soon we will be able to automatically detect the RAS errors. The developed framework can also be integrated to the Linux kernel RAS subsystem for generic implementation thereby providing flexibility of using it across various architectures and other PCI windows. Thank you. Me and my team members Padmanabhan and Pankaj are here in case you need help with any query. Thank you.


Americans pride themselves on being civic-minded people, but for most of us, it's just that. Something in our minds. Civic duty is something we think about. We know concern. We consider participation. But seldom think of risk as part of our civic duty. Lewis Peters got a chance to do more than think about being a good citizen. He received the ultimate test, and what he did for his community and his country was, in the words of Patriot Nathaniel Hale, above and beyond the call of duty. The story begins here in Lodi, California, a suburb of Sacramento, at Lewis Cadillac Car Dealership. Lewis was just a normal American businessman, doing a job, doing that job well, too. On a quiet afternoon, Lou sat down to tell the whole story to Roger Young, inspector in charge of public affairs for the FBI, an old friend of Lou and Marilyn Peters. And over the years, in 1970 through 1977, we became very successful and was quite prosperous. And it was during the first part of June of 1977, when a local contractor by the name of Elmer Birch came into my office and said, Lou, I have some people that want to buy an agency. And I said, it's not for sale. He said, but name any price. He said they've got all kinds of money and they really want to buy your agency. And after me saying no a couple of times, I finally said $2 million. So it was a couple of days later he came back and they said the $2 million was okay. He said, have you ever heard of Joe Bonanno, senior? And I really hadn't, so I said no. And he said he's the head of the mafia for the whole United States. Well immediately I changed my whole train of thought to negative to positive because right away I want to know what the hell does he want to do? Why does he want to come into Lodi? So I said to Elmer, I said, if I'm going to deal with these people, I'm going to deal with them direct. And he said, okay, well I'll set up a meeting. So I got into my Cadillac and drove to the chief of police in Lodi and told him what happened. And the first thing he said is, oh my God, because he could see all kinds of problems. He said, what are you going to do? And I said, well I'm going to the FBI. So I went down to the office and they ushered me into one of their interview rooms I guess. And then in came, I don't know, four to five agents. And I told them the story. Then they had photographs and I picked out Bill Bonanno. Joe Bonanno, I wasn't too sure. There was enough shady characters there that I couldn't pick him out because I hadn't spent that much time with him. His was just a brief interview, I mean a brief introduction. So then they asked me if I would help them gather intelligence information. And I said I would have to think about it tonight and I said I'll let you know tomorrow. And so I called them and told them yes, I would do it. I didn't understand why these people wanted to come into our county. And I just, I wanted to find out because I know from past experience that once they get in a town, there's just a bunch of animals that take advantage of everyone and everything that they can. Lou, did you ever have any concern for your safety, any fear in this operation? No. Never even thought about it. I felt it was the right thing to do and I just did it. I was asked to help and I was more than willing to help the FBI. So I discussed this with Bob Anderson, the FBI agent in Stockton, that the combination they wanted me to buy property and real estate and in order to do this, I felt that I should be single. I should also be single so that I'd have a reason to move out of the house and get an apartment in Stockton and set up an operation in Stockton. And of course they said that's impossible. You can't get a legal separation from UI. I said this is, you just can't do that. It's not expected. No one would ever ask you. And I said no, but I said I'm just stating what I'm going to do. I came home and told my wife I wanted a legal separation. It had to be tough though when you came home and told Marilyn here's what I'm going to do. What kinds of things happened that night? The hardest part was telling the girls. Did you tell the girls why or just what? I told them that I was on a project and I had to be single in order to do this. Were you having any second thoughts? Wasn't it getting a little expensive in terms of time and effort? It got more expensive, but I could see that there was a tremendous need for this information for the Bureau and I was willing to sacrifice because I felt it was important and I felt it was right and because we didn't want these animals in this county or in any county in the United States but certainly not here. So we found a, Bob and I found an apartment in Stockton and he got the apartment upstairs and they were putting all this electronic equipment. They had the fireplace all turned up upstairs and they lowered a man upside down down the chimney and built shelves and put audio-video cameras behind the wall and had microphones in the walls. They had two cameras set up. One was facing the living room couch and one was facing this dining room table here. It was my dining room table in the apartment. So it was quite an elaborate setup that we had in the apartment in Stockton and Bob Anderson upstairs handled all the tapes and he was aware of when the people were coming into my apartment and he would activate the audio-video and do all the mechanical work upstairs. How was it in the apartment, Lou? You've been a family man. It had to be a little lonely after a while. It was many lonely nights that I spent in the apartment. But as I told my wife, I said, look at it as if I had to go into the service on my true duty. Although I had been in the Marine Corps for three years, I explained that to her that it was like, I was going into the service for a short period of time. At some point, Lou, you had one sufficient confidence of Joe Bonanno to go over to visit his home, him at his home in Tucson. In all these meetings, I tried to portray myself as a very close friend. Like, for example, one time when he came to Lodi and he saw the agency, I was driving him back to my apartment. He was sitting in the car next to me and I said, you know, there's something that I would like to say, but I don't want to bother you. He said, no, Lou, go ahead. He was always very polite to me. And I said, you know, my dad came from the old country and I said there's a lot of mannerisms and things that you do just like my dad and I said my dad, as you know, passed away a couple of years ago and I said you're like a second dad to me and he was very pleased that I felt that way towards him and it was a continuing process of using everything that I could think of to get close to him and the resemblance of his mannerisms and my father's is like a jackass and a human being. But again, I used everything. It was just a continuing process in my mind of getting closer and closer to the old man because I felt that's where any intelligence information would come out from the old man. It had to by this time be taking a little bit by surprise, didn't it, that you had been really getting a lot further than the advice that the FBI tended to indicate you would be the position to be in, including the stay in his home and now going out to dinner with him. Did this have any special effect on you? Did you see this as giving you more opportunities to do something? I just felt that I was getting close enough to him now that things would probably start happening. I even volunteered when I knew that I was going to Tucson to have a nagra. I said I won't be able to remember everything. I said why don't you give me a nagra and I can change the tape and pick up anything that's important. I said no, no, it's too dangerous. They wouldn't let me do it. I was willing to do it because I wanted to nail him. But I always tried to use everything and probably the hardest part for me was to try to keep my mind going three steps ahead of him and yet remember everything that was said so that I could tell Bob in my column, like a debriefing session, everything had happened because I didn't have any tape or anything and it was all by memory. How was the case coming now at this point in time? Was the FBI satisfied with the way things are going? Yes, the FBI was satisfied and I was very disappointed because I felt I was failing. Although I turned in I guess 67 names of people across the country that were involved with the Banana family most of them they had never heard of before. And I think it was probably in November or it was in the month of November of 1978 that they wanted to close everything down and pull out the monitoring devices in the apartment and Bob and I talked about it and I wanted to continue because I hadn't succeeded yet and I felt that something was going to happen before too long and I said, we've got to keep it open we can't close it down and Bob spent hours writing a report and all the reasons why we should stay open and so again we got the OK to leave it in operation for another couple of months then in January they came in and said OK, this is January of 1979 they said at the end of February it's closing period no more reasons or anything it's closing because they felt that they overextended themselves to a degree and they were right on the borderline of whether we should continue the operation and they wanted to close it they had not made a decision at that time as to whether they would prosecute or not based on what they had or they didn't have adequate information they felt to do anything and so then they were trying to figure out OK, how are we going to get Lou out of this situation well I had two heart attacks back in 75 or 76 so they thought they would set up a fake heart attack to get me out and they wanted to subpoena me before the federal grand jury as another reason to get me out and I said no I don't want to go before the federal grand jury because they said there will be 19 more people that will know what I've been doing I said I don't want to do that so I thought about it and I said well all right, send me the subpoena I changed my mind and I said might as well get this thing over with do it and do it right that will give me a reason for calling the old man so on the morning of the 15th of February 1979 I was sent the subpoena to appear before the federal grand jury everything was formal and legal so I went to the office that morning and I called the old man's home and he said what are they looking for the records well when he said that I don't know why but it triggered in my mind the fact that I did sell a Cadillac for Bill Bonanno and he wanted all the money in cash because I guess the Treasury Department had his three companies banking or checking account secured and the car was registered to one of the corporations and he wanted all cash which I gave him and he had to sign all the receipts and everything so I was protected then I mentioned this I said the only thing that I can think of is this car and I explained it to him that he wanted cash and the reason why and I said that's why I called because I didn't know what to do he said well you cannot discuss this with the grand jury because you'll hurt the boy and he said we discussed it a little bit more and then he said can you pull the records so when he said that I knew I was getting on solid ground and I said yes I can pull the records he said pull them and rent them I said fine I'll do anything you want me to do you know that and just build up his confidence and I never asked him for what or how he wanted me to do this I let him tell me what he wanted I did not want to get involved in entrapment which had been discussed with me many times I had to be careful not to lead them into something that they had to bring it up and once they brought it up then it was open territory for me so we discussed the records and he asked me several times to pull the records to destroy them it wasn't just a casual remark and I would play I'm a little hard of hearing anyway but I played a little hard of hearing and had him repeat several times that he wanted me to pull the records and destroy them so he did repeat yes he said pull the records and destroy them because it will hurt the boy that ended the conversation I took the tape out of the recorder in my office and went to Stockton and went up to Bob Anderson's apartment on the tapes if there was anything important he always made a duplicate so he asked me should I make a duplicate I said well I said you might as well there might be something on there that would be important and so he was duplicating the tape and we were listening to it and all of a sudden he jumped up he said you got him he was excited you know as much as I was and then in the next couple of months we were able to get Jack D. Filippi on perjury and obstruction of justice I think there were seven counts against Jack D. Filippi and I think they have him on five I could be off one or two charges but then on April 5th of 1979 I did go before the federal grand jury and I did testify When did the trial take place? It started probably some of the preliminaries towards the end of May of 1980 and I went down to testify and get ready for the trial probably the first week in June and the prosecuting attorney was getting the dates that he was going to cover and wanted me to refresh my memory and going over the evidence that we had then he looked up at me and he said Lou Peters he said you're my biggest problem and I said what? he said you're my biggest problem he said how in hell am I going to explain you to the judge to convince him of everything that you've done for the bureau he said I could walk up and down the streets of America for ten years and would never find another Lou Peters who did you have any special feeling after your testimony was over for long days how did you feel when you came down off the stand? I felt great I felt great and when the judge brought down the verdict on September 2nd of 1980 he did state in the in the report that the evidence and the testimony of Louis Peters left no doubt to the guilt of both Bonanno and Jagdy Philippi which kind of made me feel good Lou as you look back is there anything you would have done differently? the only thing that one thing that I would change when they asked me if I would work with them I would have said yes instead of waiting to the next day as I told one of the attorneys at the justice department I couldn't understand why they terminated it because they could use that same evidence six months down the road because I felt I was very close and with them knowing that I had this information I pulled all the records I did what they wanted me to do and I kind of made a statement to the old man that well this should really bring me into the family he said Lou you're already in the family and they didn't mean just friends I was looking for something bigger than just obstruction of justice and I felt if I'd had more time I could have gotten something more concrete, heavier that maybe they'd have dragged him from his home instead of calling him on the phone and asking him to come down he is 74, 75 years old but he's also a killer murderer and the hurt that he's created for people across the country he doesn't deserve any sympathy he doesn't deserve anything but the punishment that the law requires based on the conviction that he has received Lou let's talk just a little bit about the nature of the beast the organized crime family I feel that well during the case I said to Bob Anderson I said who came up with this organized crime and he said what do you mean I said who came up with the name organized crime and he was puzzled by my question because it's a term that the Bureau and the Justice Department use for any white collar worker that's involved in illegal activity or a group of white collar workers and he said why do you ask that and I said because I think they're the most disorganized group of people that I've ever met in my life I said no wonder they go broke because by the time they make a decision you could lose your business I said I make my decisions quick and fast and today not sometime down the road I was that was the biggest thing that I was totally amazed with their total disorganization that they have maybe it's their way of being very cautious and very protective but that's the thing that almost made me a nervous wreck is to get them off dead center and get them moving you've talked about your contacts with FBI agents in particular Agent Bob Anderson and Raphor that you two developed over the years what kinds of things did Bob and other FBI people indicate to you which helped develop your confidence in them they are very sincere caring about me as an individual I would come up with some really wild ideas about because I wanted to nail them and they were always very protective of me making sure that my safety was always number one on their list and when I would meet agents they had a very sincere feeling about me caring or pleased to to work with me because I was really trying to do something that they've been trying to get businessmen to do all over the United States there's a time I believe when you have to stand up and be counted for and I agree that I probably want the extreme but that's my way of life when I tackle something I believe and going at it 100% Lou and decisions were made during the course of the investigation were they joint decisions you would participate in them and sometimes what you would it was more of a like a round table discussion not all of them but most of them anything it was you know really important or would have some effect on me personally it was always discussed ahead of time and the general path that I was to take was laid out and but I always felt made to feel that I wasn't just another citizen that they really cared about me and if the same thing happened again and I knew the results or I knew someone else having the same problem I would still go to the FBI suppose a businessman were to come to you and ask for advice what kind of advice would you give him Lou? well I believe that 90% of it would be covered in his own mind because if he felt that it was the right thing to do he would have the feeling inside that I have a responsibility depending on how deep he wanted to get involved I suppose even if he got involved just on the periphery at some point he may have to go public with that cooperation does that change things in terms of concern for one's family safety? well I suppose it would I wanted to go public for one reason which I've already mentioned and that is that I would hope that businessmen across the country would stand up and be accounted for and if these animals came into that town that they would at least call the FBI to let them know they're here they may be nervous they may be scared but not half as nervous or half as scared as if these people actually did get in that community and took control of city hall and took control of the police department they'd have more problems than they whatever dream could exist if they didn't stand up to do what's right when I when I heard the news of the conviction that they were both found guilty I felt that all the time and all the waiting and all the effort was certainly with the effort because of the conviction and I was very proud of what I did for my country on September 2nd 1980 Joseph Bonanno and Jack D. Philippi were convicted of conspiracy to obstruct justice Bonanno was sentenced to 5 years in prison D. Philippi also convicted of perjury was sentenced to 2 years in prison on June 12th 1981 in Sacramento Louis Peters received the Attorney General's Award for Meritorious Service Assistant Director Roger Young presented this high commendation as Lou's family looked on I was very proud of everything that I did for the FBI and I'd be very proud to do it again