1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2024-12-23 21:33:05 +00:00

Initialized byte tables need not have all 256 bytes initialized.

This commit is contained in:
Chris Pressey 2018-02-02 16:31:23 +00:00
parent 55ae845345
commit 548905dce4
12 changed files with 91 additions and 318 deletions

View File

@ -1,6 +1,12 @@
History of SixtyPical
=====================
0.11
----
* Each table has a specified size now (although, bounds checking is not performed.)
* Initialized `byte table` values need not have all 256 bytes initialized.
0.10
----
@ -12,6 +18,7 @@ History of SixtyPical
* Subtract word (constant or memory location) from word memory location.
* `trash` instruction explicitly indicates a value is no longer considered meaningful.
* `copy []+y, a` can indirectly read a byte value into the `a` register.
* Initialized `byte table` memory locations.
* Fixed bug which was preventing `if` branches to diverge in what they initialized,
if it was already initialized when going into the `if`.
* Fixed a bug which was making it crash when trying to analyze `repeat forever` loops.

View File

@ -1,6 +1,8 @@
SixtyPical
==========
_Version 0.11. Work-in-progress, everything is subject to change._
SixtyPical is a very low-level programming language, similar to 6502 assembly,
with static analysis through abstract interpretation.
@ -22,9 +24,6 @@ based on common machine-language programming idioms, such as
The reference implementation can execute, analyze, and compile SixtyPical
programs to 6502 machine code.
SixtyPical is a work in progress. The current released version of SixtyPical
is 0.10.
Documentation
-------------
@ -83,7 +82,6 @@ assumed to be meaningful.
### And at some point...
* Check that the buffer being read or written to through pointer, appears in approporiate inputs or outputs set.
* `byte table` and `word table` of sizes other than 256
* always analyze before executing or compiling, unless told not to
* `interrupt` routines -- to indicate that "the supervisor" has stored values on the stack, so we can trash them.
* error messages that include the line number of the source code

View File

@ -1,7 +1,7 @@
SixtyPical
==========
This document describes the SixtyPical programming language version 0.10,
This document describes the SixtyPical programming language version 0.11,
both its execution aspect and its static analysis aspect (even though
these are, technically speaking, separate concepts.)
@ -25,8 +25,8 @@ There are six *primitive types* in SixtyPical:
There are also two *type constructors*:
* T table (256 entries, each holding a value of type T, where T is either
`byte` or `word`)
* T table (up to 256 entries, each holding a value of type T, where T is
either `byte` or `word`)
* buffer[N] (N entries; each entry is a byte; N is a power of 2, ≤ 64K)
Memory locations

View File

@ -9,15 +9,15 @@
byte vic_border @ 53280
byte vic_bg @ 53281
byte table screen1 @ 1024
byte table screen2 @ 1274
byte table screen3 @ 1524
byte table screen4 @ 1774
byte table[256] screen1 @ 1024
byte table[256] screen2 @ 1274
byte table[256] screen3 @ 1524
byte table[256] screen4 @ 1774
byte table colormap1 @ 55296
byte table colormap2 @ 55546
byte table colormap3 @ 55796
byte table colormap4 @ 56046
byte table[256] colormap1 @ 55296
byte table[256] colormap2 @ 55546
byte table[256] colormap3 @ 55796
byte table[256] colormap4 @ 56046
buffer[2048] screen @ 1024
byte joy2 @ $dc00
@ -28,15 +28,15 @@ byte joy2 @ $dc00
pointer ptr @ 254
word table actor_pos
word table[256] actor_pos
word pos
word new_pos
word table actor_delta
word table[256] actor_delta
word delta
byte button_down : 0 // effectively static-local to check_button
byte table press_fire_msg: "PRESS`FIRE`TO`PLAY"
byte table[18] press_fire_msg: "PRESS`FIRE`TO`PLAY"
byte save_x
word compare_target

View File

