1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2025-02-21 21:29:11 +00:00

memory map hover + click; nes presets

This commit is contained in:
Steven Hugg 2019-02-26 10:56:51 -05:00
parent 4e17913823
commit ccf5824bb4
13 changed files with 186 additions and 102 deletions

View File

@ -409,6 +409,10 @@ div.markdown th {
color: #333; color: #333;
background-color:#999; background-color:#999;
} }
.segment:hover {
border-color: #ffffff;
cursor: pointer;
}
.segment.segment-ram { .segment.segment-ram {
background-color:#aaeeaa; background-color:#aaeeaa;
} }

View File

@ -54,18 +54,17 @@ HelloMsg:
; set palette colors ; set palette colors
SetPalette: subroutine SetPalette: subroutine
ldy #$00 ldy #$00 ; Y = $00 (also palette index)
lda #$3f lda #$3f ; A = $3F
sta PPU_ADDR sta PPU_ADDR ; $3F?? -> PPU address
sty PPU_ADDR sty PPU_ADDR ; $3F00 -> PPU address
ldx #32
.loop: .loop:
lda Palette,y lda Palette,y ; lookup byte in ROM
sta PPU_DATA sta PPU_DATA ; store byte to PPU data
iny iny ; Y = Y + 1
dex cpy #32 ; is Y equal to 32?
bne .loop bne .loop ; not yet, loop
rts rts ; return to caller
;;;;; COMMON SUBROUTINES ;;;;; COMMON SUBROUTINES

View File

@ -38,31 +38,30 @@ Start:
FillVRAM: subroutine FillVRAM: subroutine
txa txa
ldy #$20 ldy #$20
sty PPU_ADDR sty PPU_ADDR ; $20?? -> PPU address
sta PPU_ADDR sta PPU_ADDR ; $2000 -> PPU address
ldy #$10 ldy #$10 ; set $10 pages ($1000 bytes)
.loop: .loop:
stx PPU_DATA stx PPU_DATA ; X -> PPU data port
inx inx ; X = X + 1
bne .loop bne .loop ; repeat until 256 bytes
dey dey ; Y = Y - 1
bne .loop bne .loop ; repeat until Y is 0
rts rts ; return to caller
; set palette colors ; set palette colors
SetPalette: subroutine SetPalette: subroutine
ldy #$00 ldy #$00 ; Y = $00 (also palette index)
lda #$3f lda #$3f ; A = $3F
sta PPU_ADDR sta PPU_ADDR ; $3F?? -> PPU address
sty PPU_ADDR sty PPU_ADDR ; $3F00 -> PPU address
ldx #32
.loop: .loop:
lda Palette,y lda Palette,y ; lookup byte in ROM
sta PPU_DATA sta PPU_DATA ; store byte to PPU data
iny iny ; Y = Y + 1
dex cpy #32 ; is Y equal to 32?
bne .loop bne .loop ; not yet, loop
rts rts ; return to caller
;;;;; COMMON SUBROUTINES ;;;;; COMMON SUBROUTINES

View File

