|
Post by moodswing on Dec 1, 2008 10:42:07 GMT -5
Does anyone play with the Logo programming language? The original Logo disk always knocks the read/write head. So, get rid of that problem by following these steps, (where I abbreviated with JiffyDOS commands). * Insert your logo disk. * /logo * change line 60 from ,8,1 to ,peek(186),1 * Switch to a different disk. * ←logo * Again insert your logo disk. * /logo.bin * poke 2391, 208 * poke 2472, 242 * poke 12079, 165 * poke 12080, 186 * Switch to the other disk. * ←logo.binNot only does this get rid of the knocking, but now you can boot from any device. How cool is that?  Don't have an original Logo disk? You can find it at www.zimmers.net/anonftp/pub/cbm/c64/programming/index.html
|
|
|
Post by moodswing on Dec 1, 2008 10:43:03 GMT -5
Logo's randomize command always seeds with the same value on startup. To randomize the initial seed, I sometimes execute a (randomize (256 * .examine 162) + .examine 161) at the beginning of a programming session. This is a little like BASIC's A=RND(-TI). (Actually, it's a lot like that...'cept longer.)
If you're happy with 256 different seed possibilities, then try (randomize .examine 162).
|
|
|
Post by moodswing on Dec 1, 2008 11:32:04 GMT -5
Sometimes it's handy to insert pauses in a program--such as momentarily displaying something on the screen, or waiting briefly for a sound to be heard from the SID chip before turning it off again. The utilities disk uses examples that rely on 1 MHz timing, like this... to wait :n repeat :n [] end Logo is fortunately compatible with both the Turbo Master and SuperCPU accelerator cartridges. But now we need a pause that is independent of the speed at which the microprocessor is running. Wouldn't it be great to be able to say wait 30 for a 30 jiffy pause, or wait 60 for a pause of one second, and it would work at 1 MHz, 4 MHz, or 20 MHz? Well, how about this? to wait :jiffies .deposit 162 0 loop: if :jiffies > .examine 162 go "loop end Logo periodically does garbage collection, which unintentionally inserts short pauses in a program where we don't want them. There isn't much we can do about this, but if you know you're going to be waiting, say, longer than half a second, we could get rid of one pause, anyway, just after we have already done a wait. So the above might become to wait :jiffies .deposit 162 0 if :jiffies > 30 then .gcoll loop: if :jiffies > .examine 162 go "loop end Now, instead of burning up half a second doing nothing, we force garbage collection. If C64 emulators sped up just the microprocessor instead of the whole machine, including the 60 times per second interrupt, the above would work great on an emulator too. Why doesn't somebody fix this?! 
|
|
|
Post by moodswing on Dec 15, 2008 9:48:19 GMT -5
How do you find if a number is even or odd? I used this when I wanted to know if the screen cursor was on an even or odd column. Everyone knows that when an even number is divided by two, it's remainder is zero, whereas an odd number has a remainder of one. Using this we could write even? and odd? as to even? :n output remainder :n 2 = 0 end to odd? :n output not even? :n endBut division takes a lot of time, and having odd? call even?, even more expensive. In binary, even numbers have bit zero clear, and odd numbers have bit zero set. So it would be faster to test this bit using Logo's bitand procedure, such as to even? :n output bitand :n 1 = 0 end to odd? :n output bitand :n 1 = 1 endEven? becomes about 17% or 18% faster than before. And odd? about 55% or 56% faster! So here's a question. Is 3.5 even or odd? Whether we use the remainder method or the bitand method, Logo responds that 3.5 is even. Why? Because it rounds 3.5 to 4 when it does the bitand operation. I don't know why it rounds with remainder--maybe Logo is smart that way. 
|
|
|
Post by Robin Harbron on Dec 20, 2008 16:14:29 GMT -5
I'm finding these posts interesting, even if I'm unlikely to make use of the info 
|
|
|
Post by moodswing on Dec 21, 2008 10:28:44 GMT -5
Good to know someone has glanced at this. A couple years ago I started tinkering with Logo, but had little information to get started. I used a machine language monitor to examine memory to find the Logo primitives, and experimented in how to use them. I found a few Logo examples on some early LOADSTAR disks, as well as a BASIC puzzle called "TABLES AND PEOPLE" that I thought might be a good first programming project in Logo for me to try. The uninspired BASIC version used characters from the Commodore set.  I ripped a GEOS font, wrote an ML driver to print them to Logo's bitmap, and added extended text mode dice using Logo's splitscreen ability.  I also allowed entering the puzzle solution on the bitmap.  Memory in Logo is very limited. There really isn't room enough to store a 4 kilobyte GEOS font other than in the bitmap itself. Since my program only displays the upper half of the bitmap, the lower half stores the font information--hidden by the dice.  Recently, I have been rewriting parts of Logo to use 65C02 opcodes. I decided not to try to stay 6510 compatible because Logo at 1 MHz is too slow. The Turbo Master has enough grunt to get Logo off the ground, and by optimizing with indirect addressing, it shaves off some cycles and feels more like 5 MHz. Instead of this... LDY #0 LDA ($5C),Y PHA INY LDA ($5C),Y PHAI can say... LDA ($5C) PHA LDY #1 LDA ($5C),Y PHAand save myself a byte and two cycles. I estimate I have shortened Logo by maybe 500 bytes, and a ton of cycles.
|
|
|
Post by robertb on Dec 21, 2008 21:52:07 GMT -5
Recently, I have been rewriting parts of Logo to use 65C02 opcodes. I decided not to try to stay 6510 compatible because Logo at 1 MHz is too slow. The Turbo Master has enough grunt to get Logo off the ground... That's interesting to know. I've never tried Logo with my Turbo Master CPU. I should try it, Robert Bernardo Fresno Commodore User Group videocam.net.au/fcugThe Other Group of Amigoids www.calweb.com/~rabel1/Southern California Commodore/Amiga Network www.sccaners.org/
|
|
|
Post by Unseen on Dec 29, 2008 18:38:42 GMT -5
Oooh, LOGO... Some sources call LOGO a functional programming language, but does anyone use it (or at least the C64 implementation) that way?
Adding some of the usual higher-order functions isn't hard (Warning: Code may contain excessive parenthesis):
TO MAP :FUNCTION :LIST IF EMPTY? :LIST OP [] OP FPUT ( RUN ( LPUT WORD "" ( FIRST :LIST ) :FUNCTION ) ) ( MAP :FUNCTION BF :LIST ) END
TO FOLDL :FUNC :ACCU :LIST IF EMPTY? :LIST OP :ACCU LOCAL "TMP MAKE "TMP RUN ( LPUT WORD "" ( FIRST :LIST ) ( LPUT :ACCU :FUNC ) ) OP FOLDL :FUNC :TMP ( BF :LIST ) END
TO FOLDR :FUNC :ACCU :LIST IF EMPTY? :LIST OP :ACCU LOCAL "TMP MAKE "TMP RUN ( LPUT :ACCU ( LPUT WORD "" ( FIRST :LIST ) :FUNC ) ) OP FOLDR :FUNC :TMP ( BF :LIST ) END (I wonder which genius decided to implement a [ code ]-tag for this web forum that discards all leading spaces...)
MAP takes a function and applies it to each element of the list, FOLDL/FOLDR take a function and a start value and apply the function to the current value and a list element for all elements in the list - L or R only differ in the order of the arguments to the function.
Unfortunately the C64 logo defines arithmetic operators only as infix functions, so a few additional definitions are required for the demonstrations:
TO SQUARE :A OP :A * :A END
TO ADD :A :B OP :A + :B END
TO MULT :A :B OP :A * :B END
Those three functions should be obvious enough... Now for the usual "what can one do with map"-demonstrations:
?MAP [SQUARE] [1 2 3 4 5] RESULT: [1 4 9 16 25]
Applying SQUARE to each number in a list does just what you would expect. Of course you're not limited to a single word, anything that accepts a value can be used:
?MAP [SQUARE SQUARE] [1 2 3 4 5] RESULT: [1 16 81 256 625]
Squaring followed by square root is a computationally expensive almost-always identity function for positive integers:
?MAP [SQRT] MAP [SQUARE] [1 2 3 4 5] RESULT: [1 2 3 4 5]
Sticking to numbers is boring:
?MAP [CHAR (-1) + ASCII] [I B M] RESULT: [H A L]
FOLD can be used to sum up the contents of a list:
?FOLDL [ADD] 0 [1 2 3 4 5] RESULT: 15
Or to multiply it:
?FOLDL [MULT] 1 [1 2 3 4 5] RESULT: 120
I didn't see any REVERSE function in the manual, so let's write one with FOLDR:
?FOLDR [FPUT] [] [1 2 3 4 5] RESULT: [5 4 3 2 1]
The ADD/MULT examples used functions that take the same type of input for both of their parameters so it didn't matter if the example used FOLDL or FOLDR - FPUT and LPUT expect the list as their second parameter though, so they require FOLDR which uses the accumulator as the second parameter.
If you have FOLDR then you don't really need MAP, this is the squaring example rewritten with FOLDR:
?FOLDR [LPUT SQUARE] [] [1 2 3 4 5] RESULT: [1 4 9 16 25]
Splitting a word into a list of its characters is now simple:
?FOLDR [LPUT] [] "HELLO RESULT: [H E L L O]
Exercise for the reader: Use folding to reverse the previous example, i.e. use it to concatenate a list of words into a single one. May require bugfixes in the definition of FOLDL/FOLDR, but make sure not to break any of the other examples...
|
|
|
Post by Robin Harbron on Dec 30, 2008 11:11:11 GMT -5
(I wonder which genius decided to implement a [ code ]-tag for this web forum that discards all leading spaces...) Yeah, I've been using [ pre ] instead of [ code ] because of this. Not a perfect solution, but the best I've found...
|
|