Remarks: threadbare and thread
From Maze
(Difference between revisions)
(First complete draft of thread remark.) | |||
| Line 32: | Line 32: | ||
<pre> | <pre> | ||
| − | *= $1000 ; starting memory location | + | *= $1000 ; starting memory location |
</pre> | </pre> | ||
| Line 101: | Line 101: | ||
BASIC makes both of these acts compact and accessible. Print a character, generate a random number. Normally, carrying out either of these in assembly is an arduous task. Here's an example of a commonly used routine for generating a random 8-bit number in 6502 assembly: | BASIC makes both of these acts compact and accessible. Print a character, generate a random number. Normally, carrying out either of these in assembly is an arduous task. Here's an example of a commonly used routine for generating a random 8-bit number in 6502 assembly: | ||
| − | Rand8 | + | <pre> |
| − | lda random ; get seed from a zero-page memory address (must be non-zero) | + | Rand8 |
| − | asl ; shift byte | + | lda random ; get seed from a zero-page memory address (must be non-zero) |
| − | bcc Rand8.no_eor ; branch if carry flag not set after shift | + | asl ; shift byte |
| − | eor #$CF ; otherwise EOR with literal $CF | + | bcc Rand8.no_eor ; branch if carry flag not set after shift |
| − | Rand8.no_eor | + | eor #$CF ; otherwise EOR with literal $CF |
| − | sta random ; save number as next seed | + | Rand8.no_eor |
| + | sta random ; save number as next seed | ||
| + | </pre> | ||
Remember that each assembly instruction (lda, asl, etc.) uses a single byte in the program, and in this case the ones with operands (random, #$CF) are also a byte in size. That makes this routine nine bytes in size, or 25% of the space needed for the entire 10 Print program in BASIC (given that each character of BASIC text taking up a byte). That's not surprising; a high-level language is supposed to abstract more complex, lower-level routines into more easily usable functions. But such functions can also be built into the hardware itself, stored in ROM as executable instructions, or produced through a combination of seemingly unrelated affordances. | Remember that each assembly instruction (lda, asl, etc.) uses a single byte in the program, and in this case the ones with operands (random, #$CF) are also a byte in size. That makes this routine nine bytes in size, or 25% of the space needed for the entire 10 Print program in BASIC (given that each character of BASIC text taking up a byte). That's not surprising; a high-level language is supposed to abstract more complex, lower-level routines into more easily usable functions. But such functions can also be built into the hardware itself, stored in ROM as executable instructions, or produced through a combination of seemingly unrelated affordances. | ||
| Line 123: | Line 125: | ||
Apart from its sonic functions, the SID also has he ability to generate random values. To do so, the programmer must select the noise waveform on the SID's voice 3 oscillator and set that voice's frequency to a non-zero value. Setting a higher frequency value will cause the noise values to change more rapidly, yielding a greater variety of random numbers. The first three instructions of the assembly program above accomplish these settings: | Apart from its sonic functions, the SID also has he ability to generate random values. To do so, the programmer must select the noise waveform on the SID's voice 3 oscillator and set that voice's frequency to a non-zero value. Setting a higher frequency value will cause the noise values to change more rapidly, yielding a greater variety of random numbers. The first three instructions of the assembly program above accomplish these settings: | ||
| − | lda #$80 ; set this value in... | + | <pre> |
| − | sta $d40f ; ... the noise speed hi SID register | + | lda #$80 ; set this value in... |
| − | sta $d412 ; ... and the noise waveform SID register | + | sta $d40f ; ... the noise speed hi SID register |
| + | sta $d412 ; ... and the noise waveform SID register | ||
| + | </pre> | ||
... and once done, the program can get a new 8-bit random number by reading from memory location $d41b. While it looks a little messier than just calling RND in BASIC, the result is equally abstracted from the programmer's perspective--it's just abstracted to a different place, namely the SID chip. | ... and once done, the program can get a new 8-bit random number by reading from memory location $d41b. While it looks a little messier than just calling RND in BASIC, the result is equally abstracted from the programmer's perspective--it's just abstracted to a different place, namely the SID chip. | ||
| Line 139: | Line 143: | ||
But as with the SID random number solution, the C64's underlying hardware ROM provides a much simpler solution. The C64 has a low-level operating system core, most of which it inherited from the earlier Commodore PET. This core is referred to as the KERNAL, and it occupies the last 8KB of the machine's address space ($E000-$FFFF). The KERNAL handles keyboard input and screen output, among other functions, including a routine that will send the PETSCII character value currently in the 6502 processor's accumulator to the current output device (the screen by default). That routine lives at memory address $ffd2, and it can be executed by jumping to subroutine at that address. This is just what the 10 Print assembly rendition above does, after loading a random value and manipulating it to insure that it will be one of the two slash characters that comprise the maze: | But as with the SID random number solution, the C64's underlying hardware ROM provides a much simpler solution. The C64 has a low-level operating system core, most of which it inherited from the earlier Commodore PET. This core is referred to as the KERNAL, and it occupies the last 8KB of the machine's address space ($E000-$FFFF). The KERNAL handles keyboard input and screen output, among other functions, including a routine that will send the PETSCII character value currently in the 6502 processor's accumulator to the current output device (the screen by default). That routine lives at memory address $ffd2, and it can be executed by jumping to subroutine at that address. This is just what the 10 Print assembly rendition above does, after loading a random value and manipulating it to insure that it will be one of the two slash characters that comprise the maze: | ||
| − | jsr $ffd2 ; output character via kernal routine | + | <pre> |
| + | jsr $ffd2 ; output character via kernal routine | ||
| + | </pre> | ||
The output of the assembly program is essentially identical to 10 Print (it runs a bit faster, because the microprocessor is running machine instructions directly, rather than interpreting them first as BASIC commands and functions. But the program that generates that output is really no more or less lengthy or complex than is the BASIC program. When measured in bytes, the assembly program is even shorter than its BASIC cousin (22 bytes for the assembly program, compared to 36 bytes, or characters, for the BASIC program). While the assembly program is clearly more esoteric and less human readable than the BASIC one, its implementation teaches us that the abstraction that makes the emergent elegance of 10 Print's output possible in such a small set of instructions is not a feature of the BASIC interpreter, but of the underlying hardware itself. | The output of the assembly program is essentially identical to 10 Print (it runs a bit faster, because the microprocessor is running machine instructions directly, rather than interpreting them first as BASIC commands and functions. But the program that generates that output is really no more or less lengthy or complex than is the BASIC program. When measured in bytes, the assembly program is even shorter than its BASIC cousin (22 bytes for the assembly program, compared to 36 bytes, or characters, for the BASIC program). While the assembly program is clearly more esoteric and less human readable than the BASIC one, its implementation teaches us that the abstraction that makes the emergent elegance of 10 Print's output possible in such a small set of instructions is not a feature of the BASIC interpreter, but of the underlying hardware itself. | ||