@ -2,7 +2,8 @@
from sixtypical.ast import Program, Routine, Block, Instr
from sixtypical.model import (
TYPE_BYTE, TYPE_WORD, TYPE_BYTE_TABLE, TYPE_WORD_TABLE, BufferType, PointerType, VectorType, ExecutableType,
TYPE_BYTE, TYPE_WORD,
TableType, BufferType, PointerType, VectorType, ExecutableType,
ConstantRef, LocationRef, IndirectRef, IndexedRef, AddressRef,
REG_A, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C
)
@ -231,7 +232,7 @@ class Analyzer(object):
if opcode == 'ld':
if instr.index:
if src.type == TYPE_BYTE_TABLE and dest.type == TYPE_BYTE:
if isinstance(src.type, TableType) and src.type.of_type == TYPE_BYTE and dest.type == TYPE_BYTE:
pass
else:
raise TypeMismatchError('%s and %s in %s' %
@ -245,7 +246,7 @@ class Analyzer(object):
context.set_written(dest, FLAG_Z, FLAG_N)
elif opcode == 'st':
if instr.index:
if src.type == TYPE_BYTE and dest.type == TYPE_BYTE_TABLE:
if src.type == TYPE_BYTE and isinstance(dest.type, TableType) and dest.type.of_type == TYPE_BYTE:
pass
else:
raise TypeMismatchError((src, dest))
@ -361,13 +362,13 @@ class Analyzer(object):
raise TypeMismatchError((src, dest))
elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, IndexedRef):
if src.type == TYPE_WORD and dest.ref.type == TYPE_WORD_TABLE:
if src.type == TYPE_WORD and isinstance(dest.ref.type, TableType) and dest.ref.type.of_type == TYPE_WORD:
pass
else:
raise TypeMismatchError((src, dest))
elif isinstance(src, IndexedRef) and isinstance(dest, LocationRef):
if src.ref.type == TYPE_WORD_TABLE and dest.type == TYPE_WORD:
if isinstance(src.ref.type, TableType) and src.ref.type.of_type == TYPE_WORD and dest.type == TYPE_WORD:
pass
else:
raise TypeMismatchError((src, dest))

View File

@ -3,7 +3,8 @@
from sixtypical.ast import Program, Routine, Block, Instr
from sixtypical.model import (
ConstantRef, LocationRef, IndexedRef, IndirectRef, AddressRef,
TYPE_BIT, TYPE_BYTE, TYPE_BYTE_TABLE, TYPE_WORD, TYPE_WORD_TABLE, BufferType, PointerType, RoutineType, VectorType,
TYPE_BIT, TYPE_BYTE, TYPE_WORD,
TableType, BufferType, PointerType, RoutineType, VectorType,
REG_A, REG_X, REG_Y, FLAG_C
)
from sixtypical.emitter import Byte, Word, Table, Label, Offset, LowAddressByte, HighAddressByte
@ -24,6 +25,10 @@ class UnsupportedOpcodeError(KeyError):
pass
def is_a_table_type(x, of_type):
return isinstance(x, TableType) and x.of_type == of_type
class Compiler(object):
def __init__(self, emitter):
self.emitter = emitter
@ -54,10 +59,8 @@ class Compiler(object):
length = 1
elif type_ == TYPE_WORD or isinstance(type_, (PointerType, VectorType)):
length = 2
elif type_ == TYPE_BYTE_TABLE:
length = 256
elif type_ == TYPE_WORD_TABLE:
length = 512
elif isinstance(type_, TableType):
length = type_.size * (1 if type_.of_type == TYPE_BYTE else 2)
elif isinstance(type_, BufferType):
length = type_.size
if length is None:
@ -90,8 +93,8 @@ class Compiler(object):
initial_data = Byte(defn.initial)
elif type_ == TYPE_WORD:
initial_data = Word(defn.initial)
elif type_ == TYPE_BYTE_TABLE:
initial_data = Table(defn.initial)
elif is_a_table_type(type_, TYPE_BYTE):
initial_data = Table(defn.initial, type_.size)
else:
raise NotImplementedError(type_)
label.set_length(initial_data.size())
@ -404,7 +407,7 @@ class Compiler(object):
self.emitter.emit(LDA(Immediate(LowAddressByte(src_label))))
self.emitter.emit(STA(ZeroPage(Offset(dest_label, 1))))
elif isinstance(src, LocationRef) and isinstance(dest, IndexedRef):
if src.type == TYPE_WORD and dest.ref.type == TYPE_WORD_TABLE:
if src.type == TYPE_WORD and is_a_table_type(dest.ref.type, TYPE_WORD):
src_label = self.labels[src.name]
dest_label = self.labels[dest.ref.name]
self.emitter.emit(LDA(Absolute(src_label)))
@ -414,7 +417,7 @@ class Compiler(object):
else:
raise NotImplementedError
elif isinstance(src, ConstantRef) and isinstance(dest, IndexedRef):
if src.type == TYPE_WORD and dest.ref.type == TYPE_WORD_TABLE:
if src.type == TYPE_WORD and is_a_table_type(dest.ref.type, TYPE_WORD):
dest_label = self.labels[dest.ref.name]
self.emitter.emit(LDA(Immediate(Byte(src.low_byte()))))
self.emitter.emit(STA(self.addressing_mode_for_index(dest.index)(dest_label)))
@ -423,7 +426,7 @@ class Compiler(object):
else:
raise NotImplementedError
elif isinstance(src, IndexedRef) and isinstance(dest, LocationRef):
if src.ref.type == TYPE_WORD_TABLE and dest.type == TYPE_WORD:
if is_a_table_type(src.ref.type, TYPE_WORD) and dest.type == TYPE_WORD:
src_label = self.labels[src.ref.name]
dest_label = self.labels[dest.name]
self.emitter.emit(LDA(self.addressing_mode_for_index(src.index)(src_label)))

