1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-11-29 18:49:42 +00:00

Working on lazynes print.c demonstrating lnList()

This commit is contained in:
jespergravgaard 2020-07-08 10:29:49 +02:00
parent 858c5de57a
commit 1f02f81b3d
6 changed files with 152 additions and 35 deletions

View File

@ -96,10 +96,16 @@ char ppuDataRead();
void ppuDataFill(void* const ppuData, char val, unsigned int size); void ppuDataFill(void* const ppuData, char val, unsigned int size);
// Transfer a number of bytes from the CPU memory to the PPU memory // Transfer a number of bytes from the CPU memory to the PPU memory
// - ppuData : Pointer in the PPU memory
// - cpuData : Pointer to the CPU memory (RAM of ROM)
// - size : The number of bytes to transfer
void ppuDataTransfer(void* const ppuData, void* const cpuData, unsigned int size);
// Transfer a number of bytes from the PPU memory to the CPU memory
// - cpuData : Pointer to the CPU memory (RAM of ROM) // - cpuData : Pointer to the CPU memory (RAM of ROM)
// - ppuData : Pointer in the PPU memory // - ppuData : Pointer in the PPU memory
// - size : The number of bytes to transfer // - size : The number of bytes to transfer
void ppuDataTransfer(void* const ppuData, void* const cpuData, unsigned int size); void ppuDataFetch(void* const cpuData, void* const ppuData, unsigned int size);
// Transfer a 2x2 tile into the PPU memory // Transfer a 2x2 tile into the PPU memory
// - ppuData : Pointer in the PPU memory // - ppuData : Pointer in the PPU memory

View File

