mirror of
https://github.com/badvision/lawless-legends.git
synced 2025-01-13 03:30:28 +00:00
Merge branch 'master' of https://github.com/badvision/lawless-legends
This commit is contained in:
commit
13eb9afbe7
@ -49,10 +49,10 @@ for the **make** program to build all the dependencies and run the module.
|
||||
All identifiers and reserved words are case insensitive. Case is only significant inside character constants and strings. Imported and exported symbols are always promoted to upper case when resolved. Because some Apple IIs only work easily with uppercase, the eases the chance of mismatched symbol names.
|
||||
|
||||
### Comments
|
||||
Comments are allowed throughout a PLASMA source file. The format follows that of an assembler: they begin with a `;` and comment out the rest of the line:
|
||||
Comments are allowed throughout a PLASMA source file. The format follows that of C like languages: they begin with a `//` and comment out the rest of the line:
|
||||
|
||||
```
|
||||
; This is a comment, the rest of this line is ignored
|
||||
// This is a comment, the rest of this line is ignored
|
||||
```
|
||||
|
||||
### Declarations
|
||||
@ -188,7 +188,7 @@ byte smallarray[4]
|
||||
byte initbarray[] = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
|
||||
byte string[64] = "Initialized string"
|
||||
word wlabel[]
|
||||
word = 1000, 2000, 3000, 4000 ; Anonymous array
|
||||
word = 1000, 2000, 3000, 4000 // Anonymous array
|
||||
word funclist = @myfunc, $0000
|
||||
```
|
||||
Arrays can be uninitialized and reserve a size, as in `smallarray` above. Initilized arrays without a size specifier in the definition will take up as much data as is present, as in `initbarray` above. Strings are special arrays that include a hidden length byte in the beginning (Pascal strings). When specified with a size, a minimum size is reserved for the string value. Labels can be defined as arrays without size or initializers; this can be useful when overlapping labels with other arrays or defining the actual array data as anonymous arrays in following lines as in `wlabel` and following lines. Addresses of other data (must be defined previously) or function definitions (pre-defined with predef), including imported references, can be initializers.
|
||||
@ -210,9 +210,9 @@ The override operator becomes more useful when multi-dimenstional arrays are use
|
||||
##### Multi-Dimensional Arrays
|
||||
Multi-dimensional arrays are implemented as arrays of arrays, not as a single block of memory. This allows constructs such as:
|
||||
```
|
||||
;
|
||||
; Hi-Res scanline addresses
|
||||
;
|
||||
//
|
||||
// Hi-Res scanline addresses
|
||||
//
|
||||
word hgrscan[] = $2000,$2400,$2800,$2C00,$3000,$3400,$3800,$3C00
|
||||
word = $2080,$2480,$2880,$2C80,$3080,$3480,$3880,$3C80
|
||||
```
|
||||
@ -245,13 +245,13 @@ Notice how xscan goes to 39 instead of 19 in the byte accessed version.
|
||||
#### Offsets (Structure Elements)
|
||||
Structures are another fundamental construct when accessing in-common data. Using fixed element offsets from a given address means you only have to pass one address around to access the entire record. Offsets are specified with a constant expression following the type override specifier.
|
||||
```
|
||||
predef puti ; print an integer
|
||||
predef puti // print an integer
|
||||
byte myrec[]
|
||||
word = 2
|
||||
byte = "PLASMA"
|
||||
|
||||
puti(myrec:0) ; ID = 2
|
||||
puti(myrec.2) ; Name length = 6 (Pascal string puts length byte first)
|
||||
puti(myrec:0) // ID = 2
|
||||
puti(myrec.2) // Name length = 6 (Pascal string puts length byte first)
|
||||
```
|
||||
This contrived example shows how one can access offsets from a variable as either `byte`s or `word`s regardless of how they were defined. This operator becomes more powerful when combined with pointers, defined next.
|
||||
|
||||
@ -275,9 +275,9 @@ const elem_id = 0
|
||||
const elem_addr = 1
|
||||
|
||||
def addentry(entry, id, addr)
|
||||
entry->elem_id = id ; set ID byte
|
||||
entry=>elem_addr = addr ; set address
|
||||
return entry + 3 ; return next enry address
|
||||
entry->elem_id = id // set ID byte
|
||||
entry=>elem_addr = addr // set address
|
||||
return entry + 3 // return next enry address
|
||||
end
|
||||
```
|
||||
The above is equivalent to:
|
||||
@ -286,16 +286,16 @@ const elem_id = 0
|
||||
const elem_addr = 1
|
||||
|
||||
def addentry(entry, id, addr)
|
||||
(entry).elem_id = id ; set ID byte
|
||||
(entry):elem_addr = addr ; set address
|
||||
return entry + 3 ; return next enry address
|
||||
(entry).elem_id = id // set ID byte
|
||||
(entry):elem_addr = addr // set address
|
||||
return entry + 3 // return next enry address
|
||||
end
|
||||
```
|
||||
|
||||
##### Addresses of Data/Code
|
||||
Along with dereferencing a pointer, there is the question of getting the address of a variable. The `@` operator prepended to a variable name or a function definition name, will return the address of the variable/definition. From the previous example, the call to `strlen` would look like:
|
||||
```
|
||||
puti(strlen(@mystring)) ; would print 17 in this example
|
||||
puti(strlen(@mystring)) // would print 17 in this example
|
||||
```
|
||||
|
||||
##### Function Pointers
|
||||
@ -311,16 +311,16 @@ def subvals(a, b)
|
||||
end
|
||||
|
||||
funcptr = @addvals
|
||||
puti(funcptr(5, 2)) ; Outputs 7
|
||||
puti(funcptr(5, 2)) // Outputs 7
|
||||
funcptr = @subvals
|
||||
puti(funcptr(5, 2)) ; Outputs 3
|
||||
puti(funcptr(5, 2)) // Outputs 3
|
||||
```
|
||||
These concepts can be combined with the structure offsets to create a function table that can be easily changed on the fly. Virtual functions in object oriented languages are implemented this way.
|
||||
```
|
||||
predef myinit, mynew, mydelete
|
||||
|
||||
export word myobject_class = @myinit, @mynew, @mydelete
|
||||
; Rest of class data/code follows...
|
||||
// Rest of class data/code follows...
|
||||
```
|
||||
And an external module can call into this library (class) like:
|
||||
```
|
||||
@ -390,7 +390,7 @@ Address operators can work on any value, i.e. anything can be an address. Parent
|
||||
| AND | logical AND
|
||||
|
||||
### Statements
|
||||
PLASMA definitions are a list of statements the carry out the algorithm. Statements are generally assignment or control flow in nature.
|
||||
PLASMA definitions are a list of statements the carry out the algorithm. Statements are generally assignment or control flow in nature. Multiple statements one a single line are seperated by a ';'. Note, this use the comment seperator in previous versions of PLASMA. It is generally considered bad form to have more than one statement per line unless they are very short.
|
||||
|
||||
#### Assignment
|
||||
Assignments evaluate an expression and save the result into memory. They can be very simple or quite complex. A simple example:
|
||||
@ -403,8 +403,8 @@ An assignment doesn't even have to save the expression into memory, although the
|
||||
```
|
||||
byte keypress
|
||||
|
||||
keypress = ^$C000 ; read keyboard
|
||||
^$C010 ; read keyboard strobe, throw away value
|
||||
keypress = ^$C000 // read keyboard
|
||||
^$C010 // read keyboard strobe, throw away value
|
||||
```
|
||||
|
||||
#### Control Flow
|
||||
@ -424,19 +424,19 @@ The complex test case is handled with `when`. Basically a `if`, `elsifF`, `else`
|
||||
```
|
||||
when key
|
||||
is 'A'
|
||||
; handle A character
|
||||
// handle A character
|
||||
break
|
||||
is 'B'
|
||||
; handle B character
|
||||
// handle B character
|
||||
break
|
||||
```
|
||||
...
|
||||
```
|
||||
is 'Z'
|
||||
; handle Z character
|
||||
// handle Z character
|
||||
break
|
||||
otherwise
|
||||
; Not a known key
|
||||
// Not a known key
|
||||
wend
|
||||
```
|
||||
With a little "Yoda-Speak", some fairly complex test can be made:
|
||||
@ -448,13 +448,13 @@ byte a
|
||||
|
||||
when TRUE
|
||||
is (a <= 10)
|
||||
; 10 or less
|
||||
// 10 or less
|
||||
break
|
||||
is (a > 10) AND (a < 20)
|
||||
; between 10 and 20
|
||||
// between 10 and 20
|
||||
break
|
||||
is (a >= 20)
|
||||
; 20 or greater
|
||||
// 20 or greater
|
||||
wend
|
||||
```
|
||||
A `when` clause can fall-through to the following clause, just like C `switch` statements by leaving out the `break` at the end of a clause.
|
||||
@ -463,11 +463,11 @@ A `when` clause can fall-through to the following clause, just like C `switch` s
|
||||
Iteration over a range is handled with the `for`/`next` loop. When iterating from a smaller to larger value, the `to` construct is used; when iterating from larger to smaller, the `downto` construct is used.
|
||||
```
|
||||
for a = 1 to 10
|
||||
; do something with a
|
||||
// do something with a
|
||||
next
|
||||
|
||||
for a = 10 downto 1
|
||||
; do something else with a
|
||||
// do something else with a
|
||||
next
|
||||
```
|
||||
An optional stepping value can be used to change the default iteration step from 1 to something else. Always use a positive value; when iterating using `downto`, the step value will be subtracted from the current value.
|
||||
@ -475,10 +475,10 @@ An optional stepping value can be used to change the default iteration step from
|
||||
##### WHILE/LOOP
|
||||
For loops that test at the top of the loop, use `while`. The loop will run zero or more times.
|
||||
```
|
||||
a = c ; Who knows what c could be
|
||||
a = c // Who knows what c could be
|
||||
while a < 10
|
||||
; do something
|
||||
a = b * 2 ; b is something special, I'm sure
|
||||
// do something
|
||||
a = b * 2 // b is something special, I'm sure
|
||||
loop
|
||||
```
|
||||
##### REPEAT/UNTIL
|
||||
@ -512,14 +512,14 @@ end
|
||||
PLASMA always returns a value from a function, even if you don't supply one. Probably the easiest optimization to make in PLASMA is to cascade a return value if you don't care about the value you return. This only works if the last thing you do before returning from your routine is calling another definition. You would go from:
|
||||
```
|
||||
def mydef
|
||||
; do some stuff
|
||||
calldef(10) ; call some other def
|
||||
// do some stuff
|
||||
calldef(10) // call some other def
|
||||
end
|
||||
```
|
||||
PLASMA will effectively add a RETURN 0 to the end of your function, as well as add code to ignore the result of `calldef(10)`. As long as you don't care about the return value from `mydef` or want to use its return as the return value fromyour function (cascade the return), you can save some code bytes with:
|
||||
```
|
||||
def mydef
|
||||
; do some stuff
|
||||
return calldef(10) ; call some other def
|
||||
// do some stuff
|
||||
return calldef(10) // call some other def
|
||||
end
|
||||
```
|
||||
|
@ -92,18 +92,18 @@ The PLASMA low level operations are defined as:
|
||||
|
||||
##PLASMA Compiler/Assembler
|
||||
|
||||
Although the low-level operations could easily by coded by hand, they were chosen to be an easy target for a simple compiler. Think along the lines of an advanced assembler or stripped down C compiler ( C--). Taking concepts from BASIC, Pascal, C and assembler, the PLASMA compiler is simple yet expressive. The syntax is line oriented; there is no statement delimiter except newline.
|
||||
Although the low-level operations could easily by coded by hand, they were chosen to be an easy target for a simple compiler. Think along the lines of an advanced assembler or stripped down C compiler ( C--). Taking concepts from BASIC, Pascal, C and assembler, the PLASMA compiler is simple yet expressive. The syntax is line oriented. However, the ';' character can seperate multiple statements on a single line. It is generally considered bad form to have multiple statements per line unless they are very short.
|
||||
|
||||
Comments are allowed throughout the source, starting with the ‘;’ character. The rest of the line is ignored.
|
||||
Comments are allowed throughout the source, starting with the ‘//’ symbol. The rest of the line is ignored.
|
||||
|
||||
```
|
||||
; Data and text buffer constants
|
||||
// Data and text buffer constants
|
||||
```
|
||||
|
||||
Hexadecimal constants are preceded with a ‘$’ to identify them as such.
|
||||
|
||||
```
|
||||
$C030 ; Speaker address
|
||||
$C030 // Speaker address
|
||||
```
|
||||
|
||||
###Constants, Variables and Functions
|
||||
@ -111,27 +111,27 @@ Hexadecimal constants are preceded with a ‘$’ to identify them as such.
|
||||
The source code of a PLASMA module first defines imports, constants, variables and data. Constants must be initialized with a value. Variables can have sizes associated with them to declare storage space. Data can be declared with or without a variable name associated with it. Arrays, tables, strings and any predeclared data can be created and accessed in multiple ways.
|
||||
|
||||
```
|
||||
;
|
||||
; Import standard library functions.
|
||||
;
|
||||
//
|
||||
// Import standard library functions.
|
||||
//
|
||||
import stdlib
|
||||
predef putc, puts, getc, gets, cls, memcpy, memset, memclr
|
||||
end
|
||||
;
|
||||
; Constants used for hardware and flags
|
||||
;
|
||||
//
|
||||
// Constants used for hardware and flags
|
||||
//
|
||||
const speaker = $C030
|
||||
const changed = 1
|
||||
const insmode = 2
|
||||
;
|
||||
; Array declaration of screen row addresses
|
||||
;
|
||||
//
|
||||
// Array declaration of screen row addresses
|
||||
//
|
||||
word txtscrn[] = $0400,$0480,$0500,$0580,$0600,$0680,$0700,$0780
|
||||
word = $0428,$04A8,$0528,$05A8,$0628,$06A8,$0728,$07A8
|
||||
word = $0450,$04D0,$0550,$05D0,$0650,$06D0,$0750,$07D0
|
||||
;
|
||||
; Misc global variables
|
||||
;
|
||||
//
|
||||
// Misc global variables
|
||||
//
|
||||
byte flags = 0
|
||||
word numlines = 0
|
||||
byte cursx, cursy
|
||||
@ -143,9 +143,9 @@ Variables can have optional brackets; empty brackets don’t reserve any space f
|
||||
Strings are defined like Pascal strings, a length byte followed by the string characters so they can be a maximum of 255 characters long. Strings can only appear in the variable definitions of a module. String constants can’t be used in expressions or statements.
|
||||
|
||||
```
|
||||
;
|
||||
; An initialized string of 64 characters
|
||||
;
|
||||
//
|
||||
// An initialized string of 64 characters
|
||||
//
|
||||
byte txtfile[64] = "UNTITLED"
|
||||
```
|
||||
|
||||
@ -195,7 +195,7 @@ Functions with parameters or expressions to be used as a function address to cal
|
||||
word keyin
|
||||
byte key
|
||||
|
||||
keyin = @keyin2plus ; address-of keyin2plus function
|
||||
keyin = @keyin2plus // address-of keyin2plus function
|
||||
key = keyin()
|
||||
```
|
||||
|
||||
@ -206,7 +206,7 @@ Expressions are algebraic. Data is free-form, but all operations on the evaluat
|
||||
```
|
||||
const speaker=$C030
|
||||
|
||||
^speaker ; click speaker
|
||||
^speaker // click speaker
|
||||
close(refnum)
|
||||
```
|
||||
|
||||
@ -257,11 +257,11 @@ Control structures affect the flow of control through the program. There are co
|
||||
```
|
||||
if ^pushbttn3 < 128
|
||||
if key == $C0
|
||||
key = $D0 ; P
|
||||
key = $D0 // P
|
||||
elsif key == $DD
|
||||
key = $CD ; M
|
||||
key = $CD // M
|
||||
elsif key == $DE
|
||||
key = $CE ; N
|
||||
key = $CE // N
|
||||
fin
|
||||
else
|
||||
key = key | $E0
|
||||
@ -346,7 +346,7 @@ romcall(aReg, xReg, yReg, statusReg, addr) returns a pointer to a four byte stru
|
||||
const xreg = 1
|
||||
const getlin = $FD6A
|
||||
|
||||
numchars = (romcall(0, 0, 0, 0, getlin)).xreg ; return char count in X reg
|
||||
numchars = (romcall(0, 0, 0, 0, getlin)).xreg // return char count in X reg
|
||||
```
|
||||
|
||||
syscall(cmd, params) calls ProDOS, returning the status value.
|
||||
@ -367,8 +367,8 @@ syscall(cmd, params) calls ProDOS, returning the status value.
|
||||
putc(char), puts(string), home, gotoxy(x,y), getc() and gets() are other handy utility routines for interacting with the console.
|
||||
|
||||
```
|
||||
putc('.')
|
||||
byte okstr[] = "OK"
|
||||
putc('.')
|
||||
puts(@okstr)
|
||||
```
|
||||
|
||||
@ -376,7 +376,7 @@ memset(addr, len, val) will fill memory with a 16 bit value. memcpy(dstaddr, sr
|
||||
|
||||
```
|
||||
byte nullstr[] = ""
|
||||
memset(strlinbuf, maxfill * 2, @nullstr) ; fill line buff with pointer to null string
|
||||
memset(strlinbuf, maxfill * 2, @nullstr) // fill line buff with pointer to null string
|
||||
memcpy(scrnptr, strptr + ofst + 1, numchars)
|
||||
```
|
||||
|
||||
@ -384,7 +384,7 @@ memset(addr, len, val) will fill memory with a 16 bit value. memcpy(dstaddr, sr
|
||||
###The Original PLASMA
|
||||
The original design concept was to create an efficient, flexible, and expressive environment for building applications directly on the Apple II. Choosing a stack based architecture was easy after much experience with other stack based implementations. It also makes the compiler simple to implement. The first take on the stack architecture was to make it a very strict stack architecture in that everything had to be on the stack. The only opcode with operands was the CONSTANT opcode. This allowed for a very small bytecode interpreter and a very easy compile target. However, only when adding an opcode with operands that would greatly improved performance, native code generation or code size was it done. The opcode table grew slowly over time but still retains a small runtime interpreter with good native code density.
|
||||
|
||||
The VM was constructed such that code generation could ouput native 6502 code, threaded code into the opcode functions, or interpreted bytecodes. This gave a level of control over speed vs memory.
|
||||
The VM was constructed such that code generation could output native 6502 code, threaded code into the opcode functions, or interpreted bytecodes. This gave a level of control over speed vs memory.
|
||||
|
||||
###The Lawless Legends PLASMA
|
||||
This version of PLASMA has dispensed with the native/threaded/bytecode code generation from the original version to focus on code density and the ability to interpret bytecode from AUX memory, should it be available. By focussing on the bytecode interpreter, certain optimizations were implemented that weren't posssible when allowing for threaded/native code; the interpreted bytecode is now about the same performance as the directly threaded code.
|
||||
|
@ -4,37 +4,37 @@ const databuff = $2000
|
||||
const MODADDR = $1000
|
||||
const symtbl = $0C00
|
||||
const freemem = $0006
|
||||
;
|
||||
; System flags: memory allocator screen holes.
|
||||
;
|
||||
//
|
||||
// System flags: memory allocator screen holes.
|
||||
//
|
||||
const restxt1 = $0001
|
||||
const restxt2 = $0002
|
||||
const reshgr1 = $0004
|
||||
const reshgr2 = $0008
|
||||
const resxhgr1 = $0010
|
||||
const resxhgr2 = $0020
|
||||
;
|
||||
; Pedefined functions.
|
||||
;
|
||||
//
|
||||
// Pedefined functions.
|
||||
//
|
||||
predef syscall, call
|
||||
predef crout, cout, prstr, cin, rdstr
|
||||
predef markheap, allocheap, allocalignheap, releaseheap, availheap
|
||||
predef memset, memcpy
|
||||
predef uword_isgt, uword_isge, uword_islt, uword_isle
|
||||
predef loadmod, execmod, lookupstrmod
|
||||
;
|
||||
; System variable.
|
||||
;
|
||||
word version = $0010 ; 00.10
|
||||
//
|
||||
// System variable.
|
||||
//
|
||||
word version = $0010 // 00.10
|
||||
word systemflags = 0
|
||||
word heap
|
||||
word xheap = $0800
|
||||
word lastsym = symtbl
|
||||
byte perr
|
||||
word cmdptr
|
||||
;
|
||||
; Standard Library exported functions.
|
||||
;
|
||||
//
|
||||
// Standard Library exported functions.
|
||||
//
|
||||
byte stdlibstr[] = "STDLIB"
|
||||
byte machidstr[] = "MACHID"
|
||||
byte sysstr[] = "SYSCALL"
|
||||
@ -81,9 +81,9 @@ word = @modadrstr, @lookupstrmod
|
||||
word = @machidstr, MACHID
|
||||
word = 0
|
||||
word stdlibsym = @exports
|
||||
;
|
||||
; String pool.
|
||||
;
|
||||
//
|
||||
// String pool.
|
||||
//
|
||||
byte autorun[] = "AUTORUN"
|
||||
byte verstr[] = "PLASMA "
|
||||
byte freestr[] = "MEM FREE:$"
|
||||
@ -91,14 +91,14 @@ byte errorstr[] = "ERR:$"
|
||||
byte okstr[] = "OK"
|
||||
byte huhstr[] = "?\n"
|
||||
byte prefix[32] = ""
|
||||
;
|
||||
; Utility functions
|
||||
;
|
||||
;asm equates included from cmdstub.s
|
||||
;
|
||||
; CALL PRODOS
|
||||
; SYSCALL(CMD, PARAMS)
|
||||
;
|
||||
//
|
||||
// Utility functions
|
||||
//
|
||||
//asm equates included from cmdstub.s
|
||||
//
|
||||
// CALL PRODOS
|
||||
// SYSCALL(CMD, PARAMS)
|
||||
//
|
||||
asm syscall
|
||||
LDA ESTKL,X
|
||||
LDY ESTKH,X
|
||||
@ -115,10 +115,10 @@ PARAMS: !WORD 0000
|
||||
STY ESTKH,X
|
||||
RTS
|
||||
end
|
||||
;
|
||||
; CALL 6502 ROUTINE
|
||||
; CALL(ADDR, AREG, XREG, YREG, STATUS)
|
||||
;
|
||||
//
|
||||
// CALL 6502 ROUTINE
|
||||
// CALL(ADDR, AREG, XREG, YREG, STATUS)
|
||||
//
|
||||
asm call
|
||||
REGVALS = SRC
|
||||
PHP
|
||||
@ -159,9 +159,9 @@ REGVALS = SRC
|
||||
RTS
|
||||
JMPTMP JMP (TMP)
|
||||
end
|
||||
;
|
||||
; CALL LOADED SYSTEM PROGRAM
|
||||
;
|
||||
//
|
||||
// CALL LOADED SYSTEM PROGRAM
|
||||
//
|
||||
asm exec
|
||||
LDX #$00
|
||||
STX IFPL
|
||||
@ -173,19 +173,19 @@ asm exec
|
||||
BIT ROMEN
|
||||
JMP $2000
|
||||
end
|
||||
;
|
||||
; EXIT
|
||||
;
|
||||
//
|
||||
// EXIT
|
||||
//
|
||||
asm reboot
|
||||
BIT ROMEN
|
||||
DEC $03F4 ; INVALIDATE POWER-UP BYTE
|
||||
JMP ($FFFC) ; RESET
|
||||
end
|
||||
;
|
||||
; SET MEMORY TO VALUE
|
||||
; MEMSET(ADDR, SIZE, VALUE)
|
||||
; With optimizations from Peter Ferrie
|
||||
;
|
||||
//
|
||||
// SET MEMORY TO VALUE
|
||||
// MEMSET(ADDR, SIZE, VALUE)
|
||||
// With optimizations from Peter Ferrie
|
||||
//
|
||||
asm memset
|
||||
LDY #$00
|
||||
LDA ESTKL+2,X
|
||||
@ -212,10 +212,10 @@ SETMEX INX
|
||||
INX
|
||||
RTS
|
||||
end
|
||||
;
|
||||
; COPY MEMORY
|
||||
; MEMCPY(DSTADDR, SRCADDR, SIZE)
|
||||
;
|
||||
//
|
||||
// COPY MEMORY
|
||||
// MEMCPY(DSTADDR, SRCADDR, SIZE)
|
||||
//
|
||||
asm memcpy
|
||||
INX
|
||||
INX
|
||||
@ -285,11 +285,11 @@ REVCPYLP LDA (SRC),Y
|
||||
BNE REVCPYLP
|
||||
CPYMEX RTS
|
||||
end
|
||||
;
|
||||
; COPY FROM MAIN MEM TO AUX MEM.
|
||||
;
|
||||
; MEMXCPY(DST, SRC, SIZE)
|
||||
;
|
||||
//
|
||||
// COPY FROM MAIN MEM TO AUX MEM.
|
||||
//
|
||||
// MEMXCPY(DST, SRC, SIZE)
|
||||
//
|
||||
asm memxcpy
|
||||
LDA ESTKL+1,X
|
||||
STA $3C
|
||||
@ -318,12 +318,12 @@ asm crout
|
||||
DEX
|
||||
LDA #$8D
|
||||
STA ESTKL,X
|
||||
; FALL THROUGH TO COUT
|
||||
// FALL THROUGH TO COUT
|
||||
end
|
||||
;
|
||||
; CHAR OUT
|
||||
; COUT(CHAR)
|
||||
;
|
||||
//
|
||||
// CHAR OUT
|
||||
// COUT(CHAR)
|
||||
//
|
||||
asm cout
|
||||
LDA ESTKL,X
|
||||
BIT $BF98
|
||||
@ -335,10 +335,10 @@ asm cout
|
||||
BIT LCRDEN+LCBNK2
|
||||
RTS
|
||||
end
|
||||
;
|
||||
; CHAR IN
|
||||
; RDKEY()
|
||||
;
|
||||
//
|
||||
// CHAR IN
|
||||
// RDKEY()
|
||||
//
|
||||
asm cin
|
||||
BIT ROMEN
|
||||
JSR $FD0C
|
||||
@ -349,10 +349,10 @@ asm cin
|
||||
STY ESTKH,X
|
||||
RTS
|
||||
end
|
||||
;
|
||||
; PRINT STRING
|
||||
; PRSTR(STR)
|
||||
;
|
||||
//
|
||||
// PRINT STRING
|
||||
// PRSTR(STR)
|
||||
//
|
||||
asm prstr
|
||||
LDY #$00
|
||||
LDA ESTKL,X
|
||||
@ -375,9 +375,9 @@ asm prstr
|
||||
BIT LCRDEN+LCBNK2
|
||||
++ RTS
|
||||
end
|
||||
;
|
||||
; PRINT BYTE
|
||||
;
|
||||
//
|
||||
// PRINT BYTE
|
||||
//
|
||||
asm prbyte
|
||||
LDA ESTKL,X
|
||||
STX ESP
|
||||
@ -387,9 +387,9 @@ asm prbyte
|
||||
BIT LCRDEN+LCBNK2
|
||||
RTS
|
||||
end
|
||||
;
|
||||
; PRINT WORD
|
||||
;
|
||||
//
|
||||
// PRINT WORD
|
||||
//
|
||||
asm prword
|
||||
STX ESP
|
||||
TXA
|
||||
@ -402,10 +402,10 @@ asm prword
|
||||
BIT LCRDEN+LCBNK2
|
||||
RTS
|
||||
end
|
||||
;
|
||||
; READ STRING
|
||||
; STR = RDSTR(PROMPTCHAR)
|
||||
;
|
||||
//
|
||||
// READ STRING
|
||||
// STR = RDSTR(PROMPTCHAR)
|
||||
//
|
||||
asm rdstr
|
||||
LDA ESTKL,X
|
||||
STA $33
|
||||
@ -476,23 +476,23 @@ asm uword_islt
|
||||
INX
|
||||
RTS
|
||||
end
|
||||
;
|
||||
; Utility routines.
|
||||
;
|
||||
; A DCI string is one that has the high bit set for every character except the last.
|
||||
; More efficient than C or Pascal strings.
|
||||
;
|
||||
;def dcitos(dci, str)
|
||||
; byte len, c
|
||||
; len = 0
|
||||
; repeat
|
||||
; c = (dci).[len]
|
||||
; len = len + 1
|
||||
; (str).[len] = c & $7F
|
||||
; until !(c & $80)
|
||||
; ^str = len
|
||||
; return len
|
||||
;end
|
||||
//
|
||||
// Utility routines.
|
||||
//
|
||||
// A DCI string is one that has the high bit set for every character except the last.
|
||||
// More efficient than C or Pascal strings.
|
||||
//
|
||||
//def dcitos(dci, str)
|
||||
// byte len, c
|
||||
// len = 0
|
||||
// repeat
|
||||
// c = (dci).[len]
|
||||
// len = len + 1
|
||||
// (str).[len] = c & $7F
|
||||
// until !(c & $80)
|
||||
// ^str = len
|
||||
// return len
|
||||
//end
|
||||
asm dcitos
|
||||
LDA ESTKL,X
|
||||
STA DSTL
|
||||
@ -517,22 +517,22 @@ asm dcitos
|
||||
STY ESTKH,X
|
||||
RTS
|
||||
end
|
||||
;def stodci(str, dci)
|
||||
; byte len, c
|
||||
; len = ^str
|
||||
; if len == 0
|
||||
; return
|
||||
; fin
|
||||
; c = toupper((str).[len]) & $7F
|
||||
; len = len - 1
|
||||
; (dci).[len] = c
|
||||
; while len
|
||||
; c = toupper((str).[len]) | $80
|
||||
; len = len - 1
|
||||
; (dci).[len] = c
|
||||
; loop
|
||||
; return ^str
|
||||
;end
|
||||
//def stodci(str, dci)
|
||||
// byte len, c
|
||||
// len = ^str
|
||||
// if len == 0
|
||||
// return
|
||||
// fin
|
||||
// c = toupper((str).[len]) & $7F
|
||||
// len = len - 1
|
||||
// (dci).[len] = c
|
||||
// while len
|
||||
// c = toupper((str).[len]) | $80
|
||||
// len = len - 1
|
||||
// (dci).[len] = c
|
||||
// loop
|
||||
// return ^str
|
||||
//end
|
||||
asm stodci
|
||||
LDA ESTKL,X
|
||||
STA DSTL
|
||||
@ -572,22 +572,22 @@ TOUPR AND #$7F
|
||||
+ STA ESTKL,X
|
||||
RTS
|
||||
end
|
||||
;
|
||||
; Module symbols are entered into the symbol table
|
||||
; pre-pended with a '#' to differentiate them
|
||||
; from normal symbols.
|
||||
;
|
||||
;def modtosym(mod, dci)
|
||||
; byte len, c
|
||||
; (dci).0 = '#'|$80
|
||||
; len = 0
|
||||
; repeat
|
||||
; c = (mod).[len]
|
||||
; len = len + 1
|
||||
; (dci).[len] = c
|
||||
; until !(c & $80)
|
||||
; return dci
|
||||
;end
|
||||
//
|
||||
// Module symbols are entered into the symbol table
|
||||
// pre-pended with a '#' to differentiate them
|
||||
// from normal symbols.
|
||||
//
|
||||
//def modtosym(mod, dci)
|
||||
// byte len, c
|
||||
// (dci).0 = '#'|$80
|
||||
// len = 0
|
||||
// repeat
|
||||
// c = (mod).[len]
|
||||
// len = len + 1
|
||||
// (dci).[len] = c
|
||||
// until !(c & $80)
|
||||
// return dci
|
||||
//end
|
||||
asm modtosym
|
||||
LDA ESTKL+1,X
|
||||
STA SRCL
|
||||
@ -609,26 +609,26 @@ asm modtosym
|
||||
BCS -
|
||||
RTS
|
||||
end
|
||||
;
|
||||
; Lookup routines.
|
||||
;
|
||||
;def lookuptbl(dci, tbl)
|
||||
; word match
|
||||
; while ^tbl
|
||||
; match = dci
|
||||
; while ^tbl == ^match
|
||||
; if !(^tbl & $80)
|
||||
; return (tbl):1
|
||||
; fin
|
||||
; tbl = tbl + 1
|
||||
; match = match + 1
|
||||
; loop
|
||||
; while (^tbl & $80)
|
||||
; tbl = tbl + 1
|
||||
; loop
|
||||
; tbl = tbl + 3
|
||||
; loop
|
||||
; return 0
|
||||
//
|
||||
// Lookup routines.
|
||||
//
|
||||
//def lookuptbl(dci, tbl)
|
||||
// word match
|
||||
// while ^tbl
|
||||
// match = dci
|
||||
// while ^tbl == ^match
|
||||
// if !(^tbl & $80)
|
||||
// return (tbl):1
|
||||
// fin
|
||||
// tbl = tbl + 1
|
||||
// match = match + 1
|
||||
// loop
|
||||
// while (^tbl & $80)
|
||||
// tbl = tbl + 1
|
||||
// loop
|
||||
// tbl = tbl + 3
|
||||
// loop
|
||||
// return 0
|
||||
asm lookuptbl
|
||||
LDA ESTKL,X
|
||||
STA DSTL
|
||||
@ -670,9 +670,9 @@ asm lookuptbl
|
||||
INC DSTH
|
||||
BCS -
|
||||
end
|
||||
;
|
||||
; ProDOS routines
|
||||
;
|
||||
//
|
||||
// ProDOS routines
|
||||
//
|
||||
def getpfx(path)
|
||||
byte params[3]
|
||||
|
||||
@ -719,9 +719,9 @@ def read(refnum, buff, len)
|
||||
perr = syscall($CA, @params)
|
||||
return params:6
|
||||
end
|
||||
;
|
||||
; Heap routines.
|
||||
;
|
||||
//
|
||||
// Heap routines.
|
||||
//
|
||||
def availheap
|
||||
byte fp
|
||||
return @fp - heap
|
||||
@ -761,11 +761,11 @@ def allocalignheap(size, pow2, freeaddr)
|
||||
return addr
|
||||
end
|
||||
def markheap
|
||||
return heap;
|
||||
return heap//
|
||||
end
|
||||
def releaseheap(newheap)
|
||||
heap = newheap;
|
||||
return @newheap - heap;
|
||||
heap = newheap//
|
||||
return @newheap - heap//
|
||||
end
|
||||
def allocxheap(size)
|
||||
word xaddr
|
||||
@ -800,9 +800,9 @@ def allocxheap(size)
|
||||
fin
|
||||
return xaddr
|
||||
end
|
||||
;
|
||||
; Symbol table routines.
|
||||
;
|
||||
//
|
||||
// Symbol table routines.
|
||||
//
|
||||
def lookupsym(sym)
|
||||
return lookuptbl(sym, symtbl)
|
||||
end
|
||||
@ -817,9 +817,9 @@ def addsym(sym, addr)
|
||||
lastsym = lastsym + 3
|
||||
^lastsym = 0
|
||||
end
|
||||
;
|
||||
; Module routines.
|
||||
;
|
||||
//
|
||||
// Module routines.
|
||||
//
|
||||
def lookupmod(mod)
|
||||
byte dci[17]
|
||||
return lookuptbl(modtosym(mod, @dci), symtbl)
|
||||
@ -858,13 +858,13 @@ def adddef(bank, addr, deflast)
|
||||
defentry = *deflast
|
||||
*deflast = defentry + 5
|
||||
if bank
|
||||
defentry=>1 = $03DC ; JSR $03DC (AUX MEM INTERP)
|
||||
defentry=>1 = $03DC // JSR $03DC (AUX MEM INTERP)
|
||||
else
|
||||
defentry=>1 = $03D6 ; JSR $03D6 (MAIN MEM INTERP)
|
||||
defentry=>1 = $03D6 // JSR $03D6 (MAIN MEM INTERP)
|
||||
fin
|
||||
defentry->0 = $20
|
||||
defentry=>3 = addr
|
||||
defentry->5 = 0 ; NULL out next entry
|
||||
defentry->5 = 0 // NULL out next entry
|
||||
return defentry
|
||||
end
|
||||
def lookupdef(addr, deftbl)
|
||||
@ -883,9 +883,9 @@ def loadmod(mod)
|
||||
word moddep, rld, esd, sym
|
||||
byte defbank, str[16], filename[64]
|
||||
byte header[128]
|
||||
;
|
||||
; Read the RELocatable module header (first 128 bytes)
|
||||
;
|
||||
//
|
||||
// Read the RELocatable module header (first 128 bytes)
|
||||
//
|
||||
dcitos(mod, @filename)
|
||||
refnum = open(@filename, iobuffer)
|
||||
if refnum > 0
|
||||
@ -894,18 +894,18 @@ def loadmod(mod)
|
||||
moddep = @header.1
|
||||
defofst = modsize
|
||||
init = 0
|
||||
if rdlen > 4 and header:2 == $DA7E ; DAVE = magic number :-)
|
||||
;
|
||||
; This is an EXTended RELocatable (data+bytecode) module.
|
||||
;
|
||||
if rdlen > 4 and header:2 == $DA7E // DAVE = magic number :-)
|
||||
//
|
||||
// This is an EXTended RELocatable (data+bytecode) module.
|
||||
//
|
||||
systemflags = header:4 | systemflags
|
||||
defofst = header:6
|
||||
defcnt = header:8
|
||||
init = header:10
|
||||
moddep = @header.12
|
||||
;
|
||||
; Load module dependencies.
|
||||
;
|
||||
//
|
||||
// Load module dependencies.
|
||||
//
|
||||
while ^moddep
|
||||
if !lookupmod(moddep)
|
||||
close(refnum)
|
||||
@ -916,57 +916,57 @@ def loadmod(mod)
|
||||
fin
|
||||
moddep = moddep + dcitos(moddep, @str)
|
||||
loop
|
||||
;
|
||||
; Init def table.
|
||||
;
|
||||
//
|
||||
// Init def table.
|
||||
//
|
||||
deftbl = allocheap(defcnt * 5 + 1)
|
||||
deflast = deftbl
|
||||
^deflast = 0
|
||||
if !refnum
|
||||
;
|
||||
; Reset read pointer.
|
||||
;
|
||||
//
|
||||
// Reset read pointer.
|
||||
//
|
||||
refnum = open(@filename, iobuffer)
|
||||
rdlen = read(refnum, @header, 128)
|
||||
fin
|
||||
fin
|
||||
;
|
||||
; Alloc heap space for relocated module (data + bytecode).
|
||||
;
|
||||
//
|
||||
// Alloc heap space for relocated module (data + bytecode).
|
||||
//
|
||||
moddep = moddep + 1
|
||||
modfix = moddep - @header.2 ; Adjust to skip header
|
||||
modfix = moddep - @header.2 // Adjust to skip header
|
||||
modsize = modsize - modfix
|
||||
rdlen = rdlen - modfix - 2
|
||||
modaddr = allocheap(modsize)
|
||||
memcpy(modaddr, moddep, rdlen)
|
||||
;
|
||||
; Read in remainder of module into memory for fixups.
|
||||
;
|
||||
addr = modaddr;
|
||||
//
|
||||
// Read in remainder of module into memory for fixups.
|
||||
//
|
||||
addr = modaddr//
|
||||
repeat
|
||||
addr = addr + rdlen
|
||||
rdlen = read(refnum, addr, 4096)
|
||||
until rdlen <= 0
|
||||
close(refnum)
|
||||
;
|
||||
; Add module to symbol table.
|
||||
;
|
||||
//
|
||||
// Add module to symbol table.
|
||||
//
|
||||
addmod(mod, modaddr)
|
||||
;
|
||||
; Apply all fixups and symbol import/export.
|
||||
;
|
||||
//
|
||||
// Apply all fixups and symbol import/export.
|
||||
//
|
||||
modfix = modaddr - modfix
|
||||
bytecode = defofst + modfix - MODADDR
|
||||
modend = modaddr + modsize
|
||||
rld = modend ; Re-Locatable Directory
|
||||
esd = rld ; Extern+Entry Symbol Directory
|
||||
while ^esd ; Scan to end of ESD
|
||||
rld = modend // Re-Locatable Directory
|
||||
esd = rld // Extern+Entry Symbol Directory
|
||||
while ^esd // Scan to end of ESD
|
||||
esd = esd + 4
|
||||
loop
|
||||
esd = esd + 1
|
||||
;
|
||||
; Locate bytecode defs in appropriate bank.
|
||||
;
|
||||
//
|
||||
// Locate bytecode defs in appropriate bank.
|
||||
//
|
||||
if ^MACHID & $30 == $30
|
||||
defbank = 1
|
||||
defaddr = allocxheap(rld - bytecode)
|
||||
@ -975,58 +975,58 @@ def loadmod(mod)
|
||||
defbank = 0
|
||||
defaddr = bytecode
|
||||
fin
|
||||
;
|
||||
; Run through the Re-Location Dictionary.
|
||||
;
|
||||
//
|
||||
// Run through the Re-Location Dictionary.
|
||||
//
|
||||
while ^rld
|
||||
if ^rld == $02
|
||||
;
|
||||
; This is a bytcode def entry - add it to the def directory.
|
||||
;
|
||||
//
|
||||
// This is a bytcode def entry - add it to the def directory.
|
||||
//
|
||||
adddef(defbank, rld=>1 - defofst + defaddr, @deflast)
|
||||
else
|
||||
addr = rld=>1 + modfix
|
||||
if uword_isge(addr, modaddr) ; Skip fixups to header
|
||||
if ^rld & $80 ; WORD sized fixup.
|
||||
if uword_isge(addr, modaddr) // Skip fixups to header
|
||||
if ^rld & $80 // WORD sized fixup.
|
||||
fixup = *addr
|
||||
else ; BYTE sized fixup.
|
||||
else // BYTE sized fixup.
|
||||
fixup = ^addr
|
||||
fin
|
||||
if ^rld & $10 ; EXTERN reference.
|
||||
if ^rld & $10 // EXTERN reference.
|
||||
fixup = fixup + lookupextern(esd, rld->3)
|
||||
else ; INTERN fixup.
|
||||
else // INTERN fixup.
|
||||
fixup = fixup + modfix - MODADDR
|
||||
if uword_isge(fixup, bytecode)
|
||||
;
|
||||
; Bytecode address - replace with call def directory.
|
||||
;
|
||||
//
|
||||
// Bytecode address - replace with call def directory.
|
||||
//
|
||||
fixup = lookupdef(fixup - bytecode + defaddr, deftbl)
|
||||
fin
|
||||
fin
|
||||
if ^rld & $80 ; WORD sized fixup.
|
||||
if ^rld & $80 // WORD sized fixup.
|
||||
*addr = fixup
|
||||
else ; BYTE sized fixup.
|
||||
else // BYTE sized fixup.
|
||||
^addr = fixup
|
||||
fin
|
||||
fin
|
||||
fin
|
||||
rld = rld + 4
|
||||
loop
|
||||
;
|
||||
; Run through the External/Entry Symbol Directory.
|
||||
;
|
||||
//
|
||||
// Run through the External/Entry Symbol Directory.
|
||||
//
|
||||
while ^esd
|
||||
sym = esd
|
||||
esd = esd + dcitos(esd, @str)
|
||||
if ^esd & $08
|
||||
;
|
||||
; EXPORT symbol - add it to the global symbol table.
|
||||
;
|
||||
//
|
||||
// EXPORT symbol - add it to the global symbol table.
|
||||
//
|
||||
addr = esd=>1 + modfix - MODADDR
|
||||
if uword_isge(addr, bytecode)
|
||||
;
|
||||
; Use the def directory address for bytecode.
|
||||
;
|
||||
//
|
||||
// Use the def directory address for bytecode.
|
||||
//
|
||||
addr = lookupdef(addr - bytecode + defaddr, deftbl)
|
||||
fin
|
||||
addsym(sym, addr)
|
||||
@ -1034,18 +1034,18 @@ def loadmod(mod)
|
||||
esd = esd + 3
|
||||
loop
|
||||
if defbank
|
||||
;
|
||||
; Move bytecode to AUX bank.
|
||||
;
|
||||
//
|
||||
// Move bytecode to AUX bank.
|
||||
//
|
||||
memxcpy(defaddr, bytecode, modsize - (bytecode - modaddr))
|
||||
fin
|
||||
fin
|
||||
if perr
|
||||
return -perr
|
||||
fin
|
||||
;
|
||||
; Call init routine if it exists.
|
||||
;
|
||||
//
|
||||
// Call init routine if it exists.
|
||||
//
|
||||
if init
|
||||
fixup = adddef(defbank, init - defofst + defaddr, @deflast)()
|
||||
if defbank
|
||||
@ -1056,15 +1056,15 @@ def loadmod(mod)
|
||||
else
|
||||
fixup = 0
|
||||
fin
|
||||
;
|
||||
; Free up the end-of-module in main memory.
|
||||
;
|
||||
//
|
||||
// Free up the end-of-module in main memory.
|
||||
//
|
||||
releaseheap(modend)
|
||||
return fixup
|
||||
end
|
||||
;
|
||||
; Command mode
|
||||
;
|
||||
//
|
||||
// Command mode
|
||||
//
|
||||
def volumes
|
||||
byte params[4]
|
||||
word strbuf
|
||||
@ -1120,7 +1120,7 @@ def catalog(optpath)
|
||||
len = type & $0F
|
||||
^entry = len
|
||||
prstr(entry)
|
||||
if type & $F0 == $D0 ; Is it a directory?
|
||||
if type & $F0 == $D0 // Is it a directory?
|
||||
cout('/')
|
||||
len = len + 1
|
||||
elsif entry->$10 == $FF
|
||||
@ -1186,14 +1186,14 @@ def parsecmd(strptr)
|
||||
return cmd
|
||||
end
|
||||
def resetmemfiles
|
||||
;
|
||||
; Close all files
|
||||
;
|
||||
//
|
||||
// Close all files
|
||||
//
|
||||
^$BFD8 = 0
|
||||
close(0)
|
||||
;
|
||||
; Set memory bitmap
|
||||
;
|
||||
//
|
||||
// Set memory bitmap
|
||||
//
|
||||
memset($BF58, 24, 0)
|
||||
^$BF58 = $CF
|
||||
^$BF6F = $01
|
||||
@ -1240,13 +1240,13 @@ def execmod(modfile)
|
||||
heap = saveheap
|
||||
fin
|
||||
end
|
||||
;
|
||||
; Get heap start.
|
||||
;
|
||||
//
|
||||
// Get heap start.
|
||||
//
|
||||
heap = *freemem
|
||||
;
|
||||
; Init symbol table.
|
||||
;
|
||||
//
|
||||
// Init symbol table.
|
||||
//
|
||||
stodci(@stdlibstr, heap)
|
||||
addmod(heap, @version)
|
||||
while *stdlibsym
|
||||
@ -1254,15 +1254,15 @@ while *stdlibsym
|
||||
addsym(heap, stdlibsym=>2)
|
||||
stdlibsym = stdlibsym + 4
|
||||
loop
|
||||
;
|
||||
; Try to run autorun module.
|
||||
;
|
||||
//
|
||||
// Try to run autorun module.
|
||||
//
|
||||
resetmemfiles()
|
||||
execmod(@autorun)
|
||||
perr = 0
|
||||
;
|
||||
; Print some startup info.
|
||||
;
|
||||
//
|
||||
// Print some startup info.
|
||||
//
|
||||
prstr(@verstr)
|
||||
prbyte(version.1)
|
||||
cout('.')
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "tokens.h"
|
||||
#include "symbols.h"
|
||||
|
||||
char *statement, *scanpos, *tokenstr;
|
||||
char *statement, *tokenstr, *scanpos = "";
|
||||
t_token scantoken, prevtoken;
|
||||
int tokenlen;
|
||||
long constval;
|
||||
@ -22,28 +22,28 @@ t_token keywords[] = {
|
||||
ENDCASE_TOKEN, 'W', 'E', 'N', 'D',
|
||||
FOR_TOKEN, 'F', 'O', 'R',
|
||||
TO_TOKEN, 'T', 'O',
|
||||
DOWNTO_TOKEN, 'D', 'O', 'W', 'N', 'T', 'O',
|
||||
DOWNTO_TOKEN, 'D', 'O', 'W', 'N', 'T', 'O',
|
||||
STEP_TOKEN, 'S', 'T', 'E', 'P',
|
||||
NEXT_TOKEN, 'N', 'E', 'X', 'T',
|
||||
REPEAT_TOKEN, 'R', 'E', 'P', 'E', 'A', 'T',
|
||||
UNTIL_TOKEN, 'U', 'N', 'T', 'I', 'L',
|
||||
BREAK_TOKEN, 'B', 'R', 'E', 'A', 'K',
|
||||
UNTIL_TOKEN, 'U', 'N', 'T', 'I', 'L',
|
||||
BREAK_TOKEN, 'B', 'R', 'E', 'A', 'K',
|
||||
ASM_TOKEN, 'A', 'S', 'M',
|
||||
DEF_TOKEN, 'D', 'E', 'F',
|
||||
EXPORT_TOKEN, 'E', 'X', 'P', 'O', 'R', 'T',
|
||||
IMPORT_TOKEN, 'I', 'M', 'P', 'O', 'R', 'T',
|
||||
EXPORT_TOKEN, 'E', 'X', 'P', 'O', 'R', 'T',
|
||||
IMPORT_TOKEN, 'I', 'M', 'P', 'O', 'R', 'T',
|
||||
RETURN_TOKEN, 'R', 'E', 'T', 'U', 'R', 'N',
|
||||
END_TOKEN, 'E', 'N', 'D',
|
||||
EXIT_TOKEN, 'E', 'X', 'I', 'T',
|
||||
DONE_TOKEN, 'D', 'O', 'N', 'E',
|
||||
LOGIC_NOT_TOKEN, 'N', 'O', 'T',
|
||||
LOGIC_AND_TOKEN, 'A', 'N', 'D',
|
||||
LOGIC_OR_TOKEN, 'O', 'R',
|
||||
LOGIC_OR_TOKEN, 'O', 'R',
|
||||
BYTE_TOKEN, 'B', 'Y', 'T', 'E',
|
||||
WORD_TOKEN, 'W', 'O', 'R', 'D',
|
||||
CONST_TOKEN, 'C', 'O', 'N', 'S', 'T',
|
||||
PREDEF_TOKEN, 'P', 'R', 'E', 'D', 'E', 'F',
|
||||
SYSFLAGS_TOKEN, 'S', 'Y', 'S', 'F', 'L', 'A', 'G', 'S',
|
||||
SYSFLAGS_TOKEN, 'S', 'Y', 'S', 'F', 'L', 'A', 'G', 'S',
|
||||
EOL_TOKEN
|
||||
};
|
||||
|
||||
@ -333,6 +333,15 @@ t_token scan(void)
|
||||
scanpos++;
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
if (scanpos[1] == '/')
|
||||
scantoken = EOL_TOKEN;
|
||||
else
|
||||
{
|
||||
scantoken = DIV_TOKEN;
|
||||
scanpos++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Simple single character tokens.
|
||||
@ -363,12 +372,21 @@ int scan_lookahead(void)
|
||||
char inputline[512];
|
||||
int next_line(void)
|
||||
{
|
||||
gets(inputline);
|
||||
lineno++;
|
||||
statement = inputline;
|
||||
scanpos = inputline;
|
||||
scantoken = EOL_TOKEN;
|
||||
scan();
|
||||
printf("; %03d: %s\n", lineno, inputline);
|
||||
if (*scanpos == ';')
|
||||
{
|
||||
statement = ++scanpos;
|
||||
scantoken = EOL_TOKEN;
|
||||
scan();
|
||||
}
|
||||
else
|
||||
{
|
||||
gets(inputline);
|
||||
lineno++;
|
||||
statement = inputline;
|
||||
scanpos = inputline;
|
||||
scantoken = EOL_TOKEN;
|
||||
scan();
|
||||
printf("; %03d: %s\n", lineno, inputline);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
@ -6,9 +6,9 @@ import stdlib
|
||||
predef isugt, isuge, isult, isule
|
||||
predef load, exec
|
||||
word MACHID, sysvars
|
||||
;
|
||||
; System flags: memory allocator screen holes.
|
||||
;
|
||||
//
|
||||
// System flags: memory allocator screen holes.
|
||||
//
|
||||
const restxt1 = $0001
|
||||
const restxt2 = $0002
|
||||
const reshgr1 = $0004
|
||||
|
@ -1,13 +1,13 @@
|
||||
;
|
||||
; Include all imported modules and their data/functions.
|
||||
;
|
||||
//
|
||||
// Include all imported modules and their data/functions.
|
||||
//
|
||||
|
||||
include(stdlib.plh)
|
||||
include(testlib.plh)
|
||||
|
||||
;
|
||||
; Declare all global variables for this module.
|
||||
;
|
||||
//
|
||||
// Declare all global variables for this module.
|
||||
//
|
||||
|
||||
byte hello[] = "Hello, Apple "
|
||||
byte a1[] = "1"
|
||||
@ -20,9 +20,9 @@ word struct[] = 1, 10, 100, 1000, 10000
|
||||
word ptr
|
||||
byte spaces[] = " "
|
||||
|
||||
;
|
||||
; Define functions.
|
||||
;
|
||||
//
|
||||
// Define functions.
|
||||
//
|
||||
|
||||
def tens(start)
|
||||
word i
|
||||
|
@ -1,21 +1,21 @@
|
||||
;
|
||||
; Include all imported modules and their data/functions.
|
||||
;
|
||||
//
|
||||
// Include all imported modules and their data/functions.
|
||||
//
|
||||
|
||||
include(stdlib.plh)
|
||||
|
||||
;
|
||||
; Module data.
|
||||
;
|
||||
//
|
||||
// Module data.
|
||||
//
|
||||
|
||||
predef puti, puth, putln
|
||||
export word print[] = @puti, @puth, @putln, @puts, @putc
|
||||
byte valstr[] = '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
|
||||
byte loadstr[] = "testlib loaded!"
|
||||
|
||||
;
|
||||
; Define functions.
|
||||
;
|
||||
//
|
||||
// Define functions.
|
||||
//
|
||||
|
||||
def puth(h)
|
||||
putc('$')
|
||||
@ -26,10 +26,7 @@ def puth(h)
|
||||
end
|
||||
|
||||
export def puti(i)
|
||||
if i < 0
|
||||
putc('-')
|
||||
i = -i
|
||||
fin
|
||||
if i < 0; putc('-'); i = -i; fin
|
||||
if i < 10
|
||||
putc(i + '0')
|
||||
else
|
||||
|
@ -38,6 +38,10 @@ NW_MAP_LOC=$52
|
||||
NE_MAP_LOC=$54
|
||||
SW_MAP_LOC=$56
|
||||
SE_MAP_LOC=$58
|
||||
NW_TILESET_LOC=$70
|
||||
NE_TILESET_LOC=$72
|
||||
SW_TILESET_LOC=$74
|
||||
SE_TILESET_LOC=$76
|
||||
; Map section IDs (255 = not loaded)
|
||||
NOT_LOADED=$FF
|
||||
NW_MAP_ID=$5A
|
||||
@ -50,18 +54,21 @@ EAST =1
|
||||
SOUTH =2
|
||||
WEST =3
|
||||
|
||||
;-- Variables used in drawing
|
||||
;-- Variables used in drawing which can not be changed by the inner drawing loop
|
||||
DRAW_X_START = $5E ; Starting column being drawn (between 0 and VIEWPORT_WIDTH)
|
||||
DRAW_Y_START = $5F ; Starting row being drawn (between 0 and VIEWPORT_WIDTH)
|
||||
DRAW_WIDTH = $62 ; Number of columns to draw for current section (cannot be destroyed by drawing loop)
|
||||
DRAW_HEIGHT = $63 ; Number of rows to draw for current section (cannot be destroyed by drawing loop)
|
||||
DRAW_SECTION = $64 ; Location of section data being drawn
|
||||
TILE_BASE = $6B ; Location of tile data
|
||||
;-- These variables are set in the outer draw section but can be destroyed by the inner routine
|
||||
SECTION_X_START = $60 ; X Offset relative to current section being drawn
|
||||
SECTION_Y_START = $61 ; Y Offset relative to current section being drawn
|
||||
DRAW_WIDTH = $62 ; Number of columns to draw for current section (cannot be destroyed by drawing loop)
|
||||
DRAW_HEIGTH = $63 ; Number of rows to draw for current section (cannot be destroyed by drawing loop)
|
||||
DRAW_SECTION = $64 ; Location of section data being drawn
|
||||
X_COUNTER = $66 ; Loop counter used during drawing
|
||||
Y_COUNTER = $67 ; Loop counter used during drawing
|
||||
ROW_LOCATION = $68 ; Used for pointing at row offset in map data
|
||||
|
||||
Y_LOC = $68 ; Current row being drawn (between 0 and VIEWPORT_WIDTH)
|
||||
ROW_LOCATION = $69 ; Used for pointing at row offset in map data
|
||||
TILE_SOURCE = $6D ; Location of tile data
|
||||
; >> INIT (reset map drawing vars)
|
||||
INIT
|
||||
LDA #NOT_LOADED
|
||||
@ -76,12 +83,12 @@ INIT
|
||||
|
||||
;----------------------------------------------------------------------
|
||||
; >> START LOADING MAP SECTIONS
|
||||
START_LOAD
|
||||
START_MAP_LOAD
|
||||
LDX #0
|
||||
LDA #START_LOAD
|
||||
JMP mainLoader
|
||||
!macro startLoad {
|
||||
JSR START_LOAD
|
||||
JSR START_MAP_LOAD
|
||||
}
|
||||
|
||||
;----------------------------------------------------------------------
|
||||
@ -113,17 +120,17 @@ LOAD_SECTION
|
||||
|
||||
;----------------------------------------------------------------------
|
||||
; >> FINISH LOADING MAP SECTIONS
|
||||
FINISH_LOAD
|
||||
FINISH_MAP_LOAD
|
||||
LDX #0 ; 1 to keep open for next load, 0 for close so you can flip to HGR page 2
|
||||
LDA #FINISH_LOAD
|
||||
JMP mainLoader
|
||||
!macro finishLoad {
|
||||
JSR FINISH_LOAD
|
||||
JSR FINISH_MAP_LOAD
|
||||
}
|
||||
|
||||
;----------------------------------------------------------------------
|
||||
; >> RELEASE MAP SECTION
|
||||
!macro releaseMapSection ptr {
|
||||
; >> RELEASE MAP SECTION OR TILESET
|
||||
!macro freeResource ptr {
|
||||
; --> free up unused resource
|
||||
LDX ptr
|
||||
LDY ptr+1
|
||||
@ -133,6 +140,18 @@ FINISH_LOAD
|
||||
;----------------------------------------------------------------------
|
||||
; >> LOAD TILES
|
||||
; Load tile resource (A = Resource ID)
|
||||
LOAD_TILESET
|
||||
TAY
|
||||
LDX #RES_TYPE_TILESET
|
||||
LDA #QUEUE_LOAD
|
||||
JMP mainLoader
|
||||
!macro loadTileset mapData, ptr {
|
||||
LDY #4
|
||||
LDA (mapData),Y
|
||||
JSR LOAD_TILESET
|
||||
STX ptr
|
||||
STY ptr+1
|
||||
}
|
||||
;----------------------------------------------------------------------
|
||||
; >> MOVE NORTH
|
||||
; Check for boundary
|
||||
@ -170,8 +189,8 @@ SET_XY
|
||||
; >> TRIGGER SCRIPT AT TILE (X,Y = Coordinates in section)
|
||||
;----------------------------------------------------------------------
|
||||
!macro move_word from, to {
|
||||
!move_byte from, to
|
||||
!move_byte from+1, to+1
|
||||
+move_byte from, to
|
||||
+move_byte from+1, to+1
|
||||
}
|
||||
|
||||
!macro move_byte from, to {
|
||||
@ -179,110 +198,139 @@ SET_XY
|
||||
STX to
|
||||
}
|
||||
|
||||
FREE_ALL_TILES
|
||||
+freeResource NW_TILESET_LOC
|
||||
+freeResource NE_TILESET_LOC
|
||||
+freeResource SW_TILESET_LOC
|
||||
+freeResource SE_TILESET_LOC
|
||||
RTS
|
||||
!macro freeAllTiles {
|
||||
JSR FREE_ALL_TILES
|
||||
}
|
||||
|
||||
LOAD_ALL_TILES
|
||||
+loadTileset NW_MAP_LOC, NW_TILESET_LOC
|
||||
+loadTileset NE_MAP_LOC, NW_TILESET_LOC
|
||||
+loadTileset SW_MAP_LOC, NW_TILESET_LOC
|
||||
+loadTileset SE_MAP_LOC, NW_TILESET_LOC
|
||||
RTS
|
||||
!macro loadAllTiles {
|
||||
JSR LOAD_ALL_TILES
|
||||
}
|
||||
|
||||
; >> CROSS NORTH BOUNDARY (Load next section to the north)
|
||||
!zone
|
||||
CROSS_NORTH
|
||||
!releaseMapSection SW_MAP_LOC
|
||||
!releaseMapSection SE_MAP_LOC
|
||||
+freeAllTiles
|
||||
+freeResource SW_MAP_LOC
|
||||
+freeResource SE_MAP_LOC
|
||||
LDA REL_Y
|
||||
CLC
|
||||
ADC #SECTION_HEIGHT
|
||||
STA REL_Y
|
||||
!move_byte NW_MAP_ID, SW_MAP_ID
|
||||
!move_word NW_MAP_LOC, SW_MAP_LOC
|
||||
!move_byte NE_MAP_ID, SE_MAP_ID
|
||||
!move_word NE_MAP_LOC, SE_MAP_LOC
|
||||
+move_byte NW_MAP_ID, SW_MAP_ID
|
||||
+move_word NW_MAP_LOC, SW_MAP_LOC
|
||||
+move_byte NE_MAP_ID, SE_MAP_ID
|
||||
+move_word NE_MAP_LOC, SE_MAP_LOC
|
||||
; Get new NW section
|
||||
!startLoad
|
||||
LDA (SW_MAP_LOC)
|
||||
+startLoad
|
||||
LDY #00
|
||||
LDA (SW_MAP_LOC),Y
|
||||
STA NW_MAP_ID
|
||||
!loadSection NW_MAP_LOC
|
||||
+loadSection NW_MAP_LOC
|
||||
; Get the new NE section
|
||||
LDA (SE_MAP_LOC)
|
||||
LDA (SE_MAP_LOC),Y
|
||||
STA NE_MAP_ID
|
||||
!loadSection NE_MAP_LOC
|
||||
!finishLoad
|
||||
+loadSection NE_MAP_LOC
|
||||
+loadAllTiles
|
||||
+finishLoad
|
||||
RTS
|
||||
;----------------------------------------------------------------------
|
||||
; >> CROSS EAST BOUNDARY (Load next section to the east)
|
||||
!zone
|
||||
CROSS_EAST
|
||||
!releaseMapSection NW_MAP_LOC
|
||||
!releaseMapSection SW_MAP_LOC
|
||||
+freeAllTiles
|
||||
+freeResource NW_MAP_LOC
|
||||
+freeResource SW_MAP_LOC
|
||||
LDA REL_X
|
||||
SEC
|
||||
SBC #SECTION_WIDTH
|
||||
STA REL_X
|
||||
!move_byte NE_MAP_ID, NW_MAP_ID
|
||||
!move_word NE_MAP_LOC, NW_MAP_LOC
|
||||
!move_byte SE_MAP_ID, SW_MAP_ID
|
||||
!move_word SE_MAP_LOC, SW_MAP_LOC
|
||||
+move_byte NE_MAP_ID, NW_MAP_ID
|
||||
+move_word NE_MAP_LOC, NW_MAP_LOC
|
||||
+move_byte SE_MAP_ID, SW_MAP_ID
|
||||
+move_word SE_MAP_LOC, SW_MAP_LOC
|
||||
; Get new NE section
|
||||
!startLoad
|
||||
+startLoad
|
||||
LDY #EAST
|
||||
LDA (NW_MAP_LOC),Y
|
||||
STA NE_MAP_ID
|
||||
!loadSection NE_MAP_LOC
|
||||
+loadSection NE_MAP_LOC
|
||||
; Get the new SE section
|
||||
LDY #EAST
|
||||
LDA (SW_MAP_LOC),Y
|
||||
STA SE_MAP_ID
|
||||
!loadSection SE_MAP_LOC
|
||||
!finishLoad
|
||||
+loadSection SE_MAP_LOC
|
||||
+loadAllTiles
|
||||
+finishLoad
|
||||
RTS
|
||||
;----------------------------------------------------------------------
|
||||
; >> CROSS SOUTH BOUNDARY (Load next section to the south)
|
||||
!zone
|
||||
CROSS_SOUTH
|
||||
!releaseMapSection NW_MAP_LOC
|
||||
!releaseMapSection NE_MAP_LOC
|
||||
+freeAllTiles
|
||||
+freeResource NW_MAP_LOC
|
||||
+freeResource NE_MAP_LOC
|
||||
LDA REL_Y
|
||||
SEC
|
||||
SBC #SECTION_HEIGHT
|
||||
STA REL_Y
|
||||
!move_byte SW_MAP_ID, NW_MAP_ID
|
||||
!move_word SW_MAP_LOC, NW_MAP_LOC
|
||||
!move_byte SE_MAP_ID, NE_MAP_ID
|
||||
!move_word SE_MAP_LOC, NE_MAP_LOC
|
||||
+move_byte SW_MAP_ID, NW_MAP_ID
|
||||
+move_word SW_MAP_LOC, NW_MAP_LOC
|
||||
+move_byte SE_MAP_ID, NE_MAP_ID
|
||||
+move_word SE_MAP_LOC, NE_MAP_LOC
|
||||
; Get new SW section
|
||||
!startLoad
|
||||
+startLoad
|
||||
LDY #SOUTH
|
||||
LDA (NW_MAP_LOC),Y
|
||||
STA SW_MAP_ID
|
||||
!loadSection SW_MAP_LOC
|
||||
+loadSection SW_MAP_LOC
|
||||
; Get the new SE section
|
||||
LDY #SOUTH
|
||||
LDA (NE_MAP_LOC),Y
|
||||
STA SE_MAP_ID
|
||||
!loadSection SE_MAP_LOC
|
||||
!finishLoad
|
||||
+loadSection SE_MAP_LOC
|
||||
+loadAllTiles
|
||||
+finishLoad
|
||||
RTS
|
||||
;----------------------------------------------------------------------
|
||||
; >> CROSS WEST BOUNDARY (load next section to the west)
|
||||
!zone
|
||||
CROSS_WEST
|
||||
!releaseMapSection NE_MAP_LOC
|
||||
!releaseMapSection SE_MAP_LOC
|
||||
+freeAllTiles
|
||||
+freeResource NE_MAP_LOC
|
||||
+freeResource SE_MAP_LOC
|
||||
LDA REL_X
|
||||
CLC
|
||||
ADC #SECTION_WIDTH
|
||||
STA REL_X
|
||||
!move_byte NW_MAP_ID, NE_MAP_ID
|
||||
!move_word NW_MAP_LOC, NE_MAP_LOC
|
||||
!move_byte SW_MAP_ID, SE_MAP_ID
|
||||
!move_word SW_MAP_LOC, SE_MAP_LOC
|
||||
+move_byte NW_MAP_ID, NE_MAP_ID
|
||||
+move_word NW_MAP_LOC, NE_MAP_LOC
|
||||
+move_byte SW_MAP_ID, SE_MAP_ID
|
||||
+move_word SW_MAP_LOC, SE_MAP_LOC
|
||||
; Get new NW section
|
||||
!startLoad
|
||||
+startLoad
|
||||
LDY #WEST
|
||||
LDA (NE_MAP_LOC),Y
|
||||
STA NW_MAP_ID
|
||||
!loadSection NW_MAP_LOC
|
||||
+loadSection NW_MAP_LOC
|
||||
; Get the new SE section
|
||||
LDY #WEST
|
||||
LDA (SE_MAP_LOC),Y
|
||||
STA SW_MAP_ID
|
||||
!loadSection SW_MAP_LOC
|
||||
!finishLoad
|
||||
+loadSection SW_MAP_LOC
|
||||
+loadAllTiles
|
||||
+finishLoad
|
||||
RTS
|
||||
;----------------------------------------------------------------------
|
||||
; >> SET PLAYER TILE (A = tile)
|
||||
@ -291,7 +339,7 @@ CROSS_WEST
|
||||
;----------------------------------------------------------------------
|
||||
; >> DRAW
|
||||
!zone draw
|
||||
!macro drawMapSection ptr, deltaX, deltaY {
|
||||
!macro drawMapSection mapPtr, tilesetPtr, deltaX, deltaY {
|
||||
; Determine X1 and X2 bounds for what is being drawn
|
||||
LDA REL_X
|
||||
SEC
|
||||
@ -304,7 +352,7 @@ CROSS_WEST
|
||||
CLC
|
||||
ADC #VIEWPORT_WIDTH
|
||||
CMP #SECTION_WIDTH
|
||||
BLT .11
|
||||
BMI .11
|
||||
LDA #SECTION_WIDTH
|
||||
.11
|
||||
SEC
|
||||
@ -322,14 +370,15 @@ CROSS_WEST
|
||||
CLC
|
||||
ADC #VIEWPORT_HEIGHT
|
||||
CMP #SECTION_HEIGHT
|
||||
BLT .21
|
||||
BMI .21
|
||||
LDA #SECTION_HEIGHT
|
||||
.21
|
||||
SEC
|
||||
SBC SECTION_Y_START
|
||||
STA DRAW_HEIGHT
|
||||
!move_word ptr, DRAW_SECTION
|
||||
jsr mainDraw
|
||||
+move_word mapPtr, DRAW_SECTION
|
||||
+move_word tilesetPtr, TILE_BASE
|
||||
JSR MainDraw
|
||||
}
|
||||
|
||||
DRAW
|
||||
@ -340,20 +389,22 @@ DRAW
|
||||
.checkNorthQuads
|
||||
LDA REL_Y
|
||||
CMP SECTION_HEIGHT+VIEWPORT_VERT_PAD
|
||||
BGE .checkSouthQuads
|
||||
BMI .checkNWQuad
|
||||
JMP .checkSouthQuads
|
||||
.checkNWQuad
|
||||
; Check for NW quadrant area
|
||||
LDA REL_X
|
||||
CMP SECTION_WIDTH+VIEWPORT_HORIZ_PAD
|
||||
BGE .checkNEQuad
|
||||
!drawMapSection NW_MAP_LOC, 0, 0
|
||||
BPL .checkNEQuad
|
||||
+drawMapSection NW_MAP_LOC, NW_TILESET_LOC, 0, 0
|
||||
; Check for NE quadrant area
|
||||
.checkNEQuad
|
||||
LDA REL_X
|
||||
CMP #VIEWPORT_HORIZ_PAD+1
|
||||
BLT .finishTopQuads
|
||||
BMI .finishTopQuads
|
||||
LDA DRAW_WIDTH
|
||||
STA DRAW_X_START
|
||||
!drawMapSection NE_MAP_LOC, SECTION_WIDTH, 0
|
||||
+drawMapSection NE_MAP_LOC, NE_TILESET_LOC, SECTION_WIDTH, 0
|
||||
.finishTopQuads
|
||||
;Update Y start for bottom quadrants
|
||||
LDA DRAW_HEIGHT
|
||||
@ -365,21 +416,21 @@ DRAW
|
||||
; Check for SW quadrant area
|
||||
LDA REL_X
|
||||
CMP SECTION_WIDTH+VIEWPORT_HORIZ_PAD
|
||||
BGE .checkSEQuad
|
||||
!drawMapSection SW_MAP_LOC, 0, SECTION_HEIGHT
|
||||
BPL .checkSEQuad
|
||||
+drawMapSection SW_MAP_LOC, SW_TILESET_LOC, 0, SECTION_HEIGHT
|
||||
.checkSEQuad
|
||||
; Check for SE quadrand area
|
||||
LDA REL_X
|
||||
CMP #VIEWPORT_HORIZ_PAD+1
|
||||
BGE .drawSEQuad
|
||||
BPL .drawSEQuad
|
||||
RTS
|
||||
.drawSEQuad
|
||||
LDA DRAW_WIDTH
|
||||
STA DRAW_X_START
|
||||
!drawMapSection SE_MAP_LOC, SECTION_WIDTH, SECTION_HEIGHT
|
||||
+drawMapSection SE_MAP_LOC, SE_TILESET_LOC, SECTION_WIDTH, SECTION_HEIGHT
|
||||
RTS
|
||||
|
||||
.mainDraw
|
||||
MainDraw
|
||||
;----- Tracking visible tile data -----
|
||||
;There are a total of 512 screen holes in a hires page located in xx78-xx7F and xxF8-xxFF
|
||||
;We only need 81 screen holes to track the 9x9 visible area. So to do this a little translation is needed
|
||||
@ -399,9 +450,14 @@ DRAW
|
||||
COL_OFFSET = 2
|
||||
ROW_OFFSET = 3
|
||||
|
||||
LDA DRAW_HEIGHT
|
||||
STA Y_COUNTER
|
||||
LDA DRAW_Y_START
|
||||
STA Y_LOC
|
||||
.rowLoop
|
||||
; Identify start of map data (upper left)
|
||||
; Self-modifying code: Update all the STA statements in the drawTile section
|
||||
LDY DRAW_Y_START
|
||||
LDY Y_LOC
|
||||
LDA tblHGRl+ROW_OFFSET, Y
|
||||
ADC #COL_OFFSET
|
||||
TAX
|
||||
@ -431,7 +487,7 @@ ROW_OFFSET = 3
|
||||
CLC
|
||||
LDA SECTION_Y_START ;row * 2
|
||||
ASL
|
||||
ADC #HEADER_LENGTH
|
||||
ADC #HEADER_LENGTH ; +6
|
||||
ADC SECTION_X_START
|
||||
STA ROW_LOCATION
|
||||
LDA SECTION_Y_START ; row * 4
|
||||
@ -449,24 +505,15 @@ ROW_OFFSET = 3
|
||||
LDA DRAW_SECTION + 1
|
||||
ADC #$00 ; This is a short way for handling carry without a branch
|
||||
STA ROW_LOCATION + 1
|
||||
LDA DRAW_SECTION
|
||||
LDA DRAW_SECTION ; DRAW_SECTION is done at the very end in case it causes an overflow
|
||||
ADC ROW_LOCATION
|
||||
STA ROW_LOCATION
|
||||
; Handle carry if needed
|
||||
BCC .doneCalculatingLocation
|
||||
INC ROW_LOCATION + 1
|
||||
.doneCalculatingLocation
|
||||
CLC
|
||||
LDA SECTION_Y_START
|
||||
ASL
|
||||
ADC ROW_LOCATION
|
||||
STA ROW_LOCATION
|
||||
LDA SECTION_Y_START
|
||||
ASL
|
||||
ASL
|
||||
ADC ROW_LOCATION
|
||||
STA ROW_LOCATION
|
||||
|
||||
LDA DRAW_WIDTH
|
||||
STA X_COUNTER
|
||||
LDX DRAW_X_START
|
||||
; Display row of tiles
|
||||
.next_col
|
||||
@ -479,15 +526,15 @@ ROW_OFFSET = 3
|
||||
ASL
|
||||
ASL
|
||||
STA TILE_SOURCE
|
||||
LDA TILE_BASE
|
||||
LDA TILE_BASE + 1
|
||||
ADC #$00
|
||||
STA TILE_SOURCE+1
|
||||
LDA TILE_BASE
|
||||
ADC TILE_SOURCE
|
||||
STA TILE_SOURCE
|
||||
BCC .doenCalculatingTileLocation
|
||||
BCC .doneCalculatingTileLocation
|
||||
INC TILE_SOURCE+1
|
||||
.doenCalculatingTileLocation
|
||||
.doneCalculatingTileLocation
|
||||
; Is there a NPC there?
|
||||
; No, use map tile
|
||||
; Yes, use NPC tile
|
||||
@ -502,27 +549,33 @@ ROW_OFFSET = 3
|
||||
ASL
|
||||
TAX
|
||||
.drawTile !for row, 16 {
|
||||
.0 LDA (TILE_SOURCE),Y
|
||||
.2 STA DRAW_ROW, X
|
||||
.5 INY
|
||||
.6 INX
|
||||
.7 LDA (TILE_SOURCE),Y
|
||||
.9 STA DRAW_ROW, X
|
||||
!if row < 15 {
|
||||
.12 INY
|
||||
.13 DEX
|
||||
}
|
||||
LDA (TILE_SOURCE),Y ;0
|
||||
STA $2000, X ;2
|
||||
INY ;5
|
||||
INX ;6
|
||||
LDA (TILE_SOURCE),Y ;7
|
||||
STA $2000, X ;9
|
||||
!if row < 15 {
|
||||
INY ;12
|
||||
DEX ;13
|
||||
}
|
||||
}
|
||||
DEC X_COUNTER
|
||||
BMI .next_row
|
||||
INX
|
||||
TXA ; Outside the drawing part we need to put X back (divide by 2)
|
||||
LSR
|
||||
TAX
|
||||
BNE .next_col
|
||||
JMP .next_col
|
||||
; Increment row
|
||||
.next_row
|
||||
|
||||
DEC Y_COUNTER
|
||||
BPL .notDone
|
||||
RTS
|
||||
.notDone
|
||||
INC Y_LOC
|
||||
INC SECTION_Y_START
|
||||
JMP .rowLoop
|
||||
; Draw player
|
||||
|
||||
tblHGRl
|
||||
|
Loading…
x
Reference in New Issue
Block a user