1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-04-08 14:37:40 +00:00

Implemented support for __address() on arrays. Removed support for pc parameter on inline kickasm. Closes #480. Closes #479

This commit is contained in:
jespergravgaard 2020-06-22 00:07:59 +02:00
parent 804d39cf0a
commit cb1b9bece1
30 changed files with 383 additions and 171 deletions

View File

@ -71,23 +71,23 @@ public class VariableBuilder {
}
variable.setMemoryArea(this.getMemoryArea());
variable.setMemoryAlignment(this.getAlignment());
variable.setMemoryAddress(this.getAddress());
variable.setDeclarationOnly(this.isDeclarationOnly());
// Check if the symbol has already been declared
Symbol declaredSymbol = scope.getLocalSymbol(varName);
if(declaredSymbol!=null && !declaredSymbol.getFullName().equals(variable.getFullName()))
if(declaredSymbol != null && !declaredSymbol.getFullName().equals(variable.getFullName()))
// We found another symbol!
declaredSymbol = null;
if(declaredSymbol!=null) {
if(declaredSymbol != null) {
if(!(declaredSymbol instanceof Variable))
throw new CompileError("Error! Conflicting declarations for: "+variable.getFullName());
throw new CompileError("Error! Conflicting declarations for: " + variable.getFullName());
Variable declaredVar = (Variable) declaredSymbol;
if(!declaredVar.isDeclarationOnly() && !variable.isDeclarationOnly())
throw new CompileError("Error! Redefinition of variable: "+variable.getFullName());
throw new CompileError("Error! Redefinition of variable: " + variable.getFullName());
if(!SymbolTypeConversion.variableDeclarationMatch(declaredVar, variable))
throw new CompileError("Error! Conflicting declarations for: "+variable.getFullName());
throw new CompileError("Error! Conflicting declarations for: " + variable.getFullName());
// Update the variable with the definition
if(!variable.isDeclarationOnly()) {
@ -249,6 +249,7 @@ public class VariableBuilder {
/**
* Declared but not defined. ( "extern" keyword)
*
* @return true if the variable is declared but not defined.
*/
public boolean isDeclarationOnly() {
@ -282,7 +283,7 @@ public class VariableBuilder {
VariableBuilderConfig.Scope scope = VariableBuilderConfig.getScope(isScopeGlobal(), isScopeLocal(), isScopeParameter(), isScopeMember());
VariableBuilderConfig.Type type = VariableBuilderConfig.getType(isTypeInteger(), isArray(), isTypePointer(), isTypeStruct());
VariableBuilderConfig.Setting setting = config.getSetting(scope, type);
if(setting!=null && VariableBuilderConfig.Optimization.MA.equals(setting.optimization))
if(setting != null && VariableBuilderConfig.Optimization.MA.equals(setting.optimization))
return false;
else
return true;
@ -328,7 +329,7 @@ public class VariableBuilder {
VariableBuilderConfig.Scope scope = VariableBuilderConfig.getScope(isScopeGlobal(), isScopeLocal(), isScopeParameter(), isScopeMember());
VariableBuilderConfig.Type type = VariableBuilderConfig.getType(isTypeInteger(), isArray(), isTypePointer(), isTypeStruct());
VariableBuilderConfig.Setting setting = config.getSetting(scope, type);
if(setting!=null && VariableBuilderConfig.MemoryArea.MEM.equals(setting.memoryArea))
if(setting != null && VariableBuilderConfig.MemoryArea.MEM.equals(setting.memoryArea))
return Variable.MemoryArea.MAIN_MEMORY;
else
return Variable.MemoryArea.ZEROPAGE_MEMORY;
@ -353,12 +354,32 @@ public class VariableBuilder {
return null;
}
/**
* Get any memory-address of the variables data
*
* @return The memory alignment
*/
public Long getAddress() {
Directive.Address addressDirective = findDirective(Directive.Address.class, directives);
if(addressDirective != null) {
if(isArray()) {
return addressDirective.address;
}
}
return null;
}
/**
* Get any hard-coded register allocation.
*
* @return Hard-coded register allocation. Null if not hard-coded.
*/
public Registers.Register getRegister() {
if(isArray())
// Arrays are not put into registers
return null;
Directive.Address addressDirective = findDirective(Directive.Address.class, directives);
if(addressDirective != null) {
Variable.MemoryArea memoryArea = (addressDirective.address < 0x100) ? Variable.MemoryArea.ZEROPAGE_MEMORY : Variable.MemoryArea.MAIN_MEMORY;
@ -394,6 +415,7 @@ public class VariableBuilder {
private <DirectiveClass extends Directive> boolean hasDirective(Class<DirectiveClass> directiveClass) {
return findDirective(directiveClass, directives) != null;
}
/**
* Examines whether a specific directive is present in the source
*

View File

@ -148,11 +148,11 @@ public class ProgramValueIterator {
if(location != null) {
execute(new ProgramValue.ProgramValueKickAsmLocation(statementKickAsm), handler, statement, statementsIt, block);
}
RValue bytes = statementKickAsm.getLocation();
RValue bytes = statementKickAsm.getBytes();
if(bytes != null) {
execute(new ProgramValue.ProgramValueKickAsmBytes(statementKickAsm), handler, statement, statementsIt, block);
}
RValue cycles = statementKickAsm.getLocation();
RValue cycles = statementKickAsm.getCycles();
if(cycles != null) {
execute(new ProgramValue.ProgramValueKickAsmCycles(statementKickAsm), handler, statement, statementsIt, block);
}

View File

@ -94,6 +94,9 @@ public class Variable implements Symbol {
/** Specifies that the variable must be aligned in memory. Only allowed for arrays & strings. [Only Variables in memory and arrays] */
private Integer memoryAlignment;
/** Specifies that the variable must be placed at an absolute address in memory. Only allowed for arrays & strings. [Only Variables in memory and arrays] */
private Long memoryAddress;
/** The data segment to put the variable into (if it is allocated in memory). [Only variables stored in memory and arrays] */
private String dataSegment;
@ -193,6 +196,7 @@ public class Variable implements Symbol {
throw new InternalError("Cannot version non-PHI variable " + phiMaster.toString());
Variable version = new Variable(phiMaster.getName() + "#" + versionNum, Kind.PHI_VERSION, phiMaster.getType(), phiMaster.getScope(), phiMaster.getMemoryArea(), phiMaster.getDataSegment(), phiMaster.getArraySpec(), null);
version.setMemoryAlignment(phiMaster.getMemoryAlignment());
version.setMemoryAddress(phiMaster.getMemoryAddress());
version.setOptimize(phiMaster.isOptimize());
version.setNoModify(phiMaster.isNoModify());
version.setRegister(phiMaster.getRegister());
@ -239,6 +243,7 @@ public class Variable implements Symbol {
public static Variable createConstant(Variable variable, ConstantValue constantValue) {
Variable constVar = new Variable(variable.getName(), Kind.CONSTANT, variable.getType(), variable.getScope(), MemoryArea.MAIN_MEMORY, variable.getDataSegment(), variable.getArraySpec(), constantValue);
constVar.setMemoryAlignment(variable.getMemoryAlignment());
constVar.setMemoryAddress(variable.getMemoryAddress());
constVar.setOptimize(variable.isOptimize());
constVar.setNoModify(variable.isNoModify());
constVar.setRegister(variable.getRegister());
@ -261,6 +266,7 @@ public class Variable implements Symbol {
public static Variable createCopy(String name, Scope scope, Variable original) {
Variable copy = new Variable(name, original.getKind(), original.getType(), scope, original.getMemoryArea(), original.getDataSegment(), original.getArraySpec(), original.getInitValue());
copy.setMemoryAlignment(original.getMemoryAlignment());
copy.setMemoryAddress(original.getMemoryAddress());
copy.setOptimize(original.isOptimize());
copy.setNoModify(original.isNoModify());
copy.setPermanent(original.isPermanent());
@ -576,6 +582,14 @@ public class Variable implements Symbol {
this.memoryAlignment = memoryAlignment;
}
public Long getMemoryAddress() {
return memoryAddress;
}
public void setMemoryAddress(Long memoryAddress) {
this.memoryAddress = memoryAddress;
}
/**
* Is the variable a struct that should be unwound to member variables
*

View File

@ -453,6 +453,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
for(AsmDirective asmDirective : asmDirectives) {
if(asmDirective instanceof AsmDirectiveLocation) {
statementKickAsm.setLocation(((AsmDirectiveLocation) asmDirective).getAddress());
throw new RuntimeException("KickAsm pc directive no longer supported!");
} else if(asmDirective instanceof AsmDirectiveBytes) {
statementKickAsm.setBytes(((AsmDirectiveBytes) asmDirective).getBytes());
} else if(asmDirective instanceof AsmDirectiveCycles) {

View File

@ -164,6 +164,7 @@ public class Pass4CodeGeneration {
currentScope = ScopeRef.ROOT;
asm.startChunk(currentScope, null, "File Data");
addData(asm, ScopeRef.ROOT);
addAbsoluteAddressData(asm, ScopeRef.ROOT);
// Add all absolutely placed inline KickAsm
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
for(Statement statement : block.getStatements()) {
@ -310,6 +311,7 @@ public class Pass4CodeGeneration {
return true;
} else {
try {
// TODO: Literal calculation should not be necessary anymore.
ConstantLiteral literal = constantValue.calculateLiteral(getScope());
if(literal instanceof ConstantString) {
return true;
@ -489,12 +491,60 @@ public class Pass4CodeGeneration {
}
/**
* Add constants with data and memory variables with data for a scope.
* Added after the the code of the scope.
* Add all constants with data that must be placed at an absolute address
* Added at the end of the file
*
* @param asm The ASM program
* @param scopeRef The scope
*/
private void addAbsoluteAddressData(AsmProgram asm, ScopeRef scopeRef) {
Scope scope = program.getScope().getScope(scopeRef);
Collection<Variable> scopeConstants = scope.getAllConstants(false);
Set<String> added = new LinkedHashSet<>();
// Add all constants arrays incl. strings with data
for(Variable constantVar : scopeConstants) {
if(hasData(constantVar)) {
// Skip if already added
String asmName = constantVar.getAsmName() == null ? constantVar.getLocalName() : constantVar.getAsmName();
if(added.contains(asmName)) {
continue;
}
// Skip if address is not absolute
if(constantVar.getMemoryAddress()==null)
continue;
// Set segment
setCurrentSegment(constantVar.getDataSegment(), asm);
// Set absolute address
asm.addLine(new AsmSetPc(asmName, AsmFormat.getAsmNumber(constantVar.getMemoryAddress())));
// Add any comments
generateComments(asm, constantVar.getComments());
// Add any alignment
Integer declaredAlignment = constantVar.getMemoryAlignment();
if(declaredAlignment != null) {
String alignment = AsmFormat.getAsmNumber(declaredAlignment);
asm.addDataAlignment(alignment);
}
ConstantValue constantValue = constantVar.getInitValue();
if(constantValue instanceof ConstantArray || constantValue instanceof ConstantString || constantValue instanceof ConstantStructValue) {
AsmDataChunk asmDataChunk = new AsmDataChunk();
addChunkData(asmDataChunk, constantValue, constantVar.getType(), constantVar.getArraySpec(), scopeRef);
asmDataChunk.addToAsm(AsmFormat.asmFix(asmName), asm);
} else {
throw new InternalError("Constant Variable not handled " + constantVar.toString(program));
}
added.add(asmName);
}
}
}
/**
* Add constants with data and memory variables with data for a scope.
* Added after the the code of the scope.
*
* @param asm The ASM program
* @param scopeRef The scope
*/
private void addData(AsmProgram asm, ScopeRef scopeRef) {
Scope scope = program.getScope().getScope(scopeRef);
Collection<Variable> scopeConstants = scope.getAllConstants(false);
@ -507,6 +557,9 @@ public class Pass4CodeGeneration {
if(added.contains(asmName)) {
continue;
}
// Skip if address is absolute
if(constantVar.getMemoryAddress()!=null)
continue;
// Set segment
setCurrentSegment(constantVar.getDataSegment(), asm);
// Add any comments

View File

@ -660,6 +660,11 @@ public class TestPrograms {
compileAndCompare("examples/kernalload/kernalload.c");
}
@Test
public void testKrillLoad() throws IOException, URISyntaxException {
compileAndCompare("examples/krillload/krillload.c");
}
@Test
public void testConstantWithPrePost() throws IOException, URISyntaxException {
assertError("constant-prepost.c", "Constant value contains a pre/post-modifier");
@ -1268,6 +1273,11 @@ public class TestPrograms {
compileAndCompare("arrays-init-kasm-0.c");
}
@Test
public void testArraysInitKasm1() throws IOException, URISyntaxException {
compileAndCompare("arrays-init-kasm-1.c");
}
@Test
public void testScreenCenterAngle() throws IOException, URISyntaxException {
compileAndCompare("screen-center-angle.c");

View File

@ -0,0 +1,13 @@
// Test initializing array using KickAssembler
// Place array at hardcoded address
// Sinus table at an absolute address in memory
__address(0x1000) char SINTAB[256] = kickasm {{
.fill 256, 128 + 128*sin(i*2*PI/256)
}};
char* SCREEN = 0x400;
void main() {
SCREEN[0] = SINTAB[0];
}

View File

@ -7,10 +7,9 @@ char SIN[256] = kickasm {{
}
}};
char* SIN_SPRITE = 0x2800;
kickasm(pc SIN_SPRITE) {{
__address(0x3800) char SIN_SPRITE[0x40] = kickasm {{
.fill $40, $ff
}}
}};
char sin_idx = 0;

View File

@ -9,10 +9,30 @@ char* const PLAYFIELD_SCREEN_2 = 0x2c00;
char* const PLAYFIELD_SPRITE_PTRS_1 = (PLAYFIELD_SCREEN_1+SPRITE_PTRS);
// Screen Sprite pointers on screen 2
char* const PLAYFIELD_SPRITE_PTRS_2 = (PLAYFIELD_SCREEN_2+SPRITE_PTRS);
// Address of the sprites covering the playfield
char* const PLAYFIELD_SPRITES = 0x3000;
// Sprites covering the playfield
__address(0x3000) char PLAYFIELD_SPRITES[30*64] = kickasm(resource "playfield-sprites.png") {{
.var sprites = LoadPicture("playfield-sprites.png", List().add($010101, $000000))
// Put the sprites into memory
.for(var sy=0;sy<10;sy++) {
.var sprite_gfx_y = sy*20
.for(var sx=0;sx<3;sx++) {
.for (var y=0;y<21; y++) {
.var gfx_y = sprite_gfx_y + mod(2100+y-sprite_gfx_y,21)
.for (var c=0; c<3; c++) {
.byte sprites.getSinglecolorByte(sx*3+c,gfx_y)
}
}
.byte 0
}
}
}};
// Address of the charset
char* const PLAYFIELD_CHARSET = 0x2800;
__address(0x2800) char PLAYFIELD_CHARSET[] = kickasm(resource "playfield-screen.imap") {{
.fill 8,$00 // Place a filled char at the start of the charset
.import binary "playfield-screen.imap"
}};
// The size of the playfield
const char PLAYFIELD_LINES = 22;

View File

@ -5,11 +5,6 @@
#include "tetris-data.c"
#include "tetris-pieces.c"
kickasm(pc PLAYFIELD_CHARSET, resource "playfield-screen.imap") {{
.fill 8,$00 // Place a filled char at the start of the charset
.import binary "playfield-screen.imap"
}}
// Address of the original playscreen chars
const char PLAYFIELD_SCREEN_ORIGINAL_WIDTH=32;
const char PLAYFIELD_SCREEN_ORIGINAL[] = kickasm(resource "playfield-screen.iscr", resource "playfield-extended.col" ) {{

View File

@ -3,23 +3,6 @@
#include <c64.h>
#include "tetris-data.c"
kickasm(pc PLAYFIELD_SPRITES, resource "playfield-sprites.png") {{
.var sprites = LoadPicture("playfield-sprites.png", List().add($010101, $000000))
// Put the sprites into memory
.for(var sy=0;sy<10;sy++) {
.var sprite_gfx_y = sy*20
.for(var sx=0;sx<3;sx++) {
.for (var y=0;y<21; y++) {
.var gfx_y = sprite_gfx_y + mod(2100+y-sprite_gfx_y,21)
.for (var c=0; c<3; c++) {
.byte sprites.getSinglecolorByte(sx*3+c,gfx_y)
}
}
.byte 0
}
}
}}
// Setup the sprites
void sprites_init() {
*SPRITES_ENABLE = %00001111;

View File

@ -438,13 +438,12 @@ void mulf_init() {
*/
// A single sprite
char* SPRITE = $3000;
kickasm(pc SPRITE, resource "balloon.png") {{
__address(0x3000) char SPRITE[] = kickasm(resource "balloon.png") {{
.var pic = LoadPicture("balloon.png", List().add($000000, $ffffff))
.for (var y=0; y<21; y++)
.for (var x=0;x<3; x++)
.byte pic.getSinglecolorByte(x,y)
}}
}};
// Perspective multiplication table containing (d/(z0-z)[z] for each z-value
signed char align(0x100) PERSP_Z[0x100] = kickasm {{

Binary file not shown.

View File

@ -0,0 +1,62 @@
// Krill's Loader for C64 v184
// https://csdb.dk/release/?id=189130
// Uses Install/Loader files built using the following command.
// > make PLATFORM=c64 prg INSTALL=3400 RESIDENT=3000 ZP=e8
// To place the loader routines elsewhere in memory: re-make the krill loader, update the 2 prg-files and update the __address() below.
// Reserve the zero-page addresses used by the Krill routines
#pragma zp_reserve(0xe8..0xfd)
// The Krill loader routine that can load files.
__address(0x3000) char KRILL_LOADER[] = kickasm(resource "loader-c64.prg") {{
.import c64 "loader-c64.prg"
}};
// The Krill Install routine that can install the drive-side code
__address(0x3400) char KRILL_INSTALL[] = kickasm(resource "install-c64.prg") {{
.import c64 "install-c64.prg"
}};
// Status returned from the Krill functions
enum KrillStatus {
KRILL_OK = 0x00,
KRILL_DEVICE_INCOMPATIBLE = 0xfb,
KRILL_TOO_MANY_DEVICES = 0xfc,
KRILL_GENERIC_KERNAL_ERROR = 0xfd,
KRILL_DEVICE_NOT_PRESENT = 0xfe,
KRILL_FILE_NOT_FOUND = 0xff
};
// Install drive-side code portion(s) must be installed in the active drive.
// Before the loader can operate, its drive-side code portion(s) must be installed in the drive(s).
// The drive-side portion remains resident in the drive. After successful
// installation, the install routine is not needed any more and may be overwritten.
// The KERNAL ROM may be disabled and zeropage variables clobbered.
// Returns the status of the installation
enum KrillStatus krill_install() {
enum KrillStatus* const status = 0xff;
asm(clobbers "AXY") {
jsr KRILL_INSTALL
sta status
}
return *status;
}
// Load a file from the active drive without decompression.
// While loading using filenames with wildcards ("?" and "*") is not possible,
// subsequent files following the previously-loaded file can be loaded via a
// zero-length filename
// - filename - The name of the file to load (zero-terminated in petscii encoding)
// Returns the status of the load
enum KrillStatus krill_loadraw(char* filename) {
enum KrillStatus* const status = 0xff;
char** const fname = 0xfe;
*fname = filename;
asm(clobbers "AXY") {
ldx fname
ldy fname+1
jsr KRILL_LOADER
sta status
}
return *status;
}

View File

@ -0,0 +1,49 @@
// Tests Krill Loader
// Load a file to memory using the Krill loader
// The krillload.ld link file creates a D64 disk image containing the executable and the sprite.
// To execute the program succesfully you must mount the D64 disk image and execute the krillload.PRG program
#pragma link("krillload.ld")
#pragma extension("d64")
// Encoding needed for filename
#pragma encoding(petscii_mixed)
#include "krill.c"
#include <c64.h>
// Sprite file
#pragma data_seg(Sprite)
// The sprite data
export __address(0x2040) char SPRITE[0x40] = kickasm(resource "sprite.png") {{
.var pic = LoadPicture("sprite.png", List().add($000000, $ffffff))
.for (var y=0; y<21; y++)
.for (var x=0;x<3; x++)
.byte pic.getSinglecolorByte(x,y)
}};
// Program file
#pragma data_seg(Data)
char* const SCREEN = 0x0400;
char* const SPRITES_PTR = SCREEN+SPRITE_PTRS;
void main() {
// Install the Krill drive code
char status = krill_install();
if(status!=KRILL_OK) {
VICII->BORDER_COLOR = 0x02;
return;
}
// Load sprite file from disk
status = krill_loadraw("sprite");
if(status!=KRILL_OK) {
VICII->BORDER_COLOR = 0x02;
return;
}
// Show the loaded sprite on screen
VICII->SPRITES_ENABLE = %00000001;
SPRITES_PTR[0] = toSpritePtr(SPRITE);
SPRITES_COLOR[0] = GREEN;
SPRITES_XPOS[0] = 0x15;
SPRITES_YPOS[0] = 0x33;
}

View File

@ -0,0 +1,13 @@
// Create a D64 disk containing the program and a sprite file
.disk [filename="%O", name="DISK", id=1] {
[name="KRILLLOAD", type="prg", segments="Program"],
[name="SPRITE", type="prg", segments="Sprite"]
}
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$080d]
.segmentdef Data [startAfter="Code"]
.segmentdef Sprite
.segment Basic
:BasicUpstart(%E)
.segment Code

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -13,13 +13,12 @@ char align(0x100) YSIN[0x100] = kickasm {{
.byte round(min+(ampl/2)+(ampl/2)*sin(toRadians(360*i/256)))
}};
char* SPRITE = $2000;
kickasm(pc SPRITE, resource "balloon.png") {{
__address(0x2000) char SPRITE[] = kickasm(resource "balloon.png") {{
.var pic = LoadPicture("balloon.png", List().add($000000, $ffffff))
.for (var y=0; y<21; y++)
.for (var x=0;x<3; x++)
.byte pic.getSinglecolorByte(x,y)
}}
}};
void main() {
asm { sei }

View File

@ -1,29 +1,26 @@
// A simple SID music player playing music in the main loop.
#include <c64.h>
char* const MUSIC = $1000;
// Load the SID
kickasm(resource "toiletrensdyr.sid") {{
// SID tune at an absolute address
__address(0x1000) char MUSIC[] = kickasm(resource "toiletrensdyr.sid") {{
.const music = LoadSid("toiletrensdyr.sid")
}}
// Place the SID into memory
kickasm(pc MUSIC) {{
.fill music.size, music.getData(i)
}}
}};
// Pointer to the music init routine
void()* musicInit = (void()*) MUSIC;
// Pointer to the music play routine
void()* musicPlay = (void()*) MUSIC+3;
// Play the music
void main() {
// Initialize the music
asm { jsr music.init }
(*musicInit)();
do {
// Wait for the RASTER
do {} while (VICII->RASTER != $fd);
(VICII->BORDER_COLOR)++;
// Play the music
asm { jsr music.play }
(*musicPlay)();
(VICII->BORDER_COLOR)--;
} while (true);
}

View File

@ -1,25 +1,20 @@
// A simple SID music player using RASTER IRQ
#include <c64.h>
char* const MUSIC = $1000;
// Load the SID
kickasm(resource "toiletrensdyr.sid") {{
// SID tune at an absolute address
__address(0x1000) char MUSIC[] = kickasm(resource "toiletrensdyr.sid") {{
.const music = LoadSid("toiletrensdyr.sid")
}}
// Place the SID into memory
kickasm(pc MUSIC) {{
.fill music.size, music.getData(i)
}}
}};
// Pointer to the music init routine
void()* musicInit = (void()*) MUSIC;
// Pointer to the music play routine
void()* musicPlay = (void()*) MUSIC+3;
// Setup Raster IRQ and initialize SID player
void main() {
asm {
sei
jsr music.init
}
asm { sei }
(*musicInit)();
// Disable CIA 1 Timer IRQ
CIA1->INTERRUPT = CIA_INTERRUPT_CLEAR;
// Set raster line to $fd
@ -36,7 +31,7 @@ void main() {
interrupt(kernel_keyboard) void irq_play() {
(VICII->BORDER_COLOR)++;
// Play SID
asm { jsr music.play }
(*musicPlay)();
// Acknowledge the IRQ
VICII->IRQ_STATUS = IRQ_RASTER;
(VICII->BORDER_COLOR)--;

View File

@ -76,10 +76,9 @@ void anim() {
}
// A single sprite
char* SPRITE = $3000;
kickasm(pc SPRITE, resource "balloon.png") {{
__address(0x3000) char SPRITE[] = kickasm(resource "balloon.png") {{
.var pic = LoadPicture("balloon.png", List().add($000000, $ffffff))
.for (var y=0; y<21; y++)
.for (var x=0;x<3; x++)
.byte pic.getSinglecolorByte(x,y)
}}
}};

View File

@ -3,14 +3,13 @@
#include <string.h>
char* SCREEN = $400;
char* LOGO = $2000;
kickasm(resource "logo.png", pc LOGO, bytes 6*40*8) {{
__address(0x2000) char LOGO[6*40*8] = kickasm(resource "logo.png") {{
.var logoPic = LoadPicture("logo.png", List().add($444444, $808080, $000000, $ffffff))
.for (var y=0; y<6 ; y++)
.for (var x=0;x<40; x++)
.for(var cp=0; cp<8; cp++)
.byte logoPic.getMulticolorByte(x,cp+y*8)
}}
}};
const unsigned int XSIN_SIZE = 512;

View File

@ -2,15 +2,13 @@
#include <string.h>
char* SCREEN = $400;
char* LOGO = $2000;
kickasm(resource "logo.png", pc LOGO, bytes 6*40*8 ) {{
__address(0x2000) char LOGO[6*40*8] = kickasm(resource "logo.png") {{
.var logoPic = LoadPicture("logo.png", List().add($444444, $808080, $000000, $ffffff))
.for (var y=0; y<6 ; y++)
.for (var x=0;x<40; x++)
.for(var cp=0; cp<8; cp++)
.byte logoPic.getMulticolorByte(x,cp+y*8)
}}
}};
void main() {
VICII->BORDER_COLOR = WHITE;

View File

@ -1,10 +1,8 @@
// Example of inline kickasm data
byte* const sintab = $1000;
kickasm(pc sintab) {{
__address(0x1000) char sintab[] = kickasm {{
.fill 25, 20 + 20*sin(toRadians(i*360/25))
}}
}};
void main() {
byte* screen = $400;

View File

@ -1,12 +1,11 @@
// Example of inline kickasm resource data
byte* const SPRITE = $0c00;
kickasm(pc SPRITE, resource "balloon.png") {{
__address(0x0c00) byte SPRITE[] = kickasm(resource "balloon.png") {{
.var pic = LoadPicture("balloon.png", List().add($000000, $ffffff))
.for (var y=0; y<21; y++)
.for (var x=0;x<3; x++)
.byte pic.getSinglecolorByte(x,y)
}}
}};
byte* const SCREEN= $400;
byte* const SPRITES_ENABLE = $d015;

View File

@ -1,6 +1,8 @@
// Test inline KickAssembler code with PC location specification
byte* TABLE = $2000;
__address(0x2000) byte TABLE[] = kickasm {{
.byte 1, 2, 3
}};
void main() {
byte* BORDER_COLOR = $d020;
@ -10,6 +12,3 @@ void main() {
}
}
kickasm(pc TABLE) {{
.byte 1, 2, 3
}}

View File

@ -28,9 +28,6 @@
.label CIA2_TIMER_AB = $dd04
.label SCREEN = $400
.label COS = SIN+$40
// A single sprite
.label SPRITE = $3000
// kickasm
// sin(x) = cos(x+PI/2)
main: {
// asm
@ -459,7 +456,7 @@ init: {
ldx #0
__b1:
// sprites_ptr[i] = (char)(SPRITE/$40)
lda #SPRITE/$40
lda #$ff&SPRITE/$40
sta sprites_ptr,x
// SPRITES_COLOR[i] = GREEN
lda #GREEN
@ -635,8 +632,10 @@ SIN:
// Positions to rotate
xs: .byte -$46, -$46, -$46, 0, 0, $46, $46, $46
ys: .byte -$46, 0, $46, -$46, $46, -$46, 0, $46
.pc = SPRITE "SPRITE"
.var pic = LoadPicture("balloon.png", List().add($000000, $ffffff))
.pc = $3000 "SPRITE"
// A single sprite
SPRITE:
.var pic = LoadPicture("balloon.png", List().add($000000, $ffffff))
.for (var y=0; y<21; y++)
.for (var x=0;x<3; x++)
.byte pic.getSinglecolorByte(x,y)

View File

@ -29,11 +29,8 @@
// Color Ram
.label COLS = $d800
.label SCREEN = $400
.label LOGO = $2000
// Remainder after unsigned 16-bit division
.label rem16u = $12
.label xsin_idx = 2
// kickasm
.label rem16u = $1d
.label xsin_idx = $27
main: {
.const toD0181_return = (>(SCREEN&$3fff)*4)|(>LOGO)/4&$f
// asm
@ -86,9 +83,9 @@ main: {
rts
}
loop: {
.label __2 = $18
.label __7 = $18
.label xpos = $18
.label __2 = $16
.label __7 = $16
.label xpos = $16
lda #<0
sta.z xsin_idx
sta.z xsin_idx+1
@ -145,13 +142,13 @@ loop: {
dec VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR
jmp __b1
}
// render_logo(signed word zp($18) xpos)
// render_logo(signed word zp($16) xpos)
render_logo: {
.label __2 = $1a
.label xpos = $18
.label x_char = $1c
.label logo_idx = 4
.label logo_idx_1 = 5
.label __2 = $1d
.label xpos = $16
.label x_char = $18
.label logo_idx = 2
.label logo_idx_1 = 3
// (char)xpos&7
lda.z xpos
and #7
@ -318,19 +315,19 @@ render_logo: {
// Generate signed int sinus table - with values in the range min-max.
// sintab - the table to generate into
// wavelength - the number of sinus points in a total sinus wavelength (the size of the table)
// sin16s_gen2(signed word* zp($18) sintab)
// sin16s_gen2(signed word* zp($14) sintab)
sin16s_gen2: {
.const min = -$140
.const max = $140
.label ampl = max-min
.label __6 = $a
.label __8 = $29
.label step = $1d
.label sintab = $18
.label __6 = 8
.label __8 = $1d
.label step = $19
.label sintab = $14
// u[4.28]
// Iterate over the table
.label x = 6
.label i = $16
.label x = 4
.label i = $27
// div32u16u(PI2_u4f28, wavelength)
jsr div32u16u
// div32u16u(PI2_u4f28, wavelength)
@ -418,13 +415,13 @@ sin16s_gen2: {
}
// Multiply of two signed ints to a signed long
// Fixes offsets introduced by using unsigned multiplication
// mul16s(signed word zp($14) a)
// mul16s(signed word zp($12) a)
mul16s: {
.label __6 = $25
.label __11 = $25
.label m = $a
.label return = $a
.label a = $14
.label __6 = $23
.label __11 = $23
.label m = 8
.label return = 8
.label a = $12
// mul16u((unsigned int)a, (unsigned int) b)
lda.z a
sta.z mul16u.a
@ -463,13 +460,13 @@ mul16s: {
rts
}
// Perform binary multiplication of two unsigned 16-bit unsigned ints into a 32-bit unsigned long
// mul16u(word zp($29) a, word zp($12) b)
// mul16u(word zp($10) a, word zp($1d) b)
mul16u: {
.label mb = $e
.label a = $29
.label res = $a
.label return = $a
.label b = $12
.label mb = $c
.label a = $10
.label res = 8
.label return = 8
.label b = $1d
// mb = b
lda.z b
sta.z mb
@ -527,20 +524,20 @@ mul16u: {
// Calculate signed int sinus sin(x)
// x: unsigned long input u[4.28] in the interval $00000000 - PI2_u4f28
// result: signed int sin(x) s[0.15] - using the full range -$7fff - $7fff
// sin16s(dword zp($e) x)
// sin16s(dword zp($c) x)
sin16s: {
.label __4 = $21
.label x = $e
.label return = $14
.label x1 = $25
.label x2 = $1a
.label x3 = $1a
.label x3_6 = $27
.label usinx = $14
.label x4 = $1a
.label x5 = $27
.label x5_128 = $27
.label sinx = $14
.label __4 = $1f
.label x = $c
.label return = $12
.label x1 = $23
.label x2 = $16
.label x3 = $16
.label x3_6 = $25
.label usinx = $12
.label x4 = $16
.label x5 = $25
.label x5_128 = $25
.label sinx = $12
// if(x >= PI_u4f28 )
lda.z x+3
cmp #>PI_u4f28>>$10
@ -738,14 +735,14 @@ sin16s: {
}
// Calculate val*val for two unsigned int values - the result is 16 selected bits of the 32-bit result.
// The select parameter indicates how many of the highest bits of the 32-bit result to skip
// mulu16_sel(word zp($1a) v1, word zp($12) v2, byte register(X) select)
// mulu16_sel(word zp($16) v1, word zp($1d) v2, byte register(X) select)
mulu16_sel: {
.label __0 = $a
.label __1 = $a
.label v1 = $1a
.label v2 = $12
.label return = $27
.label return_1 = $1a
.label __0 = 8
.label __1 = 8
.label v1 = $16
.label v2 = $1d
.label return = $25
.label return_1 = $16
// mul16u(v1, v2)
lda.z v1
sta.z mul16u.a
@ -775,9 +772,9 @@ mulu16_sel: {
// Divide unsigned 32-bit unsigned long dividend with a 16-bit unsigned int divisor
// The 16-bit unsigned int remainder can be found in rem16u after the division
div32u16u: {
.label quotient_hi = $27
.label quotient_lo = $14
.label return = $1d
.label quotient_hi = $25
.label quotient_lo = $12
.label return = $19
// divr16u(>dividend, divisor, 0)
lda #<PI2_u4f28>>$10
sta.z divr16u.dividend
@ -817,12 +814,12 @@ div32u16u: {
// Returns the quotient dividend/divisor.
// The final remainder will be set into the global variable rem16u
// Implemented using simple binary division
// divr16u(word zp($29) dividend, word zp($12) rem)
// divr16u(word zp($10) dividend, word zp($1d) rem)
divr16u: {
.label rem = $12
.label dividend = $29
.label quotient = $14
.label return = $14
.label rem = $1d
.label dividend = $10
.label quotient = $12
.label return = $12
ldx #0
txa
sta.z quotient
@ -881,11 +878,11 @@ divr16u: {
rts
}
// Copies the character c (an unsigned char) to the first num characters of the object pointed to by the argument str.
// memset(void* zp($16) str, byte register(X) c)
// memset(void* zp($14) str, byte register(X) c)
memset: {
.label end = $29
.label dst = $16
.label str = $16
.label end = $27
.label dst = $14
.label str = $14
// end = (char*)str + num
lda.z str
clc
@ -918,8 +915,9 @@ memset: {
}
.align $100
xsin: .fill 2*XSIN_SIZE, 0
.pc = LOGO "LOGO"
.var logoPic = LoadPicture("logo.png", List().add($444444, $808080, $000000, $ffffff))
.pc = $2000 "LOGO"
LOGO:
.var logoPic = LoadPicture("logo.png", List().add($444444, $808080, $000000, $ffffff))
.for (var y=0; y<6 ; y++)
.for (var x=0;x<40; x++)
.for(var cp=0; cp<8; cp++)

View File

@ -21,8 +21,6 @@
// Color Ram
.label COLS = $d800
.label SCREEN = $400
.label LOGO = $2000
// kickasm
main: {
.const toD0181_return = (>(SCREEN&$3fff)*4)|(>LOGO)/4&$f
// VICII->BORDER_COLOR = WHITE
@ -108,8 +106,9 @@ memset: {
!:
jmp __b2
}
.pc = LOGO "LOGO"
.var logoPic = LoadPicture("logo.png", List().add($444444, $808080, $000000, $ffffff))
.pc = $2000 "LOGO"
LOGO:
.var logoPic = LoadPicture("logo.png", List().add($444444, $808080, $000000, $ffffff))
.for (var y=0; y<6 ; y++)
.for (var x=0;x<40; x++)
.for(var cp=0; cp<8; cp++)