@ -142,8 +142,8 @@ void ppuDataFill(void* const ppuData, char val, unsigned int size) {
} }
// Transfer a number of bytes from the CPU memory to the PPU memory // Transfer a number of bytes from the CPU memory to the PPU memory
// - cpuData : Pointer to the CPU memory (RAM of ROM)
// - ppuData : Pointer in the PPU memory // - ppuData : Pointer in the PPU memory
// - cpuData : Pointer to the CPU memory (RAM of ROM)
// - size : The number of bytes to transfer // - size : The number of bytes to transfer
void ppuDataTransfer(void* const ppuData, void* const cpuData, unsigned int size) { void ppuDataTransfer(void* const ppuData, void* const cpuData, unsigned int size) {
ppuDataPrepare(ppuData); ppuDataPrepare(ppuData);
@ -154,8 +154,8 @@ void ppuDataTransfer(void* const ppuData, void* const cpuData, unsigned int size
} }
// Transfer a number of bytes from the PPU memory to the CPU memory // Transfer a number of bytes from the PPU memory to the CPU memory
// - ppuData : Pointer in the PPU memory
// - cpuData : Pointer to the CPU memory (RAM of ROM) // - cpuData : Pointer to the CPU memory (RAM of ROM)
// - ppuData : Pointer in the PPU memory
// - size : The number of bytes to transfer // - size : The number of bytes to transfer
void ppuDataFetch(void* const cpuData, void* const ppuData, unsigned int size) { void ppuDataFetch(void* const cpuData, void* const ppuData, unsigned int size) {
ppuDataPrepare(ppuData); ppuDataPrepare(ppuData);

View File

@ -76,6 +76,20 @@ volatile char scroll_x;
// Scroll y-position // Scroll y-position
volatile char scroll_y; volatile char scroll_y;
// Update list with data to be moved to VRAM during blank
// The data is moved by when lnSync() is called
// - The format of the update list is an array of unsigned bytes.
// - There can be 3 different commands in the update list:
// a) addressHi, addressLo, value
// b) addressHi|lfHor, addressLo, amountOfBytes, byte1, byte2, byte3, ...
// c) addressHi|lfVer, addressLo, amountOfBytes, byte1, byte2, byte3, ...
// - Multiple commands can be queued in one list,
// but there can only be one activated updatelist at a time.
// - The end of the list is marked by lfEnd! (important!)
// - It's the same format that's used in set_vram_update() of Shiru's neslib
// See https://nesdoug.com/2017/04/13/my-neslib-notes/
char * volatile vram_update_list;
// NMI Called when the PPU refreshes the screen (also known as the V-Blank period) // NMI Called when the PPU refreshes the screen (also known as the V-Blank period)
interrupt(hardware_stack) void vblank() { interrupt(hardware_stack) void vblank() {
// DMA transfer the entire sprite buffer to the PPU // DMA transfer the entire sprite buffer to the PPU
@ -130,7 +144,11 @@ ubyte lnSync(ubyte flags) {
// Update the mode // Update the mode
sync_mode = flags; sync_mode = flags;
// Move any pending data to the VRAM
lnListTransfer();
// TODO: Handle lfSplit = 2 : activates split mode, NMI waits for SPR0HIT and sets registers // TODO: Handle lfSplit = 2 : activates split mode, NMI waits for SPR0HIT and sets registers
// Return number of vblank since last sync // Return number of vblank since last sync
char res = vblank_count; char res = vblank_count;
vblank_count = 0; vblank_count = 0;
@ -147,23 +165,65 @@ void lnPush(uword o, ubyte a, void* s) {
ppuDataTransfer(o, s, a); ppuDataTransfer(o, s, a);
} }
// Write data into nametables, palettes, CHRRAM, etc. // Plan a write of data into nametables, palettes, CHRRAM, etc.
// The data will be written next time lnSync() is called.
// (Screen has to be visible, doesn't work in blank mode!) // (Screen has to be visible, doesn't work in blank mode!)
// updateList: Pointer to update list // updateList: Pointer to update list
// //
// TODO: void lnList(void* updateList); // remarks:
// TODO: enum { lfHor=64, lfVer=128, lfEnd=255 }; // - The format of the update list is an array of unsigned bytes.
// - There can be 3 different commands in the update list:
// a) addressHi, addressLo, value
// b) addressHi|lfHor, addressLo, amountOfBytes, byte1, byte2, byte3, ...
// c) addressHi|lfVer, addressLo, amountOfBytes, byte1, byte2, byte3, ...
// - Multiple commands can be queued in one list,
// but there can only be one activated updatelist at a time.
// - The end of the list is marked by lfEnd! (important!)
// - It's the same format that's used in set_vram_update() of Shiru's neslib
// See https://nesdoug.com/2017/04/13/my-neslib-notes/
void lnList(void* update_list) {
vram_update_list = update_list;
}
// Execute any planned transfer of data into nametables, palettes, CHRRAM, etc. by lnList()
void lnListTransfer() {
if(vram_update_list) {
// Index into the update list (assumes no more than 256 bytes)
char idx = 0;
for(;;) {
char addrHi = vram_update_list[idx++];
// Have we reached the end of the lsit
if(addrHi==0xff) break;
if(addrHi&lfHor) {
// The write is horizontal
char addrLo = vram_update_list[idx++];
char* ppuAddr = (char*)(uword){ addrHi&0x3f, addrLo };
char size = vram_update_list[idx++];
ppuDataTransfer(ppuAddr, vram_update_list+idx, size);
} else if(addrHi&lfVer) {
// The write is vertical
char addrLo = vram_update_list[idx++];
char* ppuAddr = (char*)(uword){ addrHi&0x3f, addrLo };
char size = vram_update_list[idx++];
// Set vertical mode ibit in PPUCTRL
char ppuCtrl = PPU->PPUCTRL;
PPU->PPUCTRL = ppuCtrl|4;
ppuDataTransfer(ppuAddr, vram_update_list+idx, size);
// restore PPUCTRL
PPU->PPUCTRL = ppuCtrl;
} else {
// The write is single-byte
char addrLo = vram_update_list[idx++];
char* ppuAddr = (char*)(uword){ addrHi, addrLo };
char value = vram_update_list[idx++];
ppuDataSet(ppuAddr, value);
}
}
// Set update list to zero
vram_update_list = 0;
}
}
// remarks:
// - The format of the update list is an array of unsigned bytes.
// - There can be 3 different commands in the update list:
// a) addressHi, addressLo, value
// b) addressHi|lfHor, addressLo, amountOfBytes, byte1, byte2, byte3, ...
// c) addressHi|lfVer, addressLo, amountOfBytes, byte1, byte2, byte3, ...
// - Multiple commands can be queued in one list,
// but there can only be one activated updatelist at a time.
// - The end of the list is marked by lfEnd! (important!)
// - It's the same format that's used in set_vram_update() of Shiru's neslib
// Scroll background // Scroll background

View File

@ -39,27 +39,28 @@ void lnPush(uword o, ubyte a, void* s);
// (Screen has to be visible, doesn't work in blank mode!) // (Screen has to be visible, doesn't work in blank mode!)
// updateList: Pointer to update list // updateList: Pointer to update list
// //
// TODO: void lnList(void* updateList); // remarks:
// - The format of the update list is an array of unsigned bytes.
// - There can be 3 different commands in the update list:
// a) addressHi, addressLo, value
// b) addressHi|lfHor, addressLo, amountOfBytes, byte1, byte2, byte3, ...
// c) addressHi|lfVer, addressLo, amountOfBytes, byte1, byte2, byte3, ...
// - Multiple commands can be queued in one list,
// but there can only be one activated updatelist at a time.
// - The end of the list is marked by lfEnd! (important!)
// - It's the same format that's used in set_vram_update() of Shiru's neslib
// See https://nesdoug.com/2017/04/13/my-neslib-notes/
void lnList(void* update_list);
// Constants used to control VRAM updates in the list passed to lnList()
enum { lfHor=64, lfVer=128, lfEnd=255 }; enum { lfHor=64, lfVer=128, lfEnd=255 };
//
// remarks:
// - The format of the update list is an array of unsigned bytes.
// - There can be 3 different commands in the update list:
// a) addressHi, addressLo, value
// b) addressHi|lfHor, addressLo, amountOfBytes, byte1, byte2, byte3, ...
// c) addressHi|lfVer, addressLo, amountOfBytes, byte1, byte2, byte3, ...
// - Multiple commands can be queued in one list,
// but there can only be one activated updatelist at a time.
// - The end of the list is marked by lfEnd! (important!)
// - It's the same format that's used in set_vram_update() of Shiru's neslib
// Common offsets for lnPush() and lnList()
// Common offsets for lnPush() and lnList() const uword lnNameTab0=0x2000, lnNameTab1=0x2400, lnNameTab2=0x2800, lnNameTab3=0x2C00,
const uword lnNameTab0=0x2000, lnNameTab1=0x2400, lnNameTab2=0x2800, lnNameTab3=0x2C00,
lnAttrTab0=0x23C0, lnAttrTab1=0x27C0, lnAttrTab2=0x2BC0, lnAttrTab3=0x2FC0, lnAttrTab0=0x23C0, lnAttrTab1=0x27C0, lnAttrTab2=0x2BC0, lnAttrTab3=0x2FC0,
lnBackCol=0x3F00, lnBackCol=0x3F00,
lnChrPal0=0x3F01, lnChrPal1=0x3F05, lnChrPal2=0x3F09, lnChrPal3=0x3F0D, lnChrPal0=0x3F01, lnChrPal1=0x3F05, lnChrPal2=0x3F09, lnChrPal3=0x3F0D,
lnSprPal0=0x3F11, lnSprPal1=0x3F15, lnSprPal2=0x3F19, lnSprPal3=0x3F1D; lnSprPal0=0x3F11, lnSprPal1=0x3F15, lnSprPal2=0x3F19, lnSprPal3=0x3F1D;
// Scroll background // Scroll background
// x: New horizotnal scrolling offset in pixels, allowed range: [0..511] // x: New horizotnal scrolling offset in pixels, allowed range: [0..511]

View File

@ -0,0 +1,49 @@
// lazyNES print demo (using lnlist)
// lazyNES - As lazy as possible NES hardware support library for vbcc6502
// (happily cooperates with Shiru's famitone2 replay code)
// V1.0, 'Lazycow 2020
// Ported to KickC 2020 by Jesper Gravgaard
// Original Source VBCC alpha 2 http://www.ibaug.de/vbcc/vbcc6502_2.zip
#pragma target(nes)
#include "lazynes.h"
// A string in ROM
#pragma data_seg(Data)
ubyte b_init[]={0,0,10,'B','U','B','B','L','E','S',':',0,0,lfEnd};
// A string in RAM
#pragma data_seg(GameRam)
ubyte b[14];
// print some text in the static area using lnList
void Print(uword offset, ubyte value) {
b[0]=(ubyte)(offset>>8)|lfHor; b[1]=(ubyte)offset; b[11]=b[12]='0';
while (value>=10) { ++b[11]; value-=10; }
while (value>=1) { ++b[12]; value-=1; }
lnList(b);
}
int lnMain() {
// Copy string from ROM to RAM
for(char i=0;i<sizeof(b_init);i++)
b[i] = b_init[i];
static const ubyte bgColors[]={45,33,2};
ubyte objects=0;
uword tics=0;
lnSync(lfBlank); // blank screen to enable lnPush() usage
lnPush(lnBackCol,3,bgColors); // set background colors
for(;;) {
// update the number to display
tics+=1;
if (tics>8) {
tics=0;
objects = (objects+1)&0x3f;
}
// display a number
Print(lnNameTab0+32,objects+1);
lnSync(0); // sync with vblank
}
return 0;
}

View File

@ -11,7 +11,8 @@
"files.associations": { "files.associations": {
"print.h": "c", "print.h": "c",
"printf.h": "c", "printf.h": "c",
"c64.h": "c" "c64.h": "c",
"sstream": "c"
}, },
"kickassembler.assemblerJar": "/Applications/KickAssembler/KickAss.jar" "kickassembler.assemblerJar": "/Applications/KickAssembler/KickAss.jar"
} }