Optimizing With Integers in Commodore 64 BASIC?

  Рет қаралды 22,661

8-Bit Show And Tell

8-Bit Show And Tell

Күн бұрын

Пікірлер: 181
@8_Bit
@8_Bit 5 жыл бұрын
Index: 0:00 Intro 1:44 Setting up a benchmark 3:15 Floating Point vs Integer results 5:58 Explaining why so slow 7:10 Trying integers in FOR/NEXT loops 8:54 So what are they good for? 11:13 Pi break 12:27 Using FRE() to measure memory use 14:28 True/False in BASIC 15:10 Defining Functions 17:44 Memory use benchmarking 20:33 Arrays
@anttimaki8188
@anttimaki8188 4 жыл бұрын
did INT(x) actually round the float to "nearest" integer, and x% just truncate it. as in INT(x) = whatever + .5 and cut the decimals, and x% just cuts the decimals.
@mapesdhs597
@mapesdhs597 5 жыл бұрын
Wish I'd known these things 25 years ago. :D Thanks for the excellent vids! Some day I hope to finish an RPG I started writing in the mid 80s but never finished. Your vids will be a great resource when that day comes.
@jim_64s8-bitprojects5
@jim_64s8-bitprojects5 5 жыл бұрын
How am I just learning about the colon trick for blank BASIC lines?! “Better 36 year late than never”?
@0LoneTech
@0LoneTech 4 жыл бұрын
By coincidence, colon is a do-nothing command in bash. It has the same effect as "true", and since they ignore their arguments, it's possible to put text after it.
@jack002tuber
@jack002tuber 4 жыл бұрын
Also you can indent. I like to use them between a for and a next to indent things between
@NeilRoy
@NeilRoy 5 жыл бұрын
Wow, first time viewer on your channel. This brings back SO MANY memories for me! I also coded on the C64 for many years. Also ran a BBS off of one (using EBBS software). I coded A LOT in BASIC, and a little in blitz like you. my favourite on the C64 though was assembly language by a long shot. 6510 was always so much fun to code for and the C64 had functions that have no equivalent BASIC instructions, but you could access via machine language... or BASIC if you knew the SYS address to call it. had a couple I still have notes (on some yellowed paper now!), like one to move the cursor to a specific location. I t hink my favourite trick was to redirect the C64's PRINT command to another area in memory then "print" sprites, or music etc... into that memory location. It was an awesome trick you could use instead of a FOR NEXT loop to read DATA and poke it. I had a rather short program many years ago for example that was only a few lines lone, but would play sound effects using simple, one line print commands. A couple pokes relocated it to sound memory followed by the print which had the relevant character numbers in quotes which matches the values you would normally poke into RAM. SO much fun, I miss those days. I owned a C64, followed by an A500, then an A1200 and an A2000HD. All great machines. I always wanted to own a C128 as I used to know a man who ran a BBS on a 128 in 128 mode so he got 80 columns. Anyhow... thanks for the memories. I'm curious, do you follow The 8-bit Guy at all? He created a new game for the C64 not long ago. Simple plot routine which locates the cursor on screen: POKE 211, X: POKE 214,Y: SYS 58732 Clear the SID chip using PRINT, if you change the print values you can create sound effects with this as well (note, that's 23 @'s, which represent zero): POKE 209,0: POKE 210,212: POKE 211,0: PRINT "@@@@@@@@@@@@@@@@@@@@@@@@@"; Load a machine language program from within another program: POKE 147,0: SYS 57812 "filename",8,1: SYS 62631
@gabrielsroka
@gabrielsroka 3 жыл бұрын
At 12:05, if I'm doing the math correctly, it's 34% faster, not 25% faster. Also, a lot of the time you're measuring is the FOR loop running by itself: for i=1 to 1000 : next takes about 60 jiffies. So if you subtract that, it's more like 55% faster.
@masqar
@masqar 4 ай бұрын
plus, if you do this... it will be even faster... 10TI$="000000":I1=1:I2=1000 20 FORI=I1TOI2
@gabrielsroka
@gabrielsroka 4 ай бұрын
@@masqar good point. If you use single letter variable names, it'll probably be even faster
@Datan0de
@Datan0de 5 жыл бұрын
This video has no business being as interesting as it was! I started it thinking I'd probably move on after a minute or two. Ended up fascinated all the way through, and can't wait to play around with some of this. Thanks for the great info.
@ArumesYT
@ArumesYT 5 жыл бұрын
Well... That was unexpected. I went into this video with the idea of suggesting another optimization I regularly used in AMOS Pro on an Amiga. If you want to do something like 3D graphics and want to keep all calculations in integers, you have to multiply all the sine and cosine calculations by a number large enough to create smooth rotations. I always used *256 instead of a round number like *300 or similar, because the AMOS interpreter (and compiler) was smart enough to just add an empty byte (00000000) to the right of the variable, or in other words shift the entire value 8 bits to the left. But after watching the video I'm pretty sure the C64 didn't do that sort of thing. :-)
@8_Bit
@8_Bit 5 жыл бұрын
Yes, BASIC 2.0 definitely doesn't do that kind of optimization :) But that's the kind of thing a C64 assembly language programmer would do, for sure. Cool that AMOS Pro did it. I've still got my boxed copy of AMOS, I love that language.
@booleanenator
@booleanenator 4 жыл бұрын
I just watched this for probably the fifth time. I love your channel man. Integers come in REALLY handy if you are trying to share variables with a machine language subroutine. Converting a float can be done (notably useful for the USR function), but since most machine language subroutines don't use floating point anyway, there is little point. It is possible to have a single PRG on disk that contains both the routines and the basic program together, this would set the Start Of Variables (BASIC), at the end of the machine language and when the Basic program runs, it can then setup variables before calling the routing. Very useful to pass parameters and results back to the Basic program to act upon. Some people like this because the BASIC if statement is way easier to understand than the processor branch instructions. Floating point math is also easier in basic, one can convert the float into an integer, call the machine language, get the result and use it in further computations.
@Shmbler
@Shmbler 5 жыл бұрын
I'm currently writing a tool to convert the C64 Pirates! Basic source code to C. Your video perfectly explains why: a) They didn't use integer variables at all. b) They stored alot of constants, even trivial ones like 256, in variables. c.) They used floating point operations to calculate memory offsets absolutely everywhere, i.e. KP=256:OF=KP*142.25:O2=KP*124.5:
@Pandamad
@Pandamad 5 жыл бұрын
I would love to see your final product. How are you handling sprites?
@Shmbler
@Shmbler 5 жыл бұрын
​@@Pandamad My first goal is to auto convert that Basic code to C to a state where it can be compiled and debugged as close to the original as possible. It doesn't necessarily have to be playable. Since I've played the game 30 years ago I''ve always been interested in the game mechanics and algorithms (e.g. how do cities grow over time? when are you allowed to assign a new governor? what exactly makes cities hide away their gold?). Once that is done, I'll see if and how I can implement the various SYS calls. I was pretty happy yesterday to have generated the first complete C function call tree for all three programs (pick, main and life). It turned out to be very complex to auto generate C functions from that unstructured Basic mess.
@hydraADL
@hydraADL 5 жыл бұрын
I am glad I am not the only one using "String" in every day speech to define a string variable, my teacher used to say "dollar" I would cringe at hearing that.
@AthenaNova1
@AthenaNova1 5 жыл бұрын
No you're not the only one! I've always called A$ "A String" and so on since I started programming when I was 8. I think a programming book I read early on called them that.
@3DPDK
@3DPDK 5 жыл бұрын
You are 100% correct. The dollar sign to denote a "literal string" of characters goes back to early TTY electric typewriters where it was used to end a "\" command break without invoking a carriage return, and tell the typewriter to go back to typing exactly what ever "string" of character code it received. IBM used the "String" symbol to program the Selectric Typewriter with automatically typed headers and footers, or any other repeatable text. It was always referred to as the "Header string" or "Footer String"
@NeilRoy
@NeilRoy 5 жыл бұрын
I have honestly never hear anyone use "dollar" to refer to that. I question your teacher's qualifications! ;) I was programming the C64 in the 80s, always called it a string.
@frixyg2050
@frixyg2050 4 жыл бұрын
One of my teachers was even worse; he pronounced it "cash". So A$ was "A Cash". Thankfully I didn't pick up that habit!
@ahicracing884
@ahicracing884 3 жыл бұрын
Back in school days our computer teacher said dollar so we all thought that was right. Met a kid from another school and they knew what school I was in because I said dollar instead of string. I quickly changed to string.
@bobns509
@bobns509 5 жыл бұрын
Why the first program is actually working when you never said how much is X? It even don't get an error like "unknown variable X"... Are all variables equal to zero initially (by default)?
@8_Bit
@8_Bit 5 жыл бұрын
Yes, the variable is automatically created and initialized to zero the first time it's used, if you haven't initialized it earlier.
@noland65
@noland65 5 жыл бұрын
It may be worth pointing out that this reduced performance of integer variables is specific to the Commodore implementations. In fact, integer variables may contribute to a substantial speed-up in MS BASIC on other machines and with BASIC interpreteters by other vendors. Regarding using variables instead of constants, using short names and defining intensively used variables early reduces lookup and runtime. Similarly, you may want to put "hot" subroutines at the beginning of your program. This may seem counterintuitive, but MS BASIC searches for line numbers from top to bottom. Therefore, putting a time critical subroutine at the end of your program may not provide the best performance, since the interpreter will have to go through all the previous lines in search for the line number provided by your GOSUB command.
@SpearM3064
@SpearM3064 5 жыл бұрын
@Norbert Landsteiner Actually, it's *not* specific to the Commodore implementations. Applesoft BASIC (but not Apple Integer BASIC, obviously) has the same problem. I've tested it on an actual Apple ][e. Atari BASIC uses a different approach; *all* numbers are stored as BCD, so longer numbers take more RAM than shorter ones. (On the other hand, you don't have the rounding errors caused by the exponent/mantissa method used by Commodore and Apple.) Also, Commodore BASIC does not necessarily search for line numbers *all the way* from top to bottom. Commodore BASIC (and Applesoft BASIC) is smart enough to look at the line number that you are trying to GOSUB to. If it's further towards the bottom (e.g. 1000 GOSUB 7000), it starts at the line it's currently on and *then* searches to the bottom. But if it's further up the program (e.g. 1000 GOSUB 100) then yes, it does start at the top. Your point still stands: It's best if you put "hot" subroutines close to the beginning of your program. Using short variable names and defining intensively-used variables early, also improves performance. These two tips work on both Commodore BASIC and Applesoft BASIC.
@noland65
@noland65 5 жыл бұрын
This is really, where you need to know your specific BASIC interpreter. (Some interpreters have even three number formats with specific characteristics regarding performance and memory consumption, integer, single precision, and floating point.) Regarding line numbers, you're correct. So make sure, your subroutine or GOTO target is either near the top or below and close to your jump command. It may be of interest in this context that lines of BASIC are implemented as a linked list with links to the next line only. This is why the interpreter has to search for the target line in a top-to-bottom fashion. If the line number of the target is higher than the current line, we may start searching from the current line, otherwise, there's no way but to start from the very first line.
@immortalsofar5314
@immortalsofar5314 5 жыл бұрын
You might want to do an episode on string garbage collection. I had 6 disks of text for my adventure game and wanted to build up a dictionary. Because it contained commas, they had to be read by GET# rather than INPUT# (f*ck you, BASIC!) 1st attempt in BASIC: 1 disk=26 hours. 2nd attempt - BASIC with assembler for GET#, put the string onto the screen and push a char 13 into the keyboard buffer: 1 disk=8 hours. Gave up, figured BASIC would run out of memory before building the dictionary so wrote the whole thing in assembler. 3rd attempt - 6 disks = 20 minutes. I think that was the last basic program I ever wrote!
@8_Bit
@8_Bit 5 жыл бұрын
26 hours!! Amazing how much faster assembly language is for some tasks. I do have garbage collection on my list of episode ideas. Idea #171, I just checked. I'm not necessarily doing them in order though, so maybe I'll get to it this year ;)
@jeffstack4217
@jeffstack4217 5 жыл бұрын
I think it's VERY cool how you look at the how it works. Meaning rather than just define some variables, you break apart what's actually happening and why and discovering the "flaws" along the way that would have programmers scratching their heads. Excellent efforts Robin!
@AiOinc1
@AiOinc1 4 жыл бұрын
They're slower because the interpreter is parsing extra characters. The benefit of not doing floating point math is outweighed by the slow interpreter! And yes, I believe floating point math was deemed to be much more important than fast integers. Arrays were also difficult to cram into the 8K ROM, so much so that it does indeed spill over partially into the Kernal ROM (I believe they put scientific functions in there. It's a mess.)
@unnecessarycomputerthings
@unnecessarycomputerthings 2 жыл бұрын
I wondered if the slower X% vs X addition was partly due to parsing and found that if you're doing X1=X1+1 and X%=X%+1 (parsing the same number of characters), the number of time spent in the VICE emulator is 395 vs. 399 jiffies. Integer is still slower but only by
@skeleton_craftGaming
@skeleton_craftGaming Жыл бұрын
In c++ ur supposed to use size_t for for loops, because because size_t is by definition able to, assuming your program is well formed, store a large enough number to loop though any data type. (size_t changes depending on what architecture you target, and what compiler you use. For instance using visual studio targeting x86 size_t is typedef'd as unsigned int how ever if you target x64 it's typedef'd as uint64_t. And uint64_t is typedef'd as unsigned lon long.)
@scotthannan8669
@scotthannan8669 4 жыл бұрын
You must understand, young Hobbit, it takes a long time to say anything in Old "Int"ish. And we never say anything unless it is worth taking a long time to say.
@Jdvc-yd5tx
@Jdvc-yd5tx Ай бұрын
OMG! It took 239/60 = 4 seconds for a measly 1000 instructions? That's why I was thinking of purchasing a Raspberry Pi 3 A+, because in ARM Assembly a quad-core 64-bit Cortexas running at 1.4 Ghz is STILL way too fast. I say 'was' because these SCBs should be free. The best way to encourage kids and adults in the UK to learn programming. Scum UK. 💩💫
@Jdvc-yd5tx
@Jdvc-yd5tx Ай бұрын
Apologies TWO instructions: ADD and BNE. My bad! 🏸 🖋
@durrcodurr
@durrcodurr 5 жыл бұрын
BTW, on modern CPUs, there isn't any performance advantages of integers over floating-point anymore, since floating-point is done in hardware with 1 clock cyle per instruction or better (either by the FPU core, or the SSE core -- most compilers now generate SSE by default). SSE can do up to 16 operations within one clock cycle. (MMX can provide a similar advantage when using integers)
@0LoneTech
@0LoneTech 2 жыл бұрын
It's rarely that simple. For instance, in the AMD family 19h instruction latencies guide, ADD has a latency of 1 cycle and throughput of 4/cycle (that's 4 adds completing simultaneously). FADD takes 6 cycles with throughput 1 (a somewhat unfair comparison because it's wider). That's 4 times as many integer additions and 1/6 the latency (which means time for anything involving feedback). AVX ADDPS can do 4*2=8 fp32 additions in 3 cycles, while SSE2 PADDD can do 4*4=16 in 1 cycle, twice the throughput and 1/3 the latency. So the integer operations are solidly faster, though the difference could be hidden if you're memory bound. Yes, that's using SSE for integer operations, because it extended the width of the vectors compared to MMX.
@mcassera1
@mcassera1 5 жыл бұрын
I have used integer variables to pass 16 bit numbers back and forth to machine language programs.
@oztrev99
@oztrev99 5 жыл бұрын
I’m really enjoying your informative videos on programming. Keep up the great work!
@Eightbitswide
@Eightbitswide 5 жыл бұрын
There is simply not enough stuff on youtube about Commodore BASIC! Most excellent! Any chance we could get you to do a video on sprites and their positioning in BASIC?
@8_Bit
@8_Bit 5 жыл бұрын
Thanks Jeff! Is it the x positioning that you're finding tricky? Because of the 9th bit being in a different register?
@Eightbitswide
@Eightbitswide 5 жыл бұрын
@@8_Bit Yes, that's the one..
@saganandroid4175
@saganandroid4175 4 жыл бұрын
The integer issue is because Bill Gates wrote this BASIC.
@0LoneTech
@0LoneTech 4 жыл бұрын
A similar thing happens in dynamically typed languages. Array types like Python's array.array can hold the type information only once as well as hold smaller types. We also see the 7-byte size quirk reoccur with e.g. boxed, tagged or unioned types (where the size always matches the largest option), or some memory allocation structures (for instance block maps).
@mykalimba
@mykalimba 5 жыл бұрын
I believe there is a small error in your FR(X) function definition. At the end of the definition, I think in your comparison of "FRE(X)
@SpearM3064
@SpearM3064 5 жыл бұрын
@mykalimba You're technically correct, but as long as X is a positive number, it won't make any difference.
@mykalimba
@mykalimba 5 жыл бұрын
Actually, it MOST broken when X is a large positive number, so it does make a difference what X is, and it's very possible to break the function by passing non-0 values (try evaluating it when X is passed as, say, 35000). Ultimately, the purpose of the "(FRE(0)
@8_Bit
@8_Bit 5 жыл бұрын
I think specifically as long as X is 0 then the FR(X) function will work, and it'll be a bit faster than using zeros. But I should have tried it with . instead of X because it might have been even faster. But yes, I shouldn't have tried that optimization in the video, and that's why I added the brief apology while editing the video after :)
@SpearM3064
@SpearM3064 5 жыл бұрын
@@mykalimba Sorry, I should amend my statement. What I meant to say is that *as long as the amount of free memory is more than 32k* and X is a positive number, it won't make any difference. However, if free memory is LESS than 32K, then yeah... it would break the function.
@JanneTompuri
@JanneTompuri 5 жыл бұрын
C128’s BASIC v7.0 added missing graphics and sound commands, but did they fix BASIC v2.0’s short-comings like support for integers?
@csbruce
@csbruce 5 жыл бұрын
Nope. C128 BASIC is slower than ever. It's only saved by the 80-column FAST mode.
@SpearM3064
@SpearM3064 5 жыл бұрын
@Janne Tompuri No, it did not. For "backwards compatibility" reasons, probably. Or Jack Tramiel's usual attitude of "it works, why do you want to change it?". (There were several features included in the C128 which the designers had to sneak in to the final design because Jack would've said "no". By the time Jack found out about it, it was too late to change it.)
@SpearM3064
@SpearM3064 5 жыл бұрын
@Mr T. Guru He might have had *some* influence on the design. Jack left a month after the summer 1984 CES (which means he left sometime in July), and the Commodore 128 was released in January 1985. I seriously doubt the development cycle was less than 6 months. However, it does mean that I mis-remembered the part about features having to be snuck into the final design. Thank you for pointing that out to me. Unlike some people I know, I can admit when I'm wrong. :^)
@stefanocrespi5424
@stefanocrespi5424 5 жыл бұрын
Basic 3.5 on plussy should be faster, thank to fast mode and higher cpu clock.
@NeilRoy
@NeilRoy 5 жыл бұрын
Not at all, because it had to be 100% compatible with the C64 or it would be rather useless.
@EgonOlsen71
@EgonOlsen71 5 жыл бұрын
While the compiler 'advantage' is true to a degree, it might lead to incompatibilities. Because doing math all in float and converting the result back into integer might create a different result than doing it all in integer. Like (5/2)*3. That will be 6 in integer math, but 7 when done with floats and truncated later. The same applies to overflows. And the compiler can't detect this, because it doesn't know what the value range of a program's variables are, especially not in a language like Commodore Basic, with no structured control flow anywhere to be seen. In my cross compiler attempt @ github.com/EgonOlsen71/basicv2 , I actually went the other way and the compiler 'optimizes' some integer stuff to float for performance reasons. It does have some integer based optimizations as well, but the cases where you can safely apply them are very limited.
@askhowiknow5527
@askhowiknow5527 5 жыл бұрын
Is that a parenthesis or a greater than sign? The world may never know.
@TheXJ12
@TheXJ12 4 жыл бұрын
My interpretation for the speed difference between "X=INT(float)" and "X%=float" is that the line being read character by character (as opposed to tokenized Applesoft BASIC), the fewer the better. Does it make sense ?
@8_Bit
@8_Bit 4 жыл бұрын
Yes, I think X%=float is parsed faster and that's why it's slightly faster than X=INT(float).
@bitti1975
@bitti1975 2 жыл бұрын
Of course, "INT" is tokenized, but the braces are not and still need to be parsed. Case in point: This Commodore BASIC V2.0 program 10X%=π 20X%=INT(π) looks like this in memory: >C:0801 0a 08 0a 00 58 25 b2 ff 00 16 08 14 00 58 25 b2 ....X%��.....X%� >C:0811 b5 28 ff 29 00 00 00 �(�)... So INT is represented by the token $b5.
@MrRobbyvent
@MrRobbyvent 5 жыл бұрын
so always use C and/or LM to program optimized code on C64 and also free 8K extra ram disabling basic!
@8_Bit
@8_Bit 5 жыл бұрын
Yes, BASIC is very limited compared to C or especially machine language, but I still find it very interesting to learn about. Even the limitations are educational when we figure out how things work behind the scenes.
@stewiegriffin6503
@stewiegriffin6503 5 жыл бұрын
6:00 am so pissed because of that float conversion
@immortalsofar5314
@immortalsofar5314 3 жыл бұрын
They had 8K (plus a little bit of overflow into the Kernel ROM) to simply make it work. They needed to convert from int to float, they needed to add floats so they managed to save a few bytes by just calling those two functions. It's slow but it works and I guess it was never intended to be a serious language. I created a dictionary of words from 6 disks of text files. BASIC took 28 hours to do one. BASIC with assembler to build up the words took 8 hours to do one. Assembler took 20 minutes to do all 6. I never looked back!
@Breakfast_of_Champions
@Breakfast_of_Champions 5 жыл бұрын
No wonder when Bill Gates himself wrote this Basic 😃
@8_Bit
@8_Bit 5 жыл бұрын
It's true, though it may have been Paul Allen that wrote this part of it?
@raulrrojas
@raulrrojas 5 жыл бұрын
Very interesting!. One other test could be do the loop with if-then instead of for-next, as if-then can probably handle integers
@ShesSometimesDoubleChocolate.
@ShesSometimesDoubleChocolate. 5 жыл бұрын
Why is that "(0)" required by the system instead of just having it be just the variable "FRE" like TI?
@davidmcgill1000
@davidmcgill1000 5 жыл бұрын
TI is a system variable and FRE is a function.
@silkwesir1444
@silkwesir1444 4 жыл бұрын
@@davidmcgill1000 The question is, why didn't they make FRE a system variable like TI
@ideegeniali
@ideegeniali 2 жыл бұрын
@@silkwesir1444 You increment TI every jiffy, so that's a variable. You calculate FRE by performing calculations when needed, so that's a function to invoke
@MagesGuild
@MagesGuild 2 жыл бұрын
FRE(0) is the same in Apple BASIC|: The FRE function was mostly written in the era of 2K to 4K machines, and the rollover is simply cause by overflowing a signed integer. BASIC doesn't normally use unsigned integers, so you simply add the negative value to 32767 and you have (in theory) your actual free RAM, but you have no way to check to extra banks/pages. If you hack BASIC to disallow signed values, it wouldn't do this; or if you modified the actual function to print a string, you could use some wacky string mechanics to displa7y what looks like unsigned int, but otherwise it is all manual. It is rather nice that the 6502 BASIC language gives us 16b+s values in the first place. I would be curious on disassembly what amount of work it would take to modify the FRE function on the Commodore to add the 65536. I believe that you were off by one though (in your description of maximums), as the max negative is -32768, but max positive is 32767, unless for some reason the C64 is unusual in this regard.
@8BitNaptime
@8BitNaptime 2 жыл бұрын
However, you can't use a DIMed variable as the index in a FOR loop. FOR T(0)= 1 TO 1000 doesn't work... but it's a floating point variable.
@duckyvirus
@duckyvirus 5 жыл бұрын
an UNOFFICIAL git with the code from these videos is available on GitHub. the link for the Code used in this one is github.com/duckyvirus/8bitshowandtell/tree/master/8-Bit%20Show%20And%20Tell%20-%20EP12
@JustWasted3HoursHere
@JustWasted3HoursHere 5 жыл бұрын
To be honest, I was glad when BASIC implementations started forgoing line numbers altogether and confined most operations to individual self-contained functions instead. As an aside, did other (interpreted) BASICs for the C64, like Simon's BASIC, improve integer performance or are they very slow as well?
@SpearM3064
@SpearM3064 5 жыл бұрын
As far as I know, Simon's BASIC mostly added a lot of graphics and sound commands, as well as a bunch of programmer's aids (like TRACE and RENUMBER) and structured programming commands (REPEAT/UNTIL, PROC/END PROC, etc.) It did not change the way the C64 handled integers (although it did add MOD, DIV, FRAC, and XOR commands). There's a good article on Simons' BASIC on Wikipedia here: en.wikipedia.org/wiki/Simons%27_BASIC
@cbm80amiga
@cbm80amiga 5 жыл бұрын
@@SpearM3064 In C64 it was very very easy to add own commands. There were a lot of BASICs available with extra functionality. Quicker way was even to add own machine code which could be called from regular BASIC with parameters like SYS49152,23,44.
@SpearM3064
@SpearM3064 5 жыл бұрын
@@cbm80amiga Oh, I'm *very* aware of that, thanks. I taught myself to program in machine language on a VIC-20 when I was just 10 years old. I wrote more than a few routines for screen manipulation in my day. What I was telling @JustWasted3HoursHere was that Simons' BASIC added a lot of commands, but did *not* change the way the C64 handled integers.
@JustWasted3HoursHere
@JustWasted3HoursHere 5 жыл бұрын
@@SpearM3064 I had Simon's BASIC back in the day, and the thing I remember the most was playing around with the embedded music commands (which were VERY tricky to do in regular 'ol Commodore BASIC). Wasn't there a compiler written for Simon's BASIC as well? I vaguely remember one (or maybe it was an announced product that never got released - which used to happen now and then, especially at the tail end of the C64's life). Thanks for the link!
@SpearM3064
@SpearM3064 5 жыл бұрын
@@JustWasted3HoursHere Oh, yes. Music was a pain because of all the POKEs you had to do just to get a chord out of the SID chip. I remember writing machine language routines that could be called from BASIC with a SYS command. For example, SYS 49152,V,A,D,S,R to set the voice envelope, where V=Voice (1 to 3), A=Attack (0 to 15), D=Decay (0-15), S=Sustain (0-15), and R=Release (0-15). (Also, I programmed it so you could set all the envelopes at once. For example, SYS 49152,1,0,0,15,0,2,5,5,8,5,3,0,10,12,5 would set voice 1 to A=0, D=0, S=15, R=0; voice 2 to A=5, D=5, S=9, R=5, and voice 3 to A=0, D=10, S=15, R=5. Normally, that'd require six POKEs. And it had range checking, too. I was pretty proud of myself when I wrote my "sound extensions".) There was no compiler that I know of that would convert Simons' BASIC to pure assembler. The Blitz! compiler would work, but Blitz only "compiled" your program into pseudocode (p-code). If you compiled a Simons' BASIC program using Blitz, and then tried to run it without the Simons' BASIC cartridge, you'd just get a ?SYNTAX ERROR when it reached one of the Simons' BASIC instructions. Also, since it wasn't pure machine code, it was only about 3 times faster than the uncompiled BASIC program. Not exactly the speed boost you'd normally expect. My only problem that I really had with Simon's BASIC was that it used all the memory from $8000 to $BFFF, and most of the memory between $C500 and $CFFF, so it was incompatible with most of the type-in games written in machine code, most of which loaded at $C000. But I am really impressed that Simon was only 16 when he wrote it!
@MagesGuild
@MagesGuild 2 жыл бұрын
@20:23 Now I am curious how many bytes both Apple Integer BASIC and AppleSoft BASIC use for ints, and for float vars, and if this sort of overusage is in either.
@paulspark7287
@paulspark7287 2 жыл бұрын
Wow.. 39 years later I learn something new about CBM BASIC :-) I had no idea there were integer variables
@3DPDK
@3DPDK 5 жыл бұрын
Type this in immediate mode. ie; no program line numbers: NEW:CLR FOR X=2058 TO 2090:POKE X,0:NEXT (don't go less than 2058 because this will over-write it's own 'X' variable name and value and error out) NEW:CLR AA=10: BB%=10:CC=10 FOR X=2048 TO 2090:?PEEK(X);:NEXT (be sure to include the semi-colon after "?PEEK(X); ) -The first zero indicates the "start of Basic" memory (2048) and the next 2 zeros are a pointer to the next program line. Since this pointer points to 00 it means this is the end of the program or "end of Basic" - there is no program in memory - everything typed above is performed from the keyboard buffer, so "Start of Variables" begins three bytes after "Start of Basic" (which in this case is also "End of Basic") -Notice that the floating point AA is stored as "65 65", but the Integer name BB% is stored as 194 194 (chr$(66+128)) - in screen code this is a shifted, reversed background 'B'. Any value greater than 128 tells Commodore the variable is an integer rather than floating point. -Notice that the variables appear in order of their definition. -Notice the variable 'X' (88 00) appears after the other three because it is defined in the command line after the other three. A variable can have a definite 'DEF" or it can be defined the first time it appears in the program, or in the order they were typed in from one or more command line(s). They will maintain this order, even after a program has stopped, until Basic encounters a NEW, CLR, or RUN command. Even then, the data remains in place, only the OS's pointers are cleared. -All numerical variables take seven memory locations, two for the 'name' and five for the number, regardless of type on C-64 so there is no memory savings from one type to the other. -Commodore's routine to find a variable is based on finding it's two character name. This makes it faster to find variables defined first in the program because it always begins it's search from the "end of Basic", or in other words; "Start of Variables". As mentioned, the consistent format in memory makes the name search much simpler. -A floating point number is stored in a 5 byte *mantissa* form, and probably why it doesn't appear to make sense. Look it up to learn how to interpret the numbers. It baffles me. - Commodore utilized the Binary Coded Decimal (BCD) math capabilities of the 6502 (or 6510). This math has much higher maximum limits than a two, eight bit integer number and is more practical in "human usable" math. Nearly all the Kernal and Basic math routines set the 'D' flag in the 6502 which causes it to work in BCD mode. Because of this, Integer numbers must first be converted to BCD or their mantissa form, perform the math, and re-converted back to Integer, which introduces rounding errors causing many early programmers to consume vast quantities of coffee, late into the night, trying to figure out why their computer couldn't divide worth a toot! -As pointed out, only in an array form is an integer stored as two bytes. The nine byte overhead (in this example) is the two character name and the dimension data; the more dimensions the larger the overhead. If I recall - two bytes for array name, two bytes for number of dimensions, and two bytes for number of places in each dimension. Arrays are stored above End of Variable memory and your array header should read 194 128, 2 0, 50 0, 50 0, 0 (last 0 marks the end of definition)
@8_Bit
@8_Bit 5 жыл бұрын
Interesting analysis. I didn't know that BCD was heavily used in Commodore BASIC, I'll have to study that more in the future.
@3DPDK
@3DPDK 5 жыл бұрын
@@8_Bit I have to correct myself; the DEF key word in Commodore Basic is only used to define a function. In other languages you use a line like "DEF X as Integer(or 'float' or 'string');" without actually assigning a value. In Commodore Basic the first occurrence of assigning a value to 'X' in the program does the same thing as the key word DEF but can be located anywhere in the program.
@cbm80amiga
@cbm80amiga 5 жыл бұрын
Really great new channel about C64! I started from BASIC too and even remember that I used some similar tricks too.
@curiousottman
@curiousottman 5 жыл бұрын
Really enjoy your easy to understand videos. I had no idea the commodore kludged int vs floating point variables. You’re probably right: it was to save space on the basic rom.
@brianwild4640
@brianwild4640 3 жыл бұрын
surely the convert to float and back to interger would take as much code at the interger maths ?????
@raimogeel9497
@raimogeel9497 5 жыл бұрын
Have you found the bug in the conversion back to integers? As far as i can remember it has something to do with the number 7. Sqrt(7*7). Gives a differen result than sqrt(7^2) or it was without the sqrt function. I don't have a c64 anymore so can't check it but I like the videos you make.
@SpearM3064
@SpearM3064 5 жыл бұрын
@Raimo Geel It isn't a "bug", it's a flaw inherent to representing floating-point numbers in binary. For example, take this short program: 10 X=1 20 X=X+0.1 30 PRINT X 40 GOTO 20 If you type in this program and run it on a Commodore 64 (or an Apple ][ running Applesoft BASIC, or most other 8-bit computers), eventually it starts printing 3.69999999 and 3.79999999. This is because most floating-point numbers have _infinite representation_ in binary. For example, in binary, 0.1 looks like this: 0.0001100110011001100110011001100110011001100110011001100110011001100110011 and it keeps going *to infinity and beyond!* (Sorry, couldn't resist slipping in a _Toy Story_ reference.) In other words, it's not equal to *exactly* 0.1; it can be slightly more than 0.1 or slightly less than 0.1 depending on how many significant bits the computer keeps. If you use only 11 significant bits, then it rounds to 0.0999755859375. (If I remember correctly, Commodore BASIC keeps 31 significant bits.) Here's two links that you should probably read, if you _really_ want to understand why this happens: www.exploringbinary.com/why-0-point-1-does-not-exist-in-floating-point/ docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
@paulfredfield
@paulfredfield 5 жыл бұрын
@@SpearM3064 In the 80's we had PET computers in an analytical lab with an in-house written calculation package, with machine code bits for speed. we had to have a dozen or so "number traps" to correct the floating point inaccuracies of numbers like 3.49999999 instead of 3.4 for example.
@rog2224
@rog2224 5 жыл бұрын
It worked as a speed optimisation on BBC BASIC 2 (more or less a contemporaneous version of BASIC in 1981) not sure of the ROM size, but BASIC 2 machines only had 32K of RAM.
@8_Bit
@8_Bit 5 жыл бұрын
I've heard BBC BASIC 2 was excellent. I just did a bit of Googling and apparently it was a 16K ROM, double the size of the typical Microsoft BASIC implementation.
@rog2224
@rog2224 5 жыл бұрын
@@8_Bit Supported functions, procedures, and data structures too. It was quite the beast. I used it to do the code for my degree dissertation - the final programme was about 200k that loaded code into a protected area of memory as needed from ADFS disk. Those disks were surprisingly fast.
@Vector_Ze
@Vector_Ze 2 жыл бұрын
I've watched quite a few of your videos! And, I see this one was posted three years ago, so maybe not too surprised with no response. Maybe old hat to you, but when optimizing for speed, substituting occurrences of 0 (zero) with the period, gets a substantial speed boost. I have no clue as to why that is.
@8_Bit
@8_Bit 2 жыл бұрын
Sometimes there are too many comments for me to keep up with, and also KZbin is sporadic with notifications about comments left. But yes, I've used the "." substitution for zero in some videos. I believe the BASIC parser interprets "." as essentially "0.0" so that's why they're equivalent. As for why it's faster, it seems the parser goes through several steps in converting "0" into a number and use of a period side-steps some of that processing.
@rodneylives
@rodneylives 11 ай бұрын
Back in my C64 coding days, I learned the hard way how useless integer variables were. Its BASIC's math routines were all floating point! It converted values from integer to floating point to do math on them, then converted them back to store! It was pretty inefficient.
@8_Bit
@8_Bit 11 ай бұрын
Yes, the only good thing about integers is that an integer array actually does just use 2 bytes per array element, so you can save a lot of RAM that way. A regular floating point array uses 7 bytes per element!
@e8root
@e8root Жыл бұрын
Your C129DCR has jailbars :O
@JohnDlugosz
@JohnDlugosz 5 жыл бұрын
4:00 In C (etc) integers are faster because they are closer to the machine representation: Starting with the '486, the x86 architecture is the same speed for floating point or integer. Adding was 1 clock cycle; multiplication was 40 clock cycles.
@sundhaug92
@sundhaug92 5 жыл бұрын
Because the 486 DX had an integrated FPU (the SX didn't), unlike earlier x86 processors, the 65xx-series, ...
@0LoneTech
@0LoneTech 2 жыл бұрын
They're not the same speed, and AFAICT never have been. There are some quirks like addition being consistently faster as an integer operation while multiply frequently was faster as floating point. Also, transferring data between the two was awkward before SSE (Pentium III).
@alexsandrosschneidinger5215
@alexsandrosschneidinger5215 2 жыл бұрын
Es ist gut für Programm Forschung (entwicklung )
@TamasKalman
@TamasKalman 5 жыл бұрын
haha yeah i never used integers in basic 2.0 =)
@ShesSometimesDoubleChocolate.
@ShesSometimesDoubleChocolate. 5 жыл бұрын
OHHH, a BASIC compiler! Thanks for bringing this up! I remember someone talking about that with you regarding Fast Hack'em! Also, I just remembered that I learned about those back in the '90s at ITT Tech. when they taught us how to make an .EXE from QBASIC on a PC.
@RedSkyHorizon
@RedSkyHorizon 5 жыл бұрын
A happy ending at least
@computernerd8157
@computernerd8157 5 жыл бұрын
When I find my code in tons of trouble and I dont know quite what to do, somewhere somebody whispers write in C.
@NuntiusLegis
@NuntiusLegis 4 жыл бұрын
You mean C on the C64?
@computernerd8157
@computernerd8157 4 жыл бұрын
@@NuntiusLegis its a parody of the beatles song called let it be and yes I was referring to writting it in the C languange, however, I am not too familiar with how you would do that on a C64 computer.
@NuntiusLegis
@NuntiusLegis 4 жыл бұрын
@@computernerd8157 Meanwhile, I was curious enough to look for some options. Seems a few commercial C compilers were availabe for the C64 which could produce programs that were faster than interpreted BASIC but slower than assembler. Compiling times were several minutes at least - following every little change in the code - probably the reason why using an interpreted high level language (usually a BASIC in ROM) was better appreciated on all the 8 bit computers.
@computernerd8157
@computernerd8157 4 жыл бұрын
@@NuntiusLegis Basic was free and I do not think the GNU C compiler existed at that time. I personally grew up on Qbasic on Dos and later I chipmunk basic on a Mac.
@proxy1035
@proxy1035 3 жыл бұрын
seeing all these weird limitations, i wonder how BASIC would've turned out of they had a 16kB or even 32kB ROM worth of space
@8_Bit
@8_Bit 3 жыл бұрын
BASIC in the C128 uses 32K ROM and it's much more capable, but actually runs even slower than the C64 due to extra bank switching and other overhead, and they still didn't optimize for integers. On the other hand, the BBC Micro has an excellent (and fast) BASIC in ROM (not sure of the size, at least 16K I think) that seems to improve on Microsoft's / Commodore's in every way.
@bitti1975
@bitti1975 2 жыл бұрын
I think the "basic" problem with Microsofts BASIC is that they didn't care much to optimize for a particular machine. Quite the contrary, they tried to abstract much of that away via the KERNAL concept and cross compile their BASIC to different machines. That of course had big advantages for them, since they could release quick to marked needs (i.e. different platforms) but of course may not been the best solution for the individual machines. I'm not sure how much Microsoft was involved in Commodore Basic V7.0 (or at all) but I guess the precedence was set.
@brianwild4640
@brianwild4640 2 жыл бұрын
atari basic does the same
@TJ-sj6yy
@TJ-sj6yy 3 жыл бұрын
Question If a basic program has been speeded up, such as using Blitz!, does that affect the relative speed of the variable types in relation to each other? i.e. Afterwords are integers still slower than floating points?
@8_Bit
@8_Bit 3 жыл бұрын
I know some BASIC compilers do special integer optimizations so they would be a lot faster than floating point. I'm not sure if Blitz! does or not, we'll have to read through the manuals (probably on archive dot org) for a few compilers and find which ones have that feature.
@E.T.S.
@E.T.S. 2 жыл бұрын
Regarding this video, there is no real difference on machine code level. 0.1 + 0.1 is calculated as 1 + 1 with a floating point added. My guess is that x% is slower because every step the x% is DIV-ed while running the loop. It's counter intuitive since a DIV operation is faster than DIV+MOD, but it's a BASIC interpreter on a slow processor. DIV+MOD is calculated as a default, and then checked to be rounded every time. 1.8 = 2, and 1.4 = 1.
@awilliams1701
@awilliams1701 4 жыл бұрын
From what I've seen in other videos you don't save enough jiffies to warrant leaving out the spaces.
@vhm14u2c
@vhm14u2c 5 жыл бұрын
Atari basic does the same thing with constants. Uses 7 byes per integer that’s not part of a string, so when coding, best to define each integer as a variable, and use the variables throughout the program to save memory. Learned this on a early antic/Atari magazine.
@shieladixon
@shieladixon 5 жыл бұрын
Hi Robin. I'm really enjoying your videos, thank you. I had a frustrating time debugging a problem this week and wondered whether there might be anything interesting that you can say about it in a future vid. Long story short, when I isolated my problem it came down to loading A with the value of a voice frequency register, modifying it and storing it back to the register. You're way ahead of me here I'm sure. In the X64 Vice emulator I simply get zeros back when peeking or LDA-ing from those sound voice registers. When I try this with a real C64, poking and peeking the values, I sometimes get the value back I've written but it's hit and miss. I couldn't immediately see anything about this in the Prog Ref Guide. In fact chapter 4 specifically mentions peeking (P185) but doesn't say that you can't peek the SID chip registers. I eventually found it in the appendix which deals with the SID, it says that some registers are write-only. Now I know this, I'm up and running again, all I need to do is to cache the values in my own labelled memory locations (which is costing me some cycles and bytes of memory). But I'm still curious about what's going on at a hardware level. Is it as simple as "the specification of the SID says that the registers are one-way and that's that"? Or is there a more interesting explanation?
@8_Bit
@8_Bit 5 жыл бұрын
Yes, the write-only nature of many SID registers have caused much frustration to programmers over the years. Even recently I witnessed one veteran C64 programmer reminding another of this fact. And yes, some of the SID-related documentation doesn't point this out enough. And yes, caching (or mirroring or shadowing, I've heard people use various words) the necessary SID registers is the solution. As for the cause, I'll have to ask some of my more hardware-knowledgable friends, but I suspect it was a decision made just because it simplified the hardware design, saving die space and development time which was apparently very rushed. If there's a more interesting story to it, I'd love to hear it, and make a video about it too! Thanks for the comment. -Robin
@peterjohnson9438
@peterjohnson9438 5 жыл бұрын
20 minutes of "don't teach your father how to screw". Excellent. :)
@LMacNeill
@LMacNeill 5 жыл бұрын
Where were you in 1986 when I was trying to write my own BBS software, and was desperate to optimize it to run faster and fit into only 38,911 Basic bytes of RAM? ;-)
@8_Bit
@8_Bit 5 жыл бұрын
In 1986 I probably didn't know any optimization either, I was lucky to get my little games barely working :)
@ShesSometimesDoubleChocolate.
@ShesSometimesDoubleChocolate. 5 жыл бұрын
If you want to show a negative number as a positive instead, why do all this that you showed instead of just using "ABS..."?
@Dan-mq8in
@Dan-mq8in 2 жыл бұрын
ABS is not quite the same as converting a signed 16- bit number to an unsigned one. For a 16 bit -1 value (represented in binary as 1111111111111111): ABS(-1) is 1 -1 + 66536 is 65535
@Dan-mq8in
@Dan-mq8in 2 жыл бұрын
That should have read -1 + 65536 = 65535
@Dan-mq8in
@Dan-mq8in 2 жыл бұрын
The way negative numbers are represented in binary can var, especially on machines from before 1980. C64 and more modern machines use "twos-compliment" to represent negative numbers: - a 16 bit unsigned integer goes from 0 then 65535 and then wraps around to 0 again. - a 16 bit signed integer goes from -32768 to 32767 and then wraps around to -32768 again. positive numbers from 0 to 32767 have - the same binary number representation for both signed and unsigned - twos-compliment refers to how you can convert a number from negative to positive, or positive to negative, by flipping all of the bits and adding one. So for the example of -1, 1111111111111111, you flip all of the bits to 0000000000000000 and add one, making the number 1.
@blackswan7292
@blackswan7292 5 жыл бұрын
I feel Robbed. Where was this video when I needed it 35 years ago?
@abcdef5414
@abcdef5414 5 жыл бұрын
Working with integer variables is slower because the interpreter has to read more characters from the program source text in order to identify if the variable is real or integer. There is just one character extra in the program source text - %. This is just the same example mentioned in the beginning of the video. This - "FORI=1TO1000" is faster than this one - "FOR I = 1 TO 1000".
@8_Bit
@8_Bit 5 жыл бұрын
The extra % character does slow things down slightly, but I just did a benchmark here, with the same FORI=1TO1000 loop, comparing A%=A%+1 and AA=AA+1. A% took 287 jiffies, while AA took 254. So even with an equal number of characters to parse, floats are still faster than integers. The difference is the time it takes to convert the integer to a float and back again.
@thorvalld
@thorvalld 5 жыл бұрын
Hi there! New subscriber here! If my comment finds your way would be kind and answer this question: I want to start programming in BASIC is there any emulators that run on windows? And if I want to get a commodore which one should I get? (For the first time!) Cheers from Norway!!
@8_Bit
@8_Bit 5 жыл бұрын
Hi Thorvald, thanks for subscribing! If I could have only one Commodore computer, it'd probably be a C128D like I use in the episodes. But if it's too expensive, I'd be happy with a regular C128 or C64 too. I think the best C128/C64 emulator is VICE which is available for Windows.
@TokyoXtreme
@TokyoXtreme 5 жыл бұрын
Datasoft’s The Goonies… and in the original packaging. Oh my.
@squire2k6
@squire2k6 5 жыл бұрын
I'm so glad I found this channel. It brings back incredible memories of programming my custom BBS on the C64... Storing my BBS user list under BASIC ROM and then validating users in ML by flipping out the BASIC ROM, reading the user list under it, and flipping it back. As far as optimizing is concerned... I already knew that all numeric variable values were stored as FP, but I also read that it was actually faster to do this A=., than this A=0 because apparently C64 BASIC has to parse the 0 as an int, then convert it to FP for storage, whereas A=. was effectively A=0.0, which was already FP. If I remember correctly, I benchmarked the difference in performance at the time, and it was substantial enough that I began initializing using A=. whenever I wrote new code. Unfortunately I sold my last C64 a LONG time ago so I can't validate whether the performance advantage actually existed or not. Anyway, again, I want to thank you for your work on this channel. Some of the most fun programming I ever did was on the C64 where I felt I could make the hardware sing and dance at my whim.
@csbruce
@csbruce 5 жыл бұрын
My guess is that whenever you give a digit, the BASIC interpreter will multiply the floating-point accumulator by 10.0 and then add the new digit, even though this is a needless waste of time for the first digit encountered. Floating-point operations are especially slow with a 6510. With a "." character, there is no need to multiply by 10. You can do performance testing using a C64 emulator. The emulation is generally cycle-for-cycle exact.
@Shmbler
@Shmbler 5 жыл бұрын
Perfect! Very useful topic for what I am working on atm.
@flyguille
@flyguille 5 жыл бұрын
you didn't save time because you are using explicit INTEGER, and parsing the % simbol takes time aswell, also if there is single character variable name VS dual character name, is time different?. Anyway, I hope , C64 BASIC has something like DEFINTA-Z like MSX world has, so no requires % simbol. In MSX that means DEFAULT = all integers, if you want floating use like A!= or A#.
@flyguille
@flyguille 5 жыл бұрын
Damn, now I watched your explanation, what way to make a slooooower basic interpreter...!. But anyway, test single character variable name vs 2 characters.
@csbruce
@csbruce 5 жыл бұрын
@@flyguille: A single-letter variable name would be a little faster to parse on every reference. Also, variables are allocated into memory in the order in which they are first encountered and variable references are looked up sequentially, so your program will run faster if your most-used variables are allocated first.
@adymode
@adymode 5 жыл бұрын
Acorn basic used on the beeb micros also had very fast integer variables as well as defined procedures, inline assembly code and other goodies, all under 16kB. Commodore basic was an old microsoft basic, it wasn't one of the machines strengths but was enough to learn the... erm.. fundamentals.
@napomania
@napomania 5 жыл бұрын
if you make poles on twitter now i have to go to twitter too :-D
@siriokds
@siriokds 5 жыл бұрын
What about fixed point math speed in c64?
@8_Bit
@8_Bit 5 жыл бұрын
Unfortunately, C64 BASIC doesn't have fixed point math. But of course you can do it in assembly just as easy as regular int math. I've used 8.8 and 12.4 in some of my games.
@be236
@be236 5 жыл бұрын
Why do you have the black border at the top-right corner masking out your monitor display?
@csbruce
@csbruce 5 жыл бұрын
The lower-right appears to be the full scene recorded by the 16:9 video camera.
@8_Bit
@8_Bit 5 жыл бұрын
Yes, I wasn't able to reliably record my CRT directly so instead I use a capture box and show the 4:3 image in the top left, and then show the 16:9 image from my camera in the bottom right. Maybe I'll change the way I do things in the future but this seems to be working okay for now; I don't have any better ideas yet.
@michaelpressler5296
@michaelpressler5296 5 жыл бұрын
Very interesting! Thanks!
@proxy1035
@proxy1035 5 жыл бұрын
man it's nice that i found your channel also would really like some more videos on the C64 innerworkings. like how does it even count RAM? also i think the reason -1 is used instead of 1 (i think this is true in a lot of programming languages) is because -1 means "all bits are 1" while 0 means "all bits are 0" so no matter how large the variable used for that is, if it's 1 bit, 8 bit, 16 bit, it will always be 0 and -1. (literally, the signed value of a 1 bit number is 0 and -1)
@SpearM3064
@SpearM3064 5 жыл бұрын
@Proxy The short version is that Commodore BASIC stores variables right after your program, using 7 bytes per variable. This is followed by the contents of your arrays (which are 2 to 7 bytes per element). Temporary strings start at the top of RAM and move down (one byte for each character in the string). BASIC keeps track of several memory pointers in zero-page. These include the start of BASIC RAM (default $0801), the end of BASIC RAM (default $A000), the end of your arrays, and the beginning of the temporary strings. For the sake of clarity, the start of memory will be called RAMBOT, the end of memory will be called RAMTOP, the start of string storage will be STRBOT, and the end of array storage will be ARRAYTOP. When you PRINT FRE(0), the first thing it does is perform "garbage collection", which means it throws out any temporary strings that are no longer being used. Then it performs the following calculations: (1) RAMTOP minus RAMBOT = Total memory available to BASIC (which we will call MEMTOT). (2) RAMTOP minus STRBOT = Memory being used by strings (which we will call STRTOT) (3) ARRAYTOP minus RAMBOT = Memory being used by your program, variables, and arrays (which we will call PRGTOT) (4) MEMTOT minus (STRTOT+PRGTOT) = the amount of memory available The available RAM is returned to the FRE(0) function as a 16-bit signed integer, so if you have more than 32K of available RAM, it will display as a negative number. If I've missed a step or gotten something wrong, then I hope someone will correct me, but at least my explanation should be enough to give you a general idea of what's going on "behind the scenes".
@csbruce
@csbruce 5 жыл бұрын
Indeed, -1 is all '1' bits as a signed integer, and the reason Commodore BASIC uses this instead of +1 to mean 'true' is to give the AND, OR, and NOT operators greater power by allowing them to be simultaneously bitwise operators (&, |, ~ in C) and logical operators (&&, ||, ! in C). «? NOT -1» gives 0, but «? NOT 1» gives -2, which means that using any value other than -1 to mean 'true' would raise the requirement for separate bitwise operators. In most other languages, 'true' is equivalent to '1' and there are separate logical and bitwise operators.
@SpearM3064
@SpearM3064 5 жыл бұрын
@@csbruce Okay, I grew up programming Commodore machines (started with a VIC-20 when I was 10, and used a C64 from 1984 all the way to 1992 before I finally got my first PC clone, and even I didn't know that! It really makes sense when you think about it. Thank you for an enlightening post. :) P.S. To be specific, I already knew that Commodore BASIC (and Applesoft BASIC) uses -1 to mean 'true'. What I *didn't* know was the reason *why.* Well, now I know. So thank you.
@csbruce
@csbruce 5 жыл бұрын
@@SpearM3064 wrote «When you PRINT FRE(0), the first thing it does is perform "garbage collection"» Actually, this is a good reason to avoid fancy formulas that call FRE(0) twice - if you have a bunch of string variables, it will be extra slow. You're better off with a simpler «FR=FRE(0): IF FR
@imbezol
@imbezol 5 жыл бұрын
Amazing stuff!
@josephcote6120
@josephcote6120 5 жыл бұрын
One factor that seems to have been overlooked is that it is an interpreted BASIC. Each line is picked up from memory, decoded and executed. All of those steps take time. More importantly, *every character* of a line has to be read in *every time* it's executed; if a line is longer, say because of the "%" type indicators, it will take more time to read it into working memory. Then when the line is ready to decode, it has to look at the variable names and decide which ones you're referring to. "Oh here's an A where I expect a variable name, what follows it? Is it a $ for a string, a % for an integer? Nothing?" If nothing, it's ready to go, if something else then that takes more time to figure out. *Every time* a line is executed. I think these are the factors making the biggest difference in your timing tests. Then, once it has the right variable name, it goes to a lookup table of variable names, to get the address where the value of that variable lives and reads it in, same amount of time for integer and fp numbers. Likewise when storing the answer, lookup to find the address to writ e the answer to. All these things so far are what make interpreted langues so slow. The actual computation cost, measured by time, is absolutely the fastest for integers. But all the other things mentioned above swamp out whatever savings you'd see.
@8_Bit
@8_Bit 5 жыл бұрын
Yes, it takes longer to interpret the variable A% than A because of the extra character. Off-camera I compared A% vs AA and A% was still slower. Commodore BASIC doesn't do any integer math though, it simply doesn't have any code for it. All math routines are floating point. By the way you're free to grab VICE emulator if you don't have a real Commodore machine, and try some of these benchmarks for yourself and see if you can improve on them.
@josephcote6120
@josephcote6120 5 жыл бұрын
@@8_Bit Fair enough. I just wanted to point out some other things that can affect performance. This is a particular interest of mine as someone who's written interpreters and compilers.
@8_Bit
@8_Bit 5 жыл бұрын
@@josephcote6120 Yeah, they're totally valid points and I didn't really mention it. I was making an effort to make a 20 minute video instead of another 40 minute video, but then I end up glossing over stuff :) Thanks for the comments.
@josephcote6120
@josephcote6120 5 жыл бұрын
@@8_Bit It really is amazing what they could stuff into a couple of k and get a pretty decent language out of.
@noland65
@noland65 5 жыл бұрын
@Joseph Cote - This is also the reason, why numeric values (constants) are slow. Since they are stored in plain text (otherwise the LIST command wouldn't work as expected), the interpreter has to parse and convert the number from ASCII to numeric value each time it comes across it. Variables, on the other hand, are already stored in a computational format. Therefore you may speed up a loop considerably by using variables even for such simple expressions as "X+1". (The opposit is true for string constants, since strings are already contained in the listing in a useful format. Therefore the interpreter can use the occurrence in the source text directly without reserving extra memory for a duplicate and engaging in any lookups in search for this memory location.)
@mariannmariann2052
@mariannmariann2052 5 жыл бұрын
Gotta go fast!
@CommodoreGreg
@CommodoreGreg 5 жыл бұрын
Fantastic!
@lenkel
@lenkel 5 жыл бұрын
Is the Integer 16 bits in the C64?
@8_Bit
@8_Bit 5 жыл бұрын
Yes, a signed 16-bit integer, from -32768 to +32767.
@csbruce
@csbruce 5 жыл бұрын
Using intergers in Commodore BASIC programs is almost entirely counter-productive. All numerical calculations are done in floating point, so when integer variables are fetched or stored, they're converted to and from floating point, which takes extra time. Also, the '%' symbol is stored in the program which means that it takes more space (one extra byte for each reference) and needs to be parsed every time, which again makes things a little slower. Integers in Commodore BASIC really only have one practical use. When storing in a scalar variable, it doesn't save space since all scalars take five data bytes (plus two bytes for the variable name and data type) to store a value, despite integers only using two of the five available data bytes and strings only using three of the five data bytes (plus the dynamically-allocated string content). However, for array variables, integers only use two bytes per element and strings only use three bytes (plus the dynamic string content). So, for a big array, you can save memory space using an integer array vs. a floating-point array. This is the only practical use for integers. The reason that BASIC doesn't allow integer index variables is presumably just because it would take more effort to support. When a FOR loop is entered, BASIC stores an 18-byte record structure for it on the stack with information including the 'TO' value, the 'STEP' value, a pointer to the line and byte position within the BASIC program code for the top of the loop body, and a pointer to the index variable. There's no specific reason that this index-variable pointer couldn't point to an integer variable since the memory record for a scalar BASIC variable includes the data type, but it would simply take more effort to handle integers. Also, as you say, you would get confusing results if you were to do something like «FOR I%=1 TO 2 STEP 0.5», which would run forever. (Of course, fractional steps can produce confusing results anyway because of floating-point round-off errors.) In principle, if they had more ROM space and more time to make the C64 BASIC, they could have added special support for integer values (not specifically for integer variables). E.g., have a special representation for values recognized as integers and do assignments, adds, subtracts, comparisons, peeks, pokes, etc. using the integer values without ever converting them to floating point, but convert them to floating point where needed. This would make programs like games run significantly faster if most of their variable values are actually integers. They had enough ROM space in the C128 to do this, but didn't bother. 18:45 You can use a leading colon character to indent code as well. Any extra spaces at the start of a line are thrown away.
@SpearM3064
@SpearM3064 5 жыл бұрын
@Brutikus Red I was going to say exactly the same thing... but considering the giant wall of text, I'm happy to have been ninja'ed. :) Also, for anyone reading this... Brutikus is *absolutely* correct. In Commodore BASIC, integers do *not* save time, and they don't save space unless they're in an array. The same rule applies to Applesoft BASIC as well, since it's based on the same version of Microsoft BASIC, but with extra commands for graphics.
@pb7379-j2k
@pb7379-j2k 5 жыл бұрын
Isn’t this what the video said?
@laureven
@laureven 5 жыл бұрын
regards
@sabriath
@sabriath 5 жыл бұрын
The "for" loop requirement is so that it doesn't have to call any conversion functions with non-floats.
@10MARC
@10MARC 5 жыл бұрын
Great video. It is fun to see some BASIC stuff again!
@frannybecker
@frannybecker 5 жыл бұрын
Hello saudações do Brasil 🇧🇷 obrigada por compartilhar lindos vídeos 👍 Uma belíssima abençoada semana 💖🙏🌷 beijos com carinho 😘 Love 😍
@8_Bit
@8_Bit 5 жыл бұрын
I'm so glad you're a Commodore computer fan, Franny!
Even More Commodore 64 BASIC Optimizations
18:16
8-Bit Show And Tell
Рет қаралды 14 М.
About Commodore 64 BASIC Abbreviations
36:51
8-Bit Show And Tell
Рет қаралды 20 М.
Spongebob ate Michael Jackson 😱 #meme #spongebob #gmod
00:14
Mr. LoLo
Рет қаралды 10 МЛН
Остановили аттракцион из-за дочки!
00:42
Victoria Portfolio
Рет қаралды 3,8 МЛН
The Extra Spaces in Commodore 64 BASIC Errors
37:09
8-Bit Show And Tell
Рет қаралды 34 М.
Adding Hex Support To C64 BASIC
28:29
8-Bit Show And Tell
Рет қаралды 21 М.
Commodore 64 BASIC: All 32 Errors!
48:17
8-Bit Show And Tell
Рет қаралды 27 М.
The Computer Chronicles - Commodore 64 (1988)
28:32
The Computer Chronicles
Рет қаралды 44 М.
10 Rarely Used Commodore 64 BASIC Features
31:20
8-Bit Show And Tell
Рет қаралды 75 М.
AMAZING New OS for the 40-year-old Commodore 64! C64 OS Review
39:47
Retro Recipes
Рет қаралды 288 М.
Commodore 64 Getting Started & Buying Guide 2023!
47:12
retrobits
Рет қаралды 48 М.
Exploring Epyx Fast Load for the Commodore 64
42:41
8-Bit Show And Tell
Рет қаралды 77 М.