@@hyper_lynx That might be possible, but I don't think there would be a way of distinguishing between 65 the ascii character and 65 the number, sind this old Basic would parse both as numbers
What needs to be done is to use the current PRINT command's line evaluation routine to create the text to be printed, then use a new machine code routine to print that to the LCD instead of to the serial port. In principle, it's quite simple. Even in practice, it shouldn't be all that complicated.
In Commodore BASIC, you could redirect PRINT's output with the CMD command. Or use PRINT# instead. That means having to hande files. Not complicated, really?
Applesoft/Microsoft BASIC tokenizes the BASIC reserved words when the command is first typed in. So its not actually looking at each individual character of the commands although most of the rest of the line needs to be parsed as it runs a program.
Just amazing, I was loaned an open university circuit board, with associated literature, for a few months to try and understand how early computers work. I worked steadily through the modules but found the modules to be weak and lacking in actual detailed explanations e.g. why registers were not set back to zero, I thus became frustrated and by the end of the three month loan I had not gained the required skills to fully understand how the code did what it was doing. Contrary to the open university course Bens short explanations of how the code is constructed and executed with resultant actions taught me more in 40 minutes than the thee month university moduled course. I found the comments section in the tutorial useful too in that the answered many of queries (misunderstandings on my behalf) I had. Big thanks to Ben and all those who answered other peoples queries, questions and constructive criticism. Thank you all.
0:40 Calculator is a vintage HP-16C programmer's calculator from the 80's. Not made anymore, but a modern reproduction is made by SwissMicros, model DM16L
I wish I hadn't thrown out my old HP-15C and HP-26C. My original HP-48C is in a display cabinet while I use an emulator for everyday calc uses. I've seen the 15, back in the day, but never cared for it.
Now this tickles the same itch as when I POKEd commands out to the LPT port in QBasic to change fonts on my dot matrix printer, back in my youth. Excellent video as always!
To be fair, many of the popular 8-bit computers had their BASIC in ROM, and BASIC's original annotated source was not public. So this kinda thing would have been very difficult to do back in the day.
Look up Simons Basic, which was an extention to C64 basic back in time. You can see that it is programmed by a Brit, because one of the commands is colour :) He was 16 years old when he programmed it, according to wikipedia. So quite impressive.
With the basic source, you make it seem pretty straight forward to add a whole new command. I can see with a custom memory-mapped I/O device, we could have all sorts of fun. Great Video Ben.
I recently rewatched all your videos about breadboard computer and 6502, immediately after I wrote emulators for both in C, it was my first time but with your videos no problem at all. Now I can enjoy your basic on my computer. It was so much fun. I love to watch your videos!
First, the BASIC editor converts the commands (POKE) into a command byte before storing the line of code. The list function converts the command bytes back to text. This saves significantly on program storage space and execution time. Second, since the LCDCMD and the LCDPRINT code are almost identical, you could re-use the identical part with a jmp or branch. Third, a more standard way to do this would be to OPEN a device file and then to PRINT to that file. You could even CLOSE the file when you are done. Printers, tape drives, and floppy drives used this method on the Commodores.
While all true points, don't forget the purpose of these videos are to teach, not to write the smallest, fastest OS. A wall of impenetrable code doesn't serve the "teaching" aspect too well, regardless of it saving 20 bytes.
Thanks Ben, I love the way you approach these solutions and explain them so carefully. I have to admit I was getting a bit bogged down following along and trying to write my own assembly. So by implementing Basic so beautifully opens the door to something I can handle much better! Absolutely fascinating how you modified the basic assembly; it really demystifies how these things work.
5:30 I think you're confusing two concepts: Just because it's interpreted does not mean it has to parse the ASCII source code from scratch each time the line is run. A reasonable implementation would _tokenize_ the line of code upon entry. When running the line, it does *not* have to read through "POKE" but rather it sees a small number indicating the command, and it doesn't have to parse "24567" (a remarkably laborious process most people don't appreciate -- each digit requires a multiplication) but can load a 16-bit value directly as two bytes. Looking it up, I see that Microsoft BASIC ca 1977 was _partially tokenized_ . The keyword like POKE was indeed replaced with a small number and was not parsed each time; but the value 24567 did have to be parsed each time.
Yes, you could shorten the word POKE by using p and then SHIFT+o which would print something like p୮ but then be interpreted as poke in the listing. I never fully figured out what that SHIFT+letter did of a difference, but I asume it's something to do with setting the bit 8 of the ASCII of letter o, which then means it doesn't have to read any further of the command. I don't know how that then makes it not interprete it as command pos instead.
@@AntiAtheismIsUnstoppable It does not use ASCII. I think the shortcuts are simply programmed in, or a side effect of the look-up process during tokenization. The actual token is a single byte, not a normal letter first.
I remember writing a basic program as a junior high school project about 35 years ago that could modify a basic token by copying a ROM image to an Apple II 16k language card.
In 4 bit mode the LCD only consumes half the pio of the via. (Port B in this case). When Ben did the PS2 keyboard he switched to 4bit mode on the LCD to free up pins on port A to read the keyboard. There wasnt a video on RUclips about 4bit mode. Maybe there was one on Patreon. The PS2 example source code on the website has all the 4bit mode routines.
This is utterly fascinating. Really glad you've made this series and keep sharing your progress. It would have never even occurred to me to just modify BASIC. Love it!
Great video. Thanks. This reminds me of the days when I added commands to the Basic of my C128. You could copy the ROM to RAM and then extend the token table. That was fun.
I've started to build my 6502. Already have the rom, the microprocessor and the VIA. But here in Brasil, unfortunatelly it's very hard to get the 62256. I only have the 6264 and I'm trying to figure out on how to use this instead of 62256. I think the max232 is not quite hard to find, and then I finally can do stuffs with my computer through the serial like this. I've learned a lot with your videos. I am really grateful for all the teachings dude
The import taxes and availability are such a pain :( my Brasilian friends usually have to ask an uncle to pick-up bits and pieces when they go to the US, for a business trip or something. But I imagine that's not available to everybody as an option
@@kaitlyn__L I totally agree. I do mechatronics engineering and sometimes I have to order things from abroad Brasil. The taxes are absurd and sometimes we wait months for our items be lost by Correios. We have to be brave to study in here. But I am hopeful some day it's gonna be worth
@@harisalic2568 I've tried to use the nand to control it in many ways already. In some way the 6264 has to use the pin 15 of the 6502 once we invert it when accessing the rom when the 15th bit is zero, we must use it when the 6502 is 1 to access the RAM. But for some reason all my tries have failed. I'm gonna keep trying until I can get the 62256.
@@harisalic2568 with the money I'll spend buying 4 6264, the logic gates and the work I'll have it's better to buy the 62256 and use the Ben's approach 🥲
@@DavidLatham-productiondave i use to confuse People when talking about stuff in MS Excel when i tell them they should use "E String 4" instead of "E Dollar 4"
That's the way I always interpreted the dollar sign in that context, too. I always just said "string" because it makes it clear that the variable or function is dealing with a string.
So, I didn’t like the fact that the lcd was showing just blocks. I wound up running the LCD initialization assembly right in front of Wozmon. I also had it print a string showing “Wozmon” after the initialization. I then had the reset vector point to the beginning of that assembly code. It then dropped right into Wozmon. I did the same thing at address $8000 so when you wanted to run basic, it printed “MSbasic” first and then dropped right into basic. This was a great video. I’m glad we’re using the lcd again! I also tried to run Oregon Trail in basic just to have an out of memory error at line 6000 something. I would love to see you show a ram banking scheme.
@@renakunisaki Although the definitions get kinda weird since BASIC is a purely interpreted language, whereas Java and JS are both JIT interpreted languages so parts of your program get compiled to machine code in memory (its more complex than that but you know) during its runtime so it's faster.
@@seshpenguin as far as I know Java is compiled two times: the first time by the javac compiler from source code into Java bytecode, and the second time by the java runtime from bytecode into machine code (the JIT part).
You could have LCDPRINT check for the quote character if it's present then call LCDPRINTSTRING which would do the string processing......but it seems fast enough on such a small display it wouldn't really be needed.
Everyday is a good day when Ben Eater puts up a new video. Peek/Poke always reminds me of the mid 80s when I was working overseas in the UK developing commercial applications for the psion organiser II and writing rudimentary games in my spare time. Fond memories of crashing the thing trying to work out how to implement things.
CS student in university, this series inspired me to focus on systems programming. Thank you for these amazing videos, I know theres a lot of older programmers reminiscing in the comments, but there’s young ones too getting exposure to low level coding/hardware!
I remember on the TRS-80 (Model 4), and on the basic that came with early PCs, you had the LPRINT, and LLIST commands (that did the same as PRINT, and LIST) except they sent the data to the printer; so you could print out your programs, or make cool banners on the printer. It's neat to see your basic kind of works the other way around by default (if you imagine the idea of swapping the LPT printer port with a RS232 serial interface). Still, it would be really neat to see a whole slew of equivalent) L-prefixed commands for your "Hitachi interface" compatible LCD module... Such as LCLS to clear it, LPRINT to write to it, LPOKE/LPEEK to set custom character graphics for the upper 128 characters, or read status, etc. Not sure if there's value in LLIST, because even the larger modules are only 40x4 characters... But you might want to account for those too, as IIRC their memory is non-linear (i.e. they behave like 20x8 screens). Anyway, just chimed in to say this is super cool, and I love what you're doing with it, (even if my imagination runs a bit wild). 🤘
I find it heartwarming anyone does a FOR I ... NEXT I. That's how I was taught for/next loops in Applesoft BASIC as a kid in 1981, so it brings me back. There must have been a book example that everyone referenced for the letter "I" to be used so often. Sure, that letter was probably chosen because it's a non-descript integer, but someone made that choice rather than, say "A", and it stuck.
I always thought the letter "i" was used in loops because it is short for "index". Not sure if that's the actual reason though or just one that someone came up with later that happens to fit.
@@thislooksfun1 It's because really old versions of Fortran determined the type of a variable by its name, so "I" was an "integer" variable, which made it suitable for loops, and it became convention.
@@codahighlandyes, variables begining I to N were integers by default, others defaulted to FLOAT - first two letters of integer. By Fortran IV though it had become best practice to explicitly declare them - was still necessary even before that for COMPLEX, CHAR or any array
Is it an oversight that you didn't preserve the state of the X-register by pushing it to the stack (and popping it back out at the end of your subroutine) or did you decide it wasn't necessary?
You only need to preserve a register if you know you're changing something that is set and shouldn't be changed. When you enter a subroutine, the only regs that are important are the ones transferring data into the subroutine. Those are the ones you don't want to change. But others don't matter (generally). Now if you're making an interrupt handler which can can be invoked absolutely anywhere in your code, then you have no idea what shouldn't be changed, and you have to be careful to preserve EVERYTHING.
It's a trade-off between portability vs performance. Preserving the register makes it easier to re-use code in other projects and for other people to build on it. I originally learned Assembly from an old textbook on Win3.1, where the recommended convention was 'preserve by default'. But the book assumed a 486 CPU, I can see why you might choose 'clobber by default' on a microcontroller system.
Sure would like video card in the day hooked up. Not a DYI video card like you did, but a CGA/EGA card that hooks up to a monitor. I know power requirements change and probably a few more chips needed. I for one would buy the interface kit.
That realtime comparison at the end is a really nice visual demonstration of how slow interpreted languages are, lol. I'm half joking ofc, modern hardware and modern languages are a lot more powerful that this, but still
@@boretrk Also he should using the . trick in the for loop maybe? So for I = . to Len(s$)-1 But I admit then he has to use a Mid(s$,I+1,1) too, should still be a little faster though
This video reminds me of my days with a vic 20 at home, and learning from CBM in school. I remember one poke value would make the CBM screen wrap around as if it were a tube. I imagine that was for changing the screen dynamics since screens were not flat back then, and this particular poke was just the maximum value, instead of a much smaller number to make the desktop look flat and rectangular. Those days were fun because the importance of computers was only just starting to be understood.
5:20 A bit of minor pedantry here: I believe that MS BASIC tokenises keywords when you type them in, so each POKE is only a 1 or 2 byte (I don't remember which) token, rather than the whole command in ASCII. OTOH, it *does* have to parse numeric constants each time, which is slow AF. Back in the day, we put all that stuff in variables to help speed things up.
Thank you for explaining what no one could explain when I was 13 trying to figure this out and asking everyone I knew All clueless and the books at the time were so much worse
Ahhhhh.. the power of editing video. The code works first time! I wish it was so easy for me...😂 Great video. So interesting to see how the BASIC interpreter is built from low level components.
I made LCDPRINT by using the formular evaluator of msbasic. So LCDPRINT is like PRINT (not well tested). The following code should fit to Ben's code on GitHub, which is a little bit different to his code in the video. The code is more or less a compressed copy of PRINT. LCDPRINT: jsr FRMEVL ; Evaluate formular bit VALTYP ; Is it a string? bmi lcd_print_string ; Yes jsr FOUT ; Format floating point output jsr STRLIT ; Build string descriptor lcd_print_string: jsr FREFAC ; Returns temp pointer to string tax ; Put count to counter ldy #0 inx ; Move one ahead lcd_print_next: dex beq lcd_print_end ; All done lda (INDEX),y ; Load char of string jsr lcd_print_char ; Output to lcd iny bne lcd_print_next ; Go on with next char lcd_print_end: rts
@@alancx523 Thanks for trying. I didn't use Ben's code from github. But I didn't want to post my complete lcd.s. I'm using the code from the video. You can try it too. The label lcd_print_char is the routing to output a char to the lcd. In Ben's older code it's labeled with print_char.
@@Ralf4511 Together like this? If so, it doesn't work. I type LCDPRINT "STUFF", it return and get nothing. Hoping I've got something wrong!! LCDPRINT: jsr FRMEVL ; Evaluate formular bit VALTYP ; Is it a string? bmi lcd_print_string ; Yes jsr FOUT ; Format floating point output jsr STRLIT ; Build string descriptor lcd_print_string: jsr FREFAC ; Returns temp pointer to string tax ; Put count to counter ldy #0 inx ; Move one ahead lcd_print_next: dex beq lcd_print_end ; All done lda (INDEX),y ; Load char of string jsr lcd_print_char ; Output to lcd iny bne lcd_print_next ; Go on with next char lcd_print_end: rts lcd_print_char: jsr lcd_wait pha lsr lsr lsr lsr ; Send high 4 bits ora #RS ; Set RS sta PORTB ora #E ; Set E bit to send instruction sta PORTB eor #E ; Clear E bit sta PORTB pla and #%00001111 ; Send low 4 bits ora #RS ; Set RS sta PORTB ora #E ; Set E bit to send instruction sta PORTB eor #E ; Clear E bit sta PORTB rts
One thing i noticed, not sure if it's relevant, but in your LCD instructions, you're calling txa to transfer X to A, but then shortly after calling pha to push A to the stack, then calling pla at the end to pop A back. It looks like whatever was in A before you run one of the LCD commands is getting lost, but I could be wrong.
Glad to see more of this. Would be cool if i can take any random chips and make a computer out of them. Guess I should get a kit before even dreaming of doing anything that lambastic.
Try to make a computer from a 555, 74S140, and a TL4242. Those were chosen randomly from a large list of integrated circuits. Why not dream for something sensible rather than just random? Would be cool if i could if i could make a car from a windshield, an exhaust hanger, and a blow-off valve.
Back in those days, i read about people using peek and poke to put assembly code into memory and then make basic interpret that code as their own basic function code or even run a native code.
Something hit me about the opening when he said “so I’ve got this 8 bit breadboard computer that runs basic” like he hasn’t spent the last 6 plus years making it. So good. Cant wait to see where we go from here!
Would love to see maybe writing a driver routine so the LCD displays runs basic natively.. it wouldn't be very good or usable but many portable computers did that, pretty much spawning graphing calculators.
I'd be interested to know how the TYPE MISMATCH ERROR works - does the GETBYT subroutine simply jump to a different memory address that reinitialises BASIC once it realises there's a problem?
Great video, but I somehow think that you should have called the routine LCDOUT instead of LCDPRINT. An easy way to make (the new) LCDPRINT do everything PRINT does is: Set a global variable that l et's PRINT know if it should use OUTCHAR or LCDOUT (new function to output a single char to the LCD). Then, LDCPRINT sets the "variable" to 1, does a JSR PRINT, clears the variable and RTS's. This would of course have a small performance hit on PRINT in general, but could still be a somewhat clean solution, since the new branch in PRINT would be set in an ifdef block. That way, you could just use LCDPRINT with any kind of expression. You could even use a global pointer, to what output method PRINT should use. That way, you would be future-proof for the hopefully coming VGA support 🙂
That's a great idea! I also felt it was a bit strange to call it "print", yet have it be unable to be given a string. But I wasn't sure what I'd call it instead - I like your "out" suggestion.
Just use the current PRINT command's line-evaluation routine to create the string to be printed, then use custom code to print that to the LCD. The only complicated part would be if you want to interpret control codes as commands rather than as text characters.
Like I said in another comment, Applesoft BASIC allows you to patch COUT() to be a custom routine (and all basic output goes through COUT).. Applesoft is made by Microsoft so I bet they'd have the same ability in msbasic.
@@misterkite I have never heard of a COUT() command in any version of BASIC which I've used, so I'd guess it only appears in Applesoft BASIC. It sounds like it's similar to the USR() function which exists in other BASICs, but specialised to character output.
@@melkiorwiseman5234 COUT() isn't a public facing command, it's the final "output" routine that outputs what's in the A register to the screen. There are various basic-specific ways to redirect cout, the most common is to use special control characters.. like PRINT CHR$(4);"CAT" the control character 4 causes the output to redirect to DOS in Applesoft.
i wrote similar code on a Commodore 64 emulator running MS BASIC and it took about 1 second to run. When i moved the POKE address to a variable and stored the INT(ASC(... in a variable, it ran almost twice as fast. You had to make optimization on these old machines (and on new ones, too).
There's now plenty of "programming world" contexts where $ doesn't mean a string. Far more than where it does, in fact. Shells and PHP use leading $ to signify a variable name, many JavaScript libraries have a convention for foo$ to be a stream or signal for a foo, etc.
@@SimonBuchanNz Yes and we're using BASIC here where $ indicates that a variable is a string. What $ is used for in 634 other languages and 12 other currencies really is irrelevant here. Since the days of yore (and I was there), S$ in BASIC is pronounced "ess string".
Dear Sir When you type 'mov' on programing enviroment, it still display on the screen as text mode before compiling, right? I have searched through internet, but none have clear answer relating how exactly computer physically detect series of 0/1 abstraction per code line to trigger control signal through circuit?? For example again: Key board: you press the letter, and it physically interact with circuit Punch card: you punch the hole and computer physically detect holes to trigger the bulb light or not ( via light through hole or not) Two clear above example shows the physical that make the bridge to link 0/1 abstraction to hardware. And about binary pattern after compilling, what's the physical mechanism to detect them to trigger electrical signals????
Dear Mr Ben, I have a question that myself not clear for a long time: When we type code display on the screen, it is translated to machine code as binary pattern. But how this text of series 0/1 interact with memory hardware and generate electricity signal as on/off switches For example, we press key and it closes the switch, we load punch card and computer has sensor to detect holes or not as 0/1
Nice stuff Ben. Im considering changing C64 BASIC to use the math capabilities of the Kawari to speed up BASIC in general, although I havent yet figured out how best to convert between FP and multiple integer operations and back again.
Microsoft didn’t bother. All math operations were done in FP. If you were worked with integer variables then they were converted to FP for processing and back again for storage. This is why using integer variables is actually slightly slower than FP.
@@stevetodd7383 yep, Im aware. The point being that Kawari can do 16x16=32bit multiplication, and the c64 has a 32 bit mantissa so it should be possible to speed up at least the mantissa multiplication (which I think is currently done with shifts and additions).
All of a sudden, I'm wondering what the largest character display is that they make, because that way, you would be getting close to a standalone computer without the need of a terminal.
@stargazer7644They use the exact same commands as well. IIRC, they're just divided up where it skips a line. The smaller displays act as if they have all of that display size as well. I think you might be able to scroll the display as well, in order to use all of that extra space, even if your LCD doesn't physically support it.
In a future video/video series, would it be possible to see if you could interface this computer with analog voltages like with an ADC or something? I’ve always loved that interplay of analog and digital, DAC, ADC, wave forms generation, reading resistance, that sorta stuff with custom circuits. Like I’d love to build like my own Data Acquisition System like a mini Keysight 34970A with a little breadboard computer like this.
It does, but that should be fine. The BASIC-internal code that calls the individual subroutines is unlikely to expect the A register to be restored by the called subroutines, so if it does need it, it will most likely push and pull it itself. The "pha" immediately after lcd_wait (which IIRC does save and restore A) is not intended to save A for the purpose of restoring it before returning from the subroutine, but it saves it for the purpose of sending the second 4 bits of A a bit further down. "pla" before the line commented with "Send low 4 bits" restores A (but the further instructions change it again and it is not restored before "rts" at the bottom).
The pha at the top of LCDPRINT is to save the A register before he strips off the upper 4 bits so that later he can restore it and then pull off the lower 4 bits. If you put the txa after the pha as you suggest, then the lower 4 bits will come from the wrong value - whatever happened to be in the uninitialized a register before the txa was done. The way he has it is correct.
Getbyt returns its result in X, so the code is transferring this to the accumulator before pushing onto the stack for retrieval later in the same routine.
in this video, where is the BASIC Interpreter stored? edit: after watching the end, it seems like there is an EEPROM somewhere that the processor boots from?
would be cool if you got the BASIC output (the one that you get in the terminal) to be shown on the LCD screen :) how hard could it be? cool video, thanks!
The comment about the interpreter having to read each character and then determine if that forms a valid keyword reminds me of how ZX Spectrum BASIC has each of its keywords assigned an ASCII code, meaning every command is only one byte.
It’s called Tokenisation, and Microsoft BASIC does it also. It was a standard way to reduce the memory requirements of a program, but Sinclair cheated in that they didn’t bother starting with the string command and converting to a token before saving the typed line to memory, they just had you type the token directly on the keyboard (resulting in a horribly complex keyboard map).
@stevetodd7383 Mmm, although I think when you typed a program in 128K mode, it did the tokenisation when you entered the line. So it took a little longer to "register" each line but then only needed to interpret the tokens at run time.
If this version of BASIC has the LPRINT command, would it not be possible to change the driver address so that it goes to the LCD instead? LLIST does the same for listing, though doing that on a 2-line LCD wouldn't be very useful!
Could define a LCDPRINTS that takes a variable as a parameter, reuse Basic's functions to parse/find the variable and to get the address where the variable's value is stored (found in var[dot]s), and write the loop over each character in assembly
If you watch closely you can see that he scrolled by those commands in the "file" section! They're ifdef'ed out right now but he could choose to turn on file features if he wanted to -- but he'd have to populate all of the associated I/O routines.
I'm simple. Ben pokes a new video onto RUclips, I have to peek... :)
😅
Basic behaviour
@@m.naexec genius
and poke the like button :D
@@grendel_eoten add all his videos to the stack
Current LCDPRINT could be called LCDCHR, and the new print function that takes the string into account could be the new LCDPRINT.
I wonder if LCDPRINT could check if there is a single byte or a string and print either one correctly instead of using multiple commands
@@hyper_lynx That might be possible, but I don't think there would be a way of distinguishing between 65 the ascii character and 65 the number, sind this old Basic would parse both as numbers
What needs to be done is to use the current PRINT command's line evaluation routine to create the text to be printed, then use a new machine code routine to print that to the LCD instead of to the serial port. In principle, it's quite simple. Even in practice, it shouldn't be all that complicated.
More is less, and ocd is always watching.
LCDPRTCHR
LCDPRTSTR
3 letters per attribute, 3 attributes per command
In Commodore BASIC, you could redirect PRINT's output with the CMD command. Or use PRINT# instead. That means having to hande files. Not complicated, really?
Applesoft/Microsoft BASIC tokenizes the BASIC reserved words when the command is first typed in. So its not actually looking at each individual character of the commands although most of the rest of the line needs to be parsed as it runs a program.
I hit the comments to make the same point. :)
Just amazing, I was loaned an open university circuit board, with associated literature, for a few months to try and understand how early computers work. I worked steadily through the modules but found the modules to be weak and lacking in actual detailed explanations e.g. why registers were not set back to zero, I thus became frustrated and by the end of the three month loan I had not gained the required skills to fully understand how the code did what it was doing. Contrary to the open university course Bens short explanations of how the code is constructed and executed with resultant actions taught me more in 40 minutes than the thee month university moduled course. I found the comments section in the tutorial useful too in that the answered many of queries (misunderstandings on my behalf) I had. Big thanks to Ben and all those who answered other peoples queries, questions and constructive criticism.
Thank you all.
0:40 Calculator is a vintage HP-16C programmer's calculator from the 80's. Not made anymore, but a modern reproduction is made by SwissMicros, model DM16L
RPN 4 LIFE
@@klchu 2,2,+
I wish I hadn't thrown out my old HP-15C and HP-26C.
My original HP-48C is in a display cabinet while I use an emulator for everyday calc uses.
I've seen the 15, back in the day, but never cared for it.
Thank you ! I was going to ask again...
I have the swissmicro replica, it's amazing!
Always a great day when Ben uploads.
He poked, and I peeked.
Now this tickles the same itch as when I POKEd commands out to the LPT port in QBasic to change fonts on my dot matrix printer, back in my youth. Excellent video as always!
That adding functionality to BASIC is so freaking cool, I wish I knew all that when I was a kid and actually using BASIC and assembly to mess around.
To be fair, many of the popular 8-bit computers had their BASIC in ROM, and BASIC's original annotated source was not public. So this kinda thing would have been very difficult to do back in the day.
Look up Simons Basic, which was an extention to C64 basic back in time. You can see that it is programmed by a Brit, because one of the commands is colour :) He was 16 years old when he programmed it, according to wikipedia. So quite impressive.
With the basic source, you make it seem pretty straight forward to add a whole new command. I can see with a custom memory-mapped I/O device, we could have all sorts of fun. Great Video Ben.
I recently rewatched all your videos about breadboard computer and 6502, immediately after I wrote emulators for both in C, it was my first time but with your videos no problem at all. Now I can enjoy your basic on my computer. It was so much fun. I love to watch your videos!
First, the BASIC editor converts the commands (POKE) into a command byte before storing the line of code. The list function converts the command bytes back to text. This saves significantly on program storage space and execution time. Second, since the LCDCMD and the LCDPRINT code are almost identical, you could re-use the identical part with a jmp or branch. Third, a more standard way to do this would be to OPEN a device file and then to PRINT to that file. You could even CLOSE the file when you are done. Printers, tape drives, and floppy drives used this method on the Commodores.
While all true points, don't forget the purpose of these videos are to teach, not to write the smallest, fastest OS. A wall of impenetrable code doesn't serve the "teaching" aspect too well, regardless of it saving 20 bytes.
Will you put FORTH on the 6502 computer later in the series? It feels like a much more fitting language for the hardware.
Thanks Ben, I love the way you approach these solutions and explain them so carefully. I have to admit I was getting a bit bogged down following along and trying to write my own assembly. So by implementing Basic so beautifully opens the door to something I can handle much better! Absolutely fascinating how you modified the basic assembly; it really demystifies how these things work.
5:30 I think you're confusing two concepts: Just because it's interpreted does not mean it has to parse the ASCII source code from scratch each time the line is run. A reasonable implementation would _tokenize_ the line of code upon entry. When running the line, it does *not* have to read through "POKE" but rather it sees a small number indicating the command, and it doesn't have to parse "24567" (a remarkably laborious process most people don't appreciate -- each digit requires a multiplication) but can load a 16-bit value directly as two bytes.
Looking it up, I see that Microsoft BASIC ca 1977 was _partially tokenized_ . The keyword like POKE was indeed replaced with a small number and was not parsed each time; but the value 24567 did have to be parsed each time.
yep, those early microsoft basic intepreters only tokenized the kewords, still better than nothing.
Yes, you could shorten the word POKE by using p and then SHIFT+o which would print something like p୮ but then be interpreted as poke in the listing. I never fully figured out what that SHIFT+letter did of a difference, but I asume it's something to do with setting the bit 8 of the ASCII of letter o, which then means it doesn't have to read any further of the command. I don't know how that then makes it not interprete it as command pos instead.
@@AntiAtheismIsUnstoppable It does not use ASCII.
I think the shortcuts are simply programmed in, or a side effect of the look-up process during tokenization. The actual token is a single byte, not a normal letter first.
I remember writing a basic program as a junior high school project about 35 years ago that could modify a basic token by copying a ROM image to an Apple II 16k language card.
Just curious, did I miss an explanation about why we're using 4-bit-mode instead of 8 bit like all the previous videos? 🤔
In 4 bit mode the LCD only consumes half the pio of the via. (Port B in this case). When Ben did the PS2 keyboard he switched to 4bit mode on the LCD to free up pins on port A to read the keyboard. There wasnt a video on RUclips about 4bit mode. Maybe there was one on Patreon. The PS2 example source code on the website has all the 4bit mode routines.
This is utterly fascinating. Really glad you've made this series and keep sharing your progress. It would have never even occurred to me to just modify BASIC. Love it!
Great video. Thanks.
This reminds me of the days when I added commands to the Basic of my C128. You could copy the ROM to RAM and then extend the token table. That was fun.
Amazing timing on this upload. I am teaching myself embedded programming and was just today doing some bare metal programming on an LCD display
I've started to build my 6502. Already have the rom, the microprocessor and the VIA. But here in Brasil, unfortunatelly it's very hard to get the 62256. I only have the 6264 and I'm trying to figure out on how to use this instead of 62256. I think the max232 is not quite hard to find, and then I finally can do stuffs with my computer through the serial like this. I've learned a lot with your videos. I am really grateful for all the teachings dude
The import taxes and availability are such a pain :( my Brasilian friends usually have to ask an uncle to pick-up bits and pieces when they go to the US, for a business trip or something. But I imagine that's not available to everybody as an option
@@kaitlyn__L I totally agree. I do mechatronics engineering and sometimes I have to order things from abroad Brasil. The taxes are absurd and sometimes we wait months for our items be lost by Correios. We have to be brave to study in here. But I am hopeful some day it's gonna be worth
You can use 4 6264 Chips and use some not Gates to Control their Chips select via the last 2 addres lines to make them behave like a Single 62256
@@harisalic2568 I've tried to use the nand to control it in many ways already. In some way the 6264 has to use the pin 15 of the 6502 once we invert it when accessing the rom when the 15th bit is zero, we must use it when the 6502 is 1 to access the RAM. But for some reason all my tries have failed. I'm gonna keep trying until I can get the 62256.
@@harisalic2568 with the money I'll spend buying 4 6264, the logic gates and the work I'll have it's better to buy the 62256 and use the Ben's approach 🥲
"CHAR$" = "char dollar"
Back in the day (1970s), we used to pronounce that like "Char string", i.e. "$" was pronounced "string". Perhaps YMMV...
Yup. I still use the word "string" in those situations. Confuses the younger folks at work.
@@DavidLatham-productiondave i use to confuse People when talking about stuff in MS Excel when i tell them they should use "E String 4" instead of "E Dollar 4"
For some reason I always read it as "ez". Like, the name Fernandez could be Fernand$
That's the way I always interpreted the dollar sign in that context, too. I always just said "string" because it makes it clear that the variable or function is dealing with a string.
But why? You assigned it the numeric value of exactly one character, while a string would mean zero or more characters
So, I didn’t like the fact that the lcd was showing just blocks. I wound up running the LCD initialization assembly right in front of Wozmon. I also had it print a string showing “Wozmon” after the initialization. I then had the reset vector point to the beginning of that assembly code. It then dropped right into Wozmon. I did the same thing at address $8000 so when you wanted to run basic, it printed “MSbasic” first and then dropped right into basic. This was a great video. I’m glad we’re using the lcd again! I also tried to run Oregon Trail in basic just to have an out of memory error at line 6000 something. I would love to see you show a ram banking scheme.
Must get back to my 6502 project ☺️
Ben eater uploading is always inspiring!
Coming from Java/JavaScript and seeing BASIC as a high-level language makes it clear how abstract modern programming languages are.
If BASIC is high level, I think JavaScript is orbital 😂
@@renakunisaki Although the definitions get kinda weird since BASIC is a purely interpreted language, whereas Java and JS are both JIT interpreted languages so parts of your program get compiled to machine code in memory (its more complex than that but you know) during its runtime so it's faster.
@@seshpenguin as far as I know Java is compiled two times: the first time by the javac compiler from source code into Java bytecode, and the second time by the java runtime from bytecode into machine code (the JIT part).
@@AntonioBarba_TheKaneB Yep that's correct
@@seshpenguin dang, I still got my java basics after all those years trying really hard to forget! :D
Ben ! Reminder to put these last 2 videos to your playlist
You could have LCDPRINT check for the quote character if it's present then call LCDPRINTSTRING which would do the string processing......but it seems fast enough on such a small display it wouldn't really be needed.
Everyday is a good day when Ben Eater puts up a new video. Peek/Poke always reminds me of the mid 80s when I was working overseas in the UK developing commercial applications for the psion organiser II and writing rudimentary games in my spare time. Fond memories of crashing the thing trying to work out how to implement things.
All you have to do is find out how the PRINT command detects numbers and strings and have LCDPRINT do the same.
(I bet you've already done that. lol)
CS student in university, this series inspired me to focus on systems programming. Thank you for these amazing videos, I know theres a lot of older programmers reminiscing in the comments, but there’s young ones too getting exposure to low level coding/hardware!
I remember on the TRS-80 (Model 4), and on the basic that came with early PCs, you had the LPRINT, and LLIST commands (that did the same as PRINT, and LIST) except they sent the data to the printer; so you could print out your programs, or make cool banners on the printer. It's neat to see your basic kind of works the other way around by default (if you imagine the idea of swapping the LPT printer port with a RS232 serial interface).
Still, it would be really neat to see a whole slew of equivalent) L-prefixed commands for your "Hitachi interface" compatible LCD module...
Such as LCLS to clear it, LPRINT to write to it, LPOKE/LPEEK to set custom character graphics for the upper 128 characters, or read status, etc. Not sure if there's value in LLIST, because even the larger modules are only 40x4 characters... But you might want to account for those too, as IIRC their memory is non-linear (i.e. they behave like 20x8 screens).
Anyway, just chimed in to say this is super cool, and I love what you're doing with it, (even if my imagination runs a bit wild). 🤘
Just a quick guess but have you tried looking up the PRINT command in the source code to see how it handles the string parameter.
I find it heartwarming anyone does a FOR I ... NEXT I. That's how I was taught for/next loops in Applesoft BASIC as a kid in 1981, so it brings me back. There must have been a book example that everyone referenced for the letter "I" to be used so often. Sure, that letter was probably chosen because it's a non-descript integer, but someone made that choice rather than, say "A", and it stuck.
I always thought the letter "i" was used in loops because it is short for "index". Not sure if that's the actual reason though or just one that someone came up with later that happens to fit.
@@thislooksfun1 It's because really old versions of Fortran determined the type of a variable by its name, so "I" was an "integer" variable, which made it suitable for loops, and it became convention.
@@codahighland Huh, neat! Today I learned!
Using I for loops probably harks back to Fortran where I, J, K, L, M and N defaulted to integers and all the other letters default to real (float).
@@codahighlandyes, variables begining I to N were integers by default, others defaulted to FLOAT - first two letters of integer. By Fortran IV though it had become best practice to explicitly declare them - was still necessary even before that for COMPLEX, CHAR or any array
Is it an oversight that you didn't preserve the state of the X-register by pushing it to the stack (and popping it back out at the end of your subroutine) or did you decide it wasn't necessary?
You only need to preserve a register if you know you're changing something that is set and shouldn't be changed. When you enter a subroutine, the only regs that are important are the ones transferring data into the subroutine. Those are the ones you don't want to change. But others don't matter (generally).
Now if you're making an interrupt handler which can can be invoked absolutely anywhere in your code, then you have no idea what shouldn't be changed, and you have to be careful to preserve EVERYTHING.
It's a trade-off between portability vs performance. Preserving the register makes it easier to re-use code in other projects and for other people to build on it.
I originally learned Assembly from an old textbook on Win3.1, where the recommended convention was 'preserve by default'. But the book assumed a 486 CPU, I can see why you might choose 'clobber by default' on a microcontroller system.
Ben is cooking again
Ben is done eating, now he's Ben Cooker
And now we're the one's eating.
Well hey there, folks!
Today we're making Basic-flavored Code Sausage... that's the Basic juice!
Haven't played with BASIC at this level before but wouldn't the necessary string parsing already exist in the PRINT command?
Sure would like video card in the day hooked up. Not a DYI video card like you did, but a CGA/EGA card that hooks up to a monitor. I know power requirements change and probably a few more chips needed. I for one would buy the interface kit.
That realtime comparison at the end is a really nice visual demonstration of how slow interpreted languages are, lol. I'm half joking ofc, modern hardware and modern languages are a lot more powerful that this, but still
It's not really a fair comparison.
The 3 integer division per character he is doing there is probably a significant portion of the execution time.
@@boretrk Also he should using the . trick in the for loop maybe?
So for I = . to Len(s$)-1
But I admit then he has to use a Mid(s$,I+1,1) too, should still be a little faster though
Love these videos. Well done, and fun to watch. How about sound for this little cpu?
I miss turning on a computer and you're right in BASIC.
This video reminds me of my days with a vic 20 at home, and learning from CBM in school. I remember one poke value would make the CBM screen wrap around as if it were a tube. I imagine that was for changing the screen dynamics since screens were not flat back then, and this particular poke was just the maximum value, instead of a much smaller number to make the desktop look flat and rectangular. Those days were fun because the importance of computers was only just starting to be understood.
thank you Ben for these videos, can I ask why you do not have github sponsors option enabled on your github account?
5:20 A bit of minor pedantry here: I believe that MS BASIC tokenises keywords when you type them in, so each POKE is only a 1 or 2 byte (I don't remember which) token, rather than the whole command in ASCII. OTOH, it *does* have to parse numeric constants each time, which is slow AF. Back in the day, we put all that stuff in variables to help speed things up.
Yeeessss, finally you uploaded, I love your videos!
Thank you for another great video ❤ is there any reason why you do not have github sponsor enabled?
Thank you for explaining what no one could explain when I was 13 trying to figure this out and asking everyone I knew
All clueless and the books at the time were so much worse
1000X better than my worthless college class where we had to memorize dma pinouts
Ahhhhh.. the power of editing video. The code works first time! I wish it was so easy for me...😂 Great video. So interesting to see how the BASIC interpreter is built from low level components.
I guess it's the power of making the video after having everything up and running ;)
I messed around with peek & poke with c64 decades ago, now I understand what I did. Thanks!
You make it look so easy... Fantastic!
I made LCDPRINT by using the formular evaluator of msbasic. So LCDPRINT is like PRINT (not well tested). The following code should fit to Ben's code on GitHub, which is a little bit different to his code in the video. The code is more or less a compressed copy of PRINT.
LCDPRINT:
jsr FRMEVL ; Evaluate formular
bit VALTYP ; Is it a string?
bmi lcd_print_string ; Yes
jsr FOUT ; Format floating point output
jsr STRLIT ; Build string descriptor
lcd_print_string:
jsr FREFAC ; Returns temp pointer to string
tax ; Put count to counter
ldy #0
inx ; Move one ahead
lcd_print_next:
dex
beq lcd_print_end ; All done
lda (INDEX),y ; Load char of string
jsr lcd_print_char ; Output to lcd
iny
bne lcd_print_next ; Go on with next char
lcd_print_end:
rts
Hi, I gave your code a go, and it doesn't seem to work. Mind you, neither does Ben's code on Github
@@alancx523 Thanks for trying. I didn't use Ben's code from github. But I didn't want to post my complete lcd.s. I'm using the code from the video. You can try it too. The label lcd_print_char is the routing to output a char to the lcd. In Ben's older code it's labeled with print_char.
@@Ralf4511 I'll have another go :)
@@Ralf4511
Together like this? If so, it doesn't work. I type LCDPRINT "STUFF", it return and get nothing.
Hoping I've got something wrong!!
LCDPRINT:
jsr FRMEVL ; Evaluate formular
bit VALTYP ; Is it a string?
bmi lcd_print_string ; Yes
jsr FOUT ; Format floating point output
jsr STRLIT ; Build string descriptor
lcd_print_string:
jsr FREFAC ; Returns temp pointer to string
tax ; Put count to counter
ldy #0
inx ; Move one ahead
lcd_print_next:
dex
beq lcd_print_end ; All done
lda (INDEX),y ; Load char of string
jsr lcd_print_char ; Output to lcd
iny
bne lcd_print_next ; Go on with next char
lcd_print_end:
rts
lcd_print_char:
jsr lcd_wait
pha
lsr
lsr
lsr
lsr ; Send high 4 bits
ora #RS ; Set RS
sta PORTB
ora #E ; Set E bit to send instruction
sta PORTB
eor #E ; Clear E bit
sta PORTB
pla
and #%00001111 ; Send low 4 bits
ora #RS ; Set RS
sta PORTB
ora #E ; Set E bit to send instruction
sta PORTB
eor #E ; Clear E bit
sta PORTB
rts
One thing i noticed, not sure if it's relevant, but in your LCD instructions, you're calling txa to transfer X to A, but then shortly after calling pha to push A to the stack, then calling pla at the end to pop A back.
It looks like whatever was in A before you run one of the LCD commands is getting lost, but I could be wrong.
Glad to see more of this.
Would be cool if i can take any random chips and make a computer out of them. Guess I should get a kit before even dreaming of doing anything that lambastic.
Try to make a computer from a 555, 74S140, and a TL4242. Those were chosen randomly from a large list of integrated circuits. Why not dream for something sensible rather than just random? Would be cool if i could if i could make a car from a windshield, an exhaust hanger, and a blow-off valve.
I don't think that word means what you think it means.
@@codefeenix meh; I much prefer building a car from an old blown subwoofer, a passenger-side door latch, and an ignition motor.
Great video. Have you ever used GFA-BASIC?
Back in those days, i read about people using peek and poke to put assembly code into memory and then make basic interpret that code as their own basic function code or even run a native code.
Something hit me about the opening when he said “so I’ve got this 8 bit breadboard computer that runs basic” like he hasn’t spent the last 6 plus years making it. So good. Cant wait to see where we go from here!
babe, wake up. new Ben Eater video just dropped
Could you maybe make a small video about incremental encoders? I‘d be very interested in your practical way of explaining!
love the special guest appearance by the HP16 🙂
Is that an buckling spring keyboard, such as an IBM Model M, I'm hearing you typing on?
This video blows my mind with the different peripherals we could hook up and control with BASIC.
Man this channel gets me GOING. I love it so much.
Would love to see maybe writing a driver routine so the LCD displays runs basic natively.. it wouldn't be very good or usable but many portable computers did that, pretty much spawning graphing calculators.
I was wondering if what he's doing here was basically writing a driver. How is a driver different than this?
This is exactly what I wanted, I've implemented this in JavaScript and using peek and pole to interact with on screen LEDs and switches
I'd be interested to know how the TYPE MISMATCH ERROR works - does the GETBYT subroutine simply jump to a different memory address that reinitialises BASIC once it realises there's a problem?
5:56 The "kbd" files are likely for the Mattel Electronics Keyboard Component's BASIC for the Intellivision gaming console.
Ben is the OG bit flippin bad boy. I commend you on your projects, as an assembly programmer its a lost art IMO
Love your 6502 content!
Great video, but I somehow think that you should have called the routine LCDOUT instead of LCDPRINT. An easy way to make (the new) LCDPRINT do everything PRINT does is: Set a global variable that l et's PRINT know if it should use OUTCHAR or LCDOUT (new function to output a single char to the LCD). Then, LDCPRINT sets the "variable" to 1, does a JSR PRINT, clears the variable and RTS's. This would of course have a small performance hit on PRINT in general, but could still be a somewhat clean solution, since the new branch in PRINT would be set in an ifdef block. That way, you could just use LCDPRINT with any kind of expression. You could even use a global pointer, to what output method PRINT should use. That way, you would be future-proof for the hopefully coming VGA support 🙂
That's a great idea! I also felt it was a bit strange to call it "print", yet have it be unable to be given a string. But I wasn't sure what I'd call it instead - I like your "out" suggestion.
Just use the current PRINT command's line-evaluation routine to create the string to be printed, then use custom code to print that to the LCD. The only complicated part would be if you want to interpret control codes as commands rather than as text characters.
Like I said in another comment, Applesoft BASIC allows you to patch COUT() to be a custom routine (and all basic output goes through COUT).. Applesoft is made by Microsoft so I bet they'd have the same ability in msbasic.
@@misterkite I have never heard of a COUT() command in any version of BASIC which I've used, so I'd guess it only appears in Applesoft BASIC. It sounds like it's similar to the USR() function which exists in other BASICs, but specialised to character output.
@@melkiorwiseman5234 COUT() isn't a public facing command, it's the final "output" routine that outputs what's in the A register to the screen. There are various basic-specific ways to redirect cout, the most common is to use special control characters.. like PRINT CHR$(4);"CAT" the control character 4 causes the output to redirect to DOS in Applesoft.
you just put a link in my brain between my interest for the computer and my job as an electrician, thanks
Methinks the PRINT command will be explored next for clues to print a string to the LCD.
wooooooo! nice to see you're still making vids ❤
You make me remember my first days in computer in middle of 90s
That was so cool. I have added commands to commodore 64 BASIC. I recommend anyone try that as well
Creating your own BASIC commands would never have occurred to me, but if you have the source code ...
i wrote similar code on a Commodore 64 emulator running MS BASIC and it took about 1 second to run. When i moved the POKE address to a variable and stored the INT(ASC(... in a variable, it ran almost twice as fast. You had to make optimization on these old machines (and on new ones, too).
I really need to pull the trigger and get a 6502 kit. This looks way too fun!
In the programming world, "S$" would be pronounced either as "ess string" or just "ess", for simplicity.
"S DOLLARSIGN" (or dollars S) just kinda rolls off the tongue in a way that ess does not.
@@codefeenix yeah back in the day I'd usually say 'ess dollar', sometimes 'ess string'
I would call this "ess string"
There's now plenty of "programming world" contexts where $ doesn't mean a string. Far more than where it does, in fact.
Shells and PHP use leading $ to signify a variable name, many JavaScript libraries have a convention for foo$ to be a stream or signal for a foo, etc.
@@SimonBuchanNz Yes and we're using BASIC here where $ indicates that a variable is a string. What $ is used for in 634 other languages and 12 other currencies really is irrelevant here. Since the days of yore (and I was there), S$ in BASIC is pronounced "ess string".
Dear Sir
When you type 'mov' on programing enviroment, it still display on the screen as text mode before compiling, right?
I have searched through internet, but none have clear answer relating how exactly computer physically detect series of 0/1 abstraction per code line to trigger control signal through circuit??
For example again:
Key board: you press the letter, and it physically interact with circuit
Punch card: you punch the hole and computer physically detect holes to trigger the bulb light or not ( via light through hole or not)
Two clear above example shows the physical that make the bridge to link 0/1 abstraction to hardware.
And about binary pattern after compilling, what's the physical mechanism to detect them to trigger electrical signals????
Dear Mr Ben, I have a question that myself not clear for a long time:
When we type code display on the screen, it is translated to machine code as binary pattern.
But how this text of series 0/1 interact with memory hardware and generate electricity signal as on/off switches
For example, we press key and it closes the switch, we load punch card and computer has sensor to detect holes or not as 0/1
Have you considered putting the LCD on the bus directly ?
Its basically a 68xx/65xx interface
Nice stuff Ben. Im considering changing C64 BASIC to use the math capabilities of the Kawari to speed up BASIC in general, although I havent yet figured out how best to convert between FP and multiple integer operations and back again.
Microsoft didn’t bother. All math operations were done in FP. If you were worked with integer variables then they were converted to FP for processing and back again for storage. This is why using integer variables is actually slightly slower than FP.
As an aside, MS BASIC was pre the IEEE FP standard, so you may have problems working with any hardware FP solution.
@@stevetodd7383 yep, Im aware. The point being that Kawari can do 16x16=32bit multiplication, and the c64 has a 32 bit mantissa so it should be possible to speed up at least the mantissa multiplication (which I think is currently done with shifts and additions).
Ben Ate with this one.
All of a sudden, I'm wondering what the largest character display is that they make, because that way, you would be getting close to a standalone computer without the need of a terminal.
They make 80x24 LCD screens for just what you're talking about.
@@stargazer7644 I wonder if any of them speak the old ADM 3 or DEC vt100 control codes. (Embedded in the strings to be printed).
@stargazer7644They use the exact same commands as well. IIRC, they're just divided up where it skips a line. The smaller displays act as if they have all of that display size as well. I think you might be able to scroll the display as well, in order to use all of that extra space, even if your LCD doesn't physically support it.
In a future video/video series, would it be possible to see if you could interface this computer with analog voltages like with an ADC or something? I’ve always loved that interplay of analog and digital, DAC, ADC, wave forms generation, reading resistance, that sorta stuff with custom circuits. Like I’d love to build like my own Data Acquisition System like a mini Keysight 34970A with a little breadboard computer like this.
Your LCDPRINT seems to be clobbering the a register, as you've put txa before pha
It does, but that should be fine. The BASIC-internal code that calls the individual subroutines is unlikely to expect the A register to be restored by the called subroutines, so if it does need it, it will most likely push and pull it itself. The "pha" immediately after lcd_wait (which IIRC does save and restore A) is not intended to save A for the purpose of restoring it before returning from the subroutine, but it saves it for the purpose of sending the second 4 bits of A a bit further down. "pla" before the line commented with "Send low 4 bits" restores A (but the further instructions change it again and it is not restored before "rts" at the bottom).
The pha at the top of LCDPRINT is to save the A register before he strips off the upper 4 bits so that later he can restore it and then pull off the lower 4 bits. If you put the txa after the pha as you suggest, then the lower 4 bits will come from the wrong value - whatever happened to be in the uninitialized a register before the txa was done. The way he has it is correct.
Getbyt returns its result in X, so the code is transferring this to the accumulator before pushing onto the stack for retrieval later in the same routine.
in this video, where is the BASIC Interpreter stored?
edit: after watching the end, it seems like there is an EEPROM somewhere that the processor boots from?
Just like that, Ben creates new BASIC commands.
would be cool if you got the BASIC output (the one that you get in the terminal) to be shown on the LCD screen :) how hard could it be?
cool video, thanks!
The comment about the interpreter having to read each character and then determine if that forms a valid keyword reminds me of how ZX Spectrum BASIC has each of its keywords assigned an ASCII code, meaning every command is only one byte.
It’s called Tokenisation, and Microsoft BASIC does it also. It was a standard way to reduce the memory requirements of a program, but Sinclair cheated in that they didn’t bother starting with the string command and converting to a token before saving the typed line to memory, they just had you type the token directly on the keyboard (resulting in a horribly complex keyboard map).
@stevetodd7383 Mmm, although I think when you typed a program in 128K mode, it did the tokenisation when you entered the line. So it took a little longer to "register" each line but then only needed to interpret the tokens at run time.
@@K-o-R yes, they fixed things for the 128 (and gave it a more conventional keyboard at the same time)
now add a command to draw 3d graphics on to a monitor
If this version of BASIC has the LPRINT command, would it not be possible to change the driver address so that it goes to the LCD instead? LLIST does the same for listing, though doing that on a 2-line LCD wouldn't be very useful!
In M$ basic, keywords are tokenized. Not completely changing what you said, but somewhat.
what would it take to play some games with the c6502 ?
Could define a LCDPRINTS that takes a variable as a parameter, reuse Basic's functions to parse/find the variable and to get the address where the variable's value is stored (found in var[dot]s), and write the loop over each character in assembly
Great stuff Ben...👍 Detailed logic Easy to follow...
for open"LCD:" as #1: print #1,"hello world"
that would be nice ;) now I don't know if MS basic has 'for open "" as #channel command.
If you watch closely you can see that he scrolled by those commands in the "file" section! They're ifdef'ed out right now but he could choose to turn on file features if he wanted to -- but he'd have to populate all of the associated I/O routines.
@@codahighland oh I didn’t see that - I was very intrigued on how everything worked together
i think maybe youd find the answer to how to print strings if you were to look at the comand in basic that asigns a string to a variable
Excellent video as usual Ben 👍
My 80's memories coming back to me. Beginners all purpose symbolic instruction code. I used to say that to my friends back then. Cringe.
I would have really loved to have a series of videos about a bare bones GPU with those 74 series chips :/
0:40 Nice to see a 16C to demonstrate hex