@ -21,11 +21,11 @@ void put_str(unsigned int adr, const char *str) {
vram_write(str, strlen(str)); // write bytes to PPU vram_write(str, strlen(str)); // write bytes to PPU
} }
static word x_scroll = 0; word x_scroll; // X scroll amount in pixels
static byte bldg_height = 8; byte bldg_height; // building height in tiles
static byte bldg_width = 8; byte bldg_width; // building width in tiles
static byte bldg_char = 1; byte bldg_char; // character to draw
static byte bldg_attr = 0x55; byte bldg_attr; // attribute table value
#define PLAYROWS 24 #define PLAYROWS 24
@ -34,6 +34,13 @@ word nt2attraddr(word a) {
((a >> 4) & 0x38) | ((a >> 2) & 0x07); ((a >> 4) & 0x38) | ((a >> 2) & 0x07);
} }
void new_building() {
bldg_height = (rand8() & 7) + 2;
bldg_width = (rand8() & 3) * 4 + 4;
bldg_char = (rand8() & 15);
bldg_attr = rand8();
}
void update_nametable() { void update_nametable() {
word addr; word addr;
char buf[PLAYROWS]; char buf[PLAYROWS];
@ -47,6 +54,8 @@ void update_nametable() {
// create vertical slice // create vertical slice
// clear empty space // clear empty space
memset(buf, 0, PLAYROWS-bldg_height); memset(buf, 0, PLAYROWS-bldg_height);
// draw a random star
buf[rand8() & 31] = '.';
// draw roof // draw roof
buf[PLAYROWS-bldg_height-1] = bldg_char & 3; buf[PLAYROWS-bldg_height-1] = bldg_char & 3;
// draw rest of building // draw rest of building
@ -66,15 +75,15 @@ void update_nametable() {
} }
// generate new building? // generate new building?
if (--bldg_width == 0) { if (--bldg_width == 0) {
bldg_height = (rand8() & 7) + 2; new_building();
bldg_width = (rand8() & 3) * 4 + 4;
bldg_char = (rand8() & 15);
bldg_attr = rand8();
} }
} }
// function to scroll window up and down until end // function to scroll window up and down until end
void scroll_demo() { void scroll_demo() {
// make 1st building
new_building();
x_scroll = 0;
// infinite loop // infinite loop
while (1) { while (1) {
// update nametable every 8 pixels // update nametable every 8 pixels

34
presets/nes/neslib1.c Normal file
View File

@ -0,0 +1,34 @@
#include "neslib.h"
#include <string.h>
// link the pattern table into CHR ROM
//#link "chr_generic.s"
// function to write a string into the name table
// adr = start address in name table
// str = pointer to string
void put_str(unsigned int adr, const char *str) {
vram_adr(adr); // set PPU read/write address
vram_write(str, strlen(str)); // write bytes to PPU
}
// main function, run after console reset
void main(void) {
// set palette colors
pal_col(1,0x04);
pal_col(2,0x20);
pal_col(3,0x30);
// write text to name table
put_str(NTADR_A(2,2),"HELLO, WORLD!");
put_str(NTADR_A(2,4),"THIS CODE PRINTS SOME TEXT");
put_str(NTADR_A(2,5),"USING ASCII-ENCODED CHARACTER");
put_str(NTADR_A(2,6),"SET WITH CAPITAL LETTERS ONLY");
// enable PPU rendering (turn on screen)
ppu_on_all();
// infinite loop
while (1) ;
}

View File

@ -6,10 +6,12 @@
#include "neslib.h" #include "neslib.h"
//#link "tileset1.c" // VRAM buffer module
#include "vrambuf.h"
//#link "vrambuf.c"
extern unsigned char palSprites[16]; // link the pattern table into CHR ROM
extern unsigned char TILESET[8*256]; //#link "chr_generic.s"
#define COLS 32 #define COLS 32
#define ROWS 27 #define ROWS 27
@ -31,48 +33,13 @@ byte getchar(byte x, byte y) {
return rd + 0x20; return rd + 0x20;
} }
// VRAM UPDATE BUFFER
byte updbuf[64];
byte updptr = 0;
void cendbuf() {
updbuf[updptr] = NT_UPD_EOF;
}
void cflushnow() {
cendbuf();
waitvsync();
flush_vram_update(updbuf);
updptr = 0;
cendbuf();
vram_adr(0x0);
}
void vdelay(byte count) {
while (count--) cflushnow();
}
void cputcxy(byte x, byte y, char ch) { void cputcxy(byte x, byte y, char ch) {
word addr = NTADR_A(x,y); putbytes(NTADR_A(x,y), &ch, 1);
if (updptr >= 60) cflushnow();
updbuf[updptr++] = addr >> 8;
updbuf[updptr++] = addr & 0xff;
updbuf[updptr++] = ch - 0x20;
cendbuf();
} }
void cputsxy(byte x, byte y, char* str) { void cputsxy(byte x, byte y, const char* str) {
word addr = NTADR_A(x,y); putbytes(NTADR_A(x,y), str, strlen(str));
byte len = strlen(str);
if (updptr >= 60 - len) cflushnow();
updbuf[updptr++] = (addr >> 8) | NT_UPD_HORZ;
updbuf[updptr++] = addr & 0xff;
updbuf[updptr++] = len;
while (len--) {
updbuf[updptr++] = *str++ - 0x20;
}
cendbuf();
} }
void clrscr() { void clrscr() {
@ -133,7 +100,7 @@ void draw_playfield() {
cputcxy(9,1,players[0].score+'0'); cputcxy(9,1,players[0].score+'0');
cputcxy(28,1,players[1].score+'0'); cputcxy(28,1,players[1].score+'0');
if (attract) { if (attract) {
cputsxy(5,ROWS-1,"ATTRACT MODE - PRESS 1"); cputsxy(3,ROWS-1,"ATTRACT MODE - PRESS ENTER");
} else { } else {
cputsxy(1,1,"PLYR1:"); cputsxy(1,1,"PLYR1:");
cputsxy(20,1,"PLYR2:"); cputsxy(20,1,"PLYR2:");
@ -229,7 +196,8 @@ void flash_colliders() {
//cv_set_attenuation(CV_SOUNDCHANNEL_0, i/2); //cv_set_attenuation(CV_SOUNDCHANNEL_0, i/2);
if (players[0].collided) players[0].head_attr ^= 0x80; if (players[0].collided) players[0].head_attr ^= 0x80;
if (players[1].collided) players[1].head_attr ^= 0x80; if (players[1].collided) players[1].head_attr ^= 0x80;
vdelay(2); cflushnow();
cflushnow();
draw_player(&players[0]); draw_player(&players[0]);
draw_player(&players[1]); draw_player(&players[1]);
} }
@ -240,7 +208,7 @@ void make_move() {
byte i; byte i;
for (i=0; i<frames_per_move; i++) { for (i=0; i<frames_per_move; i++) {
human_control(&players[0]); human_control(&players[0]);
vdelay(1); cflushnow();
} }
ai_control(&players[0]); ai_control(&players[0]);
ai_control(&players[1]); ai_control(&players[1]);
@ -254,12 +222,13 @@ void declare_winner(byte winner) {
clrscr(); clrscr();
for (i=0; i<ROWS/2-3; i++) { for (i=0; i<ROWS/2-3; i++) {
draw_box(i,i,COLS-1-i,ROWS-1-i,BOX_CHARS); draw_box(i,i,COLS-1-i,ROWS-1-i,BOX_CHARS);
vdelay(1); cflushnow();
} }
cputsxy(12,10,"WINNER:"); cputsxy(12,10,"WINNER:");
cputsxy(12,13,"PLAYER "); cputsxy(12,13,"PLAYER ");
cputcxy(12+7, 13, '1'+winner); cputcxy(12+7, 13, '1'+winner);
vdelay(75); cflushnow();
delay(75);
gameover = 1; gameover = 1;
} }
@ -338,9 +307,9 @@ void play_game() {
} }
void main() { void main() {
vram_adr(0x0);
vram_write((unsigned char*)TILESET, sizeof(TILESET));
joy_install (joy_static_stddrv); joy_install (joy_static_stddrv);
cendbuf();
set_vram_update(updbuf);
while (1) { while (1) {
attract = 1; attract = 1;
play_game(); play_game();

View File

@ -28,7 +28,7 @@ void cflushnow(void) {
// add multiple characters to update buffer // add multiple characters to update buffer
// using horizontal increment // using horizontal increment
void putbytes(word addr, char* str, byte len) { void putbytes(word addr, const char* str, byte len) {
if (updptr >= VBUFSIZE-4-len) cflushnow(); if (updptr >= VBUFSIZE-4-len) cflushnow();
updbuf[updptr++] = (addr >> 8) ^ NT_UPD_HORZ; updbuf[updptr++] = (addr >> 8) ^ NT_UPD_HORZ;
updbuf[updptr++] = addr & 0xff; updbuf[updptr++] = addr & 0xff;

View File

@ -33,6 +33,6 @@ void cflushnow(void);
// add multiple characters to update buffer // add multiple characters to update buffer
// using horizontal increment // using horizontal increment
void putbytes(word addr, char* str, byte len); void putbytes(word addr, const char* str, byte len);
#endif // vrambuf.h #endif // vrambuf.h

59
presets/nes/vrambuffer.c Normal file
View File

@ -0,0 +1,59 @@
#include "neslib.h"
#include <string.h>
#include <stdio.h>
// VRAM buffer module
#include "vrambuf.h"
//#link "vrambuf.c"
// link the pattern table into CHR ROM
//#link "chr_generic.s"
// function to scroll window up and down until end
void scroll_demo() {
int x = 0; // x scroll position
int y = 0; // y scroll position
int dy = 1; // y scroll direction
// 32-character array for string-building
char str[32];
// clear string array
memset(str, 0, sizeof(str));
// infinite loop
while (1) {
// write message to string array
sprintf(str, "%6x %6d", y, y);
// write string array into VRAM buffer
putbytes(NTADR_A(2,y%30), str, 32);
// wait for next frame
// and flush VRAM buffer
cflushnow();
// set scroll register
scroll(x, y);
// update y variable
y += dy;
// change direction when hitting either edge of scroll area
if (y >= 479) dy = -1;
if (y == 0) dy = 1;
}
}
// main function, run after console reset
void main(void) {
// set palette colors
pal_col(1,0x04);
pal_col(2,0x20);
pal_col(3,0x30);
// clear vram buffer
cclearbuf();
// set NMI handler
set_vram_update(updbuf);
// enable PPU rendering (turn on screen)
ppu_on_all();
// scroll window back and forth
scroll_demo();
}

View File

@ -16,14 +16,15 @@ const JSNES_PRESETS = [
{id:'ex4.asm', name:'Controller Demo (ASM)'}, {id:'ex4.asm', name:'Controller Demo (ASM)'},
{id:'neslib1.c', name:'Text'}, {id:'neslib1.c', name:'Text'},
{id:'scroll.c', name:'Scrolling'}, {id:'scroll.c', name:'Scrolling'},
{id:'statusbar.c', name:'Status Bar'}, {id:'vrambuffer.c', name:'VRAM Buffer'},
{id:'horizmask.c', name:'Horizontal Scrolling'},
{id:'sprites.c', name:'Sprites'}, {id:'sprites.c', name:'Sprites'},
{id:'metasprites.c', name:'Metasprites'}, {id:'metasprites.c', name:'Metasprites'},
{id:'flicker.c', name:'Flickering Sprites'}, {id:'flicker.c', name:'Flickering Sprites'},
{id:'metacursor.c', name:'Controllers'}, {id:'metacursor.c', name:'Controllers'},
{id:'metatrigger.c', name:'Trigger Mode + Vbright'}, {id:'metatrigger.c', name:'Trigger Mode + Vbright'},
{id:'neslib5.c', name:'RLE Unpack'}, {id:'neslib5.c', name:'RLE Unpack'},
{id:'statusbar.c', name:'Split Status Bar'},
{id:'horizmask.c', name:'Horizontal Scrolling'},
{id:'music.c', name:'Music Player'}, {id:'music.c', name:'Music Player'},
{id:'siegegame.c', name:'Siege Game'}, {id:'siegegame.c', name:'Siege Game'},
{id:'shoot2.c', name:'Solarian Game'}, {id:'shoot2.c', name:'Solarian Game'},

View File

@ -32,7 +32,7 @@ var toolbar = $("#controls_top");
export var current_project : CodeProject; // current CodeProject object export var current_project : CodeProject; // current CodeProject object
var projectWindows : ProjectWindows; // window manager export var projectWindows : ProjectWindows; // window manager
var stateRecorder : StateRecorderImpl; var stateRecorder : StateRecorderImpl;

View File

@ -7,7 +7,7 @@ import { SourceFile, WorkerError, Segment } from "./workertypes";
import { Platform, EmuState } from "./baseplatform"; import { Platform, EmuState } from "./baseplatform";
import { hex, lpad, rpad } from "./util"; import { hex, lpad, rpad } from "./util";
import { CodeAnalyzer } from "./analysis"; import { CodeAnalyzer } from "./analysis";
import { platform, platform_id, compparams, current_project, lastDebugState } from "./ui"; import { platform, platform_id, compparams, current_project, lastDebugState, projectWindows } from "./ui";
export interface ProjectView { export interface ProjectView {
createDiv(parent:HTMLElement, text:string) : HTMLElement; createDiv(parent:HTMLElement, text:string) : HTMLElement;
@ -608,7 +608,11 @@ export class MemoryView implements ProjectView {
$(parent).append(this.memorylist.container); $(parent).append(this.memorylist.container);
this.tick(); this.tick();
if (compparams && this.dumplines) if (compparams && this.dumplines)
this.memorylist.scrollToItem(this.findMemoryWindowLine(compparams.data_start)); this.scrollToAddress(compparams.data_start);
}
scrollToAddress(addr : number) {
this.memorylist.scrollToItem(this.findMemoryWindowLine(addr));
} }
refresh() { refresh() {
@ -694,6 +698,7 @@ export class MemoryView implements ProjectView {
return this.dumplines; return this.dumplines;
} }
// TODO: use segments list?
getMemorySegment(a:number) : string { getMemorySegment(a:number) : string {
if (!compparams) return 'unknown'; if (!compparams) return 'unknown';
if (a >= compparams.data_start && a < compparams.data_start+compparams.data_size) { if (a >= compparams.data_start && a < compparams.data_start+compparams.data_size) {
@ -805,6 +810,11 @@ export class MemoryMapView implements ProjectView {
var row = $('<div class="row"/>').append(offset, segdiv); var row = $('<div class="row"/>').append(offset, segdiv);
var container = $('<div class="container"/>').append(row); var container = $('<div class="container"/>').append(row);
this.maindiv.append(container); this.maindiv.append(container);
segdiv.click(() => {
var memview = projectWindows.createOrShow('#memory') as MemoryView;
memview.scrollToAddress(seg.start);
// TODO: this doesn't update nav bar
});
} }
refresh() { refresh() {

View File

@ -25,11 +25,11 @@ export class ProjectWindows {
} }
// TODO: delete windows ever? // TODO: delete windows ever?
setCreateFunc(id:string, createfn:WindowCreateFunction) { setCreateFunc(id:string, createfn:WindowCreateFunction) : void {
this.id2createfn[id] = createfn; this.id2createfn[id] = createfn;
} }
createOrShow(id:string) { createOrShow(id:string) : ProjectView {
var wnd = this.id2window[id]; var wnd = this.id2window[id];
if (!wnd) { if (!wnd) {
wnd = this.id2window[id] = this.id2createfn[id](id); wnd = this.id2window[id] = this.id2createfn[id](id);
@ -52,27 +52,27 @@ export class ProjectWindows {
return wnd; return wnd;
} }
put(id:string, window:ProjectView) { put(id:string, window:ProjectView) : void {
this.id2window[id] = window; this.id2window[id] = window;
} }
refresh(moveCursor:boolean) { refresh(moveCursor:boolean) : void {
// refresh current window // refresh current window
if (this.activewnd && this.activewnd.refresh) if (this.activewnd && this.activewnd.refresh)
this.activewnd.refresh(moveCursor); this.activewnd.refresh(moveCursor);
} }
tick() { tick() : void {
if (this.activewnd && this.activewnd.tick) if (this.activewnd && this.activewnd.tick)
this.activewnd.tick(); this.activewnd.tick();
} }
setErrors(errors:WorkerError[]) { setErrors(errors:WorkerError[]) : void {
this.lasterrors = errors; this.lasterrors = errors;
this.refreshErrors(); this.refreshErrors();
} }
refreshErrors() { refreshErrors() : void {
if (this.activewnd && this.activewnd.markErrors) { if (this.activewnd && this.activewnd.markErrors) {
if (this.lasterrors && this.lasterrors.length) if (this.lasterrors && this.lasterrors.length)
this.activewnd.markErrors(this.lasterrors); this.activewnd.markErrors(this.lasterrors);