View File

@ -48,12 +48,13 @@ class Word(Emittable):
class Table(Emittable):
def __init__(self, value):
def __init__(self, value, size):
# TODO: range-checking
self.value = value
self._size = size
def size(self):
return 256
return self._size
def serialize(self, addr=None):
bytes = []

View File

@ -20,9 +20,7 @@ class Type(object):
TYPE_BIT = Type('bit')
TYPE_BYTE = Type('byte')
TYPE_BYTE_TABLE = Type('byte table')
TYPE_WORD = Type('word')
TYPE_WORD_TABLE = Type('word table')
class ExecutableType(Type):
@ -62,6 +60,13 @@ class VectorType(ExecutableType):
super(VectorType, self).__init__('vector', **kwargs)
class TableType(Type):
def __init__(self, of_type, size):
self.of_type = of_type
self.size = size
self.name = '{} table[{}]'.format(self.of_type.name, self.size)
class BufferType(Type):
def __init__(self, size):
self.size = size

View File

@ -2,8 +2,8 @@
from sixtypical.ast import Program, Defn, Routine, Block, Instr
from sixtypical.model import (
TYPE_BIT, TYPE_BYTE, TYPE_BYTE_TABLE, TYPE_WORD, TYPE_WORD_TABLE,
RoutineType, VectorType, ExecutableType, BufferType, PointerType,
TYPE_BIT, TYPE_BYTE, TYPE_WORD,
RoutineType, VectorType, ExecutableType, TableType, BufferType, PointerType,
LocationRef, ConstantRef, IndirectRef, IndexedRef, AddressRef,
)
from sixtypical.scanner import Scanner
@ -89,7 +89,7 @@ class Parser(object):
initial = None
if self.scanner.consume(':'):
if type_ == TYPE_BYTE_TABLE and self.scanner.on_type('string literal'):
if isinstance(type_, TableType) and self.scanner.on_type('string literal'):
initial = self.scanner.token
else:
self.scanner.check_type('integer literal')
@ -109,23 +109,29 @@ class Parser(object):
return Defn(name=name, addr=addr, initial=initial, location=location)
def defn_size(self):
self.scanner.expect('[')
self.scanner.check_type('integer literal')
size = int(self.scanner.token)
self.scanner.scan()
self.scanner.expect(']')
return size
def defn_type(self):
if self.scanner.consume('byte'):
if self.scanner.consume('table'):
return TYPE_BYTE_TABLE
size = self.defn_size()
return TableType(TYPE_BYTE, size)
return TYPE_BYTE
elif self.scanner.consume('word'):
if self.scanner.consume('table'):
return TYPE_WORD_TABLE
size = self.defn_size()
return TableType(TYPE_WORD, size)
return TYPE_WORD
elif self.scanner.consume('vector'):
return 'vector' # will be resolved to a Type by caller
elif self.scanner.consume('buffer'):
self.scanner.expect('[')
self.scanner.check_type('integer literal')
size = int(self.scanner.token)
self.scanner.scan()
self.scanner.expect(']')
size = self.defn_size()
return BufferType(size)
else:
self.scanner.expect('pointer')

View File

