mirror of
https://github.com/dschmenk/PLASMA.git
synced 2025-02-20 17:29:11 +00:00
Merge pull request #1 from dschmenk/master
Merge latest upstream master to my master
This commit is contained in:
commit
7477f66acc
269
README.md
269
README.md
@ -1,8 +1,8 @@
|
||||
<center>
|
||||
# The PLASMA Programming Language
|
||||

|
||||
|
||||

|
||||
image credit: Luc Viatour / www.Lucnix.be
|
||||
</center>
|
||||
|
||||
|
||||
PLASMA: **P**roto **L**anguage **A**s**S**e**M**bler for **A**pple
|
||||
|
||||
@ -17,83 +17,83 @@ Different projects have led to the architecture of PLASMA, most notably Apple Pa
|
||||
<!-- TOC depthFrom:1 depthTo:6 withLinks:1 updateOnSave:1 orderedList:0 -->
|
||||
|
||||
- [Build Environment](#build-environment)
|
||||
- [acme Cross-Assembler](#acme-cross-assembler)
|
||||
- [PLASMA Source](#plasma-source)
|
||||
- [Portable VM](#portable-vm)
|
||||
- [Target VM](#target-vm)
|
||||
- [acme Cross-Assembler](#acme-cross-assembler)
|
||||
- [PLASMA Source](#plasma-source)
|
||||
- [Portable VM](#portable-vm)
|
||||
- [Target VM](#target-vm)
|
||||
- [Tutorial](#tutorial)
|
||||
- [PLASMA Compiler/Assembler](#plasma-compilerassembler)
|
||||
- [PLASMA Modules](#plasma-modules)
|
||||
- [Data Types](#data-types)
|
||||
- [Obligatory 'Hello World'](#obligatory-hello-world)
|
||||
- [Character Case](#character-case)
|
||||
- [Comments](#comments)
|
||||
- [Numbers](#numbers)
|
||||
- [Characters](#characters)
|
||||
- [Strings](#strings)
|
||||
- [Organization of a PLASMA Source File](#organization-of-a-plasma-source-file)
|
||||
- [Module Dependencies](#module-dependencies)
|
||||
- [File Inclusion](#file-inclusion)
|
||||
- [Predefined Functions](#predefined-functions)
|
||||
- [Constant Declarations](#constant-declarations)
|
||||
- [Structure Declarations](#structure-declarations)
|
||||
- [Global Data & Variables Declarations](#global-data-variables-declarations)
|
||||
- [Function Definitions](#function-definitions)
|
||||
- [Statements and Expressions](#statements-and-expressions)
|
||||
- [Exported Declarations](#exported-declarations)
|
||||
- [Module Main Initialization Function](#module-main-initialization-function)
|
||||
- [Module Done](#module-done)
|
||||
- [Runtime](#runtime)
|
||||
- [PLASMA Compiler/Assembler](#plasma-compilerassembler)
|
||||
- [PLASMA Modules](#plasma-modules)
|
||||
- [Data Types](#data-types)
|
||||
- [Obligatory 'Hello World'](#obligatory-hello-world)
|
||||
- [Character Case](#character-case)
|
||||
- [Comments](#comments)
|
||||
- [Numbers](#numbers)
|
||||
- [Characters](#characters)
|
||||
- [Strings](#strings)
|
||||
- [Organization of a PLASMA Source File](#organization-of-a-plasma-source-file)
|
||||
- [Module Dependencies](#module-dependencies)
|
||||
- [File Inclusion](#file-inclusion)
|
||||
- [Predefined Functions](#predefined-functions)
|
||||
- [Constant Declarations](#constant-declarations)
|
||||
- [Structure Declarations](#structure-declarations)
|
||||
- [Global Data & Variables Declarations](#global-data-variables-declarations)
|
||||
- [Function Definitions](#function-definitions)
|
||||
- [Statements and Expressions](#statements-and-expressions)
|
||||
- [Exported Declarations](#exported-declarations)
|
||||
- [Module Main Initialization Function](#module-main-initialization-function)
|
||||
- [Module Done](#module-done)
|
||||
- [Runtime](#runtime)
|
||||
- [Reference](#reference)
|
||||
- [Decimal and Hexadecimal Numbers](#decimal-and-hexadecimal-numbers)
|
||||
- [Character and String Literals](#character-and-string-literals)
|
||||
- [In-line String Literals](#in-line-string-literals)
|
||||
- [Words](#words)
|
||||
- [Bytes](#bytes)
|
||||
- [Addresses](#addresses)
|
||||
- [Arrays](#arrays)
|
||||
- [Type Overrides](#type-overrides)
|
||||
- [Multi-Dimensional Arrays](#multi-dimensional-arrays)
|
||||
- [Offsets (Structure Elements)](#offsets-structure-elements)
|
||||
- [Defining Structures](#defining-structures)
|
||||
- [Pointers](#pointers)
|
||||
- [Pointer Dereferencing](#pointer-dereferencing)
|
||||
- [Addresses of Data/Code](#addresses-of-datacode)
|
||||
- [Function Pointers](#function-pointers)
|
||||
- [Function Definitions](#function-definitions)
|
||||
- [Expressions and Statements](#expressions-and-statements)
|
||||
- [Address Operators](#address-operators)
|
||||
- [Arithmetic, Bitwise, and Logical Operators](#arithmetic-bitwise-and-logical-operators)
|
||||
- [Assignment](#assignment)
|
||||
- [Empty Assignments](#empty-assignments)
|
||||
- [Increment and Decrement](#increment-and-decrement)
|
||||
- [Control Flow](#control-flow)
|
||||
- [CALL](#call)
|
||||
- [RETURN](#return)
|
||||
- [IF/[ELSIF]/[ELSE]/FIN](#ifelsifelsefin)
|
||||
- [WHEN/IS/[OTHERWISE]/WEND](#whenisotherwisewend)
|
||||
- [FOR \<TO,DOWNTO\> [STEP]/NEXT](#for-todownto-stepnext)
|
||||
- [WHILE/LOOP](#whileloop)
|
||||
- [REPEAT/UNTIL](#repeatuntil)
|
||||
- [CONTINUE](#continue)
|
||||
- [BREAK](#break)
|
||||
- [Decimal and Hexadecimal Numbers](#decimal-and-hexadecimal-numbers)
|
||||
- [Character and String Literals](#character-and-string-literals)
|
||||
- [In-line String Literals](#in-line-string-literals)
|
||||
- [Words](#words)
|
||||
- [Bytes](#bytes)
|
||||
- [Addresses](#addresses)
|
||||
- [Arrays](#arrays)
|
||||
- [Type Overrides](#type-overrides)
|
||||
- [Multi-Dimensional Arrays](#multi-dimensional-arrays)
|
||||
- [Offsets (Structure Elements)](#offsets-structure-elements)
|
||||
- [Defining Structures](#defining-structures)
|
||||
- [Pointers](#pointers)
|
||||
- [Pointer Dereferencing](#pointer-dereferencing)
|
||||
- [Addresses of Data/Code](#addresses-of-datacode)
|
||||
- [Function Pointers](#function-pointers)
|
||||
- [Function Definitions](#function-definitions)
|
||||
- [Expressions and Statements](#expressions-and-statements)
|
||||
- [Address Operators](#address-operators)
|
||||
- [Arithmetic, Bitwise, and Logical Operators](#arithmetic-bitwise-and-logical-operators)
|
||||
- [Assignment](#assignment)
|
||||
- [Empty Assignments](#empty-assignments)
|
||||
- [Increment and Decrement](#increment-and-decrement)
|
||||
- [Control Flow](#control-flow)
|
||||
- [CALL](#call)
|
||||
- [RETURN](#return)
|
||||
- [IF/[ELSIF]/[ELSE]/FIN](#ifelsifelsefin)
|
||||
- [WHEN/IS/[OTHERWISE]/WEND](#whenisotherwisewend)
|
||||
- [FOR \<TO,DOWNTO\> [STEP]/NEXT](#for-todownto-stepnext)
|
||||
- [WHILE/LOOP](#whileloop)
|
||||
- [REPEAT/UNTIL](#repeatuntil)
|
||||
- [CONTINUE](#continue)
|
||||
- [BREAK](#break)
|
||||
- [Advanced Topics](#advanced-topics)
|
||||
- [Code Optimizations](#code-optimizations)
|
||||
- [Functions Without Parameters Or Local Variables](#functions-without-parameters-or-local-variables)
|
||||
- [Return Values](#return-values)
|
||||
- [Native Assembly Functions](#native-assembly-functions)
|
||||
- [Code Optimizations](#code-optimizations)
|
||||
- [Functions Without Parameters Or Local Variables](#functions-without-parameters-or-local-variables)
|
||||
- [Return Values](#return-values)
|
||||
- [Native Assembly Functions](#native-assembly-functions)
|
||||
- [Implementation](#implementation)
|
||||
- [A New Approach](#a-new-approach)
|
||||
- [The Virtual Machine](#the-virtual-machine)
|
||||
- [The Stacks](#the-stacks)
|
||||
- [Evaluation Stack](#evaluation-stack)
|
||||
- [Call Stack](#call-stack)
|
||||
- [Local Frame Stack](#local-frame-stack)
|
||||
- [Local String Pool](#local-string-pool)
|
||||
- [The Bytecodes](#the-bytecodes)
|
||||
- [Apple I PLASMA](#apple-i-plasma)
|
||||
- [Apple II PLASMA](#apple-ii-plasma)
|
||||
- [Apple III PLASMA](#apple-iii-plasma)
|
||||
- [A New Approach](#a-new-approach)
|
||||
- [The Virtual Machine](#the-virtual-machine)
|
||||
- [The Stacks](#the-stacks)
|
||||
- [Evaluation Stack](#evaluation-stack)
|
||||
- [Call Stack](#call-stack)
|
||||
- [Local Frame Stack](#local-frame-stack)
|
||||
- [Local String Pool](#local-string-pool)
|
||||
- [The Bytecodes](#the-bytecodes)
|
||||
- [Apple I PLASMA](#apple-i-plasma)
|
||||
- [Apple II PLASMA](#apple-ii-plasma)
|
||||
- [Apple III PLASMA](#apple-iii-plasma)
|
||||
- [Links](#links)
|
||||
|
||||
<!-- /TOC -->
|
||||
@ -365,9 +365,29 @@ byte[64] txtfile = "UNTITLED"
|
||||
|
||||
### Function Definitions
|
||||
|
||||
Functions are defined after all constants, variables and data. Function definitions can be `export`ed for inclusion in other modules and can be forward declared with a `predef` type in the constant and variable declarations. Functions can take parameters, passed on the evaluation stack, then copied to the local frame for easy access. They can have their own variable declarations, however, unlike the global declarations, no data can be predeclared - only storage space. A local frame is built for every function invocation and there is also a limit of 254 bytes of local storage. Each parameter takes two bytes of local storage, plus two bytes for the previous frame pointer. If a function has no parameters or local variables, no local frame will be created, improving performance. Functions always return a value; a function can specify a value to return or, if no return value is specified, a default of 0 will be returned.
|
||||
Functions are defined after all constants, variables and data. Function definitions can be `export`ed for inclusion in other modules and can be forward declared with a `predef` type in the constant and variable declarations. Functions can take parameters, passed on the evaluation stack, then copied to the local frame for easy access. They can have their own variable declarations, however, unlike the global declarations, no data can be predeclared - only storage space. A local frame is built for every function invocation and there is also a limit of 254 bytes of local storage. Each parameter takes two bytes of local storage, plus two bytes for the previous frame pointer. If a function has no parameters or local variables, no local frame will be created, improving performance. Functions always return a single value by default.
|
||||
```
|
||||
def myfunc(a, b) // Two parameters and defaults to one returned value
|
||||
```
|
||||
The number of values to return can be set by appending the number of values after the function definition with the '#' syntax, such as:
|
||||
|
||||
Note: there is no mechanism to ensure caller and callee agree on the number of parameters. Historically, programmers have used Hungarian Notation (http://en.wikipedia.org/wiki/Hungarian_notation) to embed the parameter number and type in the function name itself. This is a notational aid; the compiler enforces nothing.
|
||||
```
|
||||
def myfuncA(a, b)#3 // Two parameters and three returned values
|
||||
```
|
||||
A definition with no parameters but with return values can be written as:
|
||||
```
|
||||
def myfuncB#2 // No parameters and two returned values
|
||||
```
|
||||
A pre-defined definition should include the same number of parameters and return values as the definition:
|
||||
```
|
||||
predef myfuncA(a, b)#3
|
||||
```
|
||||
A value used as a function pointer doesn't have the parameter/return value count associated with it. It can be overridden in-line:
|
||||
```
|
||||
word funcptr = @myfuncA
|
||||
funcptr(2, 4)#3
|
||||
```
|
||||
If fewer values are returned, the remaining values will be padded with zero. It is an error to return more values than specified. Definitions returning zero values are ok and can save some stack clean-up if the definitions are called stand-alone (i.e. as a procedure).
|
||||
|
||||
After functions are defined, the main code for the module follows. The main code will be executed as soon as the module is loaded. For library modules, this is a good place to do any runtime initialization, before any of the exported functions are called. The last statement in the module must be done, or else a compile error is issued.
|
||||
|
||||
@ -394,6 +414,23 @@ byte numchars
|
||||
numchars = 0
|
||||
```
|
||||
|
||||
Multi-value assignments are written with lvalues separated by commas, and the same number of rvalues separated by commas:
|
||||
```
|
||||
a, b, c = 2, 4, 6
|
||||
```
|
||||
Definitions can return values that contribute to the rvalue count:
|
||||
```
|
||||
def myfuncC(p1, p2)#2
|
||||
return p1+p2, p1-p2
|
||||
end
|
||||
|
||||
a, b, c = 2, myfuncC(6, 7) // Note: myfuncC returns 2 values
|
||||
```
|
||||
A quick way to swap variables could be written:
|
||||
```
|
||||
a, b = b, a
|
||||
```
|
||||
|
||||
Expressions can be built up with constants, variables, function calls, addresses, and pointers/arrays. Comparison operators evaluate to 0 or -1 instead of the more traditional 0 or 1. The use of -1 allows binary operations to be applied to other non-zero values and still retain a non-zero result. Any conditional tests check only for zero and non-zero values.
|
||||
|
||||
There are four basic types of data that can be manipulated: constants, variables, addresses, and functions. Memory can only be read or written as either a byte or a word. Bytes are unsigned 8-bit quantities, words are signed 16-bit quantities. Everything on the evaluation stack is treated as a word. Other than that, any value can be treated as a pointer, address, function, character, integer, etc. There are convenience operations in PLASMA to easily manipulate addresses and expressions as pointers, arrays, structures, functions, or combinations thereof. If a variable is declared as a byte, it can be accessed as a simple, single dimension byte array by using brackets to indicate the offset. Any expression can calculate the indexed offset. A word variable can be accessed as a word array in the same fashion. In order to access expressions or constants as arrays, a type identifier has to be inserted before the brackets. a `.` character denotes a byte type, a `:` character denotes a word type. Along with brackets to calculate an indexed offset, a constant can be used after the `.` or `:` and will be added to the base address. The constant can be a defined const to allow for structure style syntax. If the offset is a known constant, using the constant offset is a much more efficient way to address the elements over an array index. Multidimensional arrays are treated as arrays of array pointers.
|
||||
@ -611,7 +648,7 @@ Numbers can be represented in either decimal (base 10), or hexadecimal (base 16)
|
||||
|
||||
## Character and String Literals
|
||||
|
||||
A character literal, represented by a single character or an escaped character enclosed in single quotes `'`, can be used wherever a number is used. String literals, a character sequence enclosed in double quotes `"`, can only appear in a data definition. A length byte will be calculated and prepended to the character data. This is the Pascal style of string definition used throughout PLASMA and ProDOS. When referencing the string, its address is used:
|
||||
A character literal, represented by a single character or an escaped character enclosed in single quotes `'`, can be used wherever a number is used. A length byte will be calculated and prepended to the character data. This is the Pascal style of string definition used throughout PLASMA and ProDOS. When referencing the string, its address is used:
|
||||
|
||||
```
|
||||
char mystring[] = "This is my string; I am very proud of it."
|
||||
@ -640,55 +677,7 @@ Strings can be used as literals inside expression or as parameters. The above pu
|
||||
puts("This is my string; I am very proud of it.")
|
||||
```
|
||||
|
||||
just like any proper language. This makes coding a much simpler task when it comes to spitting out strings to the screen. However (there always has to be a 'However'), nothing comes for free. Since PLASMA doesn't have garbage collection, memory is allocated on the stack frame for the string every time it is encountered. Translation: you can easily chew up many K of memory if you aren't careful. The memory is recovered when the function exits, just like the rest of the local variables.
|
||||
|
||||
Don't do this:
|
||||
|
||||
```
|
||||
word i
|
||||
|
||||
for i = 0 to 10000
|
||||
puts("I am eating all your memory!")
|
||||
next
|
||||
```
|
||||
|
||||
That string will be allocated anew every time through the loop. Instead, you could put the string in initialized memory, create a pointer to it before the loop, or put all the string handling in a function that gets called from inside the loop:
|
||||
|
||||
```
|
||||
byte nicestr = "This is a nice string"
|
||||
word i
|
||||
|
||||
for i = 0 to 10000
|
||||
puts(@nicestr)
|
||||
next
|
||||
```
|
||||
|
||||
or:
|
||||
|
||||
```
|
||||
word i, nicestr
|
||||
|
||||
nicerstr = "This is a nicer string"
|
||||
for i = 0 to 10000
|
||||
puts(nicestr)
|
||||
next
|
||||
```
|
||||
|
||||
or:
|
||||
|
||||
```
|
||||
word i
|
||||
|
||||
def putstr
|
||||
puts("This is a nice string, too")
|
||||
end
|
||||
|
||||
for i = 0 to 10000
|
||||
putstr
|
||||
next
|
||||
```
|
||||
|
||||
If you are curious as to why in-line strings behave this way, it is due to putting the string constant right into the bytecode stream, which makes it easy to compile and interpret. Also, when bytecode is placed in AUX memory (or extended memory in the Apple ///), it relieves the pressure of keeping all the in-line strings in precious main memory all the time. A normal compiler would move in-line strings into anonymous data memory and reference it from there. PLASMA now has a string pool associated with each function invocation, just like the local variable frame. It grows dynamically as strings are encountered and gives them an address in main memory until the function exits, freeing the string pool for that function. PLASMA is too dumb (and I'm too lazy) to implement a real string manager inside the compiler/VM. That would make for a nice library module, though.
|
||||
just like any proper language. This makes coding a much simpler task when it comes to spitting out strings to the screen.
|
||||
|
||||
## Words
|
||||
|
||||
@ -769,13 +758,13 @@ word = $2080,$2480,$2880,$2C80,$3080,$3480,$3880,$3C80
|
||||
|
||||
```
|
||||
def hgrfill(val)
|
||||
byte yscan, xscan
|
||||
byte yscan, xscan
|
||||
|
||||
for yscan = 0 to 191
|
||||
for xscan = 0 to 19
|
||||
hgrscan:[yscan, xscan] = val
|
||||
next
|
||||
next
|
||||
for yscan = 0 to 191
|
||||
for xscan = 0 to 19
|
||||
hgrscan:[yscan, xscan] = val
|
||||
next
|
||||
next
|
||||
end
|
||||
```
|
||||
|
||||
@ -783,13 +772,13 @@ Every array dimension except the last is a pointer to another array of pointers,
|
||||
|
||||
```
|
||||
def hgrfill(val)
|
||||
byte yscan, xscan
|
||||
byte yscan, xscan
|
||||
|
||||
for yscan = 0 to 191
|
||||
for xscan = 0 to 39
|
||||
hgrscan.[yscan, xscan] = val
|
||||
next
|
||||
next
|
||||
for yscan = 0 to 191
|
||||
for xscan = 0 to 39
|
||||
hgrscan.[yscan, xscan] = val
|
||||
next
|
||||
next
|
||||
end
|
||||
```
|
||||
|
||||
|
BIN
SANDBOX.PO
Normal file → Executable file
BIN
SANDBOX.PO
Normal file → Executable file
Binary file not shown.
178
doc/Rogue Instructions.rtf
Executable file
178
doc/Rogue Instructions.rtf
Executable file
@ -0,0 +1,178 @@
|
||||
{\rtf1\ansi\ansicpg1252\cocoartf1343\cocoasubrtf160
|
||||
{\fonttbl\f0\froman\fcharset0 TimesNewRomanPSMT;\f1\fmodern\fcharset0 Courier;\f2\fswiss\fcharset0 Helvetica;
|
||||
}
|
||||
{\colortbl;\red255\green255\blue255;}
|
||||
{\info
|
||||
{\author David Schmenk}}\margl1440\margr1440\vieww12540\viewh16140\viewkind1
|
||||
\deftab720
|
||||
\pard\pardeftab720\qc
|
||||
|
||||
\f0\b\fs36 \cf0 \expnd0\expndtw0\kerning0
|
||||
PLASMA goes ROGUE\
|
||||
\pard\pardeftab720
|
||||
|
||||
\fs28 \cf0 \expnd0\expndtw0\kerning0
|
||||
\ul \ulc0 Introduction\
|
||||
\pard\pardeftab720
|
||||
|
||||
\b0\fs24 \cf0 \expnd0\expndtw0\kerning0
|
||||
\ulnone This version of ROGUE is somewhat different than others. It is very simple in most ways, but I have developed a (I think) unique visibility algorithm that runs extremely fast. Fast enough to run interpreted by the PLASMA VM on a 1 MHz 6502, and space efficient enough to allow for large (in the future) dungeons. The unique feature of this ROGUE is that lighting becomes critical and strategic. You are in dark catacombs, after all. You enter with a lit lamp, throwing off a circle of light. There are also torches throughout the catacombs that light up a small surrounding circle of light. Other items in the catacombs are mana (health+energy increase), a key, a raft, and gold. You will also encounter a number of enemies that will track you down to try and kill you. You will also encounter doors, locked doors, windows, water, and crevasses.\
|
||||
\
|
||||
\pard\pardeftab720
|
||||
|
||||
\b\fs28 \cf0 \expnd0\expndtw0\kerning0
|
||||
\ul \ulc0 Strategy\
|
||||
\pard\pardeftab720
|
||||
|
||||
\b0\fs24 \cf0 \expnd0\expndtw0\kerning0
|
||||
\ulnone As you travel through the catacombs, you must watch your health, energy, and lamp oil levels. Once health reaches zero, you are dead. As energy reaches zero, your vision will narrow and you will no longer be able to run. When the lamp oil runs out, you will be cast into darkness. If you see any torches in your field of vision, you can navigate to them. Taking the torch will extinguish the torch and replenish some of your lamp oil. Note that as you travel through the catacombs, your map of what you have seen will automatically fill in. But, if you are in the dark, you cannot read your map. You must turn on your lamp or get next to a torch before you can read the map again. If you are in the dark and can\'92t see any torches in your field of vision, you are in complete darkness. It is easy to lose your bearings. As such, the absolute direction movements no longer work (NSEW) - you will end up in a random direction if you try. However, the relative turns, left/right and forward/backward controls continue to work (
|
||||
\b \expnd0\expndtw0\kerning0
|
||||
that
|
||||
\b0 \expnd0\expndtw0\kerning0
|
||||
you can do in the dark).\
|
||||
\
|
||||
Being in the dark can be advantageous, however. All the enemies in the catacombs can see you if you are in light, just as you can see them. If you are in darkness, they can't see you, and you can move around without being tracked. Don't run into them! Also, don't fall off a crevasse. You will hear certain noises giving you feedback on what is going on. A simple beep when you run into walls. A groan when an enemy moves towards you. A bleep when you pick an item up. Other noises when you fall over an edge or win a battle. These can be used strategically when moving in the dark.\
|
||||
\
|
||||
Health will slowly improve as you move around. However, energy is depleted as you move. Mana will increase both health and energy. If health is already at 100, it won\'92t go any higher. Same for energy, but it is important to keep both high. When energy goes low, you can no longer move quickly and your field-of-vision narrows. When health goes to zero, you are dead.\
|
||||
\
|
||||
\pard\pardeftab720
|
||||
|
||||
\b\fs28 \cf0 \expnd0\expndtw0\kerning0
|
||||
\ul \ulc0 Tile Description\
|
||||
\pard\pardeftab720
|
||||
|
||||
\b0\fs24 \cf0 \expnd0\expndtw0\kerning0
|
||||
\ulnone As ROGUE uses the text screen for display, a little creativity is required to interpret the map. These are the characters you will see and what the represent. Once you get the hang of it, it will be just like looking at the unencoded Matrix.\
|
||||
\
|
||||
\pard\pardeftab720
|
||||
|
||||
\f1 \cf0 \expnd0\expndtw0\kerning0
|
||||
\ul \ulc0 Screen Character\expnd0\expndtw0\kerning0
|
||||
\ulnone \'a0 \'a0 \'a0\expnd0\expndtw0\kerning0
|
||||
\ul Represents\
|
||||
\pard\pardeftab720
|
||||
\cf0 \expnd0\expndtw0\kerning0
|
||||
\ulnone \'a0\'a0\'a0# \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Wall\
|
||||
\'a0\'a0\'a0. \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Floor\
|
||||
\'a0\'a0\'a0: \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Window (barred opening)\
|
||||
\'a0 \'a0+ \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Door\
|
||||
\'a0 \'a0% \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Locked Door (need key to open)\
|
||||
\'a0\'a0\'a0' ' space \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Crevasse (pit - don't fall in)\
|
||||
\'a0\'a0\'a0= \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Exit\
|
||||
\'a0\'a0\'a0- \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Entrance\
|
||||
\'a0\'a0\'a0* \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Torch\
|
||||
\'a0\'a0\'a0& \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Mana\
|
||||
\'a0\'a0\'a0, \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Key (yep, hard to spot)\
|
||||
\'a0 \'a0@ \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Raft (need to cross water)\
|
||||
<<< Water\
|
||||
\'a0 \'a0>>> \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Water (you will drown without raft)\
|
||||
\'a0\'a0\'a0$ \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Gold\
|
||||
\
|
||||
\pard\pardeftab720
|
||||
\cf0 \expnd0\expndtw0\kerning0
|
||||
\ul \ulc0 Flashing\expnd0\expndtw0\kerning0
|
||||
\ulnone \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \expnd0\expndtw0\kerning0
|
||||
\ul Entity\
|
||||
\pard\pardeftab720
|
||||
\cf0 \expnd0\expndtw0\kerning0
|
||||
\ulnone \'a0\'a0\'a0T \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Thief\
|
||||
\'a0\'a0\'a0O \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Ogre\
|
||||
\'a0\'a0\'a0Z \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Zombie\
|
||||
\'a0\'a0\'a0R \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Rogue\
|
||||
\
|
||||
\'a0\expnd0\expndtw0\kerning0
|
||||
\ul Player\expnd0\expndtw0\kerning0
|
||||
\ulnone \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \expnd0\expndtw0\kerning0
|
||||
\ul Facing Direction\expnd0\expndtw0\kerning0
|
||||
\ulnone \
|
||||
\'a0\'a0\'a0^ \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0North\
|
||||
\'a0\'a0\'a0\\ \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0NE\
|
||||
\'a0\'a0\'a0> \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0East\
|
||||
\'a0\'a0\'a0/ \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0SE\
|
||||
\'a0\'a0\'a0v \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0South\
|
||||
\'a0\'a0\'a0\\ \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0SW\
|
||||
\'a0\'a0\'a0< \'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0West\
|
||||
\'a0\'a0\'a0/ \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0NW\
|
||||
\
|
||||
\pard\pardeftab720
|
||||
|
||||
\f0 \cf0 \expnd0\expndtw0\kerning0
|
||||
Tiles in light are inverse. Entities are displayed only when lit and in field of view. The map is only visible when lit, i.e lamp is on or standing next to a torch.\
|
||||
\
|
||||
\pard\pardeftab720
|
||||
|
||||
\b\fs28 \cf0 \expnd0\expndtw0\kerning0
|
||||
\ul \ulc0 Interaction\
|
||||
\pard\pardeftab720
|
||||
|
||||
\f1\b0\fs24 \cf0 \expnd0\expndtw0\kerning0
|
||||
\ulc0 Keyboard commands\expnd0\expndtw0\kerning0
|
||||
\ulnone \'a0\'a0\'a0\'a0 \expnd0\expndtw0\kerning0
|
||||
\ul Action\
|
||||
\pard\pardeftab720
|
||||
\cf0 \expnd0\expndtw0\kerning0
|
||||
\ulnone \'a0\'a0\'a0Q \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Run (Quick)\
|
||||
\'a0\'a0\'a0W up-arrow \'a0 \'a0 \'a0 \'a0 \'a0 Forward\
|
||||
\'a0\'a0\'a0S down-arrow \'a0 \'a0 \'a0 \'a0 Backward\
|
||||
\'a0\'a0\'a0A left-arrow \'a0 \'a0 \'a0 \'a0 Turn left\
|
||||
\'a0\'a0\'a0D right-arrow \'a0 \'a0 \'a0 Turn right\
|
||||
\'a0\'a0\'a0I \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Move N\
|
||||
\'a0\'a0\'a0J \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Move W\
|
||||
\'a0\'a0\'a0K \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Move E\
|
||||
\'a0\'a0\'a0M \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Move S\
|
||||
\'a0\'a0\'a0< , \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Turn lamp down\
|
||||
\'a0\'a0\'a0> . \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Turn lamp up/on\
|
||||
\'a0\'a0\'a0O \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Turn lamp off\
|
||||
\'a0\'a0\'a0Space-bar \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Open door\
|
||||
\'a0\'a0\'a0Return \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Pick up item\
|
||||
\'a0\'a0\'a0X \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Exit (die)\
|
||||
\pard\pardeftab720
|
||||
|
||||
\f0 \cf0 \expnd0\expndtw0\kerning0
|
||||
\
|
||||
Whenever you and an enemy end up on the same tile, battle commences. As you win fights, your skill increases, improving your attack effectiveness. As you advance through the catacombs, the enemies become more powerful. You will need to replenish health and energy with mana. Don't forget, the alternative to fighting is stealth in the darkness. During battle, you have the option to run. If you have low energy, you won't get very far. Also, when fighting, you get turned around so you can't depend on the direction you were facing before fighting. Running ('Q'uick) will get you away from enemies but will use much more energy.\
|
||||
\
|
||||
If you should die, restart the game by typing:\
|
||||
\pard\pardeftab720
|
||||
|
||||
\f1 \cf0 \expnd0\expndtw0\kerning0
|
||||
+rogue
|
||||
\f2 \
|
||||
\pard\pardeftab720
|
||||
|
||||
\f0 \cf0 \expnd0\expndtw0\kerning0
|
||||
\
|
||||
\pard\pardeftab720
|
||||
|
||||
\b\fs28 \cf0 \expnd0\expndtw0\kerning0
|
||||
\ul \ulc0 Map Levels\
|
||||
\pard\pardeftab720
|
||||
|
||||
\b0\fs24 \cf0 \expnd0\expndtw0\kerning0
|
||||
\ulnone Level maps are up to 62x62 in size (plus a wall boundary for an effective 64x64 map size). They can be smaller than this. The game will end when it tries to load an non-existent level. Levels start at file name \'93LEVEL0\'93 and can go all the way to \'93LEVEL9\'93, but must be sequential.\
|
||||
\
|
||||
There are two levels included on the disk, and an empty level for you to use as a template.\'a0You\'a0can edit the map levels, and add your own. They are simple ASCII text files. The included sandbox editor can edit the maps right on the disk. type:\
|
||||
\
|
||||
\pard\pardeftab720
|
||||
|
||||
\f1 \cf0 \expnd0\expndtw0\kerning0
|
||||
-sandbox level.empty
|
||||
\f2 \
|
||||
\pard\pardeftab720
|
||||
|
||||
\f0 \cf0 \expnd0\expndtw0\kerning0
|
||||
\
|
||||
after exiting from ROGUE. Make your changes and save it as LEVEL0" to "LEVEL9". The next free level is currently "LEVEL2". You may also edit an existing level:\
|
||||
\
|
||||
\pard\pardeftab720
|
||||
|
||||
\f1 \cf0 \expnd0\expndtw0\kerning0
|
||||
-sandbox level0
|
||||
\f2 \
|
||||
\pard\pardeftab720
|
||||
|
||||
\f0 \cf0 \expnd0\expndtw0\kerning0
|
||||
\
|
||||
for instance.\
|
||||
\
|
||||
}
|
@ -32,7 +32,7 @@ export def portRead
|
||||
end
|
||||
|
||||
def digitalWrite(pin, val)
|
||||
return ^ANN0[pin&3+val&1]
|
||||
return ^ANN0[((pin&3)<<1)+val&1]
|
||||
end
|
||||
|
||||
export def portWrite(val)
|
||||
|
@ -8,11 +8,16 @@ const SPI_SLAVE_READY = '@'
|
||||
const SPI_SLAVE_ERROR = '!'
|
||||
const SPI_SLAVE_BUSY = $FF
|
||||
|
||||
word spiReadWriteByte, spiWriteBytes, spiReadBytes
|
||||
|
||||
asm spiInc
|
||||
!SOURCE "vmsrc/plvmzp.inc"
|
||||
!SOURCE "vmsrc/plvmzp.inc"
|
||||
!CPU 65C02
|
||||
end
|
||||
|
||||
export asm spiXferByte(outbyte)
|
||||
asm spiXferByteStd(outbyte)
|
||||
PHP ; DISABLE INTS
|
||||
SEI
|
||||
STA $C05A ; ENABLE SLAVE
|
||||
LDY #0 ; ASSUME MSB IS ZERO
|
||||
LDA ESTKL,X ; GET ARGUMENT
|
||||
@ -20,7 +25,7 @@ export asm spiXferByte(outbyte)
|
||||
INY ; IT'S A ONE
|
||||
+ STA $C058,Y ; WRITE BIT 7
|
||||
STA $C040 ; CLOCK
|
||||
LDY #0 ; DOING THIS HERE GIVES TIME FOR OUTPUT TO BECOME STABLE - NOT REALLY NEEDEDd
|
||||
LDY #0 ; DOING THIS HERE GIVES TIME FOR OUTPUT TO BECOME STABLE - NOT REALLY NEEDED
|
||||
ASL $C061 ; READ BIT 7 INTO CARRY
|
||||
ROL ; ROTATE INTO ACC
|
||||
BPL + ; REPEAT FOR ALL BITS
|
||||
@ -74,10 +79,93 @@ export asm spiXferByte(outbyte)
|
||||
STA $C05B ; DISABLE SLAVE
|
||||
ROL
|
||||
STA ESTKL,X ; SAVE RETURN PARAMETER
|
||||
PLP
|
||||
RTS
|
||||
end
|
||||
|
||||
asm spiReadBytes(buf, len)
|
||||
asm spiXferByteGS(outbyte)
|
||||
PHP ; DISABLE INTS
|
||||
SEI
|
||||
LDA $C036 ; SET 1 MHZ
|
||||
PHA
|
||||
AND #$7F
|
||||
STA $C036
|
||||
STA $C05A ; ENABLE SLAVE
|
||||
LDY #0 ; ASSUME MSB IS ZERO
|
||||
LDA ESTKL,X ; GET ARGUMENT
|
||||
BPL + ; CHECK MSB
|
||||
INY ; IT'S A ONE
|
||||
+ STA $C058,Y ; WRITE BIT 7
|
||||
STA $C05C ; CLOCK FALLING EDGE
|
||||
LDY #0 ; DOING THIS HERE GIVES TIME FOR OUTPUT TO BECOME STABLE - NOT REALLY NEEDED
|
||||
STA $C05D ; CLOCK RISING EDGE
|
||||
ASL $C061 ; READ BIT 7 INTO CARRY
|
||||
ROL ; ROTATE INTO ACC
|
||||
BPL + ; REPEAT FOR ALL BITS
|
||||
INY
|
||||
+ STA $C058,Y
|
||||
STA $C05C ; CLOCK FALLING EDGE
|
||||
LDY #0
|
||||
STA $C05D ; CLOCK RISING EDGE
|
||||
ASL $C061
|
||||
ROL
|
||||
BPL +
|
||||
INY
|
||||
+ STA $C058,Y
|
||||
STA $C05C ; CLOCK FALLING EDGE
|
||||
LDY #0
|
||||
STA $C05D ; CLOCK RISING EDGE
|
||||
ASL $C061
|
||||
ROL
|
||||
BPL +
|
||||
INY
|
||||
+ STA $C058,Y
|
||||
STA $C05C ; CLOCK FALLING EDGE
|
||||
LDY #0
|
||||
STA $C05D ; CLOCK RISING EDGE
|
||||
ASL $C061
|
||||
ROL
|
||||
BPL +
|
||||
INY
|
||||
+ STA $C058,Y
|
||||
STA $C05C ; CLOCK FALLING EDGE
|
||||
LDY #0
|
||||
STA $C05D ; CLOCK RISING EDGE
|
||||
ASL $C061
|
||||
ROL
|
||||
BPL +
|
||||
INY
|
||||
+ STA $C058,Y
|
||||
STA $C05C ; CLOCK FALLING EDGE
|
||||
LDY #0
|
||||
STA $C05D ; CLOCK RISING EDGE
|
||||
ASL $C061
|
||||
ROL
|
||||
BPL +
|
||||
INY
|
||||
+ STA $C058,Y
|
||||
STA $C05C ; CLOCK FALLING EDGE
|
||||
LDY #0
|
||||
STA $C05D ; CLOCK RISING EDGE
|
||||
ASL $C061
|
||||
ROL
|
||||
BPL +
|
||||
INY
|
||||
+ STA $C058,Y
|
||||
STA $C05C ; CLOCK FALLING EDGE
|
||||
STA $C05D ; CLOCK RISING EDGE
|
||||
ASL $C061
|
||||
STA $C05B ; DISABLE SLAVE
|
||||
ROL
|
||||
STA ESTKL,X ; SAVE RETURN PARAMETER
|
||||
PLA
|
||||
STA $C036
|
||||
PLP
|
||||
RTS
|
||||
end
|
||||
asm spiReadBytesStd(buf, len)
|
||||
PHP ; DISABLE INTS
|
||||
SEI
|
||||
LDA ESTKL+1,X
|
||||
STA DSTL
|
||||
LDA ESTKH+1,X
|
||||
@ -122,10 +210,77 @@ asm spiReadBytes(buf, len)
|
||||
DEC ESTKH,X
|
||||
BNE -
|
||||
INX ; REMOVE AN ARGUMENT
|
||||
PLP
|
||||
RTS
|
||||
end
|
||||
|
||||
asm spiWriteBytes(buf, len)
|
||||
asm spiReadBytesGS(buf, len)
|
||||
PHP ; DISABLE INTS
|
||||
SEI
|
||||
LDA $C036 ; SET 1 MHZ
|
||||
PHA
|
||||
AND #$7F
|
||||
STA $C036
|
||||
LDA ESTKL+1,X
|
||||
STA DSTL
|
||||
LDA ESTKH+1,X
|
||||
STA DSTH
|
||||
LDA ESTKL,X
|
||||
BEQ +
|
||||
INC ESTKH,X
|
||||
+ LDY #$00
|
||||
- STA $C05A ; ENABLE SLAVE
|
||||
STA $C05C ; CLOCK FALLING EDGE
|
||||
STA $C05D ; CLOCK RISING EDGE
|
||||
ASL $C061 ; SHIFT IN ALL BITS STARTING WITH MSB
|
||||
ROL
|
||||
STA $C05C ; CLOCK FALLING EDGE
|
||||
STA $C05D ; CLOCK RISING EDGE
|
||||
ASL $C061
|
||||
ROL
|
||||
STA $C05C ; CLOCK FALLING EDGE
|
||||
STA $C05D ; CLOCK RISING EDGE
|
||||
ASL $C061
|
||||
ROL
|
||||
STA $C05C ; CLOCK FALLING EDGE
|
||||
STA $C05D ; CLOCK RISING EDGE
|
||||
ASL $C061
|
||||
ROL
|
||||
STA $C05C ; CLOCK FALLING EDGE
|
||||
STA $C05D ; CLOCK RISING EDGE
|
||||
ASL $C061
|
||||
ROL
|
||||
STA $C05C ; CLOCK FALLING EDGE
|
||||
STA $C05D ; CLOCK RISING EDGE
|
||||
ASL $C061
|
||||
ROL
|
||||
STA $C05C ; CLOCK FALLING EDGE
|
||||
STA $C05D ; CLOCK RISING EDGE
|
||||
ASL $C061
|
||||
ROL
|
||||
STA $C05C ; CLOCK FALLING EDGE
|
||||
STA $C05D ; CLOCK RISING EDGE
|
||||
ASL $C061
|
||||
STA $C05B ; DISABLE SLAVE
|
||||
ROL
|
||||
STA (DST),Y ; SAVE TO BUFFER
|
||||
INY
|
||||
BNE +
|
||||
INC DSTH
|
||||
+ DEC ESTKL,X
|
||||
BNE -
|
||||
DEC ESTKH,X
|
||||
BNE -
|
||||
INX ; REMOVE AN ARGUMENT
|
||||
PLA
|
||||
STA $C036
|
||||
PLP
|
||||
RTS
|
||||
end
|
||||
|
||||
asm spiWriteBytesStd(buf, len)
|
||||
PHP ; DISABLE INTS
|
||||
SEI
|
||||
LDA ESTKL+1,X
|
||||
STA SRCL
|
||||
LDA ESTKH+1,X
|
||||
@ -142,49 +297,49 @@ asm spiWriteBytes(buf, len)
|
||||
+ STA $C058,Y ; WRITE BIT 7
|
||||
STA $C040 ; CLOCK
|
||||
LDY #0 ; DOING THIS HERE GIVES TIME FOR OUTPUT TO BECOME STABLE
|
||||
ROL ; ROTATE NEXT BIT TO SEND
|
||||
ASL ; ROTATE NEXT BIT TO SEND
|
||||
BPL + ; REPEAT FOR ALL BITS
|
||||
INY
|
||||
+ STA $C058,Y
|
||||
STA $C040
|
||||
LDY #0
|
||||
ROL
|
||||
ASL
|
||||
BPL +
|
||||
INY
|
||||
+ STA $C058,Y
|
||||
STA $C040
|
||||
LDY #0
|
||||
ROL
|
||||
ASL
|
||||
BPL +
|
||||
INY
|
||||
+ STA $C058,Y
|
||||
STA $C040
|
||||
LDY #0
|
||||
ROL
|
||||
ASL
|
||||
BPL +
|
||||
INY
|
||||
+ STA $C058,Y
|
||||
STA $C040
|
||||
LDY #0
|
||||
ROL
|
||||
ASL
|
||||
BPL +
|
||||
INY
|
||||
+ STA $C058,Y
|
||||
STA $C040
|
||||
LDY #0
|
||||
ROL
|
||||
ASL
|
||||
BPL +
|
||||
INY
|
||||
+ STA $C058,Y
|
||||
STA $C040
|
||||
LDY #0
|
||||
ROL
|
||||
ASL
|
||||
BPL +
|
||||
INY
|
||||
+ STA $C058,Y
|
||||
STA $C040
|
||||
STA $C05B ; DISABLE SLAVE
|
||||
INC SRCL
|
||||
INC SRCL
|
||||
BNE +
|
||||
INC SRCH
|
||||
+ DEC ESTKL,X
|
||||
@ -192,9 +347,59 @@ asm spiWriteBytes(buf, len)
|
||||
DEC ESTKH,X
|
||||
BNE -
|
||||
INX ; REMOVE AN ARGUMENT
|
||||
PLP
|
||||
RTS
|
||||
end
|
||||
|
||||
asm spiWriteBytesGS(buf, len)
|
||||
PHP ; DISABLE INTS
|
||||
SEI
|
||||
LDA $C036 ; SET 1 MHZ
|
||||
PHA
|
||||
AND #$7F
|
||||
STA $C036
|
||||
LDA ESTKL+1,X
|
||||
STA SRCL
|
||||
LDA ESTKH+1,X
|
||||
STA SRCH
|
||||
LDA ESTKL,X
|
||||
BEQ +
|
||||
INC ESTKH,X
|
||||
+
|
||||
-- STA $C05A ; ENABLE SLAVE
|
||||
PHX
|
||||
LDX #8
|
||||
LDY #0 ; ASSUME MSB IS ZERO
|
||||
LDA (SRC),Y ; GET BYTE
|
||||
- ASL
|
||||
BCC + ; CHECK MSB
|
||||
INY ; IT'S A ONE
|
||||
+ STA $C058,Y ; WRITE BIT 7
|
||||
STA $C05C ; CLOCK FALLING EDGE
|
||||
STA $C05D ; CLOCK RISING EDGE
|
||||
LDY #0
|
||||
DEX
|
||||
BNE -
|
||||
STA $C05B ; DISABLE SLAVE
|
||||
INC SRCL
|
||||
BNE +
|
||||
INC SRCH
|
||||
+ PLX
|
||||
DEC ESTKL,X
|
||||
BNE --
|
||||
DEC ESTKH,X
|
||||
BNE --
|
||||
INX ; REMOVE AN ARGUMENT
|
||||
PLA
|
||||
STA $C036
|
||||
PLP
|
||||
RTS
|
||||
end
|
||||
|
||||
export def spiXferByte(outbyte)
|
||||
return (spiReadWriteByte)(outbyte)
|
||||
end
|
||||
|
||||
export def spiDelay(time)
|
||||
return call($FCA8, time, 0, 0, 0) // DELAY
|
||||
end
|
||||
@ -203,7 +408,7 @@ export def spiSend(data)
|
||||
byte timeout, status
|
||||
|
||||
for timeout = 1 to 100 step 10
|
||||
status = spiXferByte(data)
|
||||
status = (spiReadWriteByte)(data)
|
||||
if status <> SPI_SLAVE_BUSY
|
||||
return status
|
||||
fin
|
||||
@ -220,20 +425,20 @@ end
|
||||
export def spiWriteBuf(buf, len)
|
||||
spiSend(13) // CMD_BUF_WRITE
|
||||
spiSend(len >> 8); spiSend(len)
|
||||
return spiWriteBytes(buf, len)
|
||||
return (spiWriteBytes)(buf, len)
|
||||
end
|
||||
|
||||
export def spiReadBuf(buf, len)
|
||||
spiSend(12) // CMD_BUF_READ
|
||||
spiSend(len >> 8); spiSend(len)
|
||||
return spiReadBytes(buf, len)
|
||||
return (spiReadBytes)(buf, len)
|
||||
end
|
||||
|
||||
export def spiReady
|
||||
byte timeout
|
||||
|
||||
timeout = 0xFF
|
||||
while spiXferByte(0) <> SPI_SLAVE_READY and timeout // WAIT FOR READY
|
||||
while (spiReadWriteByte)(0) <> SPI_SLAVE_READY and timeout // WAIT FOR READY
|
||||
timeout--
|
||||
spiDelay(10)
|
||||
loop
|
||||
@ -241,9 +446,19 @@ export def spiReady
|
||||
end
|
||||
|
||||
export def spiReset
|
||||
^$C05B
|
||||
^$C05B // DISABLE SLAVE SELECT
|
||||
^$C05D // CLOCK RAISE (GS ONLY)
|
||||
return spiReady
|
||||
end
|
||||
|
||||
if call($FE1F, 0, 0, 0, 1).3 & 1 // GS ID ROUTINE
|
||||
spiReadWriteByte = @spiXferByteStd
|
||||
spiReadBytes = @spiReadBytesStd
|
||||
spiWriteBytes = @spiWriteBytesStd
|
||||
else
|
||||
spiReadWriteByte = @spiXferByteGS
|
||||
spiReadBytes = @spiReadBytesGS
|
||||
spiWriteBytes = @spiWriteBytesGS
|
||||
fin
|
||||
return spiReset <> 0
|
||||
done
|
||||
|
74
src/makefile
Normal file → Executable file
74
src/makefile
Normal file → Executable file
@ -44,8 +44,8 @@ MEMMGR = MEMMGR\#FE1000
|
||||
MEMTEST = MEMTEST\#FE1000
|
||||
FIBER = FIBER\#FE1000
|
||||
PLASM = plasm
|
||||
INCS = toolsrc/tokens.h toolsrc/symbols.h toolsrc/lex.h toolsrc/parse.h toolsrc/codegen.h
|
||||
OBJS = toolsrc/plasm.c toolsrc/parse.o toolsrc/lex.o toolsrc/codegen.o
|
||||
INCS = toolsrc/plasm.h toolsrc/tokens.h toolsrc/symbols.h toolsrc/lex.h toolsrc/parse.h toolsrc/codegen.h
|
||||
OBJS = toolsrc/plasm.c toolsrc/parse.c toolsrc/lex.c toolsrc/codegen.c
|
||||
#
|
||||
# Image filetypes for Virtual ][
|
||||
#
|
||||
@ -83,20 +83,20 @@ $(PLVM): vmsrc/plvm.c
|
||||
cc vmsrc/plvm.c -o $(PLVM)
|
||||
|
||||
vmsrc/a1cmd.a: vmsrc/a1cmd.pla $(PLASM)
|
||||
./$(PLASM) -A < vmsrc/a1cmd.pla > vmsrc/a1cmd.a
|
||||
./$(PLASM) -AO < vmsrc/a1cmd.pla > vmsrc/a1cmd.a
|
||||
|
||||
$(PLVM01): vmsrc/plvm01.s vmsrc/a1cmd.a
|
||||
acme -o $(PLVM01) -l vmsrc/plvm01.sym vmsrc/plvm01.s
|
||||
|
||||
$(CMD): vmsrc/cmd.pla vmsrc/cmdstub.s $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -A < vmsrc/cmd.pla > vmsrc/cmd.a
|
||||
./$(PLASM) -AO < vmsrc/cmd.pla > vmsrc/cmd.a
|
||||
acme --setpc 8192 -o $(CMD) vmsrc/cmdstub.s
|
||||
|
||||
$(PLVM02): vmsrc/plvm02.s
|
||||
acme -o $(PLVM02) -l vmsrc/plvm02.sym vmsrc/plvm02.s
|
||||
|
||||
vmsrc/soscmd.a: vmsrc/soscmd.pla $(PLASM)
|
||||
./$(PLASM) -A < vmsrc/soscmd.pla > vmsrc/soscmd.a
|
||||
./$(PLASM) -AO < vmsrc/soscmd.pla > vmsrc/soscmd.a
|
||||
|
||||
$(PLVM03): vmsrc/plvm03.s vmsrc/soscmd.a
|
||||
acme -o $(PLVM03) -l vmsrc/plvm03.sym vmsrc/plvm03.s
|
||||
@ -105,118 +105,118 @@ $(PLVM03): vmsrc/plvm03.s vmsrc/soscmd.a
|
||||
# Sample code
|
||||
#
|
||||
test: samplesrc/test.pla samplesrc/testlib.pla $(PLVM) $(PLASM)
|
||||
./$(PLASM) -AM < samplesrc/test.pla > samplesrc/test.a
|
||||
./$(PLASM) -AMO < samplesrc/test.pla > samplesrc/test.a
|
||||
acme --setpc 4094 -o $(TEST) samplesrc/test.a
|
||||
./$(PLASM) -AM < samplesrc/testlib.pla > samplesrc/testlib.a
|
||||
./$(PLASM) -AMO < samplesrc/testlib.pla > samplesrc/testlib.a
|
||||
acme --setpc 4094 -o $(TESTLIB) samplesrc/testlib.a
|
||||
./$(PLVM) TEST
|
||||
|
||||
$(ED): toolsrc/ed.pla $(PLVM02) $(PLASM) toolsrc/ed.pla
|
||||
./$(PLASM) -A < toolsrc/ed.pla > toolsrc/ed.a
|
||||
./$(PLASM) -AO < toolsrc/ed.pla > toolsrc/ed.a
|
||||
acme --setpc 8192 -o $(ED) toolsrc/ed.a
|
||||
|
||||
$(SB): toolsrc/sb.pla $(PLVM02) $(PLASM) toolsrc/sb.pla
|
||||
./$(PLASM) -A < toolsrc/sb.pla > toolsrc/sb.a
|
||||
./$(PLASM) -AO < toolsrc/sb.pla > toolsrc/sb.a
|
||||
acme --setpc 8192 -o $(SB) toolsrc/sb.a
|
||||
|
||||
$(ARGS): libsrc/args.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < libsrc/args.pla > libsrc/args.a
|
||||
./$(PLASM) -AMO < libsrc/args.pla > libsrc/args.a
|
||||
acme --setpc 4094 -o $(ARGS) libsrc/args.a
|
||||
|
||||
$(MEMMGR): libsrc/memmgr.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < libsrc/memmgr.pla > libsrc/memmgr.a
|
||||
./$(PLASM) -AMO < libsrc/memmgr.pla > libsrc/memmgr.a
|
||||
acme --setpc 4094 -o $(MEMMGR) libsrc/memmgr.a
|
||||
|
||||
$(MEMTEST): samplesrc/memtest.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < samplesrc/memtest.pla > samplesrc/memtest.a
|
||||
./$(PLASM) -AMO < samplesrc/memtest.pla > samplesrc/memtest.a
|
||||
acme --setpc 4094 -o $(MEMTEST) samplesrc/memtest.a
|
||||
|
||||
$(FIBER): libsrc/fiber.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < libsrc/fiber.pla > libsrc/fiber.a
|
||||
./$(PLASM) -AMO < libsrc/fiber.pla > libsrc/fiber.a
|
||||
acme --setpc 4094 -o $(FIBER) libsrc/fiber.a
|
||||
|
||||
$(MON): samplesrc/mon.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < samplesrc/mon.pla > samplesrc/mon.a
|
||||
./$(PLASM) -AMO < samplesrc/mon.pla > samplesrc/mon.a
|
||||
acme --setpc 4094 -o $(MON) samplesrc/mon.a
|
||||
|
||||
$(ROD): samplesrc/rod.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < samplesrc/rod.pla > samplesrc/rod.a
|
||||
./$(PLASM) -AMOW < samplesrc/rod.pla > samplesrc/rod.a
|
||||
acme --setpc 4094 -o $(ROD) samplesrc/rod.a
|
||||
|
||||
$(SIEVE): samplesrc/sieve.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < samplesrc/sieve.pla > samplesrc/sieve.a
|
||||
./$(PLASM) -AMO < samplesrc/sieve.pla > samplesrc/sieve.a
|
||||
acme --setpc 4094 -o $(SIEVE) samplesrc/sieve.a
|
||||
|
||||
$(UTHERNET): libsrc/uthernet.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < libsrc/uthernet.pla > libsrc/uthernet.a
|
||||
./$(PLASM) -AMO < libsrc/uthernet.pla > libsrc/uthernet.a
|
||||
acme --setpc 4094 -o $(UTHERNET) libsrc/uthernet.a
|
||||
|
||||
$(UTHERNET2): libsrc/uthernet2.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < libsrc/uthernet2.pla > libsrc/uthernet2.a
|
||||
./$(PLASM) -AMO < libsrc/uthernet2.pla > libsrc/uthernet2.a
|
||||
acme --setpc 4094 -o $(UTHERNET2) libsrc/uthernet2.a
|
||||
|
||||
$(ETHERIP): libsrc/etherip.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < libsrc/etherip.pla > libsrc/etherip.a
|
||||
./$(PLASM) -AMO < libsrc/etherip.pla > libsrc/etherip.a
|
||||
acme --setpc 4094 -o $(ETHERIP) libsrc/etherip.a
|
||||
|
||||
$(INET): libsrc/inet.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < libsrc/inet.pla > libsrc/inet.a
|
||||
./$(PLASM) -AMO < libsrc/inet.pla > libsrc/inet.a
|
||||
acme --setpc 4094 -o $(INET) libsrc/inet.a
|
||||
|
||||
$(DHCP): libsrc/dhcp.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < libsrc/dhcp.pla > libsrc/dhcp.a
|
||||
./$(PLASM) -AMO < libsrc/dhcp.pla > libsrc/dhcp.a
|
||||
acme --setpc 4094 -o $(DHCP) libsrc/dhcp.a
|
||||
|
||||
$(HTTPD): samplesrc/httpd.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < samplesrc/httpd.pla > samplesrc/httpd.a
|
||||
./$(PLASM) -AMO < samplesrc/httpd.pla > samplesrc/httpd.a
|
||||
acme --setpc 4094 -o $(HTTPD) samplesrc/httpd.a
|
||||
|
||||
$(FILEIO): libsrc/fileio.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < libsrc/fileio.pla > libsrc/fileio.a
|
||||
./$(PLASM) -AMO < libsrc/fileio.pla > libsrc/fileio.a
|
||||
acme --setpc 4094 -o $(FILEIO) libsrc/fileio.a
|
||||
|
||||
$(TONE): libsrc/tone.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < libsrc/tone.pla > libsrc/tone.a
|
||||
./$(PLASM) -AMO < libsrc/tone.pla > libsrc/tone.a
|
||||
acme --setpc 4094 -o $(TONE) libsrc/tone.a
|
||||
|
||||
$(FATCAT): samplesrc/fatcat.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < samplesrc/fatcat.pla > samplesrc/fatcat.a
|
||||
./$(PLASM) -AMO < samplesrc/fatcat.pla > samplesrc/fatcat.a
|
||||
acme --setpc 4094 -o $(FATCAT) samplesrc/fatcat.a
|
||||
|
||||
$(FATGET): samplesrc/fatget.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < samplesrc/fatget.pla > samplesrc/fatget.a
|
||||
./$(PLASM) -AMO < samplesrc/fatget.pla > samplesrc/fatget.a
|
||||
acme --setpc 4094 -o $(FATGET) samplesrc/fatget.a
|
||||
|
||||
$(FATPUT): samplesrc/fatput.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < samplesrc/fatput.pla > samplesrc/fatput.a
|
||||
./$(PLASM) -AMO < samplesrc/fatput.pla > samplesrc/fatput.a
|
||||
acme --setpc 4094 -o $(FATPUT) samplesrc/fatput.a
|
||||
|
||||
$(FATWDSK): samplesrc/fatwritedsk.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < samplesrc/fatwritedsk.pla > samplesrc/fatwritedsk.a
|
||||
./$(PLASM) -AMO < samplesrc/fatwritedsk.pla > samplesrc/fatwritedsk.a
|
||||
acme --setpc 4094 -o $(FATWDSK) samplesrc/fatwritedsk.a
|
||||
|
||||
$(FATRDSK): samplesrc/fatreaddsk.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < samplesrc/fatreaddsk.pla > samplesrc/fatreaddsk.a
|
||||
./$(PLASM) -AMO < samplesrc/fatreaddsk.pla > samplesrc/fatreaddsk.a
|
||||
acme --setpc 4094 -o $(FATRDSK) samplesrc/fatreaddsk.a
|
||||
|
||||
$(SDFAT): libsrc/sdfat.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < libsrc/sdfat.pla > libsrc/sdfat.a
|
||||
./$(PLASM) -AMO < libsrc/sdfat.pla > libsrc/sdfat.a
|
||||
acme --setpc 4094 -o $(SDFAT) libsrc/sdfat.a
|
||||
|
||||
$(SPIPORT): libsrc/spiport.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < libsrc/spiport.pla > libsrc/spiport.a
|
||||
./$(PLASM) -AMO < libsrc/spiport.pla > libsrc/spiport.a
|
||||
acme --setpc 4094 -o $(SPIPORT) libsrc/spiport.a
|
||||
|
||||
$(PORTIO): libsrc/portio.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < libsrc/portio.pla > libsrc/portio.a
|
||||
./$(PLASM) -AMO < libsrc/portio.pla > libsrc/portio.a
|
||||
acme --setpc 4094 -o $(PORTIO) libsrc/portio.a
|
||||
|
||||
$(DGR): libsrc/dgr.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < libsrc/dgr.pla > libsrc/dgr.a
|
||||
./$(PLASM) -AMO < libsrc/dgr.pla > libsrc/dgr.a
|
||||
acme --setpc 4094 -o $(DGR) libsrc/dgr.a
|
||||
|
||||
$(DGRTEST): samplesrc/dgrtest.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < samplesrc/dgrtest.pla > samplesrc/dgrtest.a
|
||||
./$(PLASM) -AMO < samplesrc/dgrtest.pla > samplesrc/dgrtest.a
|
||||
acme --setpc 4094 -o $(DGRTEST) samplesrc/dgrtest.a
|
||||
|
||||
$(ROGUE): samplesrc/rogue.pla $(PLVM02) $(PLASM)
|
||||
@ -236,12 +236,12 @@ $(ROGUEMAP): samplesrc/rogue.map.pla $(PLVM02) $(PLASM)
|
||||
acme --setpc 4094 -o $(ROGUEMAP) samplesrc/rogue.map.a
|
||||
|
||||
$(HGR1): samplesrc/hgr1.pla samplesrc/hgr1test.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AM < samplesrc/hgr1test.pla > samplesrc/hgr1test.a
|
||||
./$(PLASM) -AMO < samplesrc/hgr1test.pla > samplesrc/hgr1test.a
|
||||
acme --setpc 4094 -o $(HGR1TEST) samplesrc/hgr1test.a
|
||||
./$(PLASM) -AM < samplesrc/hgr1.pla > samplesrc/hgr1.a
|
||||
./$(PLASM) -AMO < samplesrc/hgr1.pla > samplesrc/hgr1.a
|
||||
acme --setpc 4094 -o $(HGR1) samplesrc/hgr1.a
|
||||
|
||||
hello: samplesrc/hello.pla $(PLVM) $(PLASM)
|
||||
./$(PLASM) -AM < samplesrc/hello.pla > samplesrc/hello.a
|
||||
./$(PLASM) -AMO < samplesrc/hello.pla > samplesrc/hello.a
|
||||
acme --setpc 4094 -o $(HELLO) samplesrc/hello.a
|
||||
./$(PLVM) HELLO
|
||||
|
395
src/samplesrc/a2pwm/a2pwm.s
Executable file
395
src/samplesrc/a2pwm/a2pwm.s
Executable file
@ -0,0 +1,395 @@
|
||||
;****************************************************************
|
||||
;*
|
||||
;* PWM SOUND ROUTINES
|
||||
;*
|
||||
;****************************************************************
|
||||
;*
|
||||
;* PWM ZERO PAGE LOCATIONS
|
||||
;*
|
||||
SPEAKER = $C030
|
||||
HFO = $08
|
||||
LFO = $09
|
||||
LFOINDEX= $0A ; IF LFOUSRH == 0
|
||||
LFOUSRL = $0A
|
||||
LFOUSRH = $0B
|
||||
ATK = $0C
|
||||
DCY = $0D
|
||||
SUS = $0E
|
||||
RLS = $0F
|
||||
ATKINCL = $10
|
||||
ATKINCH = $11
|
||||
DCYINCL = $12
|
||||
DCYINCH = $13
|
||||
RLSINCL = $14
|
||||
RLSINCH = $15
|
||||
ADSRL = $16
|
||||
ADSRH = $17
|
||||
ADSRINCL= $18
|
||||
ADSRINCH= $19
|
||||
TONELEN = $1B
|
||||
LPCNT = $1C
|
||||
HFOCNT = $1D
|
||||
LFOPOSL = $1E
|
||||
LFOPOSH = $1F
|
||||
LFOPTR = $00
|
||||
LFOPTRL = LFOPTR
|
||||
LFOPTRH = LFOPTRL+1
|
||||
;*
|
||||
;* PWM ENTRY POINT
|
||||
;*
|
||||
HILOPWM LDA LFOUSRL
|
||||
LDX LFOUSRH
|
||||
BNE + ; USER SUPPLIED WAVEFORM
|
||||
LDX #>LFOTBL
|
||||
ASL
|
||||
ASL
|
||||
ASL
|
||||
ASL
|
||||
ASL
|
||||
+ STA LFOPTRL
|
||||
STX LFOPTRH
|
||||
PHP
|
||||
SEI
|
||||
LDY #$00
|
||||
STY LFOPOSL
|
||||
; STY LFOPOSH
|
||||
STY LPCNT
|
||||
STY ADSRL
|
||||
; STY ADSRH
|
||||
LDA #$02
|
||||
STA HFOCNT
|
||||
ATTACK LDX #$0F
|
||||
LDA ATK
|
||||
BEQ DECAY
|
||||
LDX #$00
|
||||
STA TONELEN
|
||||
LDA ATKINCL
|
||||
STA ADSRINCL
|
||||
LDA ATKINCH
|
||||
STA ADSRINCH
|
||||
JSR HILOSND
|
||||
DECAY LDA DCY
|
||||
BEQ SUSTAIN
|
||||
STA TONELEN
|
||||
LDA #$00 ; REVERSE ATTACK RATE
|
||||
SEC
|
||||
SBC DCYINCL
|
||||
STA ADSRINCL
|
||||
LDA #$00
|
||||
SBC DCYINCH
|
||||
STA ADSRINCH
|
||||
JSR HILOSND
|
||||
SUSTAIN LDA SUS
|
||||
BEQ RELEASE
|
||||
STA TONELEN
|
||||
LDA #$00 ; SUSTAIN DOESN'T ALTER VOLUME
|
||||
STA ADSRINCL
|
||||
STA ADSRINCH
|
||||
JSR HILOSND
|
||||
RELEASE LDA RLS
|
||||
BEQ PWMEXIT
|
||||
STA TONELEN
|
||||
LDA #$00 ; REVERSE RELEASE RATE
|
||||
SEC
|
||||
SBC RLSINCL
|
||||
STA ADSRINCL
|
||||
LDA #$00
|
||||
SBC RLSINCH
|
||||
STA ADSRINCH
|
||||
JSR HILOSND
|
||||
PWMEXIT PLP
|
||||
RTS
|
||||
PWMSND CLC ; 1, 2
|
||||
LDA ADSRL ; 2, 3
|
||||
ADC ADSRINCL ; 2, 3
|
||||
STA TMP ; 2, 3
|
||||
TXA ; 1, 2
|
||||
ADC ADSRINCH ; 2, 3
|
||||
DEC LPCNT ; 2, 5
|
||||
;------
|
||||
;12,21
|
||||
|
||||
BNE HILOSND ; 2, 2
|
||||
AND #$0F ; 2, 2
|
||||
TAX ; 1, 2
|
||||
LDA TMP ; 2, 3
|
||||
STA ADSRL ; 2, 3
|
||||
DEC TONELEN ; 2, 5
|
||||
BEQ PWMRET ; 2, 2
|
||||
DEC HFOCNT ; 2, 5
|
||||
BEQ SPKRON ; 2, 2
|
||||
CLC ; 1, 2
|
||||
LDA LFOPOSL ; 2, 3
|
||||
ADC LFO ; 2, 3
|
||||
STA LFOPOSL ; 2, 3
|
||||
TYA ; 1, 2
|
||||
ADC #$00 ; 2, 2
|
||||
AND #$1F ; 2, 2
|
||||
TAY ; 1, 2
|
||||
TXA ; 1, 2
|
||||
ORA (LFOPTR),Y ; 2, 5
|
||||
STA *+4 ; 3, 4
|
||||
LDA MUL4X4 ; 3, 4
|
||||
ASL ; 1, 2
|
||||
STA SPKRPWM+1 ; 3, 4
|
||||
LDA #>PWM1 ; 2, 2
|
||||
ADC #$00 ; 2, 2
|
||||
STA SPKRPWM+2 ; 3, 4
|
||||
NOP ; 1, 2
|
||||
JMP PWMSND ; 3, 3
|
||||
;------
|
||||
;55,79
|
||||
|
||||
; BNE HILOSND ; , 3
|
||||
HILOSND DEC HFOCNT ; 2, 5
|
||||
BNE + ; 2, 2
|
||||
SPKRON BIT SPEAKER ; 3, 4
|
||||
SPKRPWM JMP PWM1 ; 3, 3+62
|
||||
;------
|
||||
;10,79
|
||||
|
||||
; BNE HILOSND ; , 3
|
||||
; DEC HFOCNT ; , 5
|
||||
; BNE + ; , 3
|
||||
+ BNE ++ ; 2, 3
|
||||
++ NOP ; 1, 2
|
||||
NOP ; 1, 2
|
||||
NOP ; 1, 2
|
||||
NOP ; 1, 2
|
||||
NOP ; 1, 2
|
||||
NOP ; 1, 2
|
||||
NOP ; 1, 2
|
||||
CLC ; 1, 2
|
||||
LDA LFOPOSL ; 2, 3
|
||||
ADC LFO ; 2, 3
|
||||
STA LFOPOSL ; 2, 3
|
||||
TYA ; 1, 2
|
||||
ADC #$00 ; 2, 2
|
||||
AND #$1F ; 2, 2
|
||||
TAY ; 1, 2
|
||||
TXA ; 1, 2
|
||||
ORA (LFOPTR),Y ; 2, 5
|
||||
STA *+4 ; 3, 4
|
||||
LDA MUL4X4 ; 3, 4
|
||||
ASL ; 1, 2
|
||||
STA SPKRPWM+1 ; 3, 4
|
||||
LDA #>PWM1 ; 2, 2
|
||||
ADC #$00 ; 2, 2
|
||||
STA SPKRPWM+2 ; 3, 4
|
||||
JMP PWMSND ; 3, 3
|
||||
;------
|
||||
;44,79
|
||||
PWMRET RTS
|
||||
;*
|
||||
;* 4 BIT x 4 BIT TO 3.5 BIT MULTIPLY TABLE
|
||||
;*
|
||||
!ALIGN 255,0
|
||||
MUL4X4 !BYTE $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
|
||||
!BYTE $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
|
||||
!BYTE $00, $00, $00, $00, $00, $00, $00, $00, $20, $20, $20, $20, $20, $20, $20, $20
|
||||
!BYTE $00, $00, $00, $00, $00, $00, $20, $20, $20, $20, $20, $20, $20, $20, $20, $20
|
||||
!BYTE $00, $00, $00, $00, $20, $20, $20, $20, $20, $20, $20, $20, $40, $40, $40, $40
|
||||
!BYTE $00, $00, $00, $00, $20, $20, $20, $20, $20, $20, $40, $40, $40, $40, $40, $40
|
||||
!BYTE $00, $00, $00, $20, $20, $20, $20, $20, $40, $40, $40, $40, $40, $40, $60, $60
|
||||
!BYTE $00, $00, $00, $20, $20, $20, $20, $40, $40, $40, $40, $40, $60, $60, $60, $60
|
||||
!BYTE $00, $00, $20, $20, $20, $20, $40, $40, $40, $40, $60, $60, $60, $60, $80, $80
|
||||
!BYTE $00, $00, $20, $20, $20, $20, $40, $40, $40, $60, $60, $60, $60, $80, $80, $80
|
||||
!BYTE $00, $00, $20, $20, $20, $40, $40, $40, $60, $60, $60, $60, $80, $80, $80, $A0
|
||||
!BYTE $00, $00, $20, $20, $20, $40, $40, $40, $60, $60, $60, $80, $80, $80, $A0, $A0
|
||||
!BYTE $00, $00, $20, $20, $40, $40, $40, $60, $60, $60, $80, $80, $A0, $A0, $A0, $C0
|
||||
!BYTE $00, $00, $20, $20, $40, $40, $40, $60, $60, $80, $80, $80, $A0, $A0, $C0, $C0
|
||||
!BYTE $00, $00, $20, $20, $40, $40, $60, $60, $80, $80, $80, $A0, $A0, $C0, $C0, $E0
|
||||
!BYTE $00, $00, $20, $20, $40, $40, $60, $60, $80, $80, $A0, $A0, $C0, $C0, $E0, $E0
|
||||
LFOTBL !SOURCE "lfotbl.s"
|
||||
!ALIGN 63,0
|
||||
PWM1 BIT SPEAKER ; 3, 4
|
||||
CLC ; 1, 2
|
||||
LDA LFOPOSL ; 2, 3
|
||||
ADC LFO ; 2, 3
|
||||
STA LFOPOSL ; 2, 3
|
||||
TYA ; 1, 2
|
||||
ADC #$00 ; 2, 2
|
||||
AND #$1F ; 2, 2
|
||||
TAY ; 1, 2
|
||||
TXA ; 1, 2
|
||||
ORA (LFOPTR),Y ; 2, 5
|
||||
STA *+4 ; 3, 4
|
||||
LDA MUL4X4 ; 3, 4
|
||||
ASL ; 1, 2
|
||||
STA SPKRPWM+1 ; 3, 4
|
||||
LDA #>PWM1 ; 2, 2
|
||||
ADC #$00 ; 2, 2
|
||||
STA SPKRPWM+2 ; 3, 4
|
||||
LDA HFO ; 2, 3
|
||||
STA HFOCNT ; 2, 3
|
||||
JMP PWMSND ; 3, 3
|
||||
;------
|
||||
;43,61
|
||||
!ALIGN 63,0
|
||||
PWM2 CLC ; 1, 2
|
||||
LDA LFOPOSL ; 2, 3
|
||||
BIT SPEAKER ; 3, 4
|
||||
ADC LFO ; 2, 3
|
||||
STA LFOPOSL ; 2, 3
|
||||
TYA ; 1, 2
|
||||
ADC #$00 ; 2, 2
|
||||
AND #$1F ; 2, 2
|
||||
TAY ; 1, 2
|
||||
TXA ; 1, 2
|
||||
ORA (LFOPTR),Y ; 2, 5
|
||||
STA *+4 ; 3, 4
|
||||
LDA MUL4X4 ; 3, 4
|
||||
ASL ; 1, 2
|
||||
STA SPKRPWM+1 ; 3, 4
|
||||
LDA #>PWM1 ; 2, 2
|
||||
ADC #$00 ; 2, 2
|
||||
STA SPKRPWM+2 ; 3, 4
|
||||
LDA HFO ; 2, 3
|
||||
STA HFOCNT ; 2, 3
|
||||
JMP PWMSND ; 3, 3
|
||||
;------
|
||||
;43,62
|
||||
!ALIGN 63,0
|
||||
PWM3 CLC ; 1, 2
|
||||
LDA LFOPOSL ; 2, 3
|
||||
ADC LFO ; 2, 3
|
||||
STA LFOPOSL ; 2, 3
|
||||
BIT SPEAKER ; 3, 4
|
||||
TYA ; 1, 2
|
||||
ADC #$00 ; 2, 2
|
||||
AND #$1F ; 2, 2
|
||||
TAY ; 1, 2
|
||||
TXA ; 1, 2
|
||||
ORA (LFOPTR),Y ; 2, 5
|
||||
STA *+4 ; 3, 4
|
||||
LDA MUL4X4 ; 3, 4
|
||||
ASL ; 1, 2
|
||||
STA SPKRPWM+1 ; 3, 4
|
||||
LDA #>PWM1 ; 2, 2
|
||||
ADC #$00 ; 2, 2
|
||||
STA SPKRPWM+2 ; 3, 4
|
||||
LDA HFO ; 2, 3
|
||||
STA HFOCNT ; 2, 3
|
||||
JMP PWMSND ; 3, 3
|
||||
;------
|
||||
;43,61
|
||||
!ALIGN 63,0
|
||||
PWM4 CLC ; 1, 2
|
||||
LDA LFOPOSL ; 2, 3
|
||||
ADC LFO ; 2, 3
|
||||
STA LFOPOSL ; 2, 3
|
||||
TYA ; 1, 2
|
||||
ADC #$00 ; 2, 2
|
||||
AND #$1F ; 2, 2
|
||||
TAY ; 1, 2
|
||||
BIT SPEAKER ; 3, 4
|
||||
TXA ; 1, 2
|
||||
ORA (LFOPTR),Y ; 2, 5
|
||||
STA *+4 ; 3, 4
|
||||
LDA MUL4X4 ; 3, 4
|
||||
ASL ; 1, 2
|
||||
STA SPKRPWM+1 ; 3, 4
|
||||
LDA #>PWM1 ; 2, 2
|
||||
ADC #$00 ; 2, 2
|
||||
STA SPKRPWM+2 ; 3, 4
|
||||
LDA HFO ; 2, 3
|
||||
STA HFOCNT ; 2, 3
|
||||
JMP PWMSND ; 3, 3
|
||||
;------
|
||||
;43,61
|
||||
!ALIGN 63,0
|
||||
PWM5 CLC ; 1, 2
|
||||
LDA LFOPOSL ; 2, 3
|
||||
ADC LFO ; 2, 3
|
||||
STA LFOPOSL ; 2, 3
|
||||
TYA ; 1, 2
|
||||
ADC #$00 ; 2, 2
|
||||
AND #$1F ; 2, 2
|
||||
TAY ; 1, 2
|
||||
TXA ; 1, 2
|
||||
ORA (LFOPTR),Y ; 2, 5
|
||||
BIT SPEAKER ; 3, 4
|
||||
STA *+4 ; 3, 4
|
||||
LDA MUL4X4 ; 3, 4
|
||||
ASL ; 1, 2
|
||||
STA SPKRPWM+1 ; 3, 4
|
||||
LDA #>PWM1 ; 2, 2
|
||||
ADC #$00 ; 2, 2
|
||||
STA SPKRPWM+2 ; 3, 4
|
||||
LDA HFO ; 2, 3
|
||||
STA HFOCNT ; 2, 3
|
||||
JMP PWMSND ; 3, 3
|
||||
;------
|
||||
;43,61
|
||||
!ALIGN 63,0
|
||||
PWM6 CLC ; 1, 2
|
||||
LDA LFOPOSL ; 2, 3
|
||||
ADC LFO ; 2, 3
|
||||
STA LFOPOSL ; 2, 3
|
||||
TYA ; 1, 2
|
||||
ADC #$00 ; 2, 2
|
||||
AND #$1F ; 2, 2
|
||||
TAY ; 1, 2
|
||||
TXA ; 1, 2
|
||||
ORA (LFOPTR),Y ; 2, 5
|
||||
STA *+4 ; 3, 4
|
||||
LDA MUL4X4 ; 3, 4
|
||||
BIT SPEAKER ; 3, 4
|
||||
ASL ; 1, 2
|
||||
STA SPKRPWM+1 ; 3, 4
|
||||
LDA #>PWM1 ; 2, 2
|
||||
ADC #$00 ; 2, 2
|
||||
STA SPKRPWM+2 ; 3, 4
|
||||
LDA HFO ; 2, 3
|
||||
STA HFOCNT ; 2, 3
|
||||
JMP PWMSND ; 3, 3
|
||||
;------
|
||||
;43,61
|
||||
!ALIGN 63,0
|
||||
PWM7 CLC ; 1, 2
|
||||
LDA LFOPOSL ; 2, 3
|
||||
ADC LFO ; 2, 3
|
||||
STA LFOPOSL ; 2, 3
|
||||
TYA ; 1, 2
|
||||
ADC #$00 ; 2, 2
|
||||
AND #$1F ; 2, 2
|
||||
TAY ; 1, 2
|
||||
TXA ; 1, 2
|
||||
ORA (LFOPTR),Y ; 2, 5
|
||||
STA *+4 ; 3, 4
|
||||
LDA MUL4X4 ; 3, 4
|
||||
ASL ; 1, 2
|
||||
STA SPKRPWM+1 ; 3, 4
|
||||
LDA #>PWM1 ; 2, 2
|
||||
ADC #$00 ; 2, 2
|
||||
BIT SPEAKER ; 3, 4
|
||||
STA SPKRPWM+2 ; 3, 4
|
||||
LDA HFO ; 2, 3
|
||||
STA HFOCNT ; 2, 3
|
||||
JMP PWMSND ; 3, 3
|
||||
;------
|
||||
;43,61
|
||||
!ALIGN 63,0
|
||||
PWM8 CLC ; 1, 2
|
||||
LDA LFOPOSL ; 2, 3
|
||||
ADC LFO ; 2, 3
|
||||
STA LFOPOSL ; 2, 3
|
||||
TYA ; 1, 2
|
||||
ADC #$00 ; 2, 2
|
||||
AND #$1F ; 2, 2
|
||||
TAY ; 1, 2
|
||||
TXA ; 1, 2
|
||||
ORA (LFOPTR),Y ; 2, 5
|
||||
STA *+4 ; 3, 4
|
||||
LDA MUL4X4 ; 3, 4
|
||||
ASL ; 1, 2
|
||||
STA SPKRPWM+1 ; 3, 4
|
||||
LDA #>PWM1 ; 2, 2
|
||||
ADC #$00 ; 2, 2
|
||||
STA SPKRPWM+2 ; 3, 4
|
||||
LDA HFO ; 2, 3
|
||||
STA HFOCNT ; 2, 3
|
||||
BIT SPEAKER ; 3, 4
|
||||
JMP PWMSND ; 3, 3
|
||||
;------
|
||||
;43,61
|
608
src/samplesrc/a2pwm/hilopwm.pla
Executable file
608
src/samplesrc/a2pwm/hilopwm.pla
Executable file
@ -0,0 +1,608 @@
|
||||
const inbuff = $200
|
||||
const freemem = $0002
|
||||
const iobuffer = $1C00
|
||||
const NMACROS = 7
|
||||
const FALSE = 0
|
||||
const TRUE = !FALSE
|
||||
//
|
||||
// Sequence values
|
||||
//
|
||||
const SEQ_MACRO = 0
|
||||
const SEQ_NOTE = 7
|
||||
const SEQ_LFO = 21
|
||||
const SEQ_LFO_INC = 29
|
||||
const SEQ_LFO_DEC = 30
|
||||
const SEQ_OCT_INC = 31
|
||||
const SEQ_OCT_DEC = 32
|
||||
const SEQ_DUR_INC = 33
|
||||
const SEQ_DUR_DEC = 34
|
||||
const SEQ_REST = 35
|
||||
//
|
||||
// Predefine replay functions
|
||||
//
|
||||
predef playback, replaynote, replayrest
|
||||
predef replaylfo, replaylfoinc, replaylfodec
|
||||
predef replayoctinc, replayoctdec, replaydurinc, replaydurdec
|
||||
//
|
||||
// Replay function pointers
|
||||
//
|
||||
word replay[] = @playback, @playback, @playback, @playback, @playback, @playback
|
||||
word = @playback
|
||||
word = @replaynote, @replaynote, @replaynote, @replaynote, @replaynote, @replaynote
|
||||
word = @replaynote, @replaynote, @replaynote, @replaynote, @replaynote, @replaynote
|
||||
word = @replaynote, @replaynote
|
||||
word = @replaylfo, @replaylfo, @replaylfo, @replaylfo, @replaylfo, @replaylfo
|
||||
word = @replaylfo, @replaylfo
|
||||
word = @replaylfoinc, @replaylfodec
|
||||
word = @replayoctinc, @replayoctdec
|
||||
word = @replaydurinc, @replaydurdec
|
||||
word = @replayrest
|
||||
|
||||
//
|
||||
// Patch state
|
||||
//
|
||||
struc t_state
|
||||
byte durAtk
|
||||
byte durDcy
|
||||
byte durSus
|
||||
byte durRel
|
||||
word rateAtk
|
||||
word rateDcy
|
||||
word rateRel
|
||||
byte octave
|
||||
byte LFO
|
||||
byte idxLFO
|
||||
end
|
||||
//
|
||||
// Macro sequence structure
|
||||
//
|
||||
struc t_macro
|
||||
byte absStart
|
||||
byte stateStart[t_state]
|
||||
byte sequence[256]
|
||||
end
|
||||
byte current[t_state] // Current state
|
||||
word macros // Pointer to macros
|
||||
byte record[t_macro] // Recording buffer
|
||||
word recording = FALSE // Recording key/flag
|
||||
byte playing = 0 // Keep track of active macros
|
||||
byte recalc = FALSE // Recalc envelope flag
|
||||
//
|
||||
// System variables.
|
||||
//
|
||||
word heap
|
||||
//
|
||||
// Periods of scale in second octave
|
||||
//
|
||||
byte scale0[] = 163, 154, 146, 137, 130, 122, 116, 109, 103, 97, 92, 87, 82, 77
|
||||
byte scale1[] = 82, 77, 73, 69, 65, 61, 58, 55, 52, 49, 46, 43, 41, 39
|
||||
byte scale2[] = 41, 39, 37, 34, 33, 31, 29, 27, 26, 24, 23, 22, 21, 19
|
||||
byte scale3[] = 21, 19, 18, 17, 16, 15, 14, 14, 13, 12, 11, 11, 10, 10
|
||||
word scale[] = @scale0, @scale1, @scale2, @scale3
|
||||
//
|
||||
// Key mapping to note
|
||||
//
|
||||
byte keytone[] = 'A','S','E','D','R','F','G','Y','H','U','J','I','K','L'
|
||||
//
|
||||
// Macro sequence keys
|
||||
//
|
||||
byte keymacro[] = 'Z', 'X', 'C', 'V', 'B', 'N', 'M'
|
||||
//
|
||||
// Macro record keys
|
||||
//
|
||||
byte keyrecord[] = $1A, $18, $03, $16, $02, $0E, $0D
|
||||
//
|
||||
// Note duration
|
||||
//
|
||||
byte duration = 16
|
||||
//
|
||||
// Patch filename
|
||||
//
|
||||
byte patch = "PATCH"
|
||||
byte modPatch = FALSE
|
||||
//
|
||||
// Import utility routines
|
||||
//
|
||||
include "util.pla"
|
||||
//
|
||||
// Load/Save PATCH
|
||||
//
|
||||
def loadPatch
|
||||
byte refnum
|
||||
|
||||
refnum = open(@patch, iobuffer)
|
||||
if refnum
|
||||
read(refnum, macros, t_macro * NMACROS) // Macros
|
||||
read(refnum, @current, t_state) // Initial values
|
||||
close(refnum)
|
||||
fin
|
||||
return refnum <> 0
|
||||
end
|
||||
def savePatch
|
||||
byte refnum
|
||||
|
||||
destroy(@patch)
|
||||
create(@patch, $C3, $06, $00) // full access, BIN file
|
||||
refnum = open(@patch, iobuffer)
|
||||
if refnum
|
||||
write(refnum, macros, t_macro * NMACROS) // Macros
|
||||
write(refnum, @current, t_state) // Initial values
|
||||
close(refnum)
|
||||
modPatch = FALSE
|
||||
fin
|
||||
return refnum <> 0
|
||||
end
|
||||
//
|
||||
// Query routines
|
||||
//
|
||||
def query(str)
|
||||
byte c
|
||||
|
||||
inverse
|
||||
clearview
|
||||
putsxy(20 - ^str / 2, 2, str)
|
||||
c = toupper(getc)
|
||||
return c == 'Y'
|
||||
end
|
||||
//
|
||||
// Display LFO bar
|
||||
//
|
||||
def showLFO
|
||||
grcolor(WHITE)
|
||||
rect(33, 39, 6, 39, FALSE)
|
||||
if current.LFO < 32
|
||||
grcolor(ORANGE)
|
||||
rect(34, 38, 7, 38-current.LFO, TRUE)
|
||||
fin
|
||||
if current.LFO
|
||||
grcolor(DRKBLU)
|
||||
rect(34, 38, 39-current.LFO, 38, TRUE)
|
||||
fin
|
||||
//
|
||||
//Show actual value
|
||||
//
|
||||
putsxy(35, 0, " ")
|
||||
gotoxy(35, 0)
|
||||
return puti(current.LFO)
|
||||
end
|
||||
//
|
||||
// Display LFO waveform
|
||||
//
|
||||
def showWaveform
|
||||
byte i, mapBar
|
||||
word mapPtr
|
||||
//
|
||||
// Get pointer to LFO waveform by calling PWM with zero note
|
||||
//
|
||||
envelope(0, 0, 0, 0, current:rateAtk, current:rateDcy, current:rateRel)
|
||||
hilopwm(0, current.LFO, current.idxLFO)
|
||||
mapPtr = *0 // Pointer at address 0
|
||||
grcolor(WHITE)
|
||||
rect(0, 33, 6, 39, FALSE)
|
||||
for i = 0 to 31
|
||||
mapBar = ^(mapPtr + i) >> 3
|
||||
grcolor(BLACK)
|
||||
vlin(7, 38-mapBar, i + 1)
|
||||
grcolor(MAGENTA)
|
||||
vlin(38 - mapBar, 38, i + 1)
|
||||
grcolor(PURPLE)
|
||||
vlin(37-mapBar, 38-mapBar, i + 1)
|
||||
next
|
||||
//
|
||||
// Restore envelope
|
||||
//
|
||||
return envelope(current.durAtk, current.durDcy, current.durSus, current.durRel, current:rateAtk, current:rateDcy, current:rateRel)
|
||||
end
|
||||
//
|
||||
// Display duration
|
||||
//
|
||||
def showDuration
|
||||
byte left, right
|
||||
|
||||
if duration == 40
|
||||
left = 0
|
||||
right = 39
|
||||
else
|
||||
left = 19-duration/2
|
||||
right = left + duration
|
||||
fin
|
||||
grcolor(BLACK)
|
||||
if left > 0
|
||||
rect(0, left-1, 0, 5, TRUE)
|
||||
fin
|
||||
if right < 39
|
||||
rect(right+1, 39, 0, 5, TRUE)
|
||||
fin
|
||||
grcolor(AQUA)
|
||||
rect(left, right, 0, 5, TRUE)
|
||||
//
|
||||
// Show actual value
|
||||
//
|
||||
putsxy(4, 3, " ")
|
||||
gotoxy(4, 3)
|
||||
return puti(duration)
|
||||
end
|
||||
//
|
||||
// Display octave
|
||||
//
|
||||
def showOctave
|
||||
inverse
|
||||
putsxy(0, 1, "----------------------------------------")
|
||||
normal
|
||||
putsxy(current.octave*10, 1, "----------")
|
||||
return inverse
|
||||
end
|
||||
def showMainPanel
|
||||
inverse
|
||||
clearview
|
||||
showDuration
|
||||
showWaveform
|
||||
showLFO
|
||||
putsxy(5, 0, "OSCILLATION OVERTHRUSTER 1.3")
|
||||
normal
|
||||
putsxy(1, 0, "1-8")
|
||||
gotoxy(34, 0); putc('<')
|
||||
gotoxy(38, 0); putc('>')
|
||||
gotoxy(3, 3); putc('-')
|
||||
gotoxy(6, 3); putc('+')
|
||||
inverse
|
||||
showOctave
|
||||
normal
|
||||
putsxy(0, 2, "<-")
|
||||
putsxy(38, 2, "->")
|
||||
inverse
|
||||
putsxy(11, 3, "A S D F G H J K L")
|
||||
normal
|
||||
gotoxy(14, 2); putc('E')
|
||||
gotoxy(16, 2); putc('R')
|
||||
gotoxy(20, 2); putc('Y')
|
||||
gotoxy(22, 2); putc('U')
|
||||
gotoxy(24, 2); putc('I')
|
||||
return inverse
|
||||
end
|
||||
def showHelp
|
||||
normal
|
||||
home
|
||||
putsxy(15, 0, "HELP")
|
||||
putsxy(0, 1, "=======================================")
|
||||
putsxy(2, 3, "KEY COMMAND")
|
||||
putsxy(2, 4, "-------------- --------------------")
|
||||
putsxy(2, 5, "ESC HELP/CANCEL RECORD")
|
||||
putsxy(2, 6, "CTRL-Q QUIT")
|
||||
putsxy(2, 7, "1..8 LFO WAVEFORM")
|
||||
putsxy(2, 8, "< , INCREASE LFO")
|
||||
putsxy(2, 9, "> . DECREASE LFO")
|
||||
putsxy(2, 10, "LEFT-ARROW PREV OCTAVE")
|
||||
putsxy(2, 11, "RIGHT-ARROW NEXT OCTAVE")
|
||||
putsxy(2, 12, "+ UP-ARROW INCREASE DURATION")
|
||||
putsxy(2, 13, "- DOWN-ARROW DECREASE DURATION")
|
||||
putsxy(2, 14, "CTRL-Z..M RECORD MACRO")
|
||||
putsxy(2, 15, "/ SAVE ABS MACRO")
|
||||
putsxy(2, 16, "? SAVE REL MACRO")
|
||||
putsxy(2, 17, "P PERSISTANT STATE")
|
||||
putsxy(2, 18, "0 TOGGLE PHASE")
|
||||
putsxy(8, 23, "PRESS A KEY TO RETURN")
|
||||
return getc
|
||||
end
|
||||
//
|
||||
// Recalc envelope parameters
|
||||
//
|
||||
def recalcEnv
|
||||
current.durAtk = duration/8
|
||||
current.durDcy = 0
|
||||
current.durRel = duration/2
|
||||
current.durSus = duration - current.durAtk - current.durRel
|
||||
current:rateAtk = $0FFF/current.durAtk
|
||||
current:rateDcy = 0
|
||||
current:rateRel = $0FFF/current.durRel
|
||||
recalc = FALSE
|
||||
return envelope(current.durAtk, current.durDcy, current.durSus, current.durRel, current:rateAtk, current:rateDcy, current:rateRel)
|
||||
end
|
||||
//
|
||||
// Playback a sequence
|
||||
//
|
||||
def playback(idx)
|
||||
word macro
|
||||
byte seq, i
|
||||
byte save[t_state]
|
||||
|
||||
//
|
||||
// Check for recursive playback
|
||||
//
|
||||
if playing & (1 << idx)
|
||||
return
|
||||
fin
|
||||
playing = playing | (1 << idx)
|
||||
macro = macros + t_macro * idx
|
||||
//
|
||||
// Save current state
|
||||
//
|
||||
memcpy(@save, @current, t_state)
|
||||
//
|
||||
// Start off with initial conditions
|
||||
//
|
||||
if macro->absStart
|
||||
memcpy(@current, macro + stateStart, t_state)
|
||||
duration = current.durAtk + current.durDcy + current.durSus + current.durRel
|
||||
envelope(current.durAtk, current.durDcy, current.durSus, current.durRel, current:rateAtk, current:rateDcy, current:rateRel)
|
||||
recalc = FALSE
|
||||
fin
|
||||
//
|
||||
// Run throught the sequence
|
||||
//
|
||||
for i = 1 to macro->sequence
|
||||
seq = macro->sequence[i]
|
||||
(replay[seq])(seq)
|
||||
next
|
||||
//
|
||||
// Restore state
|
||||
//
|
||||
memcpy(@current, @save, t_state)
|
||||
duration = current.durAtk + current.durDcy + current.durSus + current.durRel
|
||||
envelope(current.durAtk, current.durDcy, current.durSus, current.durRel, current:rateAtk, current:rateDcy, current:rateRel)
|
||||
playing = playing & ~(1 << idx)
|
||||
return recalcEnv
|
||||
end
|
||||
//
|
||||
// Replay rest
|
||||
//
|
||||
def replayrest(idx)
|
||||
byte d
|
||||
|
||||
for d = duration downto 1
|
||||
call($FCA8, $6A, 0, 0, 0)
|
||||
next
|
||||
end
|
||||
//
|
||||
// Replay note
|
||||
//
|
||||
def replaynote(idx)
|
||||
if recalc
|
||||
recalcEnv
|
||||
fin
|
||||
if current.LFO == 0
|
||||
hilopwm(scale.[current.octave, idx - SEQ_NOTE], 0, 0)
|
||||
else
|
||||
hilopwm(scale.[current.octave, idx - SEQ_NOTE], current.LFO, current.idxLFO)
|
||||
fin
|
||||
end
|
||||
//
|
||||
// Replay duration
|
||||
//
|
||||
def replaydurinc(idx)
|
||||
if duration < 40
|
||||
duration++
|
||||
recalc = TRUE;
|
||||
fin
|
||||
end
|
||||
def replaydurdec(idx)
|
||||
if duration > 1
|
||||
duration--
|
||||
recalc = TRUE;
|
||||
fin
|
||||
end
|
||||
//
|
||||
// Replay octave
|
||||
//
|
||||
def replayoctinc(idx)
|
||||
if current.octave < 3
|
||||
current.octave++
|
||||
fin
|
||||
end
|
||||
def replayoctdec(idx)
|
||||
if current.octave > 0
|
||||
current.octave--
|
||||
fin
|
||||
end
|
||||
//
|
||||
// Replay LFO
|
||||
//
|
||||
def replaylfoinc(idx)
|
||||
if current.LFO > 0
|
||||
current.LFO--
|
||||
fin
|
||||
end
|
||||
def replaylfodec(idx)
|
||||
if current.LFO < 32
|
||||
current.LFO++
|
||||
fin
|
||||
end
|
||||
def replaylfo(idx)
|
||||
current.idxLFO = idx - SEQ_LFO
|
||||
end
|
||||
//
|
||||
// Main loop
|
||||
//
|
||||
def main
|
||||
byte quit, key, i
|
||||
word seq
|
||||
|
||||
quit = FALSE
|
||||
repeat
|
||||
if keypressed
|
||||
key = toupper(getc)
|
||||
seq = -1
|
||||
//
|
||||
// Check for tone keys
|
||||
//
|
||||
for i = 0 to 13
|
||||
if keytone[i] == key
|
||||
if current.LFO == 0
|
||||
hilopwm(scale.[current.octave, i], 0, 0)
|
||||
else
|
||||
hilopwm(scale.[current.octave, i], current.LFO, current.idxLFO)
|
||||
fin
|
||||
seq = SEQ_NOTE + i
|
||||
break
|
||||
fin
|
||||
next
|
||||
//
|
||||
// Check for macro keys
|
||||
//
|
||||
if i > 13
|
||||
for i = 0 to 6
|
||||
if keymacro[i] == key
|
||||
playback(i)
|
||||
seq = SEQ_MACRO + i
|
||||
break
|
||||
fin
|
||||
next
|
||||
if i > 6
|
||||
if not recording
|
||||
for i = 0 to 6
|
||||
if keyrecord[i] == key
|
||||
recording = (key << 8) | i
|
||||
//
|
||||
// Save current state
|
||||
//
|
||||
memcpy(@record.stateStart, @current, t_state)
|
||||
record.absStart = TRUE
|
||||
record.sequence = 0
|
||||
normal
|
||||
putsxy(29, 3, "RECORDING")
|
||||
inverse
|
||||
break
|
||||
fin
|
||||
next
|
||||
fin
|
||||
if i > 6
|
||||
when key
|
||||
is $1B // ESC
|
||||
if recording // Cancel recording
|
||||
recording = FALSE
|
||||
putsxy(29, 3, " ")
|
||||
else
|
||||
textmode
|
||||
showHelp
|
||||
grmode
|
||||
showMainPanel
|
||||
fin
|
||||
break
|
||||
is $11 // CTRL-Q
|
||||
quit = query("QUIT (Y/N)?")
|
||||
if not quit
|
||||
showMainPanel
|
||||
fin
|
||||
break
|
||||
is '?'
|
||||
record.absStart = FALSE
|
||||
is '/'
|
||||
if recording // Copy recorded macro to key macro
|
||||
memcpy(macros + t_macro * (recording & $FF), @record, t_macro)
|
||||
recording = FALSE
|
||||
modPatch = TRUE
|
||||
putsxy(29, 3, " ")
|
||||
fin
|
||||
break
|
||||
is '+'
|
||||
is $0B // UP
|
||||
if duration < 40
|
||||
duration++
|
||||
recalcEnv
|
||||
showDuration
|
||||
fin
|
||||
seq = SEQ_DUR_INC
|
||||
break
|
||||
is '-'
|
||||
is $0A // DOWN
|
||||
if duration > 1
|
||||
duration--
|
||||
recalcEnv
|
||||
showDuration
|
||||
fin
|
||||
seq = SEQ_DUR_DEC
|
||||
break
|
||||
is $15 // ->
|
||||
if current.octave < 3
|
||||
current.octave++
|
||||
showOctave
|
||||
fin
|
||||
seq = SEQ_OCT_INC
|
||||
break
|
||||
is $08 // <-
|
||||
if current.octave > 0
|
||||
current.octave--
|
||||
showOctave
|
||||
fin
|
||||
seq = SEQ_OCT_DEC
|
||||
break
|
||||
is '1'
|
||||
is '2'
|
||||
is '3'
|
||||
is '4'
|
||||
is '5'
|
||||
is '6'
|
||||
is '7'
|
||||
is '8'
|
||||
current.idxLFO = key - '1'
|
||||
showWaveform
|
||||
seq = SEQ_LFO + current.idxLFO
|
||||
break
|
||||
is '>'
|
||||
is '.'
|
||||
if current.LFO < 32
|
||||
current.LFO++
|
||||
fin
|
||||
showLFO
|
||||
seq = SEQ_LFO_INC
|
||||
break
|
||||
is '<'
|
||||
is ','
|
||||
if current.LFO > 0
|
||||
current.LFO--
|
||||
fin
|
||||
showLFO
|
||||
seq = SEQ_LFO_DEC
|
||||
break
|
||||
is 'P'
|
||||
if modPatch
|
||||
savePatch
|
||||
fin
|
||||
break
|
||||
is '0' // Toggle speaker phase
|
||||
^$C030
|
||||
break
|
||||
wend
|
||||
fin
|
||||
fin
|
||||
fin
|
||||
if recording and seq >= 0
|
||||
if record.sequence < 255
|
||||
record.sequence++
|
||||
record.sequence[record.sequence] = seq
|
||||
else
|
||||
beep
|
||||
fin
|
||||
fin
|
||||
fin
|
||||
until quit
|
||||
end
|
||||
//
|
||||
// Get us into a standard 40 column video mode
|
||||
//
|
||||
call($FDED, $8D, 0, 0, 0)
|
||||
call($FDED, $91, 0, 0, 0)// CTRL-Q = turn off 80 column
|
||||
call($FDED, $8D, 0, 0, 0)
|
||||
^$C000 = 0 // Turn off 80STORE
|
||||
//
|
||||
// Get heap start.
|
||||
//
|
||||
macros = *freemem
|
||||
heap = macros + t_macro * NMACROS
|
||||
memset(macros, 0, t_macro * NMACROS)
|
||||
if not loadPatch
|
||||
showHelp
|
||||
fin
|
||||
recalcEnv
|
||||
envelope(current.durAtk, current.durDcy, current.durSus, current.durRel, current:rateAtk, current:rateDcy, current:rateRel)
|
||||
grmode
|
||||
showMainPanel
|
||||
main // Main program
|
||||
if modPatch
|
||||
if query("SAVE PATCH (Y/N)?")
|
||||
savePatch
|
||||
fin
|
||||
fin
|
||||
normal
|
||||
textmode
|
||||
done
|
BIN
src/samplesrc/a2pwm/lfo.po
Executable file
BIN
src/samplesrc/a2pwm/lfo.po
Executable file
Binary file not shown.
32
src/samplesrc/a2pwm/lfotbl.s
Executable file
32
src/samplesrc/a2pwm/lfotbl.s
Executable file
@ -0,0 +1,32 @@
|
||||
LFODWN !BYTE $F0 , $F0 , $E0 , $E0 , $D0 , $D0 , $C0 , $C0
|
||||
!BYTE $B0 , $B0 , $A0 , $A0 , $90 , $90 , $80 , $80
|
||||
!BYTE $70 , $70 , $60 , $60 , $50 , $50 , $40 , $40
|
||||
!BYTE $30 , $30 , $20 , $20 , $10 , $10 , $00 , $00
|
||||
LFOUP !BYTE $00 , $00 , $10 , $10 , $20 , $20 , $30 , $30
|
||||
!BYTE $40 , $40 , $50 , $50 , $60 , $60 , $70 , $70
|
||||
!BYTE $80 , $80 , $90 , $90 , $A0 , $A0 , $B0 , $B0
|
||||
!BYTE $C0 , $C0 , $D0 , $D0 , $E0 , $E0 , $F0 , $F0
|
||||
LFOREXP !BYTE $F0 , $D0 , $C0 , $B0 , $A0 , $90 , $90 , $80
|
||||
!BYTE $70 , $60 , $60 , $50 , $50 , $40 , $40 , $40
|
||||
!BYTE $30 , $30 , $30 , $20 , $20 , $20 , $20 , $10
|
||||
!BYTE $10 , $10 , $10 , $10 , $10 , $00 , $00 , $00
|
||||
LFOEXP !BYTE $00 , $00 , $00 , $10 , $10 , $10 , $10 , $10
|
||||
!BYTE $10 , $20 , $20 , $20 , $20 , $30 , $30 , $30
|
||||
!BYTE $40 , $40 , $40 , $50 , $50 , $60 , $60 , $70
|
||||
!BYTE $80 , $90 , $90 , $A0 , $B0 , $C0 , $D0 , $F0
|
||||
LFSAW !BYTE $00 , $10 , $20 , $30 , $40 , $50 , $60 , $70
|
||||
!BYTE $80 , $90 , $A0 , $B0 , $C0 , $D0 , $E0 , $F0
|
||||
!BYTE $F0 , $E0 , $D0 , $C0 , $B0 , $A0 , $90 , $80
|
||||
!BYTE $70 , $60 , $50 , $40 , $30 , $20 , $10 , $00
|
||||
LFOCOS !BYTE $00 , $10 , $10 , $20 , $30 , $40 , $50 , $60
|
||||
!BYTE $80 , $90 , $B0 , $C0 , $D0 , $E0 , $F0 , $F0
|
||||
!BYTE $F0 , $F0 , $F0 , $E0 , $D0 , $C0 , $B0 , $90
|
||||
!BYTE $80 , $60 , $50 , $40 , $30 , $20 , $10 , $10
|
||||
LFOSIN !BYTE $00 , $20 , $30 , $50 , $60 , $80 , $90 , $A0
|
||||
!BYTE $B0 , $C0 , $D0 , $E0 , $E0 , $F0 , $F0 , $F0
|
||||
!BYTE $F0 , $F0 , $F0 , $F0 , $E0 , $E0 , $D0 , $C0
|
||||
!BYTE $B0 , $A0 , $90 , $80 , $60 , $50 , $30 , $20
|
||||
LFOOCOS !BYTE $F0 , $F0 , $F0 , $E0 , $E0 , $E0 , $D0 , $C0
|
||||
!BYTE $C0 , $B0 , $A0 , $90 , $90 , $90 , $80 , $80
|
||||
!BYTE $80 , $80 , $80 , $90 , $90 , $90 , $A0 , $B0
|
||||
!BYTE $C0 , $C0 , $D0 , $E0 , $E0 , $E0 , $F0 , $F0
|
28
src/samplesrc/a2pwm/makefile
Executable file
28
src/samplesrc/a2pwm/makefile
Executable file
@ -0,0 +1,28 @@
|
||||
.SUFFIXES =
|
||||
AFLAGS = -o $@
|
||||
HILOPWM = hilopwm.bin
|
||||
PLASM = ../../plasm
|
||||
#
|
||||
# Image filetypes for Virtual ][
|
||||
#
|
||||
PLATYPE = .\$$ED
|
||||
BINTYPE = .BIN
|
||||
SYSTYPE = .SYS
|
||||
TXTTYPE = .TXT
|
||||
#
|
||||
# Image filetypes for CiderPress
|
||||
#
|
||||
#RELTYPE = \#FE1000
|
||||
#INTERPTYPE = \#050000
|
||||
#BINTYPE = \#060000
|
||||
#SYSTYPE = \#FF2000
|
||||
#TXTTYPE = \#040000
|
||||
|
||||
all: $(HILOPWM)
|
||||
|
||||
clean:
|
||||
-rm *.o *~ *.a *.bin
|
||||
|
||||
$(HILOPWM): a2pwm.s util.pla hilopwm.pla pwmvm.s $(PLASM)
|
||||
$(PLASM) -A < hilopwm.pla > hilopwm.a
|
||||
acme -o $(HILOPWM) pwmvm.s
|
987
src/samplesrc/a2pwm/pwmvm.s
Executable file
987
src/samplesrc/a2pwm/pwmvm.s
Executable file
@ -0,0 +1,987 @@
|
||||
;**********************************************************
|
||||
;*
|
||||
;* STAND-ALONE PLASMA INTERPETER
|
||||
;*
|
||||
;* SYSTEM ROUTINES AND LOCATIONS
|
||||
;*
|
||||
;**********************************************************
|
||||
;*
|
||||
;* VM ZERO PAGE LOCATIONS
|
||||
;*
|
||||
SRC = $02
|
||||
SRCL = SRC
|
||||
SRCH = SRC+1
|
||||
DST = SRC+2
|
||||
DSTL = DST
|
||||
DSTH = DST+1
|
||||
ESTKSZ = $20
|
||||
ESTK = $C0
|
||||
ESTKL = ESTK
|
||||
ESTKH = ESTK+ESTKSZ/2
|
||||
VMZP = ESTK+ESTKSZ
|
||||
ESP = VMZP
|
||||
DVSIGN = VMZP
|
||||
IFP = ESP+1
|
||||
IFPL = IFP
|
||||
IFPH = IFP+1
|
||||
PP = IFP+2
|
||||
PPL = PP
|
||||
PPH = PP+1
|
||||
IPY = PP+2
|
||||
TMP = IPY+1
|
||||
TMPL = TMP
|
||||
TMPH = TMP+1
|
||||
NPARMS = TMPL
|
||||
FRMSZ = TMPH
|
||||
DROP = $EF
|
||||
NEXTOP = $F0
|
||||
FETCHOP = NEXTOP+3
|
||||
IP = FETCHOP+1
|
||||
IPL = IP
|
||||
IPH = IPL+1
|
||||
OPIDX = FETCHOP+6
|
||||
OPPAGE = OPIDX+1
|
||||
;*
|
||||
;* BASIC.SYSTEM ZERO PAGE LOCATIONS
|
||||
;*
|
||||
HIMEM = $73
|
||||
;*
|
||||
;* INTERPRETER INSTRUCTION POINTER INCREMENT MACRO
|
||||
;*
|
||||
!MACRO INC_IP {
|
||||
INY
|
||||
BNE *+4
|
||||
INC IPH
|
||||
}
|
||||
;*
|
||||
;* INTERPRETER HEADER+INITIALIZATION
|
||||
;*
|
||||
*= $2000
|
||||
LDX #$FE
|
||||
TXS
|
||||
JSR VMINIT
|
||||
JSR $BF00
|
||||
!BYTE $65
|
||||
!WORD EXITTBL
|
||||
EXITTBL:
|
||||
!BYTE 4
|
||||
!BYTE 0
|
||||
;*
|
||||
;* SYSTEM INTERPRETER ENTRYPOINT
|
||||
;*
|
||||
INTERP PLA
|
||||
CLC
|
||||
ADC #$01
|
||||
STA IPL
|
||||
PLA
|
||||
ADC #$00
|
||||
STA IPH
|
||||
LDY #$00
|
||||
JMP FETCHOP
|
||||
;*
|
||||
;* ENTER INTO USER BYTECODE INTERPRETER
|
||||
;*
|
||||
IINTERP PLA
|
||||
STA TMPL
|
||||
PLA
|
||||
STA TMPH
|
||||
LDY #$02
|
||||
LDA (TMP),Y
|
||||
STA IPH
|
||||
DEY
|
||||
LDA (TMP),Y
|
||||
STA IPL
|
||||
DEY
|
||||
JMP FETCHOP
|
||||
;*
|
||||
;* MUL TOS-1 BY TOS
|
||||
;*
|
||||
MUL STY IPY
|
||||
LDY #$10
|
||||
LDA ESTKL+1,X
|
||||
EOR #$FF
|
||||
STA TMPL
|
||||
LDA ESTKH+1,X
|
||||
EOR #$FF
|
||||
STA TMPH
|
||||
LDA #$00
|
||||
STA ESTKL+1,X ; PRODL
|
||||
; STA ESTKH+1,X ; PRODH
|
||||
MULLP LSR TMPH ; MULTPLRH
|
||||
ROR TMPL ; MULTPLRL
|
||||
BCS +
|
||||
STA ESTKH+1,X ; PRODH
|
||||
LDA ESTKL,X ; MULTPLNDL
|
||||
ADC ESTKL+1,X ; PRODL
|
||||
STA ESTKL+1,X
|
||||
LDA ESTKH,X ; MULTPLNDH
|
||||
ADC ESTKH+1,X ; PRODH
|
||||
+ ASL ESTKL,X ; MULTPLNDL
|
||||
ROL ESTKH,X ; MULTPLNDH
|
||||
DEY
|
||||
BNE MULLP
|
||||
STA ESTKH+1,X ; PRODH
|
||||
LDY IPY
|
||||
; INX
|
||||
; JMP NEXTOP
|
||||
JMP DROP
|
||||
;*
|
||||
;* INCREMENT TOS
|
||||
;*
|
||||
INCR INC ESTKL,X
|
||||
BNE INCR1
|
||||
INC ESTKH,X
|
||||
INCR1 JMP NEXTOP
|
||||
;*
|
||||
;* DECREMENT TOS
|
||||
;*
|
||||
DECR LDA ESTKL,X
|
||||
BNE DECR1
|
||||
DEC ESTKH,X
|
||||
DECR1 DEC ESTKL,X
|
||||
JMP NEXTOP
|
||||
;*
|
||||
;* BITWISE COMPLIMENT TOS
|
||||
;*
|
||||
COMP LDA #$FF
|
||||
EOR ESTKL,X
|
||||
STA ESTKL,X
|
||||
LDA #$FF
|
||||
EOR ESTKH,X
|
||||
STA ESTKH,X
|
||||
JMP NEXTOP
|
||||
;*
|
||||
;* DIV TOS-1 BY TOS
|
||||
;*
|
||||
DIV JSR _DIV
|
||||
LSR DVSIGN ; SIGN(RESULT) = (SIGN(DIVIDEND) + SIGN(DIVISOR)) & 1
|
||||
BCS NEG
|
||||
JMP NEXTOP
|
||||
;*
|
||||
;* MOD TOS-1 BY TOS
|
||||
;*
|
||||
MOD JSR _DIV
|
||||
LDA TMPL ; REMNDRL
|
||||
STA ESTKL,X
|
||||
LDA TMPH ; REMNDRH
|
||||
STA ESTKH,X
|
||||
LDA DVSIGN ; REMAINDER IS SIGN OF DIVIDEND
|
||||
BMI NEG
|
||||
JMP NEXTOP
|
||||
;*
|
||||
;* NEGATE TOS
|
||||
;*
|
||||
NEG LDA #$00
|
||||
SEC
|
||||
SBC ESTKL,X
|
||||
STA ESTKL,X
|
||||
LDA #$00
|
||||
SBC ESTKH,X
|
||||
STA ESTKH,X
|
||||
JMP NEXTOP
|
||||
;*
|
||||
;* INTERNAL DIVIDE ALGORITHM
|
||||
;*
|
||||
_NEG LDA #$00
|
||||
SEC
|
||||
SBC ESTKL,X
|
||||
STA ESTKL,X
|
||||
LDA #$00
|
||||
SBC ESTKH,X
|
||||
STA ESTKH,X
|
||||
RTS
|
||||
_DIV STY IPY
|
||||
LDY #$11 ; #BITS+1
|
||||
LDA #$00
|
||||
STA TMPL ; REMNDRL
|
||||
STA TMPH ; REMNDRH
|
||||
LDA ESTKH,X
|
||||
AND #$80
|
||||
STA DVSIGN
|
||||
BPL +
|
||||
JSR _NEG
|
||||
INC DVSIGN
|
||||
+ LDA ESTKH+1,X
|
||||
BPL +
|
||||
INX
|
||||
JSR _NEG
|
||||
DEX
|
||||
INC DVSIGN
|
||||
BNE _DIV1
|
||||
+ ORA ESTKL+1,X ; DVDNDL
|
||||
BEQ _DIVEX
|
||||
_DIV1 ASL ESTKL+1,X ; DVDNDL
|
||||
ROL ESTKH+1,X ; DVDNDH
|
||||
DEY
|
||||
BCC _DIV1
|
||||
_DIVLP ROL TMPL ; REMNDRL
|
||||
ROL TMPH ; REMNDRH
|
||||
LDA TMPL ; REMNDRL
|
||||
CMP ESTKL,X ; DVSRL
|
||||
LDA TMPH ; REMNDRH
|
||||
SBC ESTKH,X ; DVSRH
|
||||
BCC +
|
||||
STA TMPH ; REMNDRH
|
||||
LDA TMPL ; REMNDRL
|
||||
SBC ESTKL,X ; DVSRL
|
||||
STA TMPL ; REMNDRL
|
||||
SEC
|
||||
+ ROL ESTKL+1,X ; DVDNDL
|
||||
ROL ESTKH+1,X ; DVDNDH
|
||||
DEY
|
||||
BNE _DIVLP
|
||||
_DIVEX INX
|
||||
LDY IPY
|
||||
RTS
|
||||
;*
|
||||
;* ADD TOS TO TOS-1
|
||||
;*
|
||||
ADD LDA ESTKL,X
|
||||
CLC
|
||||
ADC ESTKL+1,X
|
||||
STA ESTKL+1,X
|
||||
LDA ESTKH,X
|
||||
ADC ESTKH+1,X
|
||||
STA ESTKH+1,X
|
||||
; INX
|
||||
; JMP NEXTOP
|
||||
JMP DROP
|
||||
;*
|
||||
;* SUB TOS FROM TOS-1
|
||||
;*
|
||||
SUB LDA ESTKL+1,X
|
||||
SEC
|
||||
SBC ESTKL,X
|
||||
STA ESTKL+1,X
|
||||
LDA ESTKH+1,X
|
||||
SBC ESTKH,X
|
||||
STA ESTKH+1,X
|
||||
; INX
|
||||
; JMP NEXTOP
|
||||
JMP DROP
|
||||
;
|
||||
;*
|
||||
;* SHIFT TOS LEFT BY 1, ADD TO TOS-1
|
||||
;*
|
||||
IDXW LDA ESTKL,X
|
||||
ASL
|
||||
ROL ESTKH,X
|
||||
CLC
|
||||
ADC ESTKL+1,X
|
||||
STA ESTKL+1,X
|
||||
LDA ESTKH,X
|
||||
ADC ESTKH+1,X
|
||||
STA ESTKH+1,X
|
||||
; INX
|
||||
; JMP NEXTOP
|
||||
JMP DROP
|
||||
;*
|
||||
;* BITWISE AND TOS TO TOS-1
|
||||
;*
|
||||
BAND LDA ESTKL+1,X
|
||||
AND ESTKL,X
|
||||
STA ESTKL+1,X
|
||||
LDA ESTKH+1,X
|
||||
AND ESTKH,X
|
||||
STA ESTKH+1,X
|
||||
; INX
|
||||
; JMP NEXTOP
|
||||
JMP DROP
|
||||
;*
|
||||
;* INCLUSIVE OR TOS TO TOS-1
|
||||
;*
|
||||
IOR LDA ESTKL+1,X
|
||||
ORA ESTKL,X
|
||||
STA ESTKL+1,X
|
||||
LDA ESTKH+1,X
|
||||
ORA ESTKH,X
|
||||
STA ESTKH+1,X
|
||||
; INX
|
||||
; JMP NEXTOP
|
||||
JMP DROP
|
||||
;*
|
||||
;* EXLUSIVE OR TOS TO TOS-1
|
||||
;*
|
||||
XOR LDA ESTKL+1,X
|
||||
EOR ESTKL,X
|
||||
STA ESTKL+1,X
|
||||
LDA ESTKH+1,X
|
||||
EOR ESTKH,X
|
||||
STA ESTKH+1,X
|
||||
; INX
|
||||
; JMP NEXTOP
|
||||
JMP DROP
|
||||
;*
|
||||
;* SHIFT TOS-1 LEFT BY TOS
|
||||
;*
|
||||
SHL STY IPY
|
||||
LDA ESTKL,X
|
||||
CMP #$08
|
||||
BCC SHL1
|
||||
LDY ESTKL+1,X
|
||||
STY ESTKH+1,X
|
||||
LDY #$00
|
||||
STY ESTKL+1,X
|
||||
SBC #$08
|
||||
SHL1 TAY
|
||||
BEQ SHL3
|
||||
SHL2 ASL ESTKL+1,X
|
||||
ROL ESTKH+1,X
|
||||
DEY
|
||||
BNE SHL2
|
||||
SHL3 LDY IPY
|
||||
; INX
|
||||
; JMP NEXTOP
|
||||
JMP DROP
|
||||
;*
|
||||
;* SHIFT TOS-1 RIGHT BY TOS
|
||||
;*
|
||||
SHR STY IPY
|
||||
LDA ESTKL,X
|
||||
CMP #$08
|
||||
BCC SHR2
|
||||
LDY ESTKH+1,X
|
||||
STY ESTKL+1,X
|
||||
CPY #$80
|
||||
LDY #$00
|
||||
BCC SHR1
|
||||
DEY
|
||||
SHR1 STY ESTKH+1,X
|
||||
SEC
|
||||
SBC #$08
|
||||
SHR2 TAY
|
||||
BEQ SHR4
|
||||
LDA ESTKH+1,X
|
||||
SHR3 CMP #$80
|
||||
ROR
|
||||
ROR ESTKL+1,X
|
||||
DEY
|
||||
BNE SHR3
|
||||
STA ESTKH+1,X
|
||||
SHR4 LDY IPY
|
||||
; INX
|
||||
; JMP NEXTOP
|
||||
JMP DROP
|
||||
;*
|
||||
;* LOGICAL NOT
|
||||
;*
|
||||
LNOT LDA ESTKL,X
|
||||
ORA ESTKH,X
|
||||
BEQ LNOT1
|
||||
LDA #$FF
|
||||
LNOT1 EOR #$FF
|
||||
STA ESTKL,X
|
||||
STA ESTKH,X
|
||||
JMP NEXTOP
|
||||
;*
|
||||
;* LOGICAL AND
|
||||
;*
|
||||
LAND LDA ESTKL+1,X
|
||||
ORA ESTKH+1,X
|
||||
BEQ LAND2
|
||||
LDA ESTKL,X
|
||||
ORA ESTKH,X
|
||||
BEQ LAND1
|
||||
LDA #$FF
|
||||
LAND1 STA ESTKL+1,X
|
||||
STA ESTKH+1,X
|
||||
;LAND2 INX
|
||||
; JMP NEXTOP
|
||||
LAND2 JMP DROP
|
||||
;*
|
||||
;* LOGICAL OR
|
||||
;*
|
||||
LOR LDA ESTKL,X
|
||||
ORA ESTKH,X
|
||||
ORA ESTKL+1,X
|
||||
ORA ESTKH+1,X
|
||||
BEQ LOR1
|
||||
LDA #$FF
|
||||
STA ESTKL+1,X
|
||||
STA ESTKH+1,X
|
||||
;LOR1 INX
|
||||
; JMP NEXTOP
|
||||
LOR1 JMP DROP
|
||||
;*
|
||||
;* DUPLICATE TOS
|
||||
;*
|
||||
DUP DEX
|
||||
LDA ESTKL+1,X
|
||||
STA ESTKL,X
|
||||
LDA ESTKH+1,X
|
||||
STA ESTKH,X
|
||||
JMP NEXTOP
|
||||
;*
|
||||
;* PUSH FROM EVAL STACK TO CALL STACK
|
||||
;*
|
||||
PUSH LDA ESTKL,X
|
||||
PHA
|
||||
LDA ESTKH,X
|
||||
PHA
|
||||
; INX
|
||||
; JMP NEXTOP
|
||||
JMP DROP
|
||||
;*
|
||||
;* PULL FROM CALL STACK TO EVAL STACK
|
||||
;*
|
||||
PULL DEX
|
||||
PLA
|
||||
STA ESTKH,X
|
||||
PLA
|
||||
STA ESTKL,X
|
||||
JMP NEXTOP
|
||||
;*
|
||||
;* CONSTANT
|
||||
;*
|
||||
ZERO DEX
|
||||
LDA #$00
|
||||
STA ESTKL,X
|
||||
STA ESTKH,X
|
||||
JMP NEXTOP
|
||||
CB DEX
|
||||
+INC_IP
|
||||
LDA (IP),Y
|
||||
STA ESTKL,X
|
||||
LDA #$00
|
||||
STA ESTKH,X
|
||||
JMP NEXTOP
|
||||
;*
|
||||
;* LOAD ADDRESS & LOAD CONSTANT WORD (SAME THING, WITH OR WITHOUT FIXUP)
|
||||
;*
|
||||
LA = *
|
||||
CW DEX
|
||||
+INC_IP
|
||||
LDA (IP),Y
|
||||
STA ESTKL,X
|
||||
+INC_IP
|
||||
LDA (IP),Y
|
||||
STA ESTKH,X
|
||||
JMP NEXTOP
|
||||
;*
|
||||
;* CONSTANT STRING
|
||||
;*
|
||||
CS DEX
|
||||
+INC_IP
|
||||
TYA ; NORMALIZE IP AND SAVE STRING ADDR ON ESTK
|
||||
CLC
|
||||
ADC IPL
|
||||
STA IPL
|
||||
STA ESTKL,X
|
||||
LDA #$00
|
||||
TAY
|
||||
ADC IPH
|
||||
STA IPH
|
||||
STA ESTKH,X
|
||||
LDA (IP),Y
|
||||
TAY
|
||||
JMP NEXTOP
|
||||
;*
|
||||
;* LOAD VALUE FROM ADDRESS TAG
|
||||
;*
|
||||
LB LDA ESTKL,X
|
||||
STA TMPL
|
||||
LDA ESTKH,X
|
||||
STA TMPH
|
||||
STY IPY
|
||||
LDY #$00
|
||||
LDA (TMP),Y
|
||||
STA ESTKL,X
|
||||
STY ESTKH,X
|
||||
LDY IPY
|
||||
JMP NEXTOP
|
||||
LW LDA ESTKL,X
|
||||
STA TMPL
|
||||
LDA ESTKH,X
|
||||
STA TMPH
|
||||
STY IPY
|
||||
LDY #$00
|
||||
LDA (TMP),Y
|
||||
STA ESTKL,X
|
||||
INY
|
||||
LDA (TMP),Y
|
||||
STA ESTKH,X
|
||||
LDY IPY
|
||||
JMP NEXTOP
|
||||
;*
|
||||
;* LOAD ADDRESS OF LOCAL FRAME OFFSET
|
||||
;*
|
||||
LLA +INC_IP
|
||||
LDA (IP),Y
|
||||
DEX
|
||||
CLC
|
||||
ADC IFPL
|
||||
STA ESTKL,X
|
||||
LDA #$00
|
||||
ADC IFPH
|
||||
STA ESTKH,X
|
||||
JMP NEXTOP
|
||||
;*
|
||||
;* LOAD VALUE FROM LOCAL FRAME OFFSET
|
||||
;*
|
||||
LLB +INC_IP
|
||||
LDA (IP),Y
|
||||
STY IPY
|
||||
TAY
|
||||
DEX
|
||||
LDA (IFP),Y
|
||||
STA ESTKL,X
|
||||
LDA #$00
|
||||
STA ESTKH,X
|
||||
LDY IPY
|
||||
JMP NEXTOP
|
||||
LLW +INC_IP
|
||||
LDA (IP),Y
|
||||
STY IPY
|
||||
TAY
|
||||
DEX
|
||||
LDA (IFP),Y
|
||||
STA ESTKL,X
|
||||
INY
|
||||
LDA (IFP),Y
|
||||
STA ESTKH,X
|
||||
LDY IPY
|
||||
JMP NEXTOP
|
||||
;*
|
||||
;* LOAD VALUE FROM ABSOLUTE ADDRESS
|
||||
;*
|
||||
LAB +INC_IP
|
||||
LDA (IP),Y
|
||||
STA TMPL
|
||||
+INC_IP
|
||||
LDA (IP),Y
|
||||
STA TMPH
|
||||
STY IPY
|
||||
LDY #$00
|
||||
LDA (TMP),Y
|
||||
DEX
|
||||
STA ESTKL,X
|
||||
STY ESTKH,X
|
||||
LDY IPY
|
||||
JMP NEXTOP
|
||||
LAW +INC_IP
|
||||
LDA (IP),Y
|
||||
STA TMPL
|
||||
+INC_IP
|
||||
LDA (IP),Y
|
||||
STA TMPH
|
||||
STY IPY
|
||||
LDY #$00
|
||||
LDA (TMP),Y
|
||||
DEX
|
||||
STA ESTKL,X
|
||||
INY
|
||||
LDA (TMP),Y
|
||||
STA ESTKH,X
|
||||
LDY IPY
|
||||
JMP NEXTOP
|
||||
;*
|
||||
;* STORE VALUE TO ADDRESS
|
||||
;*
|
||||
SB LDA ESTKL+1,X
|
||||
STA TMPL
|
||||
LDA ESTKH+1,X
|
||||
STA TMPH
|
||||
LDA ESTKL,X
|
||||
STY IPY
|
||||
LDY #$00
|
||||
STA (TMP),Y
|
||||
LDY IPY
|
||||
INX
|
||||
; INX
|
||||
; JMP NEXTOP
|
||||
JMP DROP
|
||||
SW LDA ESTKL+1,X
|
||||
STA TMPL
|
||||
LDA ESTKH+1,X
|
||||
STA TMPH
|
||||
STY IPY
|
||||
LDY #$00
|
||||
LDA ESTKL,X
|
||||
STA (TMP),Y
|
||||
INY
|
||||
LDA ESTKH,X
|
||||
STA (TMP),Y
|
||||
LDY IPY
|
||||
INX
|
||||
; INX
|
||||
; JMP NEXTOP
|
||||
JMP DROP
|
||||
;*
|
||||
;* STORE VALUE TO LOCAL FRAME OFFSET
|
||||
;*
|
||||
SLB +INC_IP
|
||||
LDA (IP),Y
|
||||
STY IPY
|
||||
TAY
|
||||
LDA ESTKL,X
|
||||
STA (IFP),Y
|
||||
LDY IPY
|
||||
; INX
|
||||
; JMP NEXTOP
|
||||
JMP DROP
|
||||
SLW +INC_IP
|
||||
LDA (IP),Y
|
||||
STY IPY
|
||||
TAY
|
||||
LDA ESTKL,X
|
||||
STA (IFP),Y
|
||||
INY
|
||||
LDA ESTKH,X
|
||||
STA (IFP),Y
|
||||
LDY IPY
|
||||
; INX
|
||||
; JMP NEXTOP
|
||||
JMP DROP
|
||||
;*
|
||||
;* STORE VALUE TO LOCAL FRAME OFFSET WITHOUT POPPING STACK
|
||||
;*
|
||||
DLB +INC_IP
|
||||
LDA (IP),Y
|
||||
STY IPY
|
||||
TAY
|
||||
LDA ESTKL,X
|
||||
STA (IFP),Y
|
||||
LDY IPY
|
||||
JMP NEXTOP
|
||||
DLW +INC_IP
|
||||
LDA (IP),Y
|
||||
STY IPY
|
||||
TAY
|
||||
LDA ESTKL,X
|
||||
STA (IFP),Y
|
||||
INY
|
||||
LDA ESTKH,X
|
||||
STA (IFP),Y
|
||||
LDY IPY
|
||||
JMP NEXTOP
|
||||
;*
|
||||
;* STORE VALUE TO ABSOLUTE ADDRESS
|
||||
;*
|
||||
SAB +INC_IP
|
||||
LDA (IP),Y
|
||||
STA TMPL
|
||||
+INC_IP
|
||||
LDA (IP),Y
|
||||
STA TMPH
|
||||
LDA ESTKL,X
|
||||
STY IPY
|
||||
LDY #$00
|
||||
STA (TMP),Y
|
||||
LDY IPY
|
||||
; INX
|
||||
; JMP NEXTOP
|
||||
JMP DROP
|
||||
SAW +INC_IP
|
||||
LDA (IP),Y
|
||||
STA TMPL
|
||||
+INC_IP
|
||||
LDA (IP),Y
|
||||
STA TMPH
|
||||
STY IPY
|
||||
LDY #$00
|
||||
LDA ESTKL,X
|
||||
STA (TMP),Y
|
||||
INY
|
||||
LDA ESTKH,X
|
||||
STA (TMP),Y
|
||||
LDY IPY
|
||||
; INX
|
||||
; JMP NEXTOP
|
||||
JMP DROP
|
||||
;*
|
||||
;* STORE VALUE TO ABSOLUTE ADDRESS WITHOUT POPPING STACK
|
||||
;*
|
||||
DAB +INC_IP
|
||||
LDA (IP),Y
|
||||
STA TMPL
|
||||
+INC_IP
|
||||
LDA (IP),Y
|
||||
STA TMPH
|
||||
STY IPY
|
||||
LDY #$00
|
||||
LDA ESTKL,X
|
||||
STA (TMP),Y
|
||||
LDY IPY
|
||||
JMP NEXTOP
|
||||
DAW +INC_IP
|
||||
LDA (IP),Y
|
||||
STA TMPL
|
||||
+INC_IP
|
||||
LDA (IP),Y
|
||||
STA TMPH
|
||||
STY IPY
|
||||
LDY #$00
|
||||
LDA ESTKL,X
|
||||
STA (TMP),Y
|
||||
INY
|
||||
LDA ESTKH,X
|
||||
STA (TMP),Y
|
||||
LDY IPY
|
||||
JMP NEXTOP
|
||||
;*
|
||||
;* COMPARES
|
||||
;*
|
||||
ISEQ LDA ESTKL,X
|
||||
CMP ESTKL+1,X
|
||||
BNE ISFLS
|
||||
LDA ESTKH,X
|
||||
CMP ESTKH+1,X
|
||||
BNE ISFLS
|
||||
ISTRU LDA #$FF
|
||||
STA ESTKL+1,X
|
||||
STA ESTKH+1,X
|
||||
; INX
|
||||
; JMP NEXTOP
|
||||
JMP DROP
|
||||
;
|
||||
ISNE LDA ESTKL,X
|
||||
CMP ESTKL+1,X
|
||||
BNE ISTRU
|
||||
LDA ESTKH,X
|
||||
CMP ESTKH+1,X
|
||||
BNE ISTRU
|
||||
ISFLS LDA #$00
|
||||
STA ESTKL+1,X
|
||||
STA ESTKH+1,X
|
||||
; INX
|
||||
; JMP NEXTOP
|
||||
JMP DROP
|
||||
;
|
||||
ISGE LDA ESTKL+1,X
|
||||
CMP ESTKL,X
|
||||
LDA ESTKH+1,X
|
||||
SBC ESTKH,X
|
||||
BVC ISGE1
|
||||
EOR #$80
|
||||
ISGE1 BPL ISTRU
|
||||
BMI ISFLS
|
||||
;
|
||||
ISGT LDA ESTKL,X
|
||||
CMP ESTKL+1,X
|
||||
LDA ESTKH,X
|
||||
SBC ESTKH+1,X
|
||||
BVC ISGT1
|
||||
EOR #$80
|
||||
ISGT1 BMI ISTRU
|
||||
BPL ISFLS
|
||||
;
|
||||
ISLE LDA ESTKL,X
|
||||
CMP ESTKL+1,X
|
||||
LDA ESTKH,X
|
||||
SBC ESTKH+1,X
|
||||
BVC ISLE1
|
||||
EOR #$80
|
||||
ISLE1 BPL ISTRU
|
||||
BMI ISFLS
|
||||
;
|
||||
ISLT LDA ESTKL+1,X
|
||||
CMP ESTKL,X
|
||||
LDA ESTKH+1,X
|
||||
SBC ESTKH,X
|
||||
BVC ISLT1
|
||||
EOR #$80
|
||||
ISLT1 BMI ISTRU
|
||||
BPL ISFLS
|
||||
;*
|
||||
;* BRANCHES
|
||||
;*
|
||||
BRTRU INX
|
||||
LDA ESTKH-1,X
|
||||
ORA ESTKL-1,X
|
||||
BNE BRNCH
|
||||
NOBRNCH +INC_IP
|
||||
+INC_IP
|
||||
JMP NEXTOP
|
||||
BRFLS INX
|
||||
LDA ESTKH-1,X
|
||||
ORA ESTKL-1,X
|
||||
BNE NOBRNCH
|
||||
BRNCH LDA IPH
|
||||
STA TMPH
|
||||
LDA IPL
|
||||
+INC_IP
|
||||
CLC
|
||||
ADC (IP),Y
|
||||
STA TMPL
|
||||
LDA TMPH
|
||||
+INC_IP
|
||||
ADC (IP),Y
|
||||
STA IPH
|
||||
LDA TMPL
|
||||
STA IPL
|
||||
DEY
|
||||
DEY
|
||||
JMP NEXTOP
|
||||
BREQ INX
|
||||
LDA ESTKL-1,X
|
||||
CMP ESTKL,X
|
||||
BNE NOBRNCH
|
||||
LDA ESTKH-1,X
|
||||
CMP ESTKH,X
|
||||
BEQ BRNCH
|
||||
BNE NOBRNCH
|
||||
BRNE INX
|
||||
LDA ESTKL-1,X
|
||||
CMP ESTKL,X
|
||||
BNE BRNCH
|
||||
LDA ESTKH-1,X
|
||||
CMP ESTKH,X
|
||||
BEQ NOBRNCH
|
||||
BNE BRNCH
|
||||
BRGT INX
|
||||
LDA ESTKL-1,X
|
||||
CMP ESTKL,X
|
||||
LDA ESTKH-1,X
|
||||
SBC ESTKH,X
|
||||
BMI BRNCH
|
||||
BPL NOBRNCH
|
||||
BRLT INX
|
||||
LDA ESTKL,X
|
||||
CMP ESTKL-1,X
|
||||
LDA ESTKH,X
|
||||
SBC ESTKH-1,X
|
||||
BMI BRNCH
|
||||
BPL NOBRNCH
|
||||
IBRNCH LDA IPL
|
||||
CLC
|
||||
ADC ESTKL,X
|
||||
STA IPL
|
||||
LDA IPH
|
||||
ADC ESTKH,X
|
||||
STA IPH
|
||||
; INX
|
||||
; JMP NEXTOP
|
||||
JMP DROP
|
||||
;*
|
||||
;* CALL INTO ABSOLUTE ADDRESS (NATIVE CODE)
|
||||
;*
|
||||
CALL +INC_IP
|
||||
LDA (IP),Y
|
||||
STA CALLADR+1
|
||||
+INC_IP
|
||||
LDA (IP),Y
|
||||
STA CALLADR+2
|
||||
LDA IPH
|
||||
PHA
|
||||
LDA IPL
|
||||
PHA
|
||||
TYA
|
||||
PHA
|
||||
CALLADR JSR $FFFF
|
||||
PLA
|
||||
TAY
|
||||
PLA
|
||||
STA IPL
|
||||
PLA
|
||||
STA IPH
|
||||
JMP NEXTOP
|
||||
;*
|
||||
;* INDIRECT CALL TO ADDRESS (NATIVE CODE)
|
||||
;*
|
||||
ICAL LDA ESTKL,X
|
||||
STA ICALADR+1
|
||||
LDA ESTKH,X
|
||||
STA ICALADR+2
|
||||
INX
|
||||
LDA IPH
|
||||
PHA
|
||||
LDA IPL
|
||||
PHA
|
||||
TYA
|
||||
PHA
|
||||
ICALADR JSR $FFFF
|
||||
PLA
|
||||
TAY
|
||||
PLA
|
||||
STA IPL
|
||||
PLA
|
||||
STA IPH
|
||||
JMP NEXTOP
|
||||
;*
|
||||
;* ENTER FUNCTION WITH FRAME SIZE AND PARAM COUNT
|
||||
;*
|
||||
ENTER INY
|
||||
LDA (IP),Y
|
||||
PHA ; SAVE ON STACK FOR LEAVE
|
||||
EOR #$FF
|
||||
SEC
|
||||
ADC IFPL
|
||||
STA IFPL
|
||||
BCS +
|
||||
DEC IFPH
|
||||
+ INY
|
||||
LDA (IP),Y
|
||||
ASL
|
||||
TAY
|
||||
BEQ +
|
||||
- LDA ESTKH,X
|
||||
DEY
|
||||
STA (IFP),Y
|
||||
LDA ESTKL,X
|
||||
INX
|
||||
DEY
|
||||
STA (IFP),Y
|
||||
BNE -
|
||||
+ LDY #$02
|
||||
JMP NEXTOP
|
||||
;*
|
||||
;* LEAVE FUNCTION
|
||||
;*
|
||||
LEAVE PLA
|
||||
CLC
|
||||
ADC IFPL
|
||||
STA IFPL
|
||||
BCS LIFPH
|
||||
RTS
|
||||
LIFPH INC IFPH
|
||||
RET RTS
|
||||
;*
|
||||
;* OPCODE TABLE
|
||||
;*
|
||||
!ALIGN 255,0
|
||||
OPTBL !WORD ZERO,ADD,SUB,MUL,DIV,MOD,INCR,DECR ; 00 02 04 06 08 0A 0C 0E
|
||||
!WORD NEG,COMP,BAND,IOR,XOR,SHL,SHR,IDXW ; 10 12 14 16 18 1A 1C 1E
|
||||
!WORD LNOT,LOR,LAND,LA,LLA,CB,CW,CS ; 20 22 24 26 28 2A 2C 2E
|
||||
!WORD DROP,DUP,PUSH,PULL,BRGT,BRLT,BREQ,BRNE ; 30 32 34 36 38 3A 3C 3E
|
||||
!WORD ISEQ,ISNE,ISGT,ISLT,ISGE,ISLE,BRFLS,BRTRU ; 40 42 44 46 48 4A 4C 4E
|
||||
!WORD BRNCH,IBRNCH,CALL,ICAL,ENTER,LEAVE,RET,NEXTOP ; 50 52 54 56 58 5A 5C 5E
|
||||
!WORD LB,LW,LLB,LLW,LAB,LAW,DLB,DLW ; 60 62 64 66 68 6A 6C 6E
|
||||
!WORD SB,SW,SLB,SLW,SAB,SAW,DAB,DAW ; 70 72 74 76 78 7A 7C 7E
|
||||
;*
|
||||
;*SAVED ZERO PAGE
|
||||
;*
|
||||
ZPSAVE !FILL 256
|
||||
;*
|
||||
;* SOURCE PWM ASM/PLASMA PROGRAM
|
||||
;*
|
||||
!SOURCE "a2pwm.s"
|
||||
START !SOURCE "hilopwm.a"
|
||||
SEGEND = *
|
||||
VMINIT LDY #$10 ; INSTALL PAGE 0 FETCHOP ROUTINE
|
||||
- LDA PAGE0-1,Y
|
||||
STA DROP-1,Y
|
||||
DEY
|
||||
BNE -
|
||||
STY IFPL ; INIT FRAME POINTER
|
||||
LDA #$BF
|
||||
STA IFPH
|
||||
LDA #<SEGEND ; SAVE HEAP START
|
||||
STA SRCL
|
||||
LDA #>SEGEND
|
||||
STA SRCH
|
||||
LDA #$4C
|
||||
JMP START
|
||||
PAGE0 = *
|
||||
!PSEUDOPC $00EF {
|
||||
;*
|
||||
;* INTERP BYTECODE INNER LOOP
|
||||
;*
|
||||
INX ; DROP
|
||||
INY ; NEXTOP
|
||||
BEQ NEXTOPH
|
||||
LDA $FFFF,Y ; FETCHOP @ $F3, IP MAPS OVER $FFFF @ $F4
|
||||
STA OPIDX
|
||||
JMP (OPTBL)
|
||||
NEXTOPH INC IPH
|
||||
BNE FETCHOP
|
||||
}
|
51
src/samplesrc/a2pwm/readme.md
Normal file
51
src/samplesrc/a2pwm/readme.md
Normal file
@ -0,0 +1,51 @@
|
||||
# Oscillation Overthruster
|
||||
## Intro
|
||||
Oscillation Overthruster (HiLoPWM) is a synthesizer/sequencer for playing around with the Apple II and its limited sound capability. A High Frequency Oscillator (HFO) samples the waveform of a Low Frequency Oscillator (LFO) and applies an Attack/Decay/Sustain/Release envelope to the resulting value which is output as a Pulse Width Modulated (PWM) value. This can create some interesting effects and tones.
|
||||
## Running
|
||||
The HILOPWM.SYSTEM file can be launched by booting the lfo.po disk image. The first time, the help screen will be presented with a list of the available commands. Once a PATCH file has been saved, the help screen will only show up by pressing the ESCape key. The main screen displays a graphical representation of the LFO waveform, LFO period and tone duration. The lower panel displays the textual representation of the LFO period, duration, and octave. The Apple II keyboard keys that map a piano keyboard octave is shown in the middle. Macros can be recorded and played back along with playing tones and changing parameters. The macros and parameters can be made persistent by saving them to disk. The next time HILOPWM.SYSTEM is run, the help screen will be skipped and the macros and settings from the previous session will be present. When quitting (CTRL-Q), you will be prompted if want to quit in case it was an accidental keypress, then optionally prompted to save the current state if it has changed since the last save.
|
||||
## Playing Tones
|
||||
The Apple II keyboard is mapped to a one octave piano keyboard, from Bn-1 to Cn+1.
|
||||
|
||||
KEY NOTE ('n' is current octave)
|
||||
--- ----
|
||||
A Bn-1
|
||||
S Cn
|
||||
E C#n
|
||||
D Dn
|
||||
R D#n
|
||||
F En
|
||||
G Fn
|
||||
Y F#n
|
||||
H Gn
|
||||
U G#n
|
||||
J An
|
||||
I A#n
|
||||
K Bn
|
||||
L Cn+1
|
||||
|
||||
The duration of the note is in increments of 0.0255 seconds (the PWM loop is 100 cycles and runs 255 times at ~1.022 MHz). The maximum note length is slight longer than 1 second.
|
||||
|
||||
## Command keys
|
||||
KEY COMMAND
|
||||
-------------- --------------------
|
||||
ESC HELP/CANCEL RECORD
|
||||
CTRL-Q QUIT
|
||||
1..8 LFO WAVEFORM
|
||||
< , INCREASE LFO
|
||||
> . DECREASE LFO
|
||||
LEFT-ARROW PREV OCTAVE
|
||||
RIGHT-ARROW NEXT OCTAVE
|
||||
+ UP-ARROW INCREASE DURATION
|
||||
- DOWN-ARROW DECREASE DURATION
|
||||
CTRL-Z..M RECORD MACRO
|
||||
/ SAVE ABS MACRO
|
||||
? SAVE REL MACRO
|
||||
P PERSISTANT STATE
|
||||
0 TOGGLE SPEAKER PHASE
|
||||
|
||||
Command keys and note keys can be interspersed together.
|
||||
### Recording Macros
|
||||
One of the most powerful features of the Oscillation Overthruster is macro recording. There are seven macros that can be assigned to the lower row of keys, Z ... M. To record one of the macros, type the key along with the CONTROL key to begin recording. The RECORDING text will show up to the right of the text panel during recording. When recording, other macros can be called, allowing nested calls. However, recursive macros cannot be made, i.e. macro Z calling macro X calling macro Z. If, during recording, you want to cancel the macro, press ESCape. Their are two ways to save the macro: absolute and relative. An absolute macro will retain the state settings at the time the macro is recorded. Octave, duration, and LFO settings are restored before the macro is played, then restored when it is done. A relative macro will use the current settings when playing back. To record a rest, the spacebar will insert a pause for the length of the current duration. You can make the current macros persistent by pressing 'P' to write the macros and current settings to disk for the next time.
|
||||
|
||||
## A note about speaker phase
|
||||
I discovered that the Apple ][ and Apple //e are affected by the initial phase of the speaker when implementing volume control with PWM. Interestingly, the Apple //c and emulators aren't impacted by the speaker phase. The hack was to add a command to flip the speaker phase (the '0' key). If you notice diminished volume when you run Oscillation Overthruster, press '0' to see if it doesn't clear up the problem. I hope to find a solid solution to this someday, but this is the fix for now.
|
496
src/samplesrc/a2pwm/util.pla
Normal file
496
src/samplesrc/a2pwm/util.pla
Normal file
@ -0,0 +1,496 @@
|
||||
//
|
||||
// Colors
|
||||
//
|
||||
const BLACK = 0
|
||||
const MAGENTA = 1
|
||||
const DRKBLU = 2
|
||||
const PURPLE = 3
|
||||
const DRKGRN = 4
|
||||
const GREY = 5
|
||||
const MEDBLU = 6
|
||||
const LGTBLU = 7
|
||||
const BROWN = 8
|
||||
const ORANGE = 9
|
||||
const GRAY = 10
|
||||
const PINK = 11
|
||||
const LGTGRN = 12
|
||||
const YELLOW = 13
|
||||
const AQUA = 14
|
||||
const WHITE = 15
|
||||
|
||||
word txt1scrn[] = $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
|
||||
//
|
||||
// ProDOS error
|
||||
//
|
||||
byte perr
|
||||
//
|
||||
// CALL 6502 ROUTINE
|
||||
// CALL(ADDR, AREG, XREG, YREG, STATUS)
|
||||
//
|
||||
asm call
|
||||
PHP
|
||||
LDA ESTKL+4,X
|
||||
STA CALL6502+1
|
||||
LDA ESTKH+4,X
|
||||
STA CALL6502+2
|
||||
LDA ESTKL,X
|
||||
PHA
|
||||
LDA ESTKL+1,X
|
||||
TAY
|
||||
LDA ESTKL+3,X
|
||||
PHA
|
||||
LDA ESTKL+2,X
|
||||
INX
|
||||
INX
|
||||
INX
|
||||
INX
|
||||
STX ESP
|
||||
TAX
|
||||
PLA
|
||||
PLP
|
||||
CALL6502 JSR $FFFF
|
||||
PHP
|
||||
STA REGVALS+0
|
||||
STX REGVALS+1
|
||||
STY REGVALS+2
|
||||
PLA
|
||||
STA REGVALS+3
|
||||
LDX ESP
|
||||
LDA #<REGVALS
|
||||
LDY #>REGVALS
|
||||
STA ESTKL,X
|
||||
STY ESTKH,X
|
||||
PLP
|
||||
RTS
|
||||
REGVALS !FILL 4
|
||||
end
|
||||
//
|
||||
// CALL PRODOS
|
||||
// SYSCALL(CMD, PARAMS)
|
||||
//
|
||||
asm syscall
|
||||
LDA ESTKL,X
|
||||
LDY ESTKH,X
|
||||
STA PARAMS
|
||||
STY PARAMS+1
|
||||
INX
|
||||
LDA ESTKL,X
|
||||
STA CMD
|
||||
JSR $BF00
|
||||
CMD: !BYTE 00
|
||||
PARAMS: !WORD 0000
|
||||
LDY #$00
|
||||
STA ESTKL,X
|
||||
STY ESTKH,X
|
||||
RTS
|
||||
end
|
||||
//
|
||||
// SET MEMORY TO VALUE
|
||||
// MEMSET(ADDR, VALUE, SIZE)
|
||||
// With optimizations from Peter Ferrie
|
||||
//
|
||||
asm memset
|
||||
LDA ESTKL+2,X
|
||||
STA DSTL
|
||||
LDA ESTKH+2,X
|
||||
STA DSTH
|
||||
LDY ESTKL,X
|
||||
BEQ +
|
||||
INC ESTKH,X
|
||||
LDY #$00
|
||||
+ LDA ESTKH,X
|
||||
BEQ SETMEX
|
||||
SETMLPL CLC
|
||||
LDA ESTKL+1,X
|
||||
SETMLPH STA (DST),Y
|
||||
DEC ESTKL,X
|
||||
BEQ ++
|
||||
- INY
|
||||
BEQ +
|
||||
-- BCS SETMLPL
|
||||
SEC
|
||||
LDA ESTKH+1,X
|
||||
BCS SETMLPH
|
||||
+ INC DSTH
|
||||
BNE --
|
||||
++ DEC ESTKH,X
|
||||
BNE -
|
||||
SETMEX INX
|
||||
INX
|
||||
RTS
|
||||
end
|
||||
//
|
||||
// COPY MEMORY
|
||||
// MEMCPY(DSTADDR, SRCADDR, SIZE)
|
||||
//
|
||||
asm memcpy
|
||||
INX
|
||||
INX
|
||||
LDA ESTKL-2,X
|
||||
ORA ESTKH-2,X
|
||||
BEQ CPYMEX
|
||||
LDA ESTKL-1,X
|
||||
CMP ESTKL,X
|
||||
LDA ESTKH-1,X
|
||||
SBC ESTKH,X
|
||||
BCC REVCPY
|
||||
;
|
||||
; FORWARD COPY
|
||||
;
|
||||
LDA ESTKL,X
|
||||
STA DSTL
|
||||
LDA ESTKH,X
|
||||
STA DSTH
|
||||
LDA ESTKL-1,X
|
||||
STA SRCL
|
||||
LDA ESTKH-1,X
|
||||
STA SRCH
|
||||
LDY ESTKL-2,X
|
||||
BEQ FORCPYLP
|
||||
INC ESTKH-2,X
|
||||
LDY #$00
|
||||
FORCPYLP LDA (SRC),Y
|
||||
STA (DST),Y
|
||||
INY
|
||||
BNE +
|
||||
INC DSTH
|
||||
INC SRCH
|
||||
+ DEC ESTKL-2,X
|
||||
BNE FORCPYLP
|
||||
DEC ESTKH-2,X
|
||||
BNE FORCPYLP
|
||||
RTS
|
||||
;
|
||||
; REVERSE COPY
|
||||
;
|
||||
REVCPY ;CLC
|
||||
LDA ESTKL-2,X
|
||||
ADC ESTKL,X
|
||||
STA DSTL
|
||||
LDA ESTKH-2,X
|
||||
ADC ESTKH,X
|
||||
STA DSTH
|
||||
CLC
|
||||
LDA ESTKL-2,X
|
||||
ADC ESTKL-1,X
|
||||
STA SRCL
|
||||
LDA ESTKH-2,X
|
||||
ADC ESTKH-1,X
|
||||
STA SRCH
|
||||
DEC DSTH
|
||||
DEC SRCH
|
||||
LDY #$FF
|
||||
LDA ESTKL-2,X
|
||||
BEQ REVCPYLP
|
||||
INC ESTKH-2,X
|
||||
REVCPYLP LDA (SRC),Y
|
||||
STA (DST),Y
|
||||
DEY
|
||||
CPY #$FF
|
||||
BNE +
|
||||
DEC DSTH
|
||||
DEC SRCH
|
||||
+ DEC ESTKL-2,X
|
||||
BNE REVCPYLP
|
||||
DEC ESTKH-2,X
|
||||
BNE REVCPYLP
|
||||
CPYMEX RTS
|
||||
end
|
||||
//
|
||||
// Unsigned word comparisons.
|
||||
//
|
||||
asm uword_isge
|
||||
LDA ESTKL+1,X
|
||||
CMP ESTKL,X
|
||||
LDA ESTKH+1,X
|
||||
SBC ESTKH,X
|
||||
LDA #$FF
|
||||
ADC #$00
|
||||
EOR #$FF
|
||||
STA ESTKL+1,X
|
||||
STA ESTKH+1,X
|
||||
INX
|
||||
RTS
|
||||
end
|
||||
asm uword_isle
|
||||
LDA ESTKL,X
|
||||
CMP ESTKL+1,X
|
||||
LDA ESTKH,X
|
||||
SBC ESTKH+1,X
|
||||
LDA #$FF
|
||||
ADC #$00
|
||||
EOR #$FF
|
||||
STA ESTKL+1,X
|
||||
STA ESTKH+1,X
|
||||
INX
|
||||
RTS
|
||||
end
|
||||
asm uword_isgt
|
||||
LDA ESTKL,X
|
||||
CMP ESTKL+1,X
|
||||
LDA ESTKH,X
|
||||
SBC ESTKH+1,X
|
||||
LDA #$FF
|
||||
ADC #$00
|
||||
STA ESTKL+1,X
|
||||
STA ESTKH+1,X
|
||||
INX
|
||||
RTS
|
||||
end
|
||||
asm uword_islt
|
||||
LDA ESTKL+1,X
|
||||
CMP ESTKL,X
|
||||
LDA ESTKH+1,X
|
||||
SBC ESTKH,X
|
||||
LDA #$FF
|
||||
ADC #$00
|
||||
STA ESTKL+1,X
|
||||
STA ESTKH+1,X
|
||||
INX
|
||||
RTS
|
||||
end
|
||||
//
|
||||
// Addresses of internal routines.
|
||||
//
|
||||
asm _hilopwm
|
||||
TXA
|
||||
PHA
|
||||
JSR HILOPWM
|
||||
PLA
|
||||
TAX
|
||||
DEX
|
||||
RTS
|
||||
end
|
||||
asm toupper
|
||||
LDA ESTKL,X
|
||||
TOUPR AND #$7F
|
||||
CMP #'a'
|
||||
BCC +
|
||||
CMP #'z'+1
|
||||
BCS +
|
||||
SBC #$1F
|
||||
+ STA ESTKL,X
|
||||
RTS
|
||||
end
|
||||
//
|
||||
// CONSOLE I/O
|
||||
//
|
||||
asm putc
|
||||
LDA ESTKL,X
|
||||
; JSR TOUPR
|
||||
ORA #$80
|
||||
JMP $FDF0
|
||||
end
|
||||
asm getc
|
||||
DEX
|
||||
- LDA $C000
|
||||
BPL -
|
||||
BIT $C010
|
||||
AND #$7F
|
||||
STA ESTKL,X
|
||||
LDA #$00
|
||||
STA ESTKH,X
|
||||
RTS
|
||||
end
|
||||
def keypressed
|
||||
return ^$C000 >= 128
|
||||
end
|
||||
def pdl(num)
|
||||
return call($FB1E, 0, num, 0, 0)->2
|
||||
end
|
||||
def bttn(num)
|
||||
return (^$C061+num) >= 128
|
||||
end
|
||||
def putln
|
||||
return putc($0D)
|
||||
end
|
||||
def beep
|
||||
return putc($07)
|
||||
end
|
||||
def puts(str)
|
||||
byte i
|
||||
|
||||
for i = 1 to ^str
|
||||
putc(^(str+i))
|
||||
next
|
||||
end
|
||||
def puti(i)
|
||||
byte numstr[7]
|
||||
byte place, sign
|
||||
|
||||
place = 6
|
||||
if i < 0
|
||||
sign = 1
|
||||
i = -i
|
||||
else
|
||||
sign = 0
|
||||
fin
|
||||
while i >= 10
|
||||
numstr[place] = i % 10 + '0'
|
||||
i = i / 10
|
||||
place--
|
||||
loop
|
||||
numstr[place] = i + '0'
|
||||
place--
|
||||
if sign
|
||||
numstr[place] = '-'
|
||||
place--
|
||||
fin
|
||||
numstr[place] = 6 - place
|
||||
return puts(@numstr[place])
|
||||
end
|
||||
def normal
|
||||
^$32 = $FF
|
||||
end
|
||||
def inverse
|
||||
^$32 = $3F
|
||||
end
|
||||
def gotoxy(x, y)
|
||||
^$24 = x + ^$20
|
||||
return call($FB5B, y + ^$22, 0, 0, 0)
|
||||
end
|
||||
def home
|
||||
return call($FC58, 0, 0, 0, 0)
|
||||
end
|
||||
def putsxy(x, y, str)
|
||||
gotoxy(x, y)
|
||||
return puts(str)
|
||||
end
|
||||
def textmode
|
||||
call($FB39, 0, 0, 0, 0) // textmode()
|
||||
return home
|
||||
end
|
||||
//
|
||||
// Clear viewport to white
|
||||
//
|
||||
def clearview
|
||||
byte i
|
||||
word c
|
||||
|
||||
c = ' ' | $80 & ^$32
|
||||
c = c | (c << 8)
|
||||
for i = ^$22 to ^$23
|
||||
memset(txt1scrn[i] + ^$20, c, ^$21)
|
||||
next
|
||||
return gotoxy(0,0)
|
||||
end
|
||||
def grmode
|
||||
call($FB2F, 0, 0, 0, 0) // initmode()
|
||||
call($FB40, 0, 0, 0, 0) // grmode()
|
||||
return home
|
||||
end
|
||||
def grcolor(color)
|
||||
return call($F864, color, 0, 0, 0)
|
||||
end
|
||||
def plot(x, y)
|
||||
return call($F800, y, 0, x, 0)
|
||||
end
|
||||
def hlin(left, right, y)
|
||||
^$2C = right;
|
||||
return call($F819, y, 0, left, 0)
|
||||
end
|
||||
def vlin(top, bottom, x)
|
||||
^$2D = bottom;
|
||||
return call($F828, top, 0, x, 0)
|
||||
end
|
||||
def rect(left, right, top, bottom, fill)
|
||||
byte y
|
||||
|
||||
hlin(left, right, top)
|
||||
hlin(left, right, bottom)
|
||||
top++
|
||||
bottom--
|
||||
if fill
|
||||
for y = top to bottom
|
||||
hlin(left, right, y)
|
||||
next
|
||||
else
|
||||
vlin(top, bottom, left)
|
||||
vlin(top, bottom, right)
|
||||
fin
|
||||
end
|
||||
//
|
||||
// ProDOS routines
|
||||
//
|
||||
def open(path, buff)
|
||||
byte params[6]
|
||||
|
||||
params.0 = 3
|
||||
params:1 = path
|
||||
params:3 = buff
|
||||
params.5 = 0
|
||||
perr = syscall($C8, @params)
|
||||
return params.5
|
||||
end
|
||||
def close(refnum)
|
||||
byte params[2]
|
||||
|
||||
params.0 = 1
|
||||
params.1 = refnum
|
||||
perr = syscall($CC, @params)
|
||||
return perr
|
||||
end
|
||||
def read(refnum, buff, len)
|
||||
byte params[8]
|
||||
|
||||
params.0 = 4
|
||||
params.1 = refnum
|
||||
params:2 = buff
|
||||
params:4 = len
|
||||
params:6 = 0
|
||||
perr = syscall($CA, @params)
|
||||
return params:6
|
||||
end
|
||||
def write(refnum, buff, len)
|
||||
byte params[8]
|
||||
|
||||
params.0 = 4
|
||||
params.1 = refnum
|
||||
params:2 = buff
|
||||
params:4 = len
|
||||
params:6 = 0
|
||||
perr = syscall($CB, @params)
|
||||
return params:6
|
||||
end
|
||||
def create(path, access, type, aux)
|
||||
byte params[12]
|
||||
|
||||
params.0 = 7
|
||||
params:1 = path
|
||||
params.3 = access
|
||||
params.4 = type
|
||||
params:5 = aux
|
||||
params.7 = $1
|
||||
params:8 = 0
|
||||
params:10 = 0
|
||||
perr = syscall($C0, @params)
|
||||
return perr
|
||||
end
|
||||
def destroy(path)
|
||||
byte params[3]
|
||||
|
||||
params.0 = 1
|
||||
params:1 = path
|
||||
perr = syscall($C1, @params)
|
||||
return perr
|
||||
end
|
||||
//
|
||||
// HFO/LFO PWM sound routines
|
||||
//
|
||||
def envelope(attack, decay, sustain, release, ainc, dinc, rinc)
|
||||
^$0C = attack
|
||||
^$0D = decay
|
||||
^$0E = sustain
|
||||
^$0F = release
|
||||
*$10 = ainc
|
||||
*$12 = dinc
|
||||
*$14 = rinc
|
||||
end
|
||||
def hilopwm(hfo, lfo, usr)
|
||||
^$08 = hfo
|
||||
^$09 = lfo
|
||||
*$0A = usr
|
||||
return _hilopwm
|
||||
end
|
@ -1,5 +1,5 @@
|
||||
import cmdsys
|
||||
predef syscall, call, memset, getc, putc, puts, modaddr
|
||||
predef syscall(f,p)#1, call(adr,a,x,y,p)#1, memset(d,s,l)#1, getc#1, putc(c)#1, puts(s)#1, modaddr(a)#1
|
||||
byte MACHID
|
||||
end
|
||||
//
|
||||
@ -30,7 +30,7 @@ const page2 = 1
|
||||
//
|
||||
// Predefined functions.
|
||||
//
|
||||
predef a2keypressed, a2gotoxy, a2grmode, a2textmode
|
||||
predef a2keypressed#1, a2gotoxy(x,y)#0, a2grmode(m)#0, a2textmode#0
|
||||
//
|
||||
// String data.
|
||||
//
|
||||
@ -71,7 +71,7 @@ end
|
||||
//
|
||||
// def grscrn(rowaddrs)
|
||||
//
|
||||
asm grscrn
|
||||
asm grscrn(rowaddrs)#0
|
||||
GRSCRN = $26
|
||||
GRSCRNL = GRSCRN
|
||||
GRSCRNH = GRSCRNL+1
|
||||
@ -79,12 +79,13 @@ GRSCRNH = GRSCRNL+1
|
||||
STA GRSCRNL
|
||||
LDA ESTKH,X
|
||||
STA GRSCRNH
|
||||
INX
|
||||
RTS
|
||||
end
|
||||
//
|
||||
// def grcolor(color)
|
||||
//
|
||||
asm grcolor
|
||||
asm grcolor(color)#0
|
||||
GRCLR = $30
|
||||
LDA #$0F
|
||||
AND ESTKL,X
|
||||
@ -95,12 +96,13 @@ GRCLR = $30
|
||||
ASL
|
||||
ORA GRCLR
|
||||
STA GRCLR
|
||||
INX
|
||||
RTS
|
||||
end
|
||||
//
|
||||
// def grplot(x, y)
|
||||
//
|
||||
asm grplot
|
||||
asm grplot(x, y)#0
|
||||
STY IPY
|
||||
LDA ESTKL,X
|
||||
AND #$FE
|
||||
@ -125,56 +127,57 @@ asm grplot
|
||||
STA (DST),Y
|
||||
LDY IPY
|
||||
INX
|
||||
INX
|
||||
RTS
|
||||
end
|
||||
//
|
||||
// Apple II routines.
|
||||
//
|
||||
def a2keypressed
|
||||
def a2keypressed#1
|
||||
if ^keyboard >= 128
|
||||
return ^keystrobe
|
||||
fin
|
||||
return FALSE
|
||||
end
|
||||
def a2gotoxy(x, y)
|
||||
def a2gotoxy(x, y)#0
|
||||
^$24 = x + ^$20
|
||||
return call($FB5B, y + ^$22, 0, 0, 0)
|
||||
call($FB5B, y + ^$22, 0, 0, 0)
|
||||
end
|
||||
def a2grmode(mix)
|
||||
def a2grmode(mix)#0
|
||||
call($FB2F, 0, 0, 0, 0) // initmode()
|
||||
call($FB40, 0, 0, 0, 0) // grmode()
|
||||
if !mix
|
||||
^showfull
|
||||
fin
|
||||
call($FC58, 0, 0, 0, 0) // home()
|
||||
return grscrn(@txt1scrn) // point to lo-res screen
|
||||
grscrn(@txt1scrn) // point to lo-res screen
|
||||
end
|
||||
def a2textmode
|
||||
def a2textmode#0
|
||||
call($FB39, 0, 0, 0, 0) // textmode()
|
||||
return call($FC58, 0, 0, 0, 0) // home()
|
||||
call($FC58, 0, 0, 0, 0) // home()
|
||||
end
|
||||
//
|
||||
// Apple III routines.
|
||||
//
|
||||
def dev_control(devnum, code, list)
|
||||
def dev_control(devnum, code, list)#1
|
||||
byte params[5]
|
||||
|
||||
|
||||
params.0 = 3
|
||||
params.1 = devnum
|
||||
params.2 = code
|
||||
params:3 = list
|
||||
return syscall($83, @params)
|
||||
end
|
||||
def dev_status(devnum, code, list)
|
||||
def dev_status(devnum, code, list)#1
|
||||
byte params[5]
|
||||
|
||||
|
||||
params.0 = 3
|
||||
params.1 = devnum
|
||||
params.2 = code
|
||||
params:3 = list
|
||||
return syscall($82, @params)
|
||||
end
|
||||
def a3keypressed
|
||||
def a3keypressed#1
|
||||
byte count
|
||||
dev_status(devcons, 5, @count)
|
||||
if count
|
||||
@ -182,13 +185,13 @@ def a3keypressed
|
||||
fin
|
||||
return FALSE
|
||||
end
|
||||
def a3gotoxy(x, y)
|
||||
def a3gotoxy(x, y)#0
|
||||
putc(24)
|
||||
putc(x)
|
||||
putc(25)
|
||||
return putc(y)
|
||||
putc(y)
|
||||
end
|
||||
def a3viewport(left, top, width, height)
|
||||
def a3viewport(left, top, width, height)#0
|
||||
putc(1) // Reset viewport
|
||||
putc(26)
|
||||
putc(left)
|
||||
@ -198,9 +201,9 @@ def a3viewport(left, top, width, height)
|
||||
putc(left + width - 1)
|
||||
putc(top + height - 1)
|
||||
putc(3)
|
||||
return a3gotoxy(0, 0)
|
||||
a3gotoxy(0, 0)
|
||||
end
|
||||
def a3grmode(mix)
|
||||
def a3grmode(mix)#0
|
||||
byte i
|
||||
if mix
|
||||
mix = 19
|
||||
@ -214,17 +217,17 @@ def a3grmode(mix)
|
||||
memset(txt1scrn[i], $0000, 40) // text screen
|
||||
memset(txt2scrn[i], $0000, 40) // color screen
|
||||
next
|
||||
return grscrn(@txt2scrn) // point to color screen
|
||||
grscrn(@txt2scrn) // point to color screen
|
||||
end
|
||||
def a3textmode
|
||||
def a3textmode#0
|
||||
puts(@textbwmode)
|
||||
a3viewport(0, 0, 40, 24)
|
||||
return putc(28)
|
||||
putc(28)
|
||||
end
|
||||
//
|
||||
// Rod's Colors.
|
||||
//
|
||||
def rod
|
||||
def rod#0
|
||||
byte i, j, k, w, fmi, fmk, color
|
||||
while TRUE
|
||||
for w = 3 to 50
|
||||
@ -234,16 +237,16 @@ def rod
|
||||
color = (j * 3) / (i + 3) + i * w / 12
|
||||
fmi = 40 - i
|
||||
fmk = 40 - k
|
||||
grcolor(color)
|
||||
grplot(i, k)
|
||||
grplot(k, i)
|
||||
grplot(fmi, fmk)
|
||||
grplot(fmk, fmi)
|
||||
grplot(k, fmi)
|
||||
grplot(fmi, k)
|
||||
grplot(i, fmk)
|
||||
grplot(fmk, i)
|
||||
if keypressed()
|
||||
grcolor(color)#0
|
||||
grplot(i, k)#0
|
||||
grplot(k, i)#0
|
||||
grplot(fmi, fmk)#0
|
||||
grplot(fmk, fmi)#0
|
||||
grplot(k, fmi)#0
|
||||
grplot(fmi, k)#0
|
||||
grplot(i, fmk)#0
|
||||
grplot(fmk, i)#0
|
||||
if keypressed()#1
|
||||
return
|
||||
fin
|
||||
next
|
||||
@ -271,10 +274,10 @@ when MACHID & $C8
|
||||
fin
|
||||
otherwise // Apple ][
|
||||
wend
|
||||
grmode(MIXMODE)
|
||||
gotoxy(11, 1)
|
||||
grmode(MIXMODE)#0
|
||||
gotoxy(11, 1)#0
|
||||
puts(@exitmsg)
|
||||
rod
|
||||
textmode()
|
||||
textmode()#0
|
||||
puts(@goodbye)
|
||||
done
|
||||
done
|
||||
|
@ -119,7 +119,6 @@ word ascii_entity = @ascii_thief, @ascii_ogre, @ascii_zombie, @ascii_rogue
|
||||
//
|
||||
// Monster types
|
||||
//
|
||||
|
||||
byte thief = "Thief", 5
|
||||
byte ogre = "Ogre", 20
|
||||
byte zombie = "Zombie", 40
|
||||
@ -127,17 +126,6 @@ byte rogue = "Rogue", 80
|
||||
export word entity = @thief, @ogre, @zombie, @rogue
|
||||
export word entities = 0
|
||||
|
||||
//
|
||||
// Combat status strings
|
||||
//
|
||||
|
||||
byte skillstr = "Skill :"
|
||||
byte healthstr = "Health :"
|
||||
byte energystr = "Energy :"
|
||||
byte powerstr = "Power :"
|
||||
byte lifestr = "Life :"
|
||||
byte fightstr = "F)ight or R)un?"
|
||||
|
||||
//
|
||||
// Combat Return 1 if running away, 0 if end of fight
|
||||
//
|
||||
@ -157,24 +145,24 @@ export def fight(player, enemy)
|
||||
gotoxy(0, 0)
|
||||
puts(player+name)
|
||||
gotoxy(1, 2)
|
||||
puts(@skillstr); puti(player->skill)
|
||||
puts("Skill :"); puti(player->skill)
|
||||
gotoxy(1, 3)
|
||||
puts(@healthstr); puti(player->health)
|
||||
puts("Health :"); puti(player->health)
|
||||
gotoxy(1, 4)
|
||||
puts(@energystr); puti(player->energy)
|
||||
puts("Energy :"); puti(player->energy)
|
||||
gotoxy(20, 0)
|
||||
puts(entity[enemy->kind])
|
||||
gotoxy(21, 2)
|
||||
puts(@powerstr); puti(enemy->power)
|
||||
puts("Power :"); puti(enemy->power)
|
||||
gotoxy(21, 3)
|
||||
puts(@lifestr); puti(enemy->life)
|
||||
puts("Life :"); puti(enemy->life)
|
||||
for e_atck = 0 to 9
|
||||
gotoxy(0, 10 + e_atck)
|
||||
puts(@ascii_warrior + e_atck * 11)
|
||||
gotoxy(20, 10 + e_atck)
|
||||
puts(ascii_entity[enemy->kind] + e_atck * 11)
|
||||
next
|
||||
gotoxy(12, 8); puts(@fightstr)
|
||||
gotoxy(12, 8); puts("F)ight or R)un?")
|
||||
if toupper(getkb()) == 'R'
|
||||
return 1
|
||||
else
|
||||
@ -204,10 +192,10 @@ export def fight(player, enemy)
|
||||
entities = enemy=>next_other
|
||||
fin
|
||||
if enemy=>next_other
|
||||
enemy=>next_other=>prev_other = enemy=>prev_other
|
||||
enemy=>next_other=>prev_other = enemy=>prev_other
|
||||
fin
|
||||
if enemy=>prev_other
|
||||
enemy=>prev_other=>next_other = enemy=>next_other
|
||||
enemy=>prev_other=>next_other = enemy=>next_other
|
||||
fin
|
||||
fin
|
||||
if player->health > e_atck
|
||||
@ -224,4 +212,4 @@ export def fight(player, enemy)
|
||||
return 0
|
||||
end
|
||||
|
||||
done
|
||||
done
|
||||
|
@ -32,17 +32,18 @@ byte constr = "Constant expression = "
|
||||
byte[] offsets = "Structure offsets:"
|
||||
word array[] = 1, 10, 100, 1000, 10000
|
||||
word ptr
|
||||
byte spaces = " "
|
||||
//
|
||||
// Define functions.
|
||||
//
|
||||
def tens(start)
|
||||
word i
|
||||
word i, pptr
|
||||
|
||||
i = start
|
||||
pptr = @print
|
||||
repeat
|
||||
print:hex(i)
|
||||
print:str(@spaces)
|
||||
print:dec(i)
|
||||
print:str(" ")
|
||||
pptr=>dec(i)
|
||||
print:newln()
|
||||
i = i / 10
|
||||
until i == 0
|
||||
@ -76,10 +77,15 @@ def nums(range)
|
||||
puti(array[1]);putln
|
||||
end
|
||||
export def main(range)
|
||||
byte a
|
||||
a = 10
|
||||
|
||||
nums(*range)
|
||||
tens(*range*10)
|
||||
ascii
|
||||
putln
|
||||
puts("10 * 8 = "); puti(a * 8); putln
|
||||
puts("10 / 2 = "); puti(a / 2); putln
|
||||
puts(@hello)
|
||||
when MACHID & $C8
|
||||
is $08
|
||||
|
@ -1,13 +1,11 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include "tokens.h"
|
||||
#include "lex.h"
|
||||
#include "symbols.h"
|
||||
#include "codegen.h"
|
||||
#include "plasm.h"
|
||||
/*
|
||||
* Symbol table and fixup information.
|
||||
*/
|
||||
#define ID_LEN 32
|
||||
#define ID_LEN 32
|
||||
static int consts = 0;
|
||||
static int externs = 0;
|
||||
static int globals = 0;
|
||||
@ -29,8 +27,10 @@ static int idlocal_offset[128];
|
||||
static char fixup_size[2048];
|
||||
static int fixup_type[2048];
|
||||
static int fixup_tag[2048];
|
||||
#define FIXUP_BYTE 0x00
|
||||
#define FIXUP_WORD 0x80
|
||||
static t_opseq optbl[256];
|
||||
static t_opseq *freeop_lst = &optbl[0];
|
||||
#define FIXUP_BYTE 0x00
|
||||
#define FIXUP_WORD 0x80
|
||||
int id_match(char *name, int len, char *id)
|
||||
{
|
||||
if (len == id[0])
|
||||
@ -147,13 +147,13 @@ int idglobal_add(char *name, int len, int type, int size)
|
||||
if (!(type & EXTERN_TYPE))
|
||||
{
|
||||
emit_idglobal(globals, size, name);
|
||||
idglobal_tag[globals] = globals;
|
||||
globals++;
|
||||
idglobal_tag[globals] = globals;
|
||||
globals++;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\t\t\t\t\t; %s -> X%03d\n", &idglobal_name[globals][1], externs);
|
||||
idglobal_tag[globals++] = externs++;
|
||||
idglobal_tag[globals++] = externs++;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
@ -161,6 +161,11 @@ int id_add(char *name, int len, int type, int size)
|
||||
{
|
||||
return ((type & LOCAL_TYPE) ? idlocal_add(name, len, type, size) : idglobal_add(name, len, type, size));
|
||||
}
|
||||
void idlocal_reset(void)
|
||||
{
|
||||
locals = 0;
|
||||
localsize = 0;
|
||||
}
|
||||
int idfunc_add(char *name, int len, int type, int tag)
|
||||
{
|
||||
if (globals > 1024)
|
||||
@ -254,10 +259,6 @@ int fixup_new(int tag, int type, int size)
|
||||
/*
|
||||
* Emit assembly code.
|
||||
*/
|
||||
#define BYTECODE_SEG 8
|
||||
#define INIT 16
|
||||
#define SYSFLAGS 32
|
||||
static int outflags = 0;
|
||||
static const char *DB = ".BYTE";
|
||||
static const char *DW = ".WORD";
|
||||
static const char *DS = ".RES";
|
||||
@ -304,8 +305,7 @@ void emit_dci(char *str, int len)
|
||||
}
|
||||
void emit_flags(int flags)
|
||||
{
|
||||
outflags = flags;
|
||||
if (outflags & ACME)
|
||||
if (flags & ACME)
|
||||
{
|
||||
DB = "!BYTE";
|
||||
DW = "!WORD";
|
||||
@ -315,6 +315,8 @@ void emit_flags(int flags)
|
||||
}
|
||||
void emit_header(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (outflags & ACME)
|
||||
printf("; ACME COMPATIBLE OUTPUT\n");
|
||||
else
|
||||
@ -323,7 +325,7 @@ void emit_header(void)
|
||||
{
|
||||
printf("\t%s\t_SEGEND-_SEGBEGIN\t; LENGTH OF HEADER + CODE/DATA + BYTECODE SEGMENT\n", DW);
|
||||
printf("_SEGBEGIN%c\n", LBL);
|
||||
printf("\t%s\t$DA7E\t\t\t; MAGIC #\n", DW);
|
||||
printf("\t%s\t$DA7F\t\t\t; MAGIC #\n", DW);
|
||||
printf("\t%s\t_SYSFLAGS\t\t\t; SYSTEM FLAGS\n", DW);
|
||||
printf("\t%s\t_SUBSEG\t\t\t; BYTECODE SUB-SEGMENT\n", DW);
|
||||
printf("\t%s\t_DEFCNT\t\t\t; BYTECODE DEF COUNT\n", DW);
|
||||
@ -333,6 +335,12 @@ void emit_header(void)
|
||||
{
|
||||
printf("\tJMP\t_INIT\t\t\t; MODULE INITIALIZATION ROUTINE\n");
|
||||
}
|
||||
/*
|
||||
* Init free op sequence table
|
||||
*/
|
||||
for (i = 0; i < sizeof(optbl)/sizeof(t_opseq)-1; i++)
|
||||
optbl[i].nextop = &optbl[i+1];
|
||||
optbl[i].nextop = NULL;
|
||||
}
|
||||
void emit_rld(void)
|
||||
{
|
||||
@ -447,9 +455,16 @@ void emit_idglobal(int tag, int size, char *name)
|
||||
else
|
||||
printf("_D%03d%c\t%s\t%d\t\t\t; %s\n", tag, LBL, DS, size, name);
|
||||
}
|
||||
void emit_idfunc(int tag, int type, char *name)
|
||||
void emit_idfunc(int tag, int type, char *name, int is_bytecode)
|
||||
{
|
||||
printf("%s%c\t\t\t\t\t; %s()\n", tag_string(tag, type), LBL, name);
|
||||
if (name)
|
||||
printf("%s%c\t\t\t\t\t; %s()\n", tag_string(tag, type), LBL, name);
|
||||
if (!(outflags & MODULE))
|
||||
{
|
||||
//printf("%s%c\n", name, LBL);
|
||||
if (is_bytecode)
|
||||
printf("\tJSR\tINTERP\n");
|
||||
}
|
||||
}
|
||||
void emit_idconst(char *name, int value)
|
||||
{
|
||||
@ -458,7 +473,7 @@ void emit_idconst(char *name, int value)
|
||||
int emit_data(int vartype, int consttype, long constval, int constsize)
|
||||
{
|
||||
int datasize, i;
|
||||
char *str;
|
||||
unsigned char *str;
|
||||
if (consttype == 0)
|
||||
{
|
||||
datasize = constsize;
|
||||
@ -466,9 +481,10 @@ int emit_data(int vartype, int consttype, long constval, int constsize)
|
||||
}
|
||||
else if (consttype & STRING_TYPE)
|
||||
{
|
||||
datasize = constsize;
|
||||
str = (char *)(uintptr_t)constval;
|
||||
printf("\t%s\t$%02X\n", DB, --constsize);
|
||||
str = (unsigned char *)constval;
|
||||
constsize = *str++;
|
||||
datasize = constsize + 1;
|
||||
printf("\t%s\t$%02X\n", DB, constsize);
|
||||
while (constsize-- > 0)
|
||||
{
|
||||
printf("\t%s\t$%02X", DB, *str++);
|
||||
@ -518,17 +534,6 @@ int emit_data(int vartype, int consttype, long constval, int constsize)
|
||||
}
|
||||
return (datasize);
|
||||
}
|
||||
void emit_def(const char *name, int is_bytecode)
|
||||
{
|
||||
if (!(outflags & MODULE))
|
||||
{
|
||||
//printf("%s%c\n", name, LBL);
|
||||
if (is_bytecode)
|
||||
printf("\tJSR\tINTERP\n");
|
||||
}
|
||||
locals = 0;
|
||||
localsize = 0;
|
||||
}
|
||||
void emit_codetag(int tag)
|
||||
{
|
||||
printf("_B%03d%c\n", tag, LBL);
|
||||
@ -542,10 +547,10 @@ void emit_const(int cval)
|
||||
else
|
||||
printf("\t%s\t$2C,$%02X,$%02X\t\t; CW\t%d\n", DB, cval&0xFF,(cval>>8)&0xFF, cval);
|
||||
}
|
||||
void emit_conststr(long conststr, int strsize)
|
||||
void emit_conststr(long conststr)
|
||||
{
|
||||
printf("\t%s\t$2E\t\t\t; CS\n", DB);
|
||||
emit_data(0, STRING_TYPE, conststr, strsize);
|
||||
emit_data(0, STRING_TYPE, conststr, 0);
|
||||
}
|
||||
void emit_lb(void)
|
||||
{
|
||||
@ -565,17 +570,31 @@ void emit_llw(int index)
|
||||
}
|
||||
void emit_lab(int tag, int offset, int type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$68\t\t\t; LAB\t%s+%d\n", DB, taglbl, offset);
|
||||
printf("_F%03d%c\t%s\t%s+%d\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl, offset);
|
||||
if (type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$68\t\t\t; LAB\t%s+%d\n", DB, taglbl, offset);
|
||||
printf("_F%03d%c\t%s\t%s+%d\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl, offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\t%s\t$68,$%02X,$%02X\t\t; LAB\t%d\n", DB, offset&0xFF,(offset>>8)&0xFF, offset);
|
||||
}
|
||||
}
|
||||
void emit_law(int tag, int offset, int type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$6A\t\t\t; LAW\t%s+%d\n", DB, taglbl, offset);
|
||||
printf("_F%03d%c\t%s\t%s+%d\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl, offset);
|
||||
if (type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$6A\t\t\t; LAW\t%s+%d\n", DB, taglbl, offset);
|
||||
printf("_F%03d%c\t%s\t%s+%d\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl, offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\t%s\t$6A,$%02X,$%02X\t\t; LAW\t%d\n", DB, offset&0xFF,(offset>>8)&0xFF, offset);
|
||||
}
|
||||
}
|
||||
void emit_sb(void)
|
||||
{
|
||||
@ -603,31 +622,45 @@ void emit_dlw(int index)
|
||||
}
|
||||
void emit_sab(int tag, int offset, int type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$78\t\t\t; SAB\t%s+%d\n", DB, taglbl, offset);
|
||||
printf("_F%03d%c\t%s\t%s+%d\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl, offset);
|
||||
if (type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$78\t\t\t; SAB\t%s+%d\n", DB, taglbl, offset);
|
||||
printf("_F%03d%c\t%s\t%s+%d\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl, offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\t%s\t$78,$%02X,$%02X\t\t; SAB\t%d\n", DB, offset&0xFF,(offset>>8)&0xFF, offset);
|
||||
}
|
||||
}
|
||||
void emit_saw(int tag, int offset, int type)
|
||||
{
|
||||
if (type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$7A\t\t\t; SAW\t%s+%d\n", DB, taglbl, offset);
|
||||
printf("_F%03d%c\t%s\t%s+%d\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl, offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\t%s\t$7A,$%02X,$%02X\t\t; SAW\t%d\n", DB, offset&0xFF,(offset>>8)&0xFF, offset);
|
||||
}
|
||||
}
|
||||
void emit_dab(int tag, int offset, int type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$7A\t\t\t; SAW\t%s+%d\n", DB, taglbl, offset);
|
||||
printf("\t%s\t$7C\t\t\t; DAB\t%s+%d\n", DB, taglbl, offset);
|
||||
printf("_F%03d%c\t%s\t%s+%d\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl, offset);
|
||||
}
|
||||
void emit_dab(int tag, int type)
|
||||
void emit_daw(int tag, int offset, int type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$7C\t\t\t; DAB\t%s\n", DB, taglbl);
|
||||
printf("_F%03d%c\t%s\t%s\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl);
|
||||
}
|
||||
void emit_daw(int tag, int type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$7E\t\t\t; DAW\t%s\n", DB, taglbl);
|
||||
printf("_F%03d%c\t%s\t%s\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl);
|
||||
printf("\t%s\t$7E\t\t\t; DAW\t%s+%d\n", DB, taglbl, offset);
|
||||
printf("_F%03d%c\t%s\t%s+%d\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl, offset);
|
||||
}
|
||||
void emit_localaddr(int index)
|
||||
{
|
||||
@ -724,27 +757,23 @@ void emit_start(void)
|
||||
outflags |= INIT;
|
||||
defs++;
|
||||
}
|
||||
void emit_dup(void)
|
||||
void emit_push_exp(void)
|
||||
{
|
||||
printf("\t%s\t$32\t\t\t; DUP\n", DB);
|
||||
printf("\t%s\t$34\t\t\t; PUSH EXP\n", DB);
|
||||
}
|
||||
void emit_push(void)
|
||||
void emit_pull_exp(void)
|
||||
{
|
||||
printf("\t%s\t$34\t\t\t; PUSH\n", DB);
|
||||
}
|
||||
void emit_pull(void)
|
||||
{
|
||||
printf("\t%s\t$36\t\t\t; PULL\n", DB);
|
||||
}
|
||||
void emit_swap(void)
|
||||
{
|
||||
printf("\t%s\t$2E\t\t\t; SWAP\n", DB);
|
||||
printf("\t%s\t$36\t\t\t; PULL EXP\n", DB);
|
||||
}
|
||||
void emit_drop(void)
|
||||
{
|
||||
printf("\t%s\t$30\t\t\t; DROP\n", DB);
|
||||
}
|
||||
int emit_unaryop(int op)
|
||||
void emit_dup(void)
|
||||
{
|
||||
printf("\t%s\t$32\t\t\t; DUP\n", DB);
|
||||
}
|
||||
int emit_unaryop(t_token op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
@ -840,3 +869,543 @@ int emit_op(t_token op)
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
/*
|
||||
* New/release sequence ops
|
||||
*/
|
||||
t_opseq *new_op(void)
|
||||
{
|
||||
t_opseq* op = freeop_lst;
|
||||
if (!op)
|
||||
{
|
||||
fprintf(stderr, "Compiler out of sequence ops!\n");
|
||||
return (NULL);
|
||||
}
|
||||
freeop_lst = freeop_lst->nextop;
|
||||
op->nextop = NULL;
|
||||
return (op);
|
||||
}
|
||||
void release_op(t_opseq *op)
|
||||
{
|
||||
if (op)
|
||||
{
|
||||
op->nextop = freeop_lst;
|
||||
freeop_lst = op;
|
||||
}
|
||||
}
|
||||
void release_seq(t_opseq *seq)
|
||||
{
|
||||
t_opseq *op;
|
||||
while (seq)
|
||||
{
|
||||
op = seq;
|
||||
seq = seq->nextop;
|
||||
/*
|
||||
* Free this op
|
||||
*/
|
||||
op->nextop = freeop_lst;
|
||||
freeop_lst = op;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Crunch sequence (peephole optimize)
|
||||
*/
|
||||
int crunch_seq(t_opseq **seq)
|
||||
{
|
||||
t_opseq *opnext, *opnextnext;
|
||||
t_opseq *op = *seq;
|
||||
int crunched = 0;
|
||||
int freeops = 0;
|
||||
int shiftcnt;
|
||||
|
||||
while (op && (opnext = op->nextop))
|
||||
{
|
||||
switch (op->code)
|
||||
{
|
||||
case CONST_CODE:
|
||||
if (op->val == 1)
|
||||
{
|
||||
if (opnext->code == BINARY_CODE(ADD_TOKEN))
|
||||
{
|
||||
op->code = INC_CODE;
|
||||
freeops = 1;
|
||||
break;
|
||||
}
|
||||
if (opnext->code == BINARY_CODE(SUB_TOKEN))
|
||||
{
|
||||
op->code = DEC_CODE;
|
||||
freeops = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (opnext->code)
|
||||
{
|
||||
case NEG_CODE:
|
||||
op->val = -(op->val);
|
||||
freeops = 1;
|
||||
break;
|
||||
case COMP_CODE:
|
||||
op->val = ~(op->val);
|
||||
freeops = 1;
|
||||
break;
|
||||
case LOGIC_NOT_CODE:
|
||||
op->val = op->val ? 0 : 1;
|
||||
freeops = 1;
|
||||
break;
|
||||
case UNARY_CODE(BPTR_TOKEN):
|
||||
case LB_CODE:
|
||||
op->offsz = op->val;
|
||||
op->code = LAB_CODE;
|
||||
freeops = 1;
|
||||
break;
|
||||
case UNARY_CODE(WPTR_TOKEN):
|
||||
case LW_CODE:
|
||||
op->offsz = op->val;
|
||||
op->code = LAW_CODE;
|
||||
freeops = 1;
|
||||
break;
|
||||
case SB_CODE:
|
||||
op->offsz = op->val;
|
||||
op->code = SAB_CODE;
|
||||
freeops = 1;
|
||||
break;
|
||||
case SW_CODE:
|
||||
op->offsz = op->val;
|
||||
op->code = SAW_CODE;
|
||||
freeops = 1;
|
||||
break;
|
||||
case BRFALSE_CODE:
|
||||
if (op->val)
|
||||
{
|
||||
opnextnext = opnext->nextop; // Remove never taken branch
|
||||
if (op == *seq)
|
||||
*seq = opnextnext;
|
||||
opnext->nextop = NULL;
|
||||
release_seq(op);
|
||||
opnext = opnextnext;
|
||||
crunched = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
op->code = BRNCH_CODE; // Always taken branch
|
||||
op->tag = opnext->tag;
|
||||
freeops = 1;
|
||||
}
|
||||
break;
|
||||
case BRTRUE_CODE:
|
||||
if (!op->val)
|
||||
{
|
||||
opnextnext = opnext->nextop; // Remove never taken branch
|
||||
if (op == *seq)
|
||||
*seq = opnextnext;
|
||||
opnext->nextop = NULL;
|
||||
release_seq(op);
|
||||
opnext = opnextnext;
|
||||
crunched = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
op->code = BRNCH_CODE; // Always taken branch
|
||||
op->tag = opnext->tag;
|
||||
freeops = 1;
|
||||
}
|
||||
break;
|
||||
case CONST_CODE: // Collapse constant operation
|
||||
if ((opnextnext = opnext->nextop))
|
||||
switch (opnextnext->code)
|
||||
{
|
||||
case BINARY_CODE(MUL_TOKEN):
|
||||
op->val *= opnext->val;
|
||||
freeops = 2;
|
||||
break;
|
||||
case BINARY_CODE(DIV_TOKEN):
|
||||
op->val /= opnext->val;
|
||||
freeops = 2;
|
||||
break;
|
||||
case BINARY_CODE(MOD_TOKEN):
|
||||
op->val %= opnext->val;
|
||||
freeops = 2;
|
||||
break;
|
||||
case BINARY_CODE(ADD_TOKEN):
|
||||
op->val += opnext->val;
|
||||
freeops = 2;
|
||||
break;
|
||||
case BINARY_CODE(SUB_TOKEN):
|
||||
op->val -= opnext->val;
|
||||
freeops = 2;
|
||||
break;
|
||||
case BINARY_CODE(SHL_TOKEN):
|
||||
op->val <<= opnext->val;
|
||||
freeops = 2;
|
||||
break;
|
||||
case BINARY_CODE(SHR_TOKEN):
|
||||
op->val >>= opnext->val;
|
||||
freeops = 2;
|
||||
break;
|
||||
case BINARY_CODE(AND_TOKEN):
|
||||
op->val &= opnext->val;
|
||||
freeops = 2;
|
||||
break;
|
||||
case BINARY_CODE(OR_TOKEN):
|
||||
op->val |= opnext->val;
|
||||
freeops = 2;
|
||||
break;
|
||||
case BINARY_CODE(EOR_TOKEN):
|
||||
op->val ^= opnext->val;
|
||||
freeops = 2;
|
||||
break;
|
||||
case BINARY_CODE(EQ_TOKEN):
|
||||
op->val = op->val == opnext->val ? 1 : 0;
|
||||
freeops = 2;
|
||||
break;
|
||||
case BINARY_CODE(NE_TOKEN):
|
||||
op->val = op->val != opnext->val ? 1 : 0;
|
||||
freeops = 2;
|
||||
break;
|
||||
case BINARY_CODE(GE_TOKEN):
|
||||
op->val = op->val >= opnext->val ? 1 : 0;
|
||||
freeops = 2;
|
||||
break;
|
||||
case BINARY_CODE(LT_TOKEN):
|
||||
op->val = op->val < opnext->val ? 1 : 0;
|
||||
freeops = 2;
|
||||
break;
|
||||
case BINARY_CODE(GT_TOKEN):
|
||||
op->val = op->val > opnext->val ? 1 : 0;
|
||||
freeops = 2;
|
||||
break;
|
||||
case BINARY_CODE(LE_TOKEN):
|
||||
op->val = op->val <= opnext->val ? 1 : 0;
|
||||
freeops = 2;
|
||||
break;
|
||||
case BINARY_CODE(LOGIC_OR_TOKEN):
|
||||
op->val = op->val || opnext->val ? 1 : 0;
|
||||
freeops = 2;
|
||||
break;
|
||||
case BINARY_CODE(LOGIC_AND_TOKEN):
|
||||
op->val = op->val && opnext->val ? 1 : 0;
|
||||
freeops = 2;
|
||||
break;
|
||||
}
|
||||
break; // CONST_CODE
|
||||
case BINARY_CODE(MUL_TOKEN):
|
||||
for (shiftcnt = 0; shiftcnt < 16; shiftcnt++)
|
||||
{
|
||||
if (op->val == (1 << shiftcnt))
|
||||
{
|
||||
op->val = shiftcnt;
|
||||
opnext->code = BINARY_CODE(SHL_TOKEN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BINARY_CODE(DIV_TOKEN):
|
||||
for (shiftcnt = 0; shiftcnt < 16; shiftcnt++)
|
||||
{
|
||||
if (op->val == (1 << shiftcnt))
|
||||
{
|
||||
op->val = shiftcnt;
|
||||
opnext->code = BINARY_CODE(SHR_TOKEN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break; // CONST_CODE
|
||||
case LADDR_CODE:
|
||||
switch (opnext->code)
|
||||
{
|
||||
case CONST_CODE:
|
||||
if ((opnextnext = opnext->nextop))
|
||||
switch (opnextnext->code)
|
||||
{
|
||||
case ADD_CODE:
|
||||
case INDEXB_CODE:
|
||||
op->offsz += opnext->val;
|
||||
freeops = 2;
|
||||
break;
|
||||
case INDEXW_CODE:
|
||||
op->offsz += opnext->val * 2;
|
||||
freeops = 2;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case LB_CODE:
|
||||
op->code = LLB_CODE;
|
||||
freeops = 1;
|
||||
break;
|
||||
case LW_CODE:
|
||||
op->code = LLW_CODE;
|
||||
freeops = 1;
|
||||
break;
|
||||
case SB_CODE:
|
||||
op->code = SLB_CODE;
|
||||
freeops = 1;
|
||||
break;
|
||||
case SW_CODE:
|
||||
op->code = SLW_CODE;
|
||||
freeops = 1;
|
||||
break;
|
||||
}
|
||||
break; // LADDR_CODE
|
||||
case GADDR_CODE:
|
||||
switch (opnext->code)
|
||||
{
|
||||
case CONST_CODE:
|
||||
if ((opnextnext = opnext->nextop))
|
||||
switch (opnextnext->code)
|
||||
{
|
||||
case ADD_CODE:
|
||||
case INDEXB_CODE:
|
||||
op->offsz += opnext->val;
|
||||
freeops = 2;
|
||||
break;
|
||||
case INDEXW_CODE:
|
||||
op->offsz += opnext->val * 2;
|
||||
freeops = 2;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case LB_CODE:
|
||||
op->code = LAB_CODE;
|
||||
freeops = 1;
|
||||
break;
|
||||
case LW_CODE:
|
||||
op->code = LAW_CODE;
|
||||
freeops = 1;
|
||||
break;
|
||||
case SB_CODE:
|
||||
op->code = SAB_CODE;
|
||||
freeops = 1;
|
||||
break;
|
||||
case SW_CODE:
|
||||
op->code = SAW_CODE;
|
||||
freeops = 1;
|
||||
break;
|
||||
case ICAL_CODE:
|
||||
op->code = CALL_CODE;
|
||||
freeops = 1;
|
||||
break;
|
||||
}
|
||||
break; // GADDR_CODE
|
||||
case LOGIC_NOT_CODE:
|
||||
switch (opnext->code)
|
||||
{
|
||||
case BRFALSE_CODE:
|
||||
op->code = BRTRUE_CODE;
|
||||
op->tag = opnext->tag;
|
||||
freeops = 1;
|
||||
break;
|
||||
case BRTRUE_CODE:
|
||||
op->code = BRFALSE_CODE;
|
||||
op->tag = opnext->tag;
|
||||
freeops = 1;
|
||||
break;
|
||||
}
|
||||
break; // LOGIC_NOT_CODE
|
||||
}
|
||||
//
|
||||
// Free up crunched ops
|
||||
//
|
||||
while (freeops)
|
||||
{
|
||||
op->nextop = opnext->nextop;
|
||||
opnext->nextop = freeop_lst;
|
||||
freeop_lst = opnext;
|
||||
opnext = op->nextop;
|
||||
crunched = 1;
|
||||
freeops--;
|
||||
}
|
||||
op = opnext;
|
||||
}
|
||||
return (crunched);
|
||||
}
|
||||
/*
|
||||
* Generate a sequence of code
|
||||
*/
|
||||
t_opseq *gen_seq(t_opseq *seq, int opcode, long cval, int tag, int offsz, int type)
|
||||
{
|
||||
t_opseq *op;
|
||||
|
||||
if (!seq)
|
||||
{
|
||||
op = seq = new_op();
|
||||
}
|
||||
else
|
||||
{
|
||||
op = seq;
|
||||
while (op->nextop)
|
||||
op = op->nextop;
|
||||
op->nextop = new_op();
|
||||
op = op->nextop;
|
||||
}
|
||||
op->code = opcode;
|
||||
op->val = cval;
|
||||
op->tag = tag;
|
||||
op->offsz = offsz;
|
||||
op->type = type;
|
||||
return (seq);
|
||||
}
|
||||
/*
|
||||
* Append one sequence to the end of another
|
||||
*/
|
||||
t_opseq *cat_seq(t_opseq *seq1, t_opseq *seq2)
|
||||
{
|
||||
t_opseq *op;
|
||||
|
||||
if (!seq1)
|
||||
return (seq2);
|
||||
for (op = seq1; op->nextop; op = op->nextop);
|
||||
op->nextop = seq2;
|
||||
return (seq1);
|
||||
}
|
||||
/*
|
||||
* Emit a sequence of ops
|
||||
*/
|
||||
int emit_seq(t_opseq *seq)
|
||||
{
|
||||
t_opseq *op;
|
||||
int emitted = 0;
|
||||
|
||||
if (outflags & OPTIMIZE)
|
||||
while (crunch_seq(&seq));
|
||||
while (seq)
|
||||
{
|
||||
op = seq;
|
||||
switch (op->code)
|
||||
{
|
||||
case NEG_CODE:
|
||||
case COMP_CODE:
|
||||
case LOGIC_NOT_CODE:
|
||||
case INC_CODE:
|
||||
case DEC_CODE:
|
||||
case BPTR_CODE:
|
||||
case WPTR_CODE:
|
||||
emit_unaryop(op->code);
|
||||
break;
|
||||
case MUL_CODE:
|
||||
case DIV_CODE:
|
||||
case MOD_CODE:
|
||||
case ADD_CODE:
|
||||
case SUB_CODE:
|
||||
case SHL_CODE:
|
||||
case SHR_CODE:
|
||||
case AND_CODE:
|
||||
case OR_CODE:
|
||||
case EOR_CODE:
|
||||
case EQ_CODE:
|
||||
case NE_CODE:
|
||||
case GE_CODE:
|
||||
case LT_CODE:
|
||||
case GT_CODE:
|
||||
case LE_CODE:
|
||||
case LOGIC_OR_CODE:
|
||||
case LOGIC_AND_CODE:
|
||||
emit_op(op->code);
|
||||
break;
|
||||
case CONST_CODE:
|
||||
emit_const(op->val);
|
||||
break;
|
||||
case STR_CODE:
|
||||
emit_conststr(op->val);
|
||||
break;
|
||||
case LB_CODE:
|
||||
emit_lb();
|
||||
break;
|
||||
case LW_CODE:
|
||||
emit_lw();
|
||||
break;
|
||||
case LLB_CODE:
|
||||
emit_llb(op->offsz);
|
||||
break;
|
||||
case LLW_CODE:
|
||||
emit_llw(op->offsz);
|
||||
break;
|
||||
case LAB_CODE:
|
||||
emit_lab(op->tag, op->offsz, op->type);
|
||||
break;
|
||||
case LAW_CODE:
|
||||
emit_law(op->tag, op->offsz, op->type);
|
||||
break;
|
||||
case SB_CODE:
|
||||
emit_sb();
|
||||
break;
|
||||
case SW_CODE:
|
||||
emit_sw();
|
||||
break;
|
||||
case SLB_CODE:
|
||||
emit_slb(op->offsz);
|
||||
break;
|
||||
case SLW_CODE:
|
||||
emit_slw(op->offsz);
|
||||
break;
|
||||
case DLB_CODE:
|
||||
emit_dlb(op->offsz);
|
||||
break;
|
||||
case DLW_CODE:
|
||||
emit_dlw(op->offsz);
|
||||
break;
|
||||
case SAB_CODE:
|
||||
emit_sab(op->tag, op->offsz, op->type);
|
||||
break;
|
||||
case SAW_CODE:
|
||||
emit_saw(op->tag, op->offsz, op->type);
|
||||
break;
|
||||
case DAB_CODE:
|
||||
emit_dab(op->tag, op->offsz, op->type);
|
||||
break;
|
||||
case DAW_CODE:
|
||||
emit_daw(op->tag, op->offsz, op->type);
|
||||
break;
|
||||
case CALL_CODE:
|
||||
emit_call(op->tag, op->type);
|
||||
break;
|
||||
case ICAL_CODE:
|
||||
emit_ical();
|
||||
break;
|
||||
case LADDR_CODE:
|
||||
emit_localaddr(op->offsz);
|
||||
break;
|
||||
case GADDR_CODE:
|
||||
emit_globaladdr(op->tag, op->offsz, op->type);
|
||||
break;
|
||||
case INDEXB_CODE:
|
||||
emit_indexbyte();
|
||||
break;
|
||||
case INDEXW_CODE:
|
||||
emit_indexword();
|
||||
break;
|
||||
case DROP_CODE:
|
||||
emit_drop();
|
||||
break;
|
||||
case DUP_CODE:
|
||||
emit_dup();
|
||||
break;
|
||||
break;
|
||||
case PUSH_EXP_CODE:
|
||||
emit_push_exp();
|
||||
break;
|
||||
case PULL_EXP_CODE:
|
||||
emit_pull_exp();
|
||||
break;
|
||||
case BRNCH_CODE:
|
||||
emit_brnch(op->tag);
|
||||
break;
|
||||
case BRFALSE_CODE:
|
||||
emit_brfls(op->tag);
|
||||
break;
|
||||
case BRTRUE_CODE:
|
||||
emit_brtru(op->tag);
|
||||
break;
|
||||
default:
|
||||
return (0);
|
||||
}
|
||||
emitted++;
|
||||
seq = seq->nextop;
|
||||
/*
|
||||
* Free this op
|
||||
*/
|
||||
op->nextop = freeop_lst;
|
||||
freeop_lst = op;
|
||||
}
|
||||
return (emitted);
|
||||
}
|
||||
|
@ -1,5 +1,89 @@
|
||||
#define ACME 1
|
||||
#define MODULE 2
|
||||
typedef struct _opseq {
|
||||
int code;
|
||||
long val;
|
||||
int tag;
|
||||
int offsz;
|
||||
int type;
|
||||
struct _opseq *nextop;
|
||||
} t_opseq;
|
||||
#define UNARY_CODE(tkn) ((tkn)|0x0100)
|
||||
#define BINARY_CODE(tkn) ((tkn)|0x0200)
|
||||
#define NEG_CODE 0x0100|NEG_TOKEN
|
||||
#define COMP_CODE 0x0100|COMP_TOKEN
|
||||
#define LOGIC_NOT_CODE 0x0100|LOGIC_NOT_TOKEN
|
||||
#define INC_CODE 0x0100|INC_TOKEN
|
||||
#define DEC_CODE 0x0100|DEC_TOKEN
|
||||
#define BPTR_CODE 0x0100|BPTR_TOKEN
|
||||
#define WPTR_CODE 0x0100|WPTR_TOKEN
|
||||
#define MUL_CODE 0x0200|MUL_TOKEN
|
||||
#define DIV_CODE 0x0200|DIV_TOKEN
|
||||
#define MOD_CODE 0x0200|MOD_TOKEN
|
||||
#define ADD_CODE 0x0200|ADD_TOKEN
|
||||
#define SUB_CODE 0x0200|SUB_TOKEN
|
||||
#define SHL_CODE 0x0200|SHL_TOKEN
|
||||
#define SHR_CODE 0x0200|SHR_TOKEN
|
||||
#define AND_CODE 0x0200|AND_TOKEN
|
||||
#define OR_CODE 0x0200|OR_TOKEN
|
||||
#define EOR_CODE 0x0200|EOR_TOKEN
|
||||
#define EQ_CODE 0x0200|EQ_TOKEN
|
||||
#define NE_CODE 0x0200|NE_TOKEN
|
||||
#define GE_CODE 0x0200|GE_TOKEN
|
||||
#define LT_CODE 0x0200|LT_TOKEN
|
||||
#define GT_CODE 0x0200|GT_TOKEN
|
||||
#define LE_CODE 0x0200|LE_TOKEN
|
||||
#define LOGIC_OR_CODE 0x0200|LOGIC_OR_TOKEN
|
||||
#define LOGIC_AND_CODE 0x0200|LOGIC_AND_TOKEN
|
||||
#define CONST_CODE 0x0300
|
||||
#define STR_CODE 0x0301
|
||||
#define LB_CODE 0x0302
|
||||
#define LW_CODE 0x0303
|
||||
#define LLB_CODE 0x0304
|
||||
#define LLW_CODE 0x0305
|
||||
#define LAB_CODE 0x0306
|
||||
#define LAW_CODE 0x0307
|
||||
#define SB_CODE 0x0308
|
||||
#define SW_CODE 0x0309
|
||||
#define SLB_CODE 0x030A
|
||||
#define SLW_CODE 0x030B
|
||||
#define DLB_CODE 0x030C
|
||||
#define DLW_CODE 0x030D
|
||||
#define SAB_CODE 0x030E
|
||||
#define SAW_CODE 0x030F
|
||||
#define DAB_CODE 0x0310
|
||||
#define DAW_CODE 0x0311
|
||||
#define CALL_CODE 0x0312
|
||||
#define ICAL_CODE 0x0313
|
||||
#define LADDR_CODE 0x0314
|
||||
#define GADDR_CODE 0x0315
|
||||
#define INDEXB_CODE 0x0316
|
||||
#define INDEXW_CODE 0x0317
|
||||
#define DROP_CODE 0x0318
|
||||
#define DUP_CODE 0x0319
|
||||
#define PUSH_EXP_CODE 0x031A
|
||||
#define PULL_EXP_CODE 0x031B
|
||||
#define BRNCH_CODE 0x031C
|
||||
#define BRFALSE_CODE 0x031D
|
||||
#define BRTRUE_CODE 0x031E
|
||||
|
||||
#define gen_uop(seq,op) gen_seq(seq,UNARY_CODE(op),0,0,0,0)
|
||||
#define gen_op(seq,op) gen_seq(seq,BINARY_CODE(op),0,0,0,0)
|
||||
#define gen_const(seq,val) gen_seq(seq,CONST_CODE,val,0,0,0)
|
||||
#define gen_str(seq,str) gen_seq(seq,STR_CODE,str,0,0,0)
|
||||
#define gen_lcladr(seq,idx) gen_seq(seq,LADDR_CODE,0,0,idx,0)
|
||||
#define gen_gbladr(seq,tag,typ) gen_seq(seq,GADDR_CODE,0,tag,0,typ)
|
||||
#define gen_idxb(seq) gen_seq(seq,ADD_CODE,0,0,0,0)
|
||||
#define gen_idxw(seq) gen_seq(seq,INDEXW_CODE,0,0,0,0)
|
||||
#define gen_lb(seq) gen_seq(seq,LB_CODE,0,0,0,0)
|
||||
#define gen_lw(seq) gen_seq(seq,LW_CODE,0,0,0,0)
|
||||
#define gen_sb(seq) gen_seq(seq,SB_CODE,0,0,0,0)
|
||||
#define gen_sw(seq) gen_seq(seq,SW_CODE,0,0,0,0)
|
||||
#define gen_icall(seq) gen_seq(seq,ICAL_CODE,0,0,0,0)
|
||||
#define gen_pushexp(seq) gen_seq(seq,PUSH_EXP_CODE,0,0,0,0)
|
||||
#define gen_pullexp(seq) gen_seq(seq,PULL_EXP_CODE,0,0,0,0)
|
||||
#define gen_drop(seq) gen_seq(seq,DROP_CODE,0,0,0,0)
|
||||
#define gen_brfls(seq,tag) gen_seq(seq,BRFALSE_CODE,0,tag,0,0)
|
||||
#define gen_brtru(seq,tag) gen_seq(seq,BRTRUE_CODE,0,tag,0,0)
|
||||
|
||||
void emit_flags(int flags);
|
||||
void emit_header(void);
|
||||
void emit_trailer(void);
|
||||
@ -10,13 +94,12 @@ void emit_comment(char *s);
|
||||
void emit_asm(char *s);
|
||||
void emit_idlocal(char *name, int value);
|
||||
void emit_idglobal(int value, int size, char *name);
|
||||
void emit_idfunc(int tag, int type, char *name);
|
||||
void emit_idfunc(int tag, int type, char *name, int is_bytecode);
|
||||
void emit_idconst(char *name, int value);
|
||||
void emit_def(const char *name, int is_bytecode);
|
||||
int emit_data(int vartype, int consttype, long constval, int constsize);
|
||||
void emit_codetag(int tag);
|
||||
void emit_const(int cval);
|
||||
void emit_conststr(long conststr, int strsize);
|
||||
void emit_conststr(long conststr);
|
||||
void emit_lb(void);
|
||||
void emit_lw(void);
|
||||
void emit_llb(int index);
|
||||
@ -30,16 +113,16 @@ void emit_slw(int index);
|
||||
void emit_dlb(int index);
|
||||
void emit_dlw(int index);
|
||||
void emit_sab(int tag, int offset, int type);
|
||||
void emit_saw(int tag, int ofset, int type);
|
||||
void emit_dab(int tag, int type);
|
||||
void emit_daw(int tag, int type);
|
||||
void emit_saw(int tag, int offset, int type);
|
||||
void emit_dab(int tag, int offset, int type);
|
||||
void emit_daw(int tag, int offset, int type);
|
||||
void emit_call(int tag, int type);
|
||||
void emit_ical(void);
|
||||
void emit_localaddr(int index);
|
||||
void emit_globaladdr(int tag, int offset, int type);
|
||||
void emit_indexbyte(void);
|
||||
void emit_indexword(void);
|
||||
int emit_unaryop(int op);
|
||||
int emit_unaryop(t_token op);
|
||||
int emit_op(t_token op);
|
||||
void emit_brtru(int tag);
|
||||
void emit_brfls(int tag);
|
||||
@ -47,14 +130,19 @@ void emit_brgt(int tag);
|
||||
void emit_brlt(int tag);
|
||||
void emit_brne(int tag);
|
||||
void emit_brnch(int tag);
|
||||
void emit_swap(void);
|
||||
void emit_dup(void);
|
||||
void emit_push(void);
|
||||
void emit_pull(void);
|
||||
void emit_empty(void);
|
||||
void emit_push_exp(void);
|
||||
void emit_pull_exp(void);
|
||||
void emit_drop(void);
|
||||
void emit_dup(void);
|
||||
void emit_leave(void);
|
||||
void emit_ret(void);
|
||||
void emit_enter(int cparams);
|
||||
void emit_start(void);
|
||||
void emit_rld(void);
|
||||
void emit_esd(void);
|
||||
void release_seq(t_opseq *seq);
|
||||
int crunch_seq(t_opseq **seq);
|
||||
t_opseq *gen_seq(t_opseq *seq, int opcode, long cval, int tag, int offsz, int type);
|
||||
t_opseq *cat_seq(t_opseq *seq1, t_opseq *seq2);
|
||||
int emit_seq(t_opseq *seq);
|
||||
|
@ -1,21 +1,11 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The 8-Bit Bunch. Licensed under the Apache License, Version 1.1
|
||||
* (the "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at <http://www.apache.org/licenses/LICENSE-1.1>.
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under
|
||||
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
* ANY KIND, either express or implied. See the License for the specific language
|
||||
* governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include "tokens.h"
|
||||
#include "symbols.h"
|
||||
#include <ctype.h>
|
||||
#include "plasm.h"
|
||||
|
||||
char *statement, *tokenstr, *scanpos = (char*) "";
|
||||
char *statement, *tokenstr, *scanpos = "", *strpos = "";
|
||||
t_token scantoken, prevtoken;
|
||||
int tokenlen;
|
||||
long constval;
|
||||
@ -37,34 +27,36 @@ t_token keywords[] = {
|
||||
DEFAULT_TOKEN, 'O', 'T', 'H', 'E', 'R', 'W', 'I', 'S', 'E',
|
||||
ENDCASE_TOKEN, 'W', 'E', 'N', 'D',
|
||||
FOR_TOKEN, 'F', 'O', 'R',
|
||||
TO_TOKEN, 'T', 'O',
|
||||
DOWNTO_TOKEN, 'D', 'O', 'W', 'N', 'T', 'O',
|
||||
STEP_TOKEN, 'S', 'T', 'E', 'P',
|
||||
TO_TOKEN, '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',
|
||||
CONTINUE_TOKEN, 'C', 'O', 'N', 'T', 'I', 'N', 'U', 'E',
|
||||
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',
|
||||
UNTIL_TOKEN, 'U', 'N', 'T', 'I', 'L',
|
||||
BREAK_TOKEN, 'B', 'R', 'E', 'A', 'K',
|
||||
CONTINUE_TOKEN, 'C', 'O', 'N', 'T', 'I', 'N', 'U', 'E',
|
||||
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',
|
||||
INCLUDE_TOKEN, 'I', 'N', 'C', 'L', 'U', 'D', 'E',
|
||||
RETURN_TOKEN, 'R', 'E', 'T', 'U', 'R', 'N',
|
||||
END_TOKEN, 'E', 'N', 'D',
|
||||
DONE_TOKEN, 'D', 'O', 'N', 'E',
|
||||
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',
|
||||
WORD_TOKEN, 'W', 'O', 'R', 'D',
|
||||
CONST_TOKEN, 'C', 'O', 'N', 'S', 'T',
|
||||
STRUC_TOKEN, 'S', 'T', 'R', 'U', 'C',
|
||||
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
|
||||
};
|
||||
|
||||
extern int outflags;
|
||||
|
||||
void parse_error(const char *errormsg)
|
||||
{
|
||||
char *error_carrot = statement;
|
||||
@ -75,7 +67,18 @@ void parse_error(const char *errormsg)
|
||||
fprintf(stderr, "^\nError: %s\n", errormsg);
|
||||
exit(1);
|
||||
}
|
||||
void parse_warn(const char *warnmsg)
|
||||
{
|
||||
if (outflags & WARNINGS)
|
||||
{
|
||||
char *error_carrot = statement;
|
||||
|
||||
fprintf(stderr, "\n%s %4d: %s\n%*s ", filename, lineno, statement, (int)strlen(filename), "");
|
||||
for (error_carrot = statement; error_carrot != tokenstr; error_carrot++)
|
||||
putc(*error_carrot == '\t' ? '\t' : ' ', stderr);
|
||||
fprintf(stderr, "^\nWarning: %s\n", warnmsg);
|
||||
}
|
||||
}
|
||||
int hexdigit(char ch)
|
||||
{
|
||||
ch = toupper(ch);
|
||||
@ -103,8 +106,8 @@ t_token scan(void)
|
||||
else if (*scanpos == '\0' || *scanpos == '\n' || *scanpos == ';')
|
||||
scantoken = EOL_TOKEN;
|
||||
else if ((scanpos[0] >= 'a' && scanpos[0] <= 'z')
|
||||
|| (scanpos[0] >= 'A' && scanpos[0] <= 'Z')
|
||||
|| (scanpos[0] == '_'))
|
||||
|| (scanpos[0] >= 'A' && scanpos[0] <= 'Z')
|
||||
|| (scanpos[0] == '_'))
|
||||
{
|
||||
/*
|
||||
* ID, either variable name or reserved word.
|
||||
@ -116,9 +119,9 @@ t_token scan(void)
|
||||
scanpos++;
|
||||
}
|
||||
while ((*scanpos >= 'a' && *scanpos <= 'z')
|
||||
|| (*scanpos >= 'A' && *scanpos <= 'Z')
|
||||
|| (*scanpos == '_')
|
||||
|| (*scanpos >= '0' && *scanpos <= '9'));
|
||||
|| (*scanpos >= 'A' && *scanpos <= 'Z')
|
||||
|| (*scanpos == '_')
|
||||
|| (*scanpos >= '0' && *scanpos <= '9'));
|
||||
scantoken = ID_TOKEN;
|
||||
tokenlen = scanpos - tokenstr;
|
||||
/*
|
||||
@ -221,65 +224,68 @@ t_token scan(void)
|
||||
scanpos += 4;
|
||||
}
|
||||
}
|
||||
else if (scanpos[0] == '\"')
|
||||
else if (scanpos[0] == '\"') // Hack for string quote char in case we have to rewind later
|
||||
{
|
||||
char *scanshift;
|
||||
int scanoffset;
|
||||
/*
|
||||
* String constant.
|
||||
*/
|
||||
scantoken = STRING_TOKEN;
|
||||
constval = (long)(uintptr_t)(++scanpos);
|
||||
scantoken = STRING_TOKEN;
|
||||
constval = (long)strpos++;
|
||||
scanpos++;
|
||||
while (*scanpos && *scanpos != '\"')
|
||||
{
|
||||
if (*scanpos == '\\')
|
||||
{
|
||||
scanoffset = 1;
|
||||
scanoffset = 2;
|
||||
switch (scanpos[1])
|
||||
{
|
||||
case 'n':
|
||||
*scanpos = 0x0D;
|
||||
*strpos++ = 0x0D;
|
||||
break;
|
||||
case 'r':
|
||||
*scanpos = 0x0A;
|
||||
*strpos++ = 0x0A;
|
||||
break;
|
||||
case 't':
|
||||
*scanpos = '\t';
|
||||
*strpos++ = '\t';
|
||||
break;
|
||||
case '\'':
|
||||
*scanpos = '\'';
|
||||
*strpos++ = '\'';
|
||||
break;
|
||||
case '\"':
|
||||
*scanpos = '\"';
|
||||
*strpos++ = '\"';
|
||||
break;
|
||||
case '\\':
|
||||
*scanpos = '\\';
|
||||
*strpos++ = '\\';
|
||||
break;
|
||||
case '0':
|
||||
*scanpos = '\0';
|
||||
*strpos++ = '\0';
|
||||
break;
|
||||
case '$':
|
||||
if (hexdigit(scanpos[2]) < 0 || hexdigit(scanpos[3]) < 0) {
|
||||
parse_error("Bad string constant");
|
||||
return (-1);
|
||||
}
|
||||
*scanpos = hexdigit(scanpos[2]) * 16 + hexdigit(scanpos[3]);
|
||||
scanoffset = 3;
|
||||
*strpos++ = hexdigit(scanpos[2]) * 16 + hexdigit(scanpos[3]);
|
||||
scanoffset = 4;
|
||||
break;
|
||||
default:
|
||||
parse_error("Bad string constant");
|
||||
return (-1);
|
||||
}
|
||||
for (scanshift = scanpos + 1; *scanshift; scanshift++)
|
||||
scanshift[0] = scanshift[scanoffset];
|
||||
scanpos += scanoffset;
|
||||
}
|
||||
scanpos++;
|
||||
else
|
||||
*strpos++ = *scanpos++;
|
||||
}
|
||||
if (!*scanpos++)
|
||||
if (!*scanpos)
|
||||
{
|
||||
parse_error("Unterminated string");
|
||||
return (-1);
|
||||
}
|
||||
*((unsigned char *)constval) = (long)strpos - constval - 1;
|
||||
*strpos++ = '\0';
|
||||
scanpos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -398,27 +404,34 @@ void scan_rewind(char *backptr)
|
||||
}
|
||||
int scan_lookahead(void)
|
||||
{
|
||||
char *backpos = scanpos;
|
||||
char *backstr = tokenstr;
|
||||
char *backscan = scanpos;
|
||||
char *backtkn = tokenstr;
|
||||
char *backstr = strpos;
|
||||
int prevtoken = scantoken;
|
||||
int prevlen = tokenlen;
|
||||
int prevlen = tokenlen;
|
||||
int look = scan();
|
||||
scanpos = backpos;
|
||||
tokenstr = backstr;
|
||||
scanpos = backscan;
|
||||
tokenstr = backtkn;
|
||||
strpos = backstr;
|
||||
scantoken = prevtoken;
|
||||
tokenlen = prevlen;
|
||||
return (look);
|
||||
}
|
||||
char inputline[512];
|
||||
char conststr[1024];
|
||||
int next_line(void)
|
||||
{
|
||||
int len;
|
||||
t_token token;
|
||||
char* new_filename;
|
||||
if (inputfile == NULL) {
|
||||
// First-time init
|
||||
strpos = conststr;
|
||||
if (inputfile == NULL)
|
||||
{
|
||||
/*
|
||||
* First-time init
|
||||
*/
|
||||
inputfile = stdin;
|
||||
filename = (char*) "<stdin>";
|
||||
filename = "<stdin>";
|
||||
}
|
||||
if (*scanpos == ';')
|
||||
{
|
||||
@ -429,11 +442,17 @@ int next_line(void)
|
||||
{
|
||||
statement = inputline;
|
||||
scanpos = inputline;
|
||||
// Read next line from the current file, and strip newline from the end.
|
||||
if (fgets(inputline, 512, inputfile) == NULL) {
|
||||
/*
|
||||
* Read next line from the current file, and strip newline from the end.
|
||||
*/
|
||||
if (fgets(inputline, 512, inputfile) == NULL)
|
||||
{
|
||||
inputline[0] = 0;
|
||||
// At end of file, return to previous file if any, else return EOF_TOKEN
|
||||
if (outer_inputfile != NULL) {
|
||||
/*
|
||||
* At end of file, return to previous file if any, else return EOF_TOKEN
|
||||
*/
|
||||
if (outer_inputfile != NULL)
|
||||
{
|
||||
fclose(inputfile);
|
||||
free(filename);
|
||||
inputfile = outer_inputfile;
|
||||
@ -441,7 +460,8 @@ int next_line(void)
|
||||
lineno = outer_lineno - 1; // -1 because we're about to incr again
|
||||
outer_inputfile = NULL;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
scantoken = EOF_TOKEN;
|
||||
return EOF_TOKEN;
|
||||
}
|
||||
@ -454,15 +474,20 @@ int next_line(void)
|
||||
printf("; %s: %04d: %s\n", filename, lineno, inputline);
|
||||
}
|
||||
token = scan();
|
||||
// Handle single level of file inclusion
|
||||
if (token == INCLUDE_TOKEN) {
|
||||
/*
|
||||
* Handle single level of file inclusion
|
||||
*/
|
||||
if (token == INCLUDE_TOKEN)
|
||||
{
|
||||
token = scan();
|
||||
if (token != STRING_TOKEN) {
|
||||
if (token != STRING_TOKEN)
|
||||
{
|
||||
parse_error("Missing include filename");
|
||||
scantoken = EOF_TOKEN;
|
||||
return EOF_TOKEN;
|
||||
}
|
||||
if (outer_inputfile != NULL) {
|
||||
if (outer_inputfile != NULL)
|
||||
{
|
||||
parse_error("Only one level of includes allowed");
|
||||
scantoken = EOF_TOKEN;
|
||||
return EOF_TOKEN;
|
||||
@ -470,11 +495,11 @@ int next_line(void)
|
||||
outer_inputfile = inputfile;
|
||||
outer_filename = filename;
|
||||
outer_lineno = lineno;
|
||||
new_filename = (char*) malloc(tokenlen-1);
|
||||
strncpy(new_filename, (char*)(uintptr_t)constval, tokenlen-2);
|
||||
new_filename[tokenlen-2] = 0;
|
||||
new_filename = (char *) malloc(*((unsigned char *)constval) + 1);
|
||||
strncpy(new_filename, (char *)(constval + 1), *((unsigned char *)constval) + 1);
|
||||
inputfile = fopen(new_filename, "r");
|
||||
if (inputfile == NULL) {
|
||||
if (inputfile == NULL)
|
||||
{
|
||||
parse_error("Error opening include file");
|
||||
scantoken = EOF_TOKEN;
|
||||
return EOF_TOKEN;
|
||||
|
@ -4,6 +4,7 @@ extern int tokenlen;
|
||||
extern long constval;
|
||||
extern char inputline[];
|
||||
void parse_error(const char *errormsg);
|
||||
void parse_warn(const char *warnmsg);
|
||||
int next_line(void);
|
||||
void scan_rewind(char *backptr);
|
||||
int scan_lookahead(void);
|
||||
|
1110
src/toolsrc/parse.c
1110
src/toolsrc/parse.c
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#include "tokens.h"
|
||||
#include "lex.h"
|
||||
#include "codegen.h"
|
||||
#include "parse.h"
|
||||
#include "plasm.h"
|
||||
|
||||
int outflags = 0;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
@ -10,23 +9,28 @@ int main(int argc, char **argv)
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (argv[i][0] == '-')
|
||||
{
|
||||
{
|
||||
j = 1;
|
||||
while (argv[i][j])
|
||||
{
|
||||
switch(argv[i][j++])
|
||||
{
|
||||
case 'A':
|
||||
flags |= ACME;
|
||||
outflags |= ACME;
|
||||
break;
|
||||
case 'M':
|
||||
flags |= MODULE;
|
||||
outflags |= MODULE;
|
||||
break;
|
||||
case 'O':
|
||||
outflags |= OPTIMIZE;
|
||||
break;
|
||||
case 'W':
|
||||
outflags |= WARNINGS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
emit_flags(flags);
|
||||
emit_flags(outflags);
|
||||
if (parse_module())
|
||||
{
|
||||
fprintf(stderr, "Compilation complete.\n");
|
||||
|
16
src/toolsrc/plasm.h
Executable file
16
src/toolsrc/plasm.h
Executable file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Global flags.
|
||||
*/
|
||||
#define ACME (1<<0)
|
||||
#define MODULE (1<<1)
|
||||
#define OPTIMIZE (1<<2)
|
||||
#define BYTECODE_SEG (1<<3)
|
||||
#define INIT (1<<4)
|
||||
#define SYSFLAGS (1<<5)
|
||||
#define WARNINGS (1<<6)
|
||||
extern int outflags;
|
||||
#include "tokens.h"
|
||||
#include "lex.h"
|
||||
#include "symbols.h"
|
||||
#include "parse.h"
|
||||
#include "codegen.h"
|
@ -90,7 +90,7 @@ word = $0450,$04D0,$0550,$05D0,$0650,$06D0,$0750,$07D0
|
||||
// Editor variables
|
||||
//
|
||||
byte nullstr = ""
|
||||
byte version = "PLASMA ][ SANDBOX VERSION 00.95"
|
||||
byte version = "PLASMA ][ SANDBOX VERSION 00.96"
|
||||
byte errorstr = "ERROR: $"
|
||||
byte okstr = "OK"
|
||||
byte outofmem = "OUT OF MEMORY!"
|
||||
|
@ -10,7 +10,7 @@
|
||||
#define DEF_TYPE (1 << 4)
|
||||
#define BRANCH_TYPE (1 << 5)
|
||||
#define LOCAL_TYPE (1 << 6)
|
||||
#define EXTERN_TYPE (1 << 7)
|
||||
#define EXTERN_TYPE (1 << 7)
|
||||
#define ADDR_TYPE (VAR_TYPE | FUNC_TYPE | EXTERN_TYPE)
|
||||
#define WPTR_TYPE (1 << 8)
|
||||
#define BPTR_TYPE (1 << 9)
|
||||
@ -18,8 +18,16 @@
|
||||
#define STRING_TYPE (1 << 10)
|
||||
#define TAG_TYPE (1 << 11)
|
||||
#define EXPORT_TYPE (1 << 12)
|
||||
#define PREDEF_TYPE (1 << 13)
|
||||
#define PREDEF_TYPE (1 << 13)
|
||||
#define FUNC_TYPE (ASM_TYPE | DEF_TYPE | PREDEF_TYPE)
|
||||
#define FUNC_PARMS (0x0F << 16)
|
||||
#define FUNC_VALS (0x0F << 20)
|
||||
#define FUNC_PARMVALS (FUNC_PARMS|FUNC_VALS)
|
||||
#define funcparms_type(p) (((p)&0x0F)<<16)
|
||||
#define funcparms_cnt(t) (((t)>>16)&0x0F)
|
||||
#define funcvals_type(v) (((v)&0x0F)<<20)
|
||||
#define funcvals_cnt(t) (((t)>>20)&0x0F)
|
||||
|
||||
int id_match(char *name, int len, char *id);
|
||||
int idlocal_lookup(char *name, int len);
|
||||
int idglobal_lookup(char *name, int len);
|
||||
@ -27,6 +35,7 @@ int idconst_lookup(char *name, int len);
|
||||
int idlocal_add(char *name, int len, int type, int size);
|
||||
int idglobal_add(char *name, int len, int type, int size);
|
||||
int id_add(char *name, int len, int type, int size);
|
||||
void idlocal_reset(void);
|
||||
int idfunc_set(char *name, int len, int type, int tag);
|
||||
int idfunc_add(char *name, int len, int type, int tag);
|
||||
int idconst_add(char *name, int len, int value);
|
||||
|
878
src/vmsrc/a1cmd.pla
Normal file → Executable file
878
src/vmsrc/a1cmd.pla
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
1148
src/vmsrc/cmd.pla
Normal file → Executable file
1148
src/vmsrc/cmd.pla
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
@ -17,32 +17,32 @@ int show_state = 0;
|
||||
/*
|
||||
* Bytecode memory
|
||||
*/
|
||||
#define BYTE_PTR(bp) ((byte)((bp)[0]))
|
||||
#define WORD_PTR(bp) ((word)((bp)[0] | ((bp)[1] << 8)))
|
||||
#define UWORD_PTR(bp) ((uword)((bp)[0] | ((bp)[1] << 8)))
|
||||
#define TO_UWORD(w) ((uword)((w)))
|
||||
#define MOD_ADDR 0x1000
|
||||
#define DEF_CALL 0x0800
|
||||
#define DEF_CALLSZ 0x0800
|
||||
#define DEF_ENTRYSZ 6
|
||||
#define MEM_SIZE 65536
|
||||
#define BYTE_PTR(bp) ((byte)((bp)[0]))
|
||||
#define WORD_PTR(bp) ((word)((bp)[0] | ((bp)[1] << 8)))
|
||||
#define UWORD_PTR(bp) ((uword)((bp)[0] | ((bp)[1] << 8)))
|
||||
#define TO_UWORD(w) ((uword)((w)))
|
||||
#define MOD_ADDR 0x1000
|
||||
#define DEF_CALL 0x0800
|
||||
#define DEF_CALLSZ 0x0800
|
||||
#define DEF_ENTRYSZ 6
|
||||
#define MEM_SIZE 65536
|
||||
byte mem_data[MEM_SIZE];
|
||||
uword sp = 0x01FE, fp = 0xFFFF, heap = 0x0200, deftbl = DEF_CALL, lastdef = DEF_CALL;
|
||||
#define PHA(b) (mem_data[sp--]=(b))
|
||||
#define PLA() (mem_data[++sp])
|
||||
#define EVAL_STACKSZ 16
|
||||
#define PUSH(v) (*(--esp))=(v)
|
||||
#define POP ((word)(*(esp++)))
|
||||
#define UPOP ((uword)(*(esp++)))
|
||||
#define TOS (esp[0])
|
||||
#define PHA(b) (mem_data[sp--]=(b))
|
||||
#define PLA (mem_data[++sp])
|
||||
#define EVAL_STACKSZ 16
|
||||
#define PUSH(v) (*(--esp))=(v)
|
||||
#define POP ((word)(*(esp++)))
|
||||
#define UPOP ((uword)(*(esp++)))
|
||||
#define TOS (esp[0])
|
||||
word eval_stack[EVAL_STACKSZ];
|
||||
word *esp = eval_stack + EVAL_STACKSZ;
|
||||
|
||||
#define SYMTBLSZ 1024
|
||||
#define SYMSZ 16
|
||||
#define MODTBLSZ 128
|
||||
#define MODSZ 16
|
||||
#define MODLSTSZ 32
|
||||
#define SYMTBLSZ 1024
|
||||
#define SYMSZ 16
|
||||
#define MODTBLSZ 128
|
||||
#define MODSZ 16
|
||||
#define MODLSTSZ 32
|
||||
byte symtbl[SYMTBLSZ];
|
||||
byte *lastsym = symtbl;
|
||||
byte modtbl[MODTBLSZ];
|
||||
@ -53,7 +53,7 @@ byte *lastmod = modtbl;
|
||||
void interp(code *ip);
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@ -126,7 +126,7 @@ void dump_tbl(byte *tbl)
|
||||
putchar(':');
|
||||
while (len++ < 15)
|
||||
putchar(' ');
|
||||
printf("$%04X\n", tbl[0] | (tbl[1] << 8));
|
||||
printf("$%04X\n", tbl[0] | (tbl[1] << 8));
|
||||
tbl += 2;
|
||||
}
|
||||
}
|
||||
@ -248,7 +248,7 @@ int load_mod(byte *mod)
|
||||
moddep = header + 1;
|
||||
modsize = header[0] | (header[1] << 8);
|
||||
magic = header[2] | (header[3] << 8);
|
||||
if (magic == 0xDA7E)
|
||||
if (magic == 0xDA7F)
|
||||
{
|
||||
/*
|
||||
* This is a relocatable bytecode module.
|
||||
@ -282,7 +282,7 @@ int load_mod(byte *mod)
|
||||
}
|
||||
/*
|
||||
* Alloc heap space for relocated module (data + bytecode).
|
||||
*/
|
||||
*/
|
||||
moddep += 1;
|
||||
hdrlen = moddep - header;
|
||||
len -= hdrlen;
|
||||
@ -381,7 +381,7 @@ int load_mod(byte *mod)
|
||||
{
|
||||
if (show_state) printf("BYTE");
|
||||
mem_data[addr] = fixup;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -502,18 +502,18 @@ void call(uword pc)
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* OPCODE TABLE
|
||||
*
|
||||
OPTBL: DW ZERO,ADD,SUB,MUL,DIV,MOD,INCR,DECR ; 00 02 04 06 08 0A 0C 0E
|
||||
DW NEG,COMP,AND,IOR,XOR,SHL,SHR,IDXW ; 10 12 14 16 18 1A 1C 1E
|
||||
DW NOT,LOR,LAND,LA,LLA,CB,CW,CS ; 20 22 24 26 28 2A 2C 2E
|
||||
DW DROP,DUP,PUSH,PULL,BRGT,BRLT,BREQ,BRNE ; 30 32 34 36 38 3A 3C 3E
|
||||
DW ISEQ,ISNE,ISGT,ISLT,ISGE,ISLE,BRFLS,BRTRU ; 40 42 44 46 48 4A 4C 4E
|
||||
DW BRNCH,IBRNCH,CALL,ICAL,ENTER,LEAVE,RET,??? ; 50 52 54 56 58 5A 5C 5E
|
||||
DW LB,LW,LLB,LLW,LAB,LAW,DLB,DLW ; 60 62 64 66 68 6A 6C 6E
|
||||
DW SB,SW,SLB,SLW,SAB,SAW,DAB,DAW ; 70 72 74 76 78 7A 7C 7E
|
||||
OPTBL: DW ZERO,ADD,SUB,MUL,DIV,MOD,INCR,DECR ; 00 02 04 06 08 0A 0C 0E
|
||||
DW NEG,COMP,AND,IOR,XOR,SHL,SHR,IDXW ; 10 12 14 16 18 1A 1C 1E
|
||||
DW NOT,LOR,LAND,LA,LLA,CB,CW,CS ; 20 22 24 26 28 2A 2C 2E
|
||||
DW DROP,DUP,PUSH,PULL,BRGT,BRLT,BREQ,BRNE ; 30 32 34 36 38 3A 3C 3E
|
||||
DW ISEQ,ISNE,ISGT,ISLT,ISGE,ISLE,BRFLS,BRTRU ; 40 42 44 46 48 4A 4C 4E
|
||||
DW BRNCH,IBRNCH,CALL,ICAL,ENTER,LEAVE,RET,??? ; 50 52 54 56 58 5A 5C 5E
|
||||
DW LB,LW,LLB,LLW,LAB,LAW,DLB,DLW ; 60 62 64 66 68 6A 6C 6E
|
||||
DW SB,SW,SLB,SLW,SAB,SAW,DAB,DAW ; 70 72 74 76 78 7A 7C 7E
|
||||
*/
|
||||
void interp(code *ip)
|
||||
{
|
||||
@ -533,9 +533,9 @@ void interp(code *ip)
|
||||
}
|
||||
switch (*ip++)
|
||||
{
|
||||
/*
|
||||
* 0x00-0x0F
|
||||
*/
|
||||
/*
|
||||
* 0x00-0x0F
|
||||
*/
|
||||
case 0x00: // ZERO : TOS = 0
|
||||
PUSH(0);
|
||||
break;
|
||||
@ -656,13 +656,11 @@ void interp(code *ip)
|
||||
PUSH(val);
|
||||
break;
|
||||
case 0x34: // PUSH : TOSP = TOS
|
||||
val = POP;
|
||||
PHA(val >> 8);
|
||||
val = esp - eval_stack;
|
||||
PHA(val);
|
||||
break;
|
||||
case 0x36: // PULL : TOS = TOSP
|
||||
PUSH(mem_data[sp] | (mem_data[sp + 1] << 8));
|
||||
sp += 2;
|
||||
esp = eval_stack + PLA;
|
||||
break;
|
||||
case 0x38: // BRGT : TOS-1 > TOS ? IP += (IP)
|
||||
val = POP;
|
||||
@ -775,7 +773,7 @@ void interp(code *ip)
|
||||
printf("\n");
|
||||
break;
|
||||
case 0x5A: // LEAVE : DEL FRAME, IP = TOFP
|
||||
fp += PLA();
|
||||
fp += PLA;
|
||||
case 0x5C: // RET : IP = TOFP
|
||||
return;
|
||||
case 0x5E: // ???
|
||||
@ -822,14 +820,14 @@ void interp(code *ip)
|
||||
/*
|
||||
* 0x70-0x7F
|
||||
*/
|
||||
case 0x70: // SB : BYTE (TOS) = TOS-1
|
||||
val = POP;
|
||||
case 0x70: // SB : BYTE (TOS-1) = TOS
|
||||
ea = UPOP;
|
||||
val = POP;
|
||||
mem_data[ea] = val;
|
||||
break;
|
||||
case 0x72: // SW : WORD (TOS) = TOS-1
|
||||
val = POP;
|
||||
case 0x72: // SW : WORD (TOS-1) = TOS
|
||||
ea = UPOP;
|
||||
val = POP;
|
||||
mem_data[ea] = val;
|
||||
mem_data[ea + 1] = val >> 8;
|
||||
break;
|
||||
@ -889,7 +887,7 @@ int main(int argc, char **argv)
|
||||
{
|
||||
byte dci[32];
|
||||
int i;
|
||||
|
||||
|
||||
if (--argc)
|
||||
{
|
||||
argv++;
|
||||
|
1522
src/vmsrc/plvm01.s
1522
src/vmsrc/plvm01.s
File diff suppressed because it is too large
Load Diff
580
src/vmsrc/plvm02.s
Normal file → Executable file
580
src/vmsrc/plvm02.s
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
1781
src/vmsrc/plvm03.s
1781
src/vmsrc/plvm03.s
File diff suppressed because it is too large
Load Diff
3
src/vmsrc/plvmzp.inc
Normal file → Executable file
3
src/vmsrc/plvmzp.inc
Normal file → Executable file
@ -10,6 +10,9 @@ DST = SRC+2
|
||||
DSTL = DST
|
||||
DSTH = DST+1
|
||||
ESTKSZ = $20
|
||||
XSTK = $A0
|
||||
XSTKL = XSTK
|
||||
XSTKH = XSTK+ESTKSZ/2
|
||||
ESTK = $C0
|
||||
ESTKL = ESTK
|
||||
ESTKH = ESTK+ESTKSZ/2
|
||||
|
1002
src/vmsrc/soscmd.pla
Normal file → Executable file
1002
src/vmsrc/soscmd.pla
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user