mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-25 20:32:25 +00:00
Working on lazynes print.c demonstrating lnList()
This commit is contained in:
parent
858c5de57a
commit
1f02f81b3d
@ -96,10 +96,16 @@ char ppuDataRead();
|
||||
void ppuDataFill(void* const ppuData, char val, unsigned int size);
|
||||
|
||||
// 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)
|
||||
// - ppuData : Pointer in the PPU memory
|
||||
// - 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
|
||||
// - ppuData : Pointer in the PPU memory
|
||||
|
@ -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
|
||||
// - cpuData : Pointer to the CPU memory (RAM of ROM)
|
||||
// - 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) {
|
||||
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
|
||||
// - ppuData : Pointer in the PPU memory
|
||||
// - cpuData : Pointer to the CPU memory (RAM of ROM)
|
||||
// - ppuData : Pointer in the PPU memory
|
||||
// - size : The number of bytes to transfer
|
||||
void ppuDataFetch(void* const cpuData, void* const ppuData, unsigned int size) {
|
||||
ppuDataPrepare(ppuData);
|
||||
|
@ -76,6 +76,20 @@ volatile char scroll_x;
|
||||
// Scroll y-position
|
||||
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)
|
||||
interrupt(hardware_stack) void vblank() {
|
||||
// DMA transfer the entire sprite buffer to the PPU
|
||||
@ -130,7 +144,11 @@ ubyte lnSync(ubyte flags) {
|
||||
// Update the mode
|
||||
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
|
||||
|
||||
// Return number of vblank since last sync
|
||||
char res = vblank_count;
|
||||
vblank_count = 0;
|
||||
@ -147,23 +165,65 @@ void lnPush(uword o, ubyte a, void* s) {
|
||||
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!)
|
||||
// updateList: Pointer to update list
|
||||
//
|
||||
// TODO: void lnList(void* updateList);
|
||||
// TODO: 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
|
||||
// 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
|
||||
|
@ -39,27 +39,28 @@ void lnPush(uword o, ubyte a, void* s);
|
||||
// (Screen has to be visible, doesn't work in blank mode!)
|
||||
// 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 };
|
||||
//
|
||||
// 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()
|
||||
const uword lnNameTab0=0x2000, lnNameTab1=0x2400, lnNameTab2=0x2800, lnNameTab3=0x2C00,
|
||||
// Common offsets for lnPush() and lnList()
|
||||
const uword lnNameTab0=0x2000, lnNameTab1=0x2400, lnNameTab2=0x2800, lnNameTab3=0x2C00,
|
||||
lnAttrTab0=0x23C0, lnAttrTab1=0x27C0, lnAttrTab2=0x2BC0, lnAttrTab3=0x2FC0,
|
||||
lnBackCol=0x3F00,
|
||||
lnChrPal0=0x3F01, lnChrPal1=0x3F05, lnChrPal2=0x3F09, lnChrPal3=0x3F0D,
|
||||
lnSprPal0=0x3F11, lnSprPal1=0x3F15, lnSprPal2=0x3F19, lnSprPal3=0x3F1D;
|
||||
lnBackCol=0x3F00,
|
||||
lnChrPal0=0x3F01, lnChrPal1=0x3F05, lnChrPal2=0x3F09, lnChrPal3=0x3F0D,
|
||||
lnSprPal0=0x3F11, lnSprPal1=0x3F15, lnSprPal2=0x3F19, lnSprPal3=0x3F1D;
|
||||
|
||||
// Scroll background
|
||||
// x: New horizotnal scrolling offset in pixels, allowed range: [0..511]
|
||||
|
49
src/test/kc/complex/lazynes/print.c
Normal file
49
src/test/kc/complex/lazynes/print.c
Normal 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;
|
||||
}
|
@ -11,7 +11,8 @@
|
||||
"files.associations": {
|
||||
"print.h": "c",
|
||||
"printf.h": "c",
|
||||
"c64.h": "c"
|
||||
"c64.h": "c",
|
||||
"sstream": "c"
|
||||
},
|
||||
"kickassembler.assemblerJar": "/Applications/KickAssembler/KickAss.jar"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user