@ -243,7 +243,7 @@ Can't `st` a `word` type.
Storing to a table, you must use an index, and vice-versa.
| byte one
| byte table many
| byte table[256] many
|
| routine main
| outputs one
@ -256,7 +256,7 @@ Storing to a table, you must use an index, and vice-versa.
= ok
| byte one
| byte table many
| byte table[256] many
|
| routine main
| outputs many
@ -269,7 +269,7 @@ Storing to a table, you must use an index, and vice-versa.
? TypeMismatchError
| byte one
| byte table many
| byte table[256] many
|
| routine main
| outputs one
@ -282,7 +282,7 @@ Storing to a table, you must use an index, and vice-versa.
? TypeMismatchError
| byte one
| byte table many
| byte table[256] many
|
| routine main
| outputs many
@ -320,7 +320,7 @@ Reading from a table, you must use an index, and vice-versa.
| }
? TypeMismatchError
| byte table many
| byte table[256] many
|
| routine main
| outputs many
@ -333,7 +333,7 @@ Reading from a table, you must use an index, and vice-versa.
| }
? TypeMismatchError
| byte table many
| byte table[256] many
|
| routine main
| outputs many
@ -349,7 +349,7 @@ Reading from a table, you must use an index, and vice-versa.
Copying to and from a word table.
| word one
| word table many
| word table[256] many
|
| routine main
| inputs one, many
@ -363,7 +363,7 @@ Copying to and from a word table.
= ok
| word one
| word table many
| word table[256] many
|
| routine main
| inputs one, many
@ -376,7 +376,7 @@ Copying to and from a word table.
? TypeMismatchError
| word one
| word table many
| word table[256] many
|
| routine main
| inputs one, many
@ -390,7 +390,7 @@ Copying to and from a word table.
You can also copy a literal word to a word table.
| word table many
| word table[256] many
|
| routine main
| inputs many

View File

