1
0
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:
ZornsLemma 2017-07-08 01:00:39 +01:00 committed by GitHub
commit 7477f66acc
36 changed files with 8243 additions and 4421 deletions

269
README.md
View File

@ -1,8 +1,8 @@
<center>
# The PLASMA Programming Language
![Luc Viatour / www.Lucnix.be](https://upload.wikimedia.org/wikipedia/commons/thumb/2/26/Plasma-lamp_2.jpg/1280px-Plasma-lamp_2.jpg)
![Luc Viatour](https://upload.wikimedia.org/wikipedia/commons/thumb/2/26/Plasma-lamp_2.jpg/1200px-Plasma-lamp_2.jpg)
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
ROGUE.PO

Binary file not shown.

BIN
SANDBOX.PO Normal file → Executable file

Binary file not shown.

BIN
SDFAT.PO

Binary file not shown.

178
doc/Rogue Instructions.rtf Executable file
View 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.\
\
}

View File

@ -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)

View File

@ -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
View 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
View 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
View 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

Binary file not shown.

32
src/samplesrc/a2pwm/lfotbl.s Executable file
View 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
View 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
View 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
}

View 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.

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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;

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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
View 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"

View File

@ -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!"

View File

@ -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

File diff suppressed because it is too large Load Diff

1148
src/vmsrc/cmd.pla Normal file → Executable file

File diff suppressed because it is too large Load Diff

View File

@ -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++;

File diff suppressed because it is too large Load Diff

580
src/vmsrc/plvm02.s Normal file → Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

3
src/vmsrc/plvmzp.inc Normal file → Executable file
View 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

File diff suppressed because it is too large Load Diff