Hacking Microsoft BASIC

Hacking Microsoft BASIC

Ben Eater 151 023 просмотров 9 591 лайков

Machine-readable: Markdown · JSON API · Site index

Поделиться Telegram VK Бот
Транскрипт Скачать .md
Анализ с AI
Описание видео
Code: https://github.com/beneater/msbasic More 6502: https://eater.net/6502 Support these videos on Patreon: https://www.patreon.com/beneater or https://eater.net/support for other ways to support. 0:00 - Peek and poke 2:13 - Poking to the LCD 5:33 - Adding new BASIC instructions 8:45 - LCDPRINT instruction 12:15 - LCDCMD instruction 12:41 - Initializing the LCD 15:16 - Testing it out ------------------ Social media: Website: https://www.eater.net Twitter: https://x.com/beneater Patreon: https://patreon.com/beneater Reddit: https://www.reddit.com/r/beneater Special thanks to these supporters for making this video possible: Adam Bursey, Adrien Friggeri, Aleksey Smolenchuk, aliceitc, Anthony Weems, anula, Ben, Ben Cochran, Benjamin D. Williams, Benjamin Elder, Benjamin Keil, Benji Bromberg, Bill Cooksey, Binh Tran, Богдан Федоров, Borko Rajkovic, Bradley Stach, Brian Haug, Carl Fooks, Carsten Schwender, Chad Fertig, Chai, Chris Anders, Chris Lajoie, Craig Hawco, criis, Cristi Cobzarenco, Daniel Tang, Dave Walter, Dave Westwood, David Clark, David Cox, David Dawkins, David House, David Klassen, David Sastre Medina, David Turner, Dean Winger, Deep Kalra, DemoniacDeath, Dennis Henderson, Dilip Gowda, Dirk Sperling, Dmitry Guyvoronsky, Dustin Schoenbrun, Dzevad Trumic, Emilio Mendoza, Eric Dynowski, Erik Broeders, Erik Chancy, Erik Granlund, Ethan Sifferman, Eugene Bulkin, Evan Serrano, Evan Thayer, Eveli László, Fifty1Ford, George Harris, George Miroshnykov, Glen Jarvis, Gregory Burns, GusGold, Hovis Biddle, Ingo Eble, Ingram Leedy, Isaac Parker, Jack McKinney, Jacob Ford, James Capuder, James Chacon, Jason DeStefano, Jason Grim, Jason Thorpe, JavaXP, Jaxon Ketterman, jemmons, Jesse Miller, Jim Kelly, Jim Knowler, Jim Rees, Joe Beda, Joel, John Henning, John Rivoire, Jon Dugan, Jonn Miller, Josh Smith, Justin Williams, Kai Wells, Kefen, Kennard Smith, Kenneth Christensen, Kristian Høy Horsberg, Kyle Kellogg, Lambda GPU Workstations, Larry Scherr, László Bácsi, Léonard Hehlen, Lithou, Marcel Wysocki, Marcos Fujisawa, Marcus Classon, Mariano Uvalle, Mark Day, Mark Frankford, Martin Noble, Matthew Clifford, melvin2001, MICHAEL SLASS, Michael Tedder, Michael Timbrook, Michael Weitman, Miguel Ríos, mikebad, Miles Macchiaroli, Mlok Karel, Nate Welch, Nicholas Counts, Nicholas Moresco, Nick Chapman, Olivier HUBER, Örn Arnarson, Owen Arnett, Paul Heller, Paul Pluzhnikov, Pete Dietl, Phil Dennis, Philip Hofstetter, Ponytail Bob, ProgrammerDor, Ralph Irons, Randal Masutani, Randy True, raoulvp, real_huitz, Richard Wagoner, Rick Hennigan, Robert Diaz, Robert Walsh, Robey Pointer, Roland Munsil, Ryan Morrison, Sagnik Bhattacharya, Sam Sturgis, Scott Holmes, Sean Patrick O’Brien, Sebastian Kopeć, SergeantBiggs, Sergey Kruk, snc, SonOfSofaman, sorek.uk, spookybassoon, Stefan Nesinger, Stéphane Dumont, Stephen Kovalcik, Stephen Riley, Steve Jones, Steve Harris, Temo Tchanukvadze, This person's name is too hard to pronounce, Thomas Eriksen, Tim Oriol, Tim Sanders, Tim Walkowski, Tom, Tom Smith, Trevor Johnston, Trey Webb, tryonlinux, Tyler Latham, Vaida Narušė, Warren Miller, Wraithan McCarroll