@ -137,9 +137,9 @@ Word memory locations with explicit address, initial value.
= $081A .byte $BB
= $081B .byte $0B
Initialized byte table.
Initialized byte table. Bytes allocated, but beyond the string, are 0's.
| byte table message : "WHAT?"
| byte table[8] message : "WHAT?"
|
| routine main
| inputs message
@ -158,254 +158,6 @@ Initialized byte table.
= $0818 BRK
= $0819 BRK
= $081A BRK
= $081B BRK
= $081C BRK
= $081D BRK
= $081E BRK
= $081F BRK
= $0820 BRK
= $0821 BRK
= $0822 BRK
= $0823 BRK
= $0824 BRK
= $0825 BRK
= $0826 BRK
= $0827 BRK
= $0828 BRK
= $0829 BRK
= $082A BRK
= $082B BRK
= $082C BRK
= $082D BRK
= $082E BRK
= $082F BRK
= $0830 BRK
= $0831 BRK
= $0832 BRK
= $0833 BRK
= $0834 BRK
= $0835 BRK
= $0836 BRK
= $0837 BRK
= $0838 BRK
= $0839 BRK
= $083A BRK
= $083B BRK
= $083C BRK
= $083D BRK
= $083E BRK
= $083F BRK
= $0840 BRK
= $0841 BRK
= $0842 BRK
= $0843 BRK
= $0844 BRK
= $0845 BRK
= $0846 BRK
= $0847 BRK
= $0848 BRK
= $0849 BRK
= $084A BRK
= $084B BRK
= $084C BRK
= $084D BRK
= $084E BRK
= $084F BRK
= $0850 BRK
= $0851 BRK
= $0852 BRK
= $0853 BRK
= $0854 BRK
= $0855 BRK
= $0856 BRK
= $0857 BRK
= $0858 BRK
= $0859 BRK
= $085A BRK
= $085B BRK
= $085C BRK
= $085D BRK
= $085E BRK
= $085F BRK
= $0860 BRK
= $0861 BRK
= $0862 BRK
= $0863 BRK
= $0864 BRK
= $0865 BRK
= $0866 BRK
= $0867 BRK
= $0868 BRK
= $0869 BRK
= $086A BRK
= $086B BRK
= $086C BRK
= $086D BRK
= $086E BRK
= $086F BRK
= $0870 BRK
= $0871 BRK
= $0872 BRK
= $0873 BRK
= $0874 BRK
= $0875 BRK
= $0876 BRK
= $0877 BRK
= $0878 BRK
= $0879 BRK
= $087A BRK
= $087B BRK
= $087C BRK
= $087D BRK
= $087E BRK
= $087F BRK
= $0880 BRK
= $0881 BRK
= $0882 BRK
= $0883 BRK
= $0884 BRK
= $0885 BRK
= $0886 BRK
= $0887 BRK
= $0888 BRK
= $0889 BRK
= $088A BRK
= $088B BRK
= $088C BRK
= $088D BRK
= $088E BRK
= $088F BRK
= $0890 BRK
= $0891 BRK
= $0892 BRK
= $0893 BRK
= $0894 BRK
= $0895 BRK
= $0896 BRK
= $0897 BRK
= $0898 BRK
= $0899 BRK
= $089A BRK
= $089B BRK
= $089C BRK
= $089D BRK
= $089E BRK
= $089F BRK
= $08A0 BRK
= $08A1 BRK
= $08A2 BRK
= $08A3 BRK
= $08A4 BRK
= $08A5 BRK
= $08A6 BRK
= $08A7 BRK
= $08A8 BRK
= $08A9 BRK
= $08AA BRK
= $08AB BRK
= $08AC BRK
= $08AD BRK
= $08AE BRK
= $08AF BRK
= $08B0 BRK
= $08B1 BRK
= $08B2 BRK
= $08B3 BRK
= $08B4 BRK
= $08B5 BRK
= $08B6 BRK
= $08B7 BRK
= $08B8 BRK
= $08B9 BRK
= $08BA BRK
= $08BB BRK
= $08BC BRK
= $08BD BRK
= $08BE BRK
= $08BF BRK
= $08C0 BRK
= $08C1 BRK
= $08C2 BRK
= $08C3 BRK
= $08C4 BRK
= $08C5 BRK
= $08C6 BRK
= $08C7 BRK
= $08C8 BRK
= $08C9 BRK
= $08CA BRK
= $08CB BRK
= $08CC BRK
= $08CD BRK
= $08CE BRK
= $08CF BRK
= $08D0 BRK
= $08D1 BRK
= $08D2 BRK
= $08D3 BRK
= $08D4 BRK
= $08D5 BRK
= $08D6 BRK
= $08D7 BRK
= $08D8 BRK
= $08D9 BRK
= $08DA BRK
= $08DB BRK
= $08DC BRK
= $08DD BRK
= $08DE BRK
= $08DF BRK
= $08E0 BRK
= $08E1 BRK
= $08E2 BRK
= $08E3 BRK
= $08E4 BRK
= $08E5 BRK
= $08E6 BRK
= $08E7 BRK
= $08E8 BRK
= $08E9 BRK
= $08EA BRK
= $08EB BRK
= $08EC BRK
= $08ED BRK
= $08EE BRK
= $08EF BRK
= $08F0 BRK
= $08F1 BRK
= $08F2 BRK
= $08F3 BRK
= $08F4 BRK
= $08F5 BRK
= $08F6 BRK
= $08F7 BRK
= $08F8 BRK
= $08F9 BRK
= $08FA BRK
= $08FB BRK
= $08FC BRK
= $08FD BRK
= $08FE BRK
= $08FF BRK
= $0900 BRK
= $0901 BRK
= $0902 BRK
= $0903 BRK
= $0904 BRK
= $0905 BRK
= $0906 BRK
= $0907 BRK
= $0908 BRK
= $0909 BRK
= $090A BRK
= $090B BRK
= $090C BRK
= $090D BRK
= $090E BRK
= $090F BRK
= $0910 BRK
= $0911 BRK
= $0912 BRK
Some instructions.
@ -600,7 +352,7 @@ The body of `repeat forever` can be empty.
Indexed access.
| byte one
| byte table many
| byte table[256] many
|
| routine main
| outputs many
@ -619,8 +371,8 @@ Indexed access.
Byte tables take up 256 bytes in memory.
| byte table tab1
| byte table tab2
| byte table[256] tab1
| byte table[256] tab2
|
| routine main
| inputs tab1
@ -706,7 +458,7 @@ Copy literal word to word.
You can also copy a literal word to a word table.
| word table many
| word table[256] many
|
| routine main
| inputs many
@ -775,7 +527,7 @@ Copy routine to vector, inside an `interrupts off` block.
Copy word to word table and back, with both `x` and `y` as indexes.
| word one
| word table many
| word table[256] many
|
| routine main
| inputs one, many

View File

@ -136,8 +136,8 @@ User-defined memory addresses of different types.
| byte byt
| word wor
| vector vec
| byte table tab
| word table wtab
| byte table[256] tab
| word table[256] wtab
| buffer[2048] buf
| pointer ptr
|
@ -177,7 +177,7 @@ Cannot have both initial value and explicit address.
User-defined locations of other types.
| byte table screen @ 1024
| byte table[256] screen @ 1024
| word r1
| word r2 @ 60000
| word r3 : 2000
@ -188,7 +188,7 @@ User-defined locations of other types.
Initialized byte table.
| byte table message : "WHAT DO YOU WANT TO DO NEXT?"
| byte table[28] message : "WHAT DO YOU WANT TO DO NEXT?"
|
| routine main {
| }
@ -290,7 +290,7 @@ Can't define two routines with the same name.
Declaring byte and word table memory location.
| byte table tab
| byte table[256] tab
|
| routine main {
| ld x, 0
@ -301,7 +301,7 @@ Declaring byte and word table memory location.
= ok
| word one
| word table many
| word table[256] many
|
| routine main {
| ld x, 0