Literature Review
Central processing unit Memory Video generation Sound Input and Output In the Commodore 64, the central processing unit (CPU) is a 6510 microprocessor chip. It executes the same instruction set as a 6502 microprocessor as used in Apple and ATARI computers. It runs with a clock frequency of 1.0225 MHz. For all practical purposes, this can be considered to be a 1 MHz clock. The 6510 has an addressing range of 65536 bytes (64K). There are two different types of memory in the Commodore 64. It has 64K of dynamic RAM, which can be banked into the address space of the other chips as necessary. There is also 20K of ROM in the system. In this ROM are the BASIC programming language and the operating system of the Commodore 64. The operating system is responsible for reading the keyboard, updating the real-time clock, and transferring data in and out of the system, among other things. Since the CPU can only address 64K of memory, all of the RAM cannot be accessed simultaneously with all of the ROM. 1b overcome this problem, the technique of bank switching is used. For instance, if you are not using BASIC, there is no need for the BASIC ROM to be accessible. In this case, it can be replaced with RAM. The CPU cannot tell the difference, so it can be “tricked” into addressing more then 64K of memory. Video generation is a task that is taken care of by a 6567 Video Interface chip (VIC 11).
All of the various graphic modes of the Commodore 64 are generated by this chip. In the process of generating the video signal, the VIC-II chip refresh~ the dynamic ram chips used in the system. The VIC-II chip also generates the system, clock from the 8.18 MHz dot clock. Sound is generated by a 6591 Sound Interface Device chip (SID). This chip can generate 3 independent voices each in a frequency range of 0 to 4 kHz. This corresponds to a range of about 9 octaves. Each voice has an independent volume envelope and a choice of waveforms. The SID chip can also provide
a number of filtering options for use with its own signals or an externally supplied signal. Input and output functions are handles primarily by a pair of 6526 Compkx Interface Adapter chips. Serial communication functions as well as the parallel port are maintained by these chips. They also handle input from the joysticks and the real time clock. These chips each provide a pair of independent 16-bit timers. H you understand how these four devices work, you can make the computer do anything it is capable of. Your program will be primarily concerned with the VIC-II chip and the SID chip. The CPU is the chip that the program is written for, and it is directed to modify the registers in the other chips at the appropriate time for the intended function. Writing almost any type of program eventually comes down to controlling just a few chips. Once you control the major chips the rest of the program should be easy.
6510 ARCHITECTURE In order to program in assembly language, you must understand the internal functions of the microprocessor.
The value of the program counter is output on the address lines of the microprocessor whenever a data access is to be performed on the systems memory. In the Commodore 64, all of the hardware registers appear to be memory locations to the microprocessor, so accesses to hardware registers and memory appear identical. The accumulator is the most important register in the computer. Almost all of the data that passes through the system goes through the accumulator. Every arithmetic function, other than incrementing and decrementing, is performed in the accumulator. Data can be read into the accumulator from memory, modified, and stored back into memory. The X and Y registers are very similar. They move data in a manner similar to the accumulator. They can also be used as an index to an array of data. It should be noted that while these two registers are similar, their functions are not identical. Some instructions require the use of the X register while others use the Y register.
INSTRUCTION TYPES There are 4 classes of instructions in the 6510. These are:
• Data movement
• Arithmetic
• Testing
• Flow of control
Data movement instructions are instructions that cause a value to be loaded from memory, stored into memory, or transferred from one register to another. There are a number of options as to how the address of the byte to be loaded will be determined. In the load accumulator instruction, LOA, there are eight different addressing modes that can be used to determine which byte to load. The different addressing modes are explained in the following section. Arithmetic instructions are used to modify data in some way. This class of instruction includes logical operations, such as the ANO and ORA instructions. There are instructions that allow a byte to be rotated as well as addition and subtraction commands. As with the data movement instructions, most of the available addressing modes can be used by the arithmetic instructions.
testing instructions allow a nondestructive test of data in the microprocessor. For instance, when a CMP instruction is used to check a value in the ACCUMULATOR, the data in the ACCUMULATOR will not be changed in any way. The bits in the STATUS register will be changed in the same way as if the data to be compared was subtracted from the ACCUMULATOR.
These instructions are generally used to modify the STATUS register prior to executing a branch instruction. Flow of control instructions are the branching and jump instructions. These are used to change the order in which different sections of code are executed. The branch instructions are all conditional branching instructions. That is, each instruction checks one of the bits in the status register and, depending on its value, will either branch to the instruction pointed to in the operand or execute the next instruction in line. Jump and jump to subroutine instructions also fall into the flow of control category. These are known as absolute commands because they do not check any conditions before performing a jump.
Significance of the Study
Symbolic instruction node and despite its ease of mastery, it is quite capable of performing most home computing tasks. BASIC is high level programming languages like FORTRAN, Pascal, and COBOL, These languages are often called problem oriented languages because they are intended to be used for solving problems in various fields such as mathematics, science or business. The counterpart of problem-oriented languages are the machine-oriented languages such as FORTH, and require more detailed knowledge of the computer hardware. Machine language is the extreme member of this category of languages. By itself, the Commodore 64 cannot understand BASIC at all. How can it execute the BASIC commands that you type in at the keyboard if it doesn’t speak BASIC? The Commodore 64 contains an “operating system” which includes BASIC interpreter. This interpreter converses with you in BASIC. The Commodore 64 converts the BASIC commands and statements into series of executable machine language instructions. You don’t even see this happening. It takes place “automatically”. Let’s take look at simple example of how the BASIC interpreter works:
If the interpreter finds the keyword in the command table, it knows what part of the operating system is to carry out that BASIC command. In our example, the interpreter searches the command table for the word PRINT. It finds the keyword and notes that the memory location which performs the PRINT statement begins at location 43680. Therefore, the interpreter lets the “program” segment (usually called routine or machine-language routine) located at 43680 perform the PRINT command.
Arrays (subscripted variables) offer powerful extension to the concept of vari ables and are worth mastering for many serious applications. They provide single name for whole series of related strings or numbers, using one or more subscripts to distinguish the separate items or elements.
Effective Programming in BASIC One-dimensional arrays have single subscript, which may take any value from to the value used in the DIM statement that defined the array (or 10 if DIM wasn’t used). The line: DIM A$(50), N%(100), SX(12) defines three arrays: string, integer, and real number, respectively. Space is allocated in memory for them, except for the string arrays. Arrays can be visualized as set of consecutively numbered pigeon holes, each capable of storing one value, and initialized with contents 0. typical application is the lookup table. string array might hold values like this:
Purpose of the Study
Chapter 1: Co-array of BASIC
The DIM statement instructs the system to reserve storage space for an array by specifying a maximum subscript (dimension). COJIIIDent: The DIM statement is an executable statement. In fact, it has to be executed in order to be effective. Numeric or string variables may be dimensioned with one or two dimensions. The maximum value for each dimension is 32767, however, the restraints of memory size usually limit this to a much lower value. An array may not be re-dimensioned. When a variable is dimensioned a reference to the same variable name will refer to the array. This is only allowed with certain types of statements (i.e., MAT). In other statements the error “Inconsistent usage” will occur. Any reference to an array beyond the allocated size will cause a subscript error. Arrays are created with a zero element in each dimension, unless OPTION BASE 1 is in effect. For instance, if the array X were dimensioned X(5), there would be six elements in the array with subscripts of 0, 1, 2, 3, 4, and 5. =================================================================================== Examples: 0010 DIM X(20),Y(2,5),A$(5,5) Incorrect Examples: 0010 DIM X(2,2,2) 0020 DIM Y(99999) Explanation: Array X has 21 elements, array Y has 18 elements, string array A$ has 36 elements. Explanation: Can have only 2 dimensions. Maximum dimension is 32767. =====================================================================
The constants in the DIM statement must be integer (no decimal point) numbers.
The DIM statement is nonexecutable. When the BASIC program is executed (RUN), the information in the statement is used by the compiler to assign memory locations. The DIM statement need appear only before the dimensioned variables. A DIM statement is not always necessary. If a single letter is used as a subscripted variable name with no preceding DIM statement, BASIC will automatically set aside memory space for the name. If the letter is used as a table, BASIC automatically sets aside 11 locations (i.e., as if it has been dimensioned 10). The same name cannot be used as both a singly and a doubly subscripted array; however, the same name can be used as an array (table or matrix) and a simple variable.
1.1 . Arrays Arrays are indexed collections of numbers or strings. Array elements can be manipulated by scalar numeric and string operations (cf. Sections 5 and 6). In addition, entire arrays may be manipulated by matrix statements.
1.2 Array Declarations
1.1.2 General Description An option in the option-statement may be used to define the lower bound for all array subscripts within a program-unit that are not explicitly stated. By use of an option-statement the subscripts of all such arrays may be declared to have a lower bound of zero or one; if no such declaration occurs, the lower bound shall be one. Arrays may have one, two, or three dimensions. The number of dimensions and subscript bounds for each dimension are declared in the declare-statement or dimension-statement. All array-names, except those appearing in a function-parm-list or a procedure-parm-list, shall be declared in one and only one such statement. If not explicitly declared, the lower subscript bound for a given dimension is one or zero, depending on the BASE option. Upper bounds shall always be explicitly declared. A one-dimensional array with subscripts 1 to 10 or 1980 to 1989 or -9 to 0 contains 10 elements. A two-dimensional array with subscript bounds 1 to 10 for each dimension contains 100 elements. Similarly, a three-dimensional array with subscript- bounds 1 to 10 for each dimension contains 1000 elements. A declare-statement can be used to dimension numeric-arrays as well as to declare maximum lengths for string-variables and string-arrays, and to dimension string-arrays. A dimension- statement can be used to dimension arrays, but not to declare the maximum length of strings in string-arrays.
1.3 Syntax
1. dimension-statement
2. dimension-list
3. array-declaration
4. numeric-array-declaration – DIM dimension-list = array-declaration (comma array-declaration)* = numeric-array-declaration / string-array-declaration – numeric-array bounds 65 AMERICAN NATIONAL STANDARD X3.113-1987
5 . bounds
6. bounds-range
7. signed-integer — = =
8. string-array-declaration =
9. option
10. string-declaration
11. numeric-declaration
12 . numeric-function-ref
13. maxsize-argument
14. bound-argument > > > > — = The number of bounds-ranges or three. left-parenthesis bounds-range (comma bounds-range)* right-parenthesis signed-integer TO signed-integer / signed-integer sign? integer string-array bounds BASE ( 0 / 1 ) string-array-declaration length-max? numeric-array-declaration MAXSIZE maxsize-argument / SIZE bound-argument / LBOUND bound-argument / UBOUND bound-argument left-parenthesis actual-array right-parenthesis left-parenthesis actual-array (comma index)? right-parenthesis in a bounds shall be one, two. An array that is named as a formal-array of a defined- function, a subprogram, a program, or a picture-def shall not be declared in a declare-statement or dimension-statement (since the formal-array in the function- or procedure-parm-list serves as its declaration). Any other array shall be so declared in a lower numbered line than any reference to that array or one of its elements. Any reference to an array and its elements shall agree in dimensionality with the declaration of that array in a declare-statement, a dimension-statement, or as a function- or procedure-parameter. No numeric- or string-array shall be dimensioned or declared more than once in a program-unit. If the optional lower bound (the first signed-integer) is included in the bounds-range, it shall be less than or equal to the upper bound (the second signed-integer). If the lower bound is not specified, then the upper bound shall not be less than the default lower bound, which may be zero or one, depending on the BASE option. An option-statement with a BASE option, if present at all, shall occur in a lower-numbered line than any declare-statement or dimension-statement or any MAT statement that uses a numeric- 66 AMERICAN NATIONAL STANDARD X3.113-1987 array-value in the same program-unit. A program-unit shall contain at most one BASE option. If a bound-argument does not specify an index, the actual- array shall be declared as one-dimensional.
1.4 Examples 1. DIM A(6), B(10,10), B$(100), D(1 TO 5, 1980 TO 1989) DIM A$ (4,4), C(-5 TO 10) 10. A$(3 TO 21) * 8 12. SIZE(A,1) SIZE(B$,2) SIZE(X) LBOUND(A) UBOUND(C$,2) 7.1.4 Semantics Each array-declaration declares the named array named to be either one-, two-, or three-dimensional, according to whether one, two, or three bounds-ranges are specified in the bounds for the array. In addition, the bounds specify the maximum and optionally minimum values that subscripts for the array shall have. If a minimum subscript is not explicitly declared and no BASE option occurs within the program-unit, then it shall be implicitly declared to be one. The BASE option in an option-statement is local to the program-unit in which it occurs and declares the minimum value for all array subscripts in that program-unit that are not explicitly declared. If the execution of a program reaches a line containing a dimension-statement, then it shall proceed to the next line with no further effect. String-array-declarations appearing in a string-declaration may include a length-max, which sets the maximum length of each element of the string-array. As with simple-string-variables, if there is no length-max in the string-declaration, then the length-max, if any, of the string-type shall take effect. If there is no length-max in either, then the implementation-defined length-max, if any, shall take effect. The value of SIZE(A,N) in which A is an actual-array and N is an index shall be the current number of permissible values for the Nth subscript of the array named by A (the value of N is 67 AMERICAN NATIONAL STANDARD X3.113-1987 rounded to the nearest integer, and the subscripts of A are indexed from left to right, starting at one). The value of SIZE (A) shall be the current number o.f elements in the entire array A. The value of MAXSIZE(A) shall be the total number of elements of the entire array named by A permitted by the array- declaration . The value of LBOUND(A,N), where A is an actual-array and N is an index, shall be the current minimum value allowed for the Nth subscript of the array named by A. The value of UBOUND(A,N) shall be the current maximum value allowed for the Nth subscript of array A. As in the SIZE function, the value of N is rounded to the nearest integer, and the subscripts of array A are indexed from left to right, starting at one. The LBOUND and UBOUND functions may be called with a single argument, provided that argument is a vector, in which case the values of LBOUND and UBOUND are the current minimum and maximum values allowed for the subscript of the vectorthe word “vector” shall mean a “one-dimensional array” and the word “matrix” shall mean a “two-dimensional array”.
1.6 Exceptions The value of the index in a SIZE reference is less than one or greater than the number of dimensions in the array (4004, fatal). The value of the index in an LBOUND reference is less than one or greater than the number of dimensions in the array (4008, fata 1) . The value of the index in a UBOUND reference is less than one or greater than the number of dimensions in the array (4009, fatal). 7.1.6 Remarks The dimension statement is retained for compatibility with minimal BASIC. All its capabilities are included within the declare-statement. If an implementation supports more than three dimensions, SIZE, LBOUND, and UBOUND should work for those extra dimensions, and an exception should be generated only when an attempt is made to inquire about a dimension beyond those declared. 68 AMERICAN NATIONAL STANDARD X3.113-1987
1.7 Numeric Arrays
1.8 General Description Numeric-arrays in BASIC may be manipulated element-by- element. However, it is often more convenient to regard numeric arrays as entities rather than as indexed collections of entities, and to manipulate the entire entity at once. BASIC provides a number of standard operations to facilitate such manipulations.
1.9 Syntax
1. array-assignment
2. numeric-array-assignment
3. numeric-array-expression
4. numeric-array-operator
5. scalar-multiplier
6. numeric-array-value
7. redim
8. redim-bounds
9. numeric-array-function-ref
10. numeric-function-ref The number of redim-bounds three. > numeric-array-assignment = MAT numeric-array equals-sign numeric-array-expression = (numeric-array numeric-array-operator)? numeric-array / scalar-multiplier numeric-array / numeric-array-value / numeric-array-function-ref = sign / asterisk = primary asterisk > scalar-multiplier? (CON / IDN / ZER) redim? = left-parenthesis redim-bounds (comma redim-bounds)* right-parenthesis = (index TO)? index = (TRN / INV) left-parenthesis numeric-array right-parenthesis > DET (left-parenthesis numeric-array right-parenthesis) / DOT left-parenthesis numeric-array comma numeric-array right-parenthesis in a redim shall be one, two, or A numeric-array being assigned a value by a numeric-array- assignment shall have the same number of dimensions as the value of the numeric-array-expression.
The numeric-arrays in a numeric-function-ref involving DOT shall be one-dimensional. There shall be no more than two redim-bounds following IDN. The numeric-arrays in a sum or difference shall have the same number of dimensions. The numeric-array serving as the argument of DET, INV, or TRN shall be two-dimensional. The numeric-arrays serving as operands for the numeric- array-operator asterisk (matrix multiply) shall be either one¬ dimensional or two-dimensional, and at least one of them shall be two-dimensional.
Examples In the following examples A, B, and C are doubly-subscripted numeric-arrays, X, Y, and Z are singly-subscripted numeric- arrays, and W is a numeric-expression.
2. MAT A = B MAT A = B + C MAT A = B*C MAT A = W * B MAT A = ZER(4,3) MAT A = INV(B) 10. DET(B) 7.2.4 Semantics MAT X = Y MAT X = Y – Z MAT X = A*Y MAT X = w * co: MAT X = ZER MAT A = TRN(B) DOT(X,Y) MAT X = Y*A
Array Assignments and Redimensioning
♦ Execution of a numeric-array-assignment shall cause the numeric-array- expression to be evaluated and its value assigned to the array named to the left of the equals-sign. If necessary, this array shall have its size changed dynamically (i.e., its number of dimensions shall be unchanged, but its size in each dimension shall be changed to conform to the size of the array given by the value of the numeric-array-expression). When the size of a numeric-array is changed dynamically, the current upper bounds for its subscripts shall be changed to conform to the new sizes. That is, new_lower_bound = old_lower_bound new_upper_bound = old_lower_bound + new_size – 1
The new sizes need not individually be less than or equal to the sizes determined in the array-declaration for that numeric-array, as long as the new total number of elements for the numeric-array 70 AMERICAN NATIONAL STANDARD X3.113-1987 does not exceed the total number of elements determined by the array-declaration for that array.
Array expressions. The evaluation of numeric- array-expressions shall follow the normal rules of matrix algebra. The symbols asterisk plus and minus represent the operations of multiplication, addition, and subtraction, respectively. shall The dimensions of numeric-arrays in numeric-array- expressions shall conform to the rules of matrix algebra. The numeric-arrays in a sum or difference shall have the same sizes in each dimension. The numeric-arrays in a product shall have sizes L x M and M x N for some L, M, and N (in which case the product shall have size L x N), or an M element vector and a size M x N matrix (in which case the product shall be an N element vector), or a size L x M matrix and an M element vector (in which case the product shall be an L element vector). All elements in a numeric-array shall be used when evaluating a numeric-array- expression; i.e., each numeric-array shall be treated as an entity. When a scalar-multiplier is present in a numeric-array- expression, the primary shall be evaluated, and then each element of the numeric-array shall be multiplied by this value. If an underflow occurs in the evaluation of a numeric-array- expression, then the value generated by the operation that resulted in the underflow shall be replaced by zero.
Array values. Numeric-array-values shall be assigned to the numeric-array on the left of the equals sign. If no redim is present, the size of the numeric-array generated shall be the same as the size of the numeric-array to which it is to be assigned. If a redim is present, a numeric-array of the dimensions specified shall be generated, and the numeric-array to which it is assigned shall be redimensioned as described in
In a redim-bounds, the values of the indices are the lower and upper bounds of the corresponding dimension in the associated array-value. If the redim-bounds consists of a single index, its value shall be the upper bound, and the lower bound shall be the current default lower bound in effect. If a redim is used with the IDN constant, then it shall produce a square matrix; i.e., the number of rows shall equal the number of columns. If a redim is not used with the IDN constant, the numeric-array being assigned to shall be square.
The ZER constant shall generate a numeric-array, all of whose elements are zero. The CON constant shall generate a numeric-array, all of whose elements are one. The IDN constant shall generate an identity matrix, i.e., a square matrix with ones on the main diagonal and zeroes elsewhere. If only one redim-bounds is used with IDN, then the effect is just as if that redim-bounds had been specified twice. If a scalar-multiplier is used with an IDN, ZER, or CON constant, then the primary (see 5.3) is evaluated and each nonzero element of the IDN, ZER, or CON constant is replaced by the value of the primary. 7.2.4.4 Array functions. The function TRN shall produce the transpose of its argument. An N x M matrix is returned for an M x N argument. The function INV shall produce the inverse of its argument. The argument shall be a square matrix. The function DET shall return the determinant of its argument. The argument shall be a square matrix. The value of DOT(X,Y) shall result in a scalar value, which is the result of the inner product multiplication of the one¬ dimensional numeric-vectors X and Y.
1.8 Exceptions The sizes of numeric-arrays in a numeric-array-expression do not conform to the rules of matrix algebra (6001, fatal). The total number of elements required for a redimensioned array exceeds the number of elements reserved by the array’s original dimensions (5001, fatal). The first index in a redim-bounds is greater than the second (6005, fatal). A redim-bounds consists of a single index that is less than the default lower bound in effect (6005, fatal). The redim following IDN does not specify a square matrix, or no redim is present and the receiving matrix is not square (6004, fatal). The argument of the DET function is not a square numeric matrix (6002, fatal)
The argument of the INV function is not a square numeric matrix (6003, fatal). Evaluation of a numeric-array-expression results in an overflow (1005, fatal). Evaluation of DET or DOT results in an overflow (1009, fatal). Application of INV to a singular matrix, or loss of all significant digits (3009, fatal).
Chapter 2: BASIC Files
2.1 Files
Files are organized collections of data external to BASIC programs. They provide the user with a means of saving data developed during execution of a program and then retrieving and modifying that data during subsequent executions of BASIC programs. The process by which external data is transferred to or from a program is called input or output, respectively. An implementation-defined means shall be provided for the creation, preservation, and retrieval of files. Input and output operations to these files shall perform as specified in this section. This section describes the logical appearance of files and devices to a BASIC program. In some cases, these attributes may reflect physical characteristics, but in general this standard makes no presumptions concerning the physical representation or organization of files or devices. There are four kinds of file-organization: sequential, stream, relative, and keyed. Sequential and keyed files are sequences of records. A relative file is a sequence of record areas, each of which may or may not contain a record. A stream file is a sequence of values. There are three kinds of record-type: display, internal, and native. A display record is a sequence of characters. An internal record is a sequence of typed values. A native record is a sequence of fields, as described by a program-specified template. Display records provide for the exchange of data between systems employing different internal representations for numeric and string values, and also manipulate data in human readable form. Internal records provide for efficient manipulation of data within a single system. Native records provide for the exchange of data among different language processors within a single system. There are three modules provided for file capabilities, based on which combinations of file-organization and record-type are supported. The core module contains sequential display files, sequential internal files, and stream internal files. The enhanced internal module contains relative internal and keyed internal files. The enhanced native module contains sequential native, relative native, and keyed native files. All other combinations of file-organization and record-type are implementation-defined. The distinction between modules is also reflected in the arrangement of the productions for the syntax. Within each subsection, the syntax rules for the core module are
presented first, followed by the additional syntax productions that pertain to the enhanced files modules. Some of the enhanced productions apply only to the enhanced-native module? these are preceded by an “N”. The meaning of certain terms used throughout this section is as follows. A “file element” is an entity, a sequence of which constitutes a file. Thus, for keyed and sequential files, a file element is a record; for relative files, it is a record-area? for stream files, it is a value. Associated with each file during execution is a “file pointer,” which either uniquely identifies a particular file element upon completion of any statement or points to the end of file. If the pointer is at the beginning of the file, then it identifies the first file element, if any. If a file is an empty sequence, then the beginning and end of file are the same, and the pointer identifies this location. Whenever reference is made to the “next” file element, it is understood that if none such exists, the end of file is substituted. For sequential, stream, and keyed files, the “end of file” is the location immediately following the last file element. For relative files, the “end of file” immediately follows the last existing record, and thus identifies an empty record-area. There are five statements that operate on the file as a whole and are thus called “file operations”: OPEN, CLOSE, ERASE, SET, and ASK. There are seven statements that apply to individual file elements and are known as “record operations”: INPUT, PRINT, READ, WRITE, REWRITE, DELETE, and SET with pointer control, including the variations using MAT and LINE. References to “INPUT operations,” “WRITE operations,” and so forth should be understood to include any of the statements using the keyword in question, e.g., “WRITE operations” includes WRITE and MAT WRITE.
The seven record operations can affect (1) data within a file, (2) variables within the program, and (3) the file pointer. PRINT, WRITE, REWRITE, and DELETE affect file data and the pointer. READ and INPUT affect program variables and the pointer. SET with pointer-items obviously affects only the pointer. Not all input and output is to or from a file, as defined above. An implementation may allow file processing statements to apply as well to devices, such as a terminal, a line printer, or a communications line. When the term “file” is used throughout Section 11, it should generally be understood to mean any source or destination of external data (i.e., either a true file or a device). In certain contexts in which it is necessary to distinguish between
from a BASIC program. Within a program-unit, a channel is identified by a channel number local to that program-unit. The channel number is an integer from 0 up to and including some implementation-defined maximum. This maximum shall be at least 99. A file, identified by its file-name, is open if it is currently assigned to a channel and closed otherwise. A channel is active if it currently has some file assigned to it and inactive otherwise. At the initiation of execution of a program, all channels except channel zero shall be inactive. Channel zero shall always be active. Execution of the open-, close-, or erase-statement (see below) for channel zero shall cause a nonfatal exception. Input and output from and to channel zero shall have the same source and destination as input-statements and printstatements that do not contain channel-expressions. Channel zero shall behave as a device with the file-attributes sequential, display, and outin, and without record-setter or erase capability.
2.1 Open-Statement.
The open-statement makes the file identified by the file-name accessible to the program through the channel number specified in the channel-expression. It is implementation-defined whether file names differing only in the case of the letters (upper or lower) denote the same file or different files. Following a successful open-statement, the associated channel shall be active and the file open. An attempt to open a file on a channel that is already active causes an exception. The effect of attempting to open a file that is already open is implementation-defined. The number of channels other than channel zero that may be active simultaneously shall be at least one for implementations conforming to the core, and at least two for implementations conforming to the enhanced file module. After a successful open, a true file shall be accessible in accordance with the associated file-attributes, whether explicitly specified or in effect by default. This accessibility consists of the ability to perform certain operations and manipulate the file pointer in certain ways.
effect as for a true file. In particular, on output, the same data will be generated, and on input, values and characters will be interpreted and assigned to variables in the same way. The ask-statement may be used to determine whether a particular device supports these capabilities. If a file is opened successfully with a given file organization, record-type, and record-size, then closed, and then opened at a later time with a different value for one of these file-attributes, then it is implementation-defined whether the file is thus accessible. Also, for files with record-type INTERNAL or NATIVE, if a different ARITHMETIC option is in effect for the two executions, it is implementation-defined whether the file is thus accessible. Conversely, if a true file is re-opened at a later time with the same values for the file-attributes mentioned and the same collate-sequence, and, for files with record-type INTERNAL and NATIVE, the same ARITHMETIC option is in effect, and the user has employed the implementation-defined means to preserve the file unchanged in the interim, then the file shall be accessible and the contents of the file faithfully preserved. Devices are not required to preserve data. In the foregoing, “same ARITHMETIC option” refers to DECIMAL or NATIVE or FIXED (cf. 15.1), not to the default specification in the FIXED option. If a KEYED file is reopened with a different collate-sequence, an exception results. If a file with record-type INTERNAL or NATIVE opened in one program-unit is accessed by another program-unit with a different ARITHMETIC option, the results are implementation-defined. Implementations must provide true files for which all access-modes are available. Implementations may also support true files for which some access-modes are not available. A device need not support all access-modes. Implementations conforming only to the core module shall accept and process three combinations of file-organization-value and record-type-value, namely, sequential and display, sequential and internal, and stream and internal. The effect of any other combination is implementation-defined. Implementations conforming to the enhanced-internal module shall accept and process, in addition to those of the core module, relative and internal, and keyed and internal.
Chapter 3.
The Commodore 64 microcomputer consists of a 6510 microprocessor, ROM, R/W memory, and various I/O devices. These are interconnected by the address bus, the databus, and the control bus. Each of the65,536 memory 22 1 D The Commodore 64 Microcomputer System locations is identified by its address. Each memory location stores eight bits of information, called an eight-bit code, an eight-bit number, or a byte. Memory is used to store both data and machine-language programs. The microprocessor can read a code stored in memory, operate on it, or store (write) a code in memory under the direction of a machine-language program. A program is an ordered set of instructions stored sequentially in memory. Instructions consist of eight-bit codes that the microprocessor reads, interprets, and executes. In order to be understood by human beings, the instruc tions are described by a mnemonic and an English language description. The instruction set of the 6510 consists of 56 different instructions. Six registers inside the 6510 are involved in the execution of these instructions. These registers are the accumulator, X register, Y register, program counter, processor status register, and the stack pointer.
INSTRUCTION TYPES
There are 4 classes of instructions in the 6510. These are:
Data movement
Arithmetic
Thsting
Flow of control
13 Data movement instructions are instructions that cause a value to be loaded from memory, stored into memory, or transferred from one register to another. There are a number of options as to how the address of the byte to be loaded will be determined. In the load accumulator instruction, LOA, there are eight different addressing modes that can be used to determine which byte to load. The different addressing modes are explained in the following section. Arithmetic instructions are used to modify data in some way. This class of instruction includes logical operations, such as the ANO and ORA instructions. There are instructions that allow a byte to be rotated as well as addition and subtraction commands. As with the data movement instructions, most of the available addressing modes can be used by the arithmetic instructions.
7 testing instructions allow a nondestructive test of data in the microprocessor. For instance, when a CMP instruction is used to check a value in the ACCUMULATOR, the data in the ACCUMULATOR will not be changed in any way. The bits in the STATUS register will be changed in the same way as if the data to be compared was subtracted from the ACCUMULATOR.
These instructions are generally used to modify the STATUS register prior to executing a branch instruction. Flow of control instructions are the branching and jump instructions. These are used to change the order in which different sections of code are executed. The branch instructions are all conditional branching instructions. That is, each instruction checks one of the bits in the status register and, depending on its value, will either branch to the instruction pointed to in the operand or execute the next instruction in line. Jump and jump to subroutine instructions also fall into the flow of control category. These are known as absolute commands because they do not check any conditions before performing a jump
Sprites, Bitmaps and Vectors
In the beginning there were essentially two different ways of making computer graphics. Sprites/Bitmaps and Vectors.
Vector graphics represented images as a series of mathematical equations, allowing for smooth lines and curves. The most notable example of vector graphics during this time was Atari’s arcade game “Asteroids,” which featured wireframe graphics. The game was widely cloned and arrived on all the 8 bit home computer systems in one form or another during the early 80s.
https://www.cadasio.com/post/8-bit-sprites-to-webgl-how-computer-graphics-have-changed-the-world
The Commodore 64 has the ability to generate sprite graphics over a character background. When this data area is created and a sprite is moving over the background, that data will not be erased. This is because the sprites are located in a different area of memory that do not conflict with the screen data. This independence gives it a great advantage when creating games. Any data or graphics remains in its own independent space.
A sprite is drawn as 24 x 21 (503 bits) or 63 bytes of memory. So a sprite can be 24 bits wide, and 21 bits high. This area is also known as an MOB (Moveable Object Block). Up to 8 sprites can be displayed, animated, and moved on the screen. However, using a technique known as sprite multiplexing, even more sprites can be occupied with raster line timing. Basic is too slow to move sprites effectively, so assembly language is the best bet when trying to create smooth movement.
The bytes are separated into individual bits for each row (ranging from 0-7), with the 0 bit being on the right. The values for each section (in an 7 bit layer) is displayed as 128,64,32,16,8,4,2, and 1. The total sum of these values in 255 which would draw a complete line across the width of the sprite.
Multicolor Sprites
Sprites can be in one color or in multiple colors, when a special mode known as multicolor is activated using memory locations ($D025 – $D02E), which is listed as 53287-53294 in Basic decimal mode. These multicolors are displayed when the sprites are grouped in pairs. As a result this expands a pixel to twice the width of a high resolution pixel. When lining up these bits during the design phase, a sprite can contain up to 4 colors (0-4). The bit pair of 00 will be transparent. The bit pair of 01 will be linked to the color in $D025 (53285). The bit pair of 11 will be linked to address $D026 (53286). Finally the bit pair of 10 will take on the color of a sprite in memory locations $D025-$D02E (53287-53294).
It is quite tedious to create a sprite on graph paper, but it can be accomplished. Essentially you will divide each area into 3 rows that occupy 8 bytes each and the height will designed the same way. Most people prefer using a Sprite Editor to accomplish this. Windows has made room for a popular editor known as SpritePad. By using this tool, you can quickly create a whole slew of sprites, add their multicolors, and even animate them.
Sprite Positions
Commodore 64 Sprites are positioned horizontally and vertically using the registers $D000-$D00F (53248-53263). So for example Sprite 0 could be positioned on the screen in a position ranging from left to right by using memory location $D000. However, there is a limit to the horizontal position up to byte 255. The vertical position of Sprite 0 can be placed using memory location $D001.
As mentioned earlier, sprites have a limited (due to their width range) area that can be placed on the screen and require another memory location to reset the horizontal position of a sprite’s high byte. The memory location that handles this is $D010 (53264). By passing in a bit from 0-7 here you can set that sprite’s appropriate horizontal most significant bit at that position.
Each of the Commodore 64 Sprites require the ability to have it turned on or off. The memory location that handles this is $D015. This is accomplished by setting a bit from 0-7 for the appropriate sprite once again. A zero contained here turns that sprite off and a 1 activates it so it displays on the screen.
A sprite can be expanded to double it’s height with memory location $D017 (53271). The expansion is controlled by setting a bit with a 0 or 1. As identical to the sprite enable function, setting a zero here turns off the expansion, and placing a 1 here will activate the sprite vertical expansion. Often in games, this could be used to create a boss character since they tend to be larger.
The Foreground Display Priority Register at memory location $D01B (53275) controls when a sprite will exist in front of a foreground or behind it. This is done again, by setting it to bit 0 or 1. If a game contains a multicolor graphics mode, the sprite will be shown behind other sprite graphics even though the priority is set here for the foreground graphics, due to the 01 bit pair being set.
Sprite Bit Pairs
A sprite can contain multiple colors within it’s bit pairs using memory location $D01C (53276). To activate this, set bit 1 here, and turn it off by replacing with bit 0. When it is turned on, the sprite shape data is gathered into pairs. Each pair controls a double wide pixel of the sprite display. Since the sprite has had the horizontal resolution reduced, it is now only 12 dots wide. This now allows the ability for using two new colors. According to Mapping the Commodore 64 the four possible combinations affecting these bit pairs get their color from the data below.
00 Background Color Register 0 (transparent)
01 Sprite Multicolor Register 0 (53285, $D025)
10 Sprite Color Registers (53287, $D027-E)
11 Sprite Multicolor Register 1 (53286, $D026)
Each sprite also contains the ability to have three foreground colors, which that color being unique to that sprite.
Sprite to Sprite Collision
The collision of a sprite is stored in registers ($D01E-$D01F) or 53278-53279 memory registers. There is some conflict when using this register however. Although a sprite can confirm with sprites overlapped each other (bit 1 is set), it is unable to accurately determine a collision when Commodore 64 Sprites are stacked up in a row. When that occurs, this register would still trigger a collision even if they are not touching each other. A collision is tracked when a bit (dot) of a sprite’s data moves over another dot that does not contain zero data in that area. Sprites that utilize this memory area, can also detect a collision even when it climbs behind the border or off the screen. Likewise setting a zero here will usually clear the collision, if multiple sprites are not conflicting with each other.
Sprite Foreground Collision
Just like it’s counterpart, memory location $D01F (53279) has the ability to see when Commodore 64 Sprites have collided with the foreground. By checking to see if a bit 0 or 1 is contained here, it can act on that information. Yet there are still conflicts that can occur so use it wisely, ensuring that sprite bits are not crossing over each other.
A sprite’s multicolor is set within memory locations $D025- $D026 as discussed earlier. It is necessary for the system to find a zero or 1 here so that sprite’s data can be set accordingly. The default color set for $D025 on power up is purple, and $D026 will contain the color black.
A standard Commodore 64 Sprites color is set and turned off using locations $D027-$D02E (53287-53294) in memory. Each corresponding sprite once again contains a default color when the computer is first turned on, but they can be changed here.
Sprite Shape Data and Animation
Memory locations $07F8-$07FF (2040-2047) contain an area that reserves sprite data. This is useful for animation. The data is contained here for each pointer to match the appropriate shape in memory. Each of the Commodore 64 Sprites, ranging from 0-7 occupy it’s own data containment in these memory addresses. The pointer value is multiplied by 64, which is equal to the starting location of that sprite’s data table. A simple calculation as found in Mapping the Commodore 64 is using Sprite 0 at memory address 704 (11*64=704) to point to the appropriate area of memory. This then leaves room for 63 bytes up to memory address 767. By cycling through data contained in these registers, simple animation is quite possible with your sprites.
SPRITES
A sprite is a small moveable object block that can move independently of the background graphics. The VIC chip can display eight sprites on the screen at anyone time. Sprites can be displayed on anyone of the display modes, and they will look the same in all of them. You can have up to 256 different sprites defined at anyone time, but only eight can be displayed at the same time. The sprite to be displayed can be changed by changing a one byte pointer, so animation can be easily performed by quickly switching through a few different sprite patterns. Sprites can be moved very smoothly by simply giving the VIC chip the X and Y coordinates of the upper left comer of the sprite. Sprites have different display priorities. That means that the sprite with a higher priority will ap pear to move in front of a sprite with a lower priori ty. This can be used to give the illusion of three dimensional movement. The priority of a sprite to the background graphics is individually selected for each sprite. If the background is given priority, the sprite will appear to move behind the background graphics.
For instance, if a tree was being displayed in the bit mapped graphics mode, and a sprite in the shape of a dog was to move past the tree, the dog would appear to be moving behind the tree. Each sprite is a block 24 pixels horizontally by 21 pixels vertically. The pixels that are set to one use 1 of the 16 available colors.
The pixels that are set to zero allow the background color to show through (are transparent). Like the other graphics modes, a sprite can be selected to be in the multicolor mode, giving it a resolution of 12 by 21 in three colors plus transparent. Wherever a sprite is transparent, whatever is behind the sprite will show through. For those times when a larger sprite is necessary, the VIC chip has the option of doubling the horizontal size, the vertical size, or both. You will not increase the detail available in your sprite by using one of the multiply options, only the size.
When a sprite is expanded, each of the pixels is twice the size of the pixels in a normal sprite. Sprite Pointers Once a sprite has been defined, the VIC chip needs to be told where to find the pattern. The sprite definition must be in the currently selected bank of memory for it to be displayed. Since each sprite definition takes up 64 bytes, a sprite definition will always start on a $0040 boundary in memory. A 16K bank of memory can hold 256 sprite definitions, so it will only require one byte to tell the VIC chip which sprite to display. The sprite pointer is a number which, when multiplied by 64, will give the starting address of the sprite definition.
Sprite definitions may not be placed in a section of memory where the VIC chip sees an image of the character generator ROM. The VIC chip will read the eight sprite pointers from the last eight bytes of the lK of text memory, 30 an offset of $03F8 from the text base address. Since only 1000 out of 1024 bytes of text memory are used to display characters on the screen, the sprite pointers will not interfere with screen graphics. For example, since the default setting of the text memory is at $0400, the first sprite pointer will be $07F8. Sprite Controls For most of the sprite control registers, each bit in the register corresponds to one of the sprites. For example, bit 0 represents sprite 0, bit 1 represents sprite 1, and so on. The rest of the sprite controls require a value (such as a vertical location), so there is one register for each sprite. Enabling a sprite. Before a sprite can be seen, it must be enabled.
The register SPREN ($DOI5), has an enable bit for each sprite. If the bit is set, the sprite will be enabled. The sprite will only be seen if the X and Y positions are set to the visi ble portion of the screen. A sprite can be disabled by clearing the appropriate bit. Setting the sprite color. There are eight registers that are used to hold color information, one for each sprite. Any of the 16 available colors may be selected for each sprite. Each bit that is set in the sprite definition will cause a pixel to be displayed in the sprite color. If the bit is clear, the pixel will be transparent. The sprite color registers are: Name SPRCLO SPRCLl SPRCL2 SPRCL3 SPRCL4 SPRCL5 SPRCL6 SPRCL7 Address $D027 $D028 $D029 $D02A $D02B $D02C $D02D $D02E Setting the multicolor mode.
The multicolor mode can be individually selected for each ($DOlC)/sprite by setting the appropriate bit in the MLTSP ($DOlC) register. Setting a bit will enable the multicolor mode, clearing the bit will disable the multicolor mode. When the multicolor mode is enabled, the horizontal resolution drops from 24 pixels across to 12 pixels. Each pair of bits in the sprite definition is treated as a bit pair, whose value determines which of the four colors will be selected for the pixel
Pair Description 00 01 10 11 TRANSPARENT, SCREEN COLOR SPRITE MULTICOLOR REGISTER #0 ($0025) SPRITE COLOR REGISTER SPRITE MULTICOLOR REGISTER #1 ($0026) Using the sprite multipliers. Each of the sprites can be expanded in either the X or Y direc tion. When a sprite is expanded, each pixel is displayed as twice the normal size in the direction of the expansion. The resolution of the sprite does not increase, only the size. To expand a sprite in the X direction, the ap propriate bit must be set in the SPRXSZ ($DOID) register. To return the sprite to its normal size, clear and bit. The expansion of a sprite in the Y direction is done in the same way as the X expansion. You must set the appropriate bit in the SPRYSZ ($DOI7) register to expand the sprite. The sprite can be returned to its normal size by clearing its bit in the . SPRYSZ register.
The sprite can also be expanded in both the X and Y directions by setting its bit in both registers. Positioning sprites. Each sprite can be posi tioned independently anywhere on the visible screen and off the visible screen in any direction. Since the screen is 320 pixels wide, it takes more than one byte to specify a horizontal position.
Each sprite has its own X position register and Y position register, and a bit in an extra most significant bit register.
The location specified by the registers is the position where the upper left comer of the sprite will appear.
For an unexpanded sprite to be completely visible, the Y value must be between $32 and $E9. Any other values will place the sprite partially off the screen. Whatever value is placed in the X position register is the least significant 8 bits of a 9 bit value. Each sprite has a ninth bit in the XMSB ($DOlO) register. An unexpanded sprite will be completely visible if the 9 bit X value is greater than $18 and less than $140. The HINC and HDEC macros can be used to perform 9 bit increments and decrements of the X position. Table 7-6 shows the screen coordinates for expanded and unexpanded sprites to be fully visible on the screen. Any sprite positions outside of these limits will be partially or fully off of the screen. This provides an easy way to reveal a sprite gradually. Assigning sprite priorities.
As mentioned before, each sprite has a display priority with respect to the other sprites and to the background. You can create a three dimensional effect by allow ing different sprites to pass in front of each other. The priority of one sprite to another is predeter mined by the VIC chip. Sprite 0 has the highest priority, meaning that it will appear to be in front of all other sprites. Sprite 7 has the lowest priority of all the sprites. Each sprite can be individually selected to either have a higher priority than the background or a lower priority. If the sprite’s bit in the BPRIOR ($D01B) register is clear, the sprite will appear to pass in front of the background. When the bit for the sprite is set in the BPRIOR register, the sprite will appear to move behind the background image and in front of the background color. Because sprites can have transparent as one of their colors, any sprite that passes behind a higher priority sprite with transparent in it will show through in the transparent areas.
Overview of System Memory Map
The System Memory Map plays a vital role in the operation of the computer. It is essentially a blueprint of the computer’s memory, showing the locations of the different memory regions and how they are used. By understanding the memory map, programmers and users can effectively use and manipulate the computer’s resources.
Compared to other Commodore computers, the C65’s memory map is unique. It features a larger address space of 24 bits, allowing for a maximum of 16MB of memory. This was a significant improvement over the 64KB limit of the popular Commodore 64. The C65’s memory map also includes a number of new memory regions, such as the SuperCPU and the burst mode, which were not present in earlier models.
The memory map is organized into different regions, each with a specific function. The first region, known as the Zero Page, contains important system variables and routines used by the computer’s operating system. The next region, the Stack, is used to store temporary data and addresses. The code area contains the main program code, and the data area is used to store program data.
The memory map also includes other regions, such as the I/O area, which is used to communicate with peripheral devices, and the ROM area, which contains read-only memory. By understanding the different regions and their functions, programmers and users can make better use of the computer’s resources and optimize their programs for maximum efficiency.
The System Memory Map is a crucial component of the Commodore C65. Its unique features and organization make it an important tool for programming and using the computer effectively. By gaining a deeper understanding of the memory map, users can unlock the full potential of the C65 and take their computing experience to new heights.
The C65 features a 128-kilobyte ROM that is organized into four regions: the system ROM, the BASIC ROM, the Kernal ROM, and the character ROM. The system ROM contains the C65’s boot code and the code that initializes its hardware, while the BASIC ROM contains the version of Commodore BASIC that was modified for the C65.
The Kernal ROM, on the other hand, contains the low-level routines that interact with the C65’s hardware, such as those used for reading and writing to disk drives and serial devices. The character ROM is responsible for storing the graphics and characters that the C65 can display.
The C65 features a 128-kilobyte ROM that is organized into four regions: the system ROM, the BASIC ROM, the Kernal ROM, and the character ROM. The system ROM contains the C65’s boot code and the code that initializes its hardware, while the BASIC ROM contains the version of Commodore BASIC that was modified for the C65.
The Kernal ROM, on the other hand, contains the low-level routines that interact with the C65’s hardware, such as those used for reading and writing to disk drives and serial devices. The character ROM is responsible for storing the graphics and characters that the C65 can display.
The system ROM is located at memory addresses $E00000-$E3FFFF, while the BASIC ROM is located at addresses $C00000-$C1FFFF. The Kernal ROM is located at addresses $E80000-$EBFFFF, and the character ROM is located at addresses $D00000-$D0FFFF.
When the C65 boots up, the system ROM is the first ROM region that is accessed. The boot code initializes the C65’s hardware and then loads the C65’s version of BASIC from the BASIC ROM into memory. The C65’s Kernal ROM is then used to interact with the hardware and perform low-level operations.
Understanding the organization and functions of each ROM region is essential for programming and effectively using the C65. By having a solid understanding of the C65’s ROM memory map, programmers can take full advantage of the capabilities of this unique and powerful computer.
https://philreichert.org/commodore-c65/system-memory-map.html
Memory-mapped I/O and interfacing To summarize what we have just explain, an input/output port (I/O port) is allocation in the memory map of the computer that can be used to transfer information either from an external device to the computer from the computer to an external device. The type of input/output operations that use sports in the memory map of the computer system is called memory mapped I/O. These ports maybe accessed with any of the instructions in the 6510instruction set that involve a read or write operation. The type of I/O in which from one to eight bits of information are transmitted simultaneously is called parallel I/O. If only one bit can be output at a time, then the I/O operations are described as serial I/O.
https://nvlpubs.nist.gov/nistpubs/Legacy/FIPS/fipspub68-2-Jan1987.pdf
References:
https://nvlpubs.nist.gov/nistpubs/Legacy/FIPS/fipspub68-2-Jan1987.pdf
https://philreichert.org/commodore-c65/system-memory-map.html
https://www.cadasio.com/post/8-bit-sprites-to-webgl-how-computer-graphics-have-changed-the-world
COMMODORE 64 ASSEMBLY LANGUAGE ARCADE GAME PROGRAMMING
STEVE BRESS
Copyright © 1985 by TAB BOOKS Inc.
Assembly Language Programming with the Commodore 64
Marvin L. De Jong The Scholte Ozarks Pt. Lookout, MO Brady Communications Company, Inc. A Prentice-Hall Publishing Company