Оглавление (7 сегментов)

Peek and poke

I've got this breadboard 6502 computer running Microsoft basic but so far you can only interact with it through this serial Port Terminal but it's got this LCD module and it would be nice if we could display stuff on there directly through uh from basic and there's a couple ways to do that you know one way would be to modify basic to add a new command for outputting directly to the LCD and we'll get to that in a minute but basic already has some rudimentary built-in commands for interacting with Hardware Peak and poke so if I print Peak 24577 I get zero so what that's doing is it's reading address 24577 and telling me the current value at that address where did I get 24577 from well if I convert 24577 from decimal to hex I get address 61 which is the address of Port A on The Versatile interface adapter which is these eight bits here so if I set one of these bits High by connecting it to 5 volts and then I peek at that address again now I get 16 which corresponds to the bit I just flipped if I connect that bit back to zero volts and Peak again as you might imagine it is back to zero so if I connect a different bit to 5 volts let's say instead of bit four I go with bit five connect that to 5 volts and peek at that address again it shows that bit's set similarly I can use the Poke command to write data to an address so if I do poke 24579 comma 255 that writes a 255 to address 24579 and address 24579 corresponds to hex address 63 which is the data Direction register for Port A so by setting that to 255 it sets all these bits now to be output instead of input so now those pins as output I can hook an LED up to one of those pins so I'll just hook a I'll hook an LED through a resistor uh to ground now I can poke 24577 that same address we were peeking at before and set it to 16 to turn on that same bit and that turns on the LED poking a zero into that address again of course turns off the LED so now we can use the same concept to poke values into a port B which is connected to the LCD so I have some poke instructions

Poking to the LCD

that initialize the LCD here that I'll paste in so the first instruction here writes 255 to address 24578 and that's the data Direction register for Port B so that just sets all of those bits to output and the rest initializes the Port into four bit mode so 2 4576 that's the address for Port B and this just writes different values uh toggling the enable bit each time to send each command to initialize the LCD and I'm not going to go into all the details of each command since I did that in a previous video but you can either check out my video on that or you can see the data sheet for the LCD that I've got uh on my website but the way the LCD works you can either send it commands or characters to print so here's some code for sending a command and this takes a command in the variable able CMD which is just going to be a number and it sends the top four bits toggling the enable bit followed by sending the bottom so then this sub routine can be called to send a command then I've also got a similar code to send a character again it sends the top four bits of the character in this case it's in this variable car Dollar Plus it sets bit for it indicate that it's a character not a command um and toggles the enable bit and then it sends the bottom four bits so with these three sub routines I could call go sub 1000 to initialize the LCD so you can see that initializes it and then I can send commands to put it into whatever modes I want so command equals 14 and then go sub 1200 to send that command turns on the cursor for example then I can set car dollar equal to a and call go sub 1300 to print the a to the screen putting it all together I could write a little program like this so we start out with go sub 1000 which initializes the CD then use go sub 1200 to send a series of commands so 40 sets up a two-line display with a 5x8 font command 14 turns the cursor on um not blinking command six uh sets up the cursor to automatically move each time we print a character and not scroll the display um and then one clears the display then I have this string s dollar equal to my message hello world and then I've got a loop to Loop through each character so I goes from one to the length of that string s dollar and I set car to the character I want to print and call go sub 1300 to print that character because that's what that sub routine does and then the mid function here just uh picks out each character from string s dollar at position I it grabs one character and then next I closes that Loop and that's it so if I run this program you can see it prints out hello world but did you notice how slow that was um let me do it again I'll set command equal to one to clear the screen and go sub 1200 and run the program again and look at it look at how slow that is and that's largely because basic is an interpreted language you know when I run that program the processor is spending a ton of time parsing each command so for every single poke command it has to read the letters p o k e and you know figure out what that means it has to read this address 2 4576 you know convert that into a number parse it you know and it has to parse and interpret all this and do the math and everything to figure out what number this computes to and it has to do that for every sing poke command so it ends up being very timec consuming so what I want to do is

Adding new BASIC instructions

add a new instruction to Basics so I could do something like LCD print 65 to print a character in this case 65 would be the asky code for the letter A so this would print the letter A to the LCD but of course you know if I try this I get a syntax error because this isn't a valid instruction but let's change that so here's a source code for Microsoft basic and there's a file token. s which lists all of the language tokens and it uses this macro key keyword RTS uh to Define each keyword with a sub routine that's called whenever that keyword's encountered so I can go down here and Define some new keywords I'll create an ifdef block here so that the new keywords that I Define will only be part of the basic that's built for my computer and I'll add a keyword for LCD command this will be a new instruction for sending a command to the LCD module then I'll also add an instruction for LCD print to print a character on the LCD screen and The Parting quotes here is the actual instruction that we'll now be able to type in our basic programs and the second label here is the an assembly label which I'll Define in a new file so let's save this and I'll create a new file LCD dos where that'll have our LCD assembly code and this is going to be assembly code that goes into the code segment and again I'll wrap everything in this file in an if def um so that it's only going to be included in the version of basic for my computer and so in this file this is where we're going to have the LCD command sub routine and the LCD print sub rtin and so these sub routines are where we're going to be able to write assembly code that will get run whenever we use our new LCD command or LCD print commands in basic and I'm also going to add an LCD a knit sub routine here to initialize the LCD so I'll save this and before I get to the actual code in here I'm going to go over to the msbasic Dos file and at the bottom of this file I'll include the LCDs the new file we just created um that way it'll be included as part of the overall build so I'll save that and then I'll go to aits and add a call to initialize the LCD when basic starts up and so this uh cold start here this is the entry point for where Bas when basic starts up so when basic starts this is where all the initialization uh code runs so this is all an existing initialization code and there's all sorts of if defs and such for different platforms but I think down here somewhere I can um just kind of add my LCD initialization code and so again I'll wrap this in an if def because I only want this code to run in the version of basic that I'm building for my RedBoard computer and inside here I'll just jump sub routine to LCD and nit so I'll save that and go back to the LCD code so now we've got LCD a nit that's going to get called when basic first starts up and then LCD command and LCD print are going to get called by the new instructions that we've added so now we just need to fill in the assembly code for each of these and again I'm not going to go into excruciating detail because I've already covered how to talk to the LCD in assembly in previous videos um so I'm just going to paste in the code I've used before I'll start out at the top here with some definitions for addresses of Port B data Direction register B uh and the bit masks for enable read write and register select then I'll start off with a code

LCDPRINT instruction

for LCD print so I'll paste that in and this code um I've used before it prints whatever character is in the a register out to the LCD screen and you know it starts out by calling this sub routine LCD weight and that's because it's possible to send commands or characters to the LCD too fast for it to process so before we send a new command or character we've got to check to see if the LCD is done processing the last one and you know this wasn't an issue when we were poking values in basic because basic runs so incredibly slowly um that there was no way we were sending instructions too fast uh but here um we do need to implement this LCD weight function but I've already done that before so I'm just going to go up to the top here and based in the function that I've used before uh for LCD weight so this sets the LCD to input and it basically just keeps reading from the LCD and checking the busy flag uh and just sits in a loop until it's ready to receive the next character so that's our LCD weight so we've got that implemented but if we look at our LCD print you know this sub routine here what it does is it prints whatever characters in The a register out to the LCD but we want to be able to you know run the LCD print command from within basic um something like this where we say LCD print 65 and we want this 65 to be the character that we print 65 is the ask key for the letter A so we want to print the letter a in this case so we don't want to get our value from the a register necessarily we want to actually get it from our Command how do we do that and so to figure out how to do that I was poking around in poke. s to see how the Poke instruction works so here's the code for poke and if you think about what poke does it's just a store a it's storing a value at an address so here's the store a instruction and it's storing whatever is in the a register to this address of line num plus y but of course Y is zero so really just address a line num and then right before that it transfers X to a so really it's taking whatever is in the X register and putting it out into address line num whatever that is so it looks like this get num sub routine here is somehow figuring out what address we want to poke to and what value there and it's putting the address to poke to in line num and it's putting the thing we want to poke there in the X register which then gets transferred to a and stored so if we go back and look at this get num sub routine which is just up at the top of the file here the comment here say says it's evaluating expression one comma expression two and expression one is a 16bit uh value and it's putting that in line num and then it says expression two is an 8bit number that it's putting into the X register and that makes sense so from what I could tell these first two sub that it's calling um is dealing with putting the 16bit number the first 16bit number into line num and we don't really need that for what we're doing we just want the value so then we get down here we have check comom which I think is just parsing uh and dealing with the comma followed by get bite which is getting the expression and putting that as a single bite into the X register so I think this get bite sub rtin is what we want so if we go back to our LCD code for our LCD print function here let's add a jump sub routine to get bite that's going to parse and read a bite into the X register and then we can transfer X to a to then put that into the a register because the rest of this code is just going to print out whatever is in the a register to the LCD and I think that takes care of LCD

LCDCMD instruction

print LCD command is basically the same story so I'll again paste my previous code in here for sending a command to the LCD and just the same as LCD print this sends whatever command is in the a register out to the LCD so we can kind of do the same thing where we just call um get bite that'll read the parameter from the instruction put that in the X register so then we can transfer X to a and the rest of this will then send whatever is in the a register to the LCD as a

Initializing the LCD

command so now we just need to implement the LCD init instruction here to initialize the LCD when basic starts up again I'll paste in my previous code and so what this does is it sets up the data Direction register for all pins to be output so that we're talking to the LCD and then it sets up the LCD in 4bit mode and the way it does that is a little bit convoluted here because when you know when we first start up we don't really know what state the LCD is in we don't know if it's in 4-bit mode or 8 bit mode and halfway through an instruction so this first attempt here to set it into a mode might be the second half of a 8-bit instruction or second four bits of an 8bit instruction if it's in four bit mode if it is then it's you know ready to receive another instruction as two Hales and so these next two attempts to set it into 8bit mode May successfully if it started in 8bit mode then all three of these um instructions are basically just repetitive um but one way or the other by the time we're done with all of that we know that the LCD is really in 8-bit mode but of course we're wired up for 4-bit mode so now we need to actually set it into 4-bit mode so at this point we now know that we're actually in 4-bit mode and this is all sort of described in the data sheet um as to how to force this thing into 4 bit mode regardless of what state it's in but this is um how that's done but once it's in forbit mode now we can just send normal instructions to set it up however we want so we want a two- line display the 5x8 font we want the display on we want the cursor on um we don't want to shift the display we want to increment the cursor automatically and we want to clear the display to start it out um and these are all commands that we're sending just like we would send with this LCD command thing um in this case I'm jumping to LCD instruction which I haven't defined here yet um but it's basically the same thing as sending a command so what I'll do um except of course we don't need to read the bite from the user so what I'll do is I'll set I'll add a label here for LCD instruction so here when we load our instruction into the a register and we jump to LCD instruction um we can skip this part where we're actually getting the instruction from the user um and just execute that instruction so hopefully all that makes sense is that's our code then to initialize the LCD but with that I think that's it you know I actually found it to be surprisingly painless to add new instructions to basic at least for something you know relatively straightforward like this so let's save this and we can rebuild no errors that's a good thing we go ahead and write that to the

Testing it out

eom so I'll put the eprom back in power up and reset and it doesn't immediately initialize the LCD because it won't do that until we start basic so here we're in Wasson um but we can start basic we go to address 80000 and run that and you can see immediately the LCD is now initialized with the cursor on just like I had it configured in that init routine and so now we're in basic and we should have a couple new instructions so if I do LCD print 65 it prints an a to the screen since 65 is the asky code for a LCD print 66 is going to print a b and so on the cool thing though is because we're using that existing get bite routine we're taking advantage of Basics parsing of the parameter so I can assign a variable let's say C to um asky of lowercase x and now if I print C it's a 120 which is the asky value for lowercase x but now I can do LCD print C and it prints an x to the screen so it's automatically resolving that variable and printing the you know the value that it that points to onto the screen we should also have the LCD command uh instruction so LCD command one that this should this is the command to clear the screen so that seems to work clear the screen and so now I can use these new instructions in a program and see if it's any faster so here's a program I'll paste in the prints hello world you can see the first instruction is LCD command one that clears the screen and then we set a string s dollar to hello world and then we just iterate over that string the length of s assigning character to each one and then we LCD print that character so we're still printing one character at a time um but we're using this LCD print instruction instead of all the Poke instructions so let's run that and see if it's any faster yeah I would say that's way faster uh here's a real-time comparison of the speed difference versus doing all the Poke statements in basic so I would say that's pretty good and you know it'd be interesting to extend this so LCD Print Works with a string rather than having to Loop through each character in basic you know it' be nice to be able to say LCD print hello something like that of course it says type mism because we're calling that get bite we're looking for a bite um it' be interesting to see if there's a way we could parse this the string I'm sure there is a way to do that and that might be pretty interesting and I bet that would even make it faster still so perhaps I'll look into that but anyway thanks to all my patrons who helped make these videos possible uh if you like these videos and are able to support me consider doing so and if you already have well thank you

Другие видео автора — Ben Eater

Ctrl+V

Экстракт Знаний в Telegram

Экстракты и дистилляты из лучших YouTube-каналов — сразу после публикации.

Подписаться

Дайджест Экстрактов

Лучшие методички за неделю — каждый понедельник