Extended write hooks and debugged sound
This commit is contained in:
@@ -53,7 +53,7 @@ Implementation note: direct writing to or reading from the control block memory
|
||||
|
||||
All the 4032 pixels of 84x48 screen are allocated in the 504-byte video memory of ESOP (`#fe00-#fff7`) in the left-to-right, top-to-bottom, high-to-low order. To output a pixel at the given coordinates, the app must calculate the appropriate byte position itself.
|
||||
|
||||
The actual screen contents get updated 60 times per second according to the video memory. Before this process, the frame vector is run, if set in the corresponding control port (`00-01`).
|
||||
The actual screen contents get updated 60 times per second according to the video memory. Before this process, the frame vector is run, if set in the corresponding control port (`00-01`). All graphics operations must be performed within this frame vector.
|
||||
|
||||
Standard input/output ports are not supported.
|
||||
|
||||
|
||||
@@ -1,9 +1,55 @@
|
||||
( ESOP stdlib )
|
||||
|
||||
|00 @Control [ &framevec $2 &input $2 &random $1 &status $1 &sound $1 &syscall $1 ]
|
||||
|
||||
( byte to short )
|
||||
( x -- 00 x )
|
||||
%BTS { #00 SWP }
|
||||
|
||||
( screen is #54 x #30 )
|
||||
|
||||
%SETSCRVEC { .Control/framevec DEO2 }
|
||||
%RND { .Control/random DEI }
|
||||
%STACKTRACE { #ff .Control/random DEO }
|
||||
%SYS { .Control/syscall DEO }
|
||||
%INKEY { .Control/input DEI2 }
|
||||
%DBG { #20 SYS SYS }
|
||||
%SND { .Control/sound DEO }
|
||||
|
||||
( x y -- ref* )
|
||||
%COORD { BTS ROT BTS SWP2 #0054 MUL2 ADD2 }
|
||||
( x y -- bitshift byteptr* )
|
||||
%PXLOFFSET { COORD DUP2 #03 SFT2 DUP2 #30 SFT2 ROT2 SWP2 SUB2 SWP POP ROT #fe00 ADD2 }
|
||||
|
||||
( x y -- )
|
||||
%PXL { PXLOFFSET DUP2 LDA #01 ROT #40 SFT SFT ORA ROT ROT STA }
|
||||
|
||||
( subtract #20 from the ASCII code and you get the offset from the nanofont label )
|
||||
%CHAR-TO-NF { #20 SUB ;nanofont ADD }
|
||||
|
||||
|0100
|
||||
#03 #02 #01
|
||||
ROT
|
||||
DBG DBG DBG
|
||||
;on-frame SETSCRVEC
|
||||
#30
|
||||
BRK
|
||||
|
||||
@on-frame
|
||||
DUP SND
|
||||
INC
|
||||
( #10 #12 PXL )
|
||||
BRK
|
||||
|
||||
|
||||
@putc
|
||||
|
||||
JMP2r
|
||||
|
||||
@draw-str ( s* -> )
|
||||
&loop LDAk #00 EQU ,&eof JCN ( did we reach \0 ? )
|
||||
LDAk ;putc JSR2 INC2 ,&loop JMP ( no so emit a char and repeat )
|
||||
&eof POP2 JMP2r ( yes so return )
|
||||
|
||||
( nanofont glyphs for ESOP, courtesy of Michaelangel007 )
|
||||
|
||||
|
||||
+21
-15
@@ -44,13 +44,13 @@ function ESOPExtensions() {
|
||||
//setup screen renderer
|
||||
function renderScreen() {
|
||||
var vram = vm.getram(vramOffset, vramSize),
|
||||
vdata = ctx.getImageData(0,0,width,height),
|
||||
vdata = ctx.createImageData(width,height),
|
||||
ppos, pval, vbval, i, j
|
||||
for(i=0;i<vRamSize;i++) {
|
||||
for(i=0;i<vramSize;i++) {
|
||||
vbval = vram[i]
|
||||
for(j=0;j<8;j++) { //iterate from highest to lowest
|
||||
ppos = ((i<<3) + j) << 2
|
||||
pval = (vbval>>>(7-j))&1 ? 255 : 0
|
||||
pval = (vbval>>>(7-j))&1 ? 0 : 0xee
|
||||
vdata.data[ppos] = pval
|
||||
vdata.data[ppos+1] = pval
|
||||
vdata.data[ppos+2] = pval
|
||||
@@ -129,18 +129,24 @@ function ESOPExtensions() {
|
||||
function setupAudio(vm, actx) {
|
||||
var osc = null //keep the existing oscillator reference here
|
||||
vm.setdev(6,0)
|
||||
vm.setWriteHook(6, function(port, portval) {
|
||||
if(osc && !portval) { //stop the note
|
||||
osc.stop()
|
||||
osc.disconnect()
|
||||
osc = null
|
||||
}
|
||||
else if(portval < sfl) { //start the note
|
||||
osc = actx.createOscillator()
|
||||
osc.type = 'square'
|
||||
osc.frequency = soundFreqs[portval]
|
||||
osc.connect(actx.destination)
|
||||
osc.start(0)
|
||||
vm.setWriteHook(6, function(port, portval, prev) {
|
||||
if(portval !== prev) {
|
||||
if(osc && !portval) { //stop the note
|
||||
osc.stop()
|
||||
osc.disconnect()
|
||||
osc = null
|
||||
}
|
||||
if(portval && portval < sfl) { //start the note
|
||||
if(osc)
|
||||
osc.frequency.value = soundFreqs[portval]
|
||||
else {
|
||||
osc = actx.createOscillator()
|
||||
osc.type = 'square'
|
||||
osc.connect(actx.destination)
|
||||
osc.frequency.value = soundFreqs[portval]
|
||||
osc.start(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
+2
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
function main() {
|
||||
var devCfg = {
|
||||
audio: window.audioContext || window.webkitAudioContext,
|
||||
audio: null,
|
||||
canvas: document.getElementById('C') //JS-specific implementation canvas DOM reference
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ function main() {
|
||||
rdr.onload = function() {
|
||||
var vm = UxnCore()
|
||||
var ext = ESOPExtensions()
|
||||
devCfg.audio = new (window.AudioContext || window.webkitAudioContext)
|
||||
vm.boot()
|
||||
ext.setup(vm, devCfg)
|
||||
vm.load(new Uint8Array(rdr.result))
|
||||
|
||||
+12
-13
@@ -26,14 +26,9 @@ function UxnCore() {
|
||||
//helper methods
|
||||
|
||||
function trapout(errcode) { //error reporting with vector execution
|
||||
var vec = (mem.dev[0] << 8) | mem.dev[1]
|
||||
if(vec)
|
||||
uxnstart(vec)
|
||||
else {
|
||||
console.error('Error code: '+errcode+' at instruction #'+pc)
|
||||
console.log('Working stack: ', mem.wst.dat)
|
||||
console.log('Return stack: ', mem.rst.dat)
|
||||
}
|
||||
console.error('Error code: '+errcode+' at instruction #'+pc)
|
||||
console.log('Working stack: ', mem.wst.dat)
|
||||
console.log('Return stack: ', mem.rst.dat)
|
||||
pc = 0
|
||||
}
|
||||
|
||||
@@ -60,18 +55,22 @@ function UxnCore() {
|
||||
function PEEK(x) {return bs ? PEEK16(x) : mem.ram[x]}
|
||||
function DEVR(x) {if(x in devReadHooks) devReadHooks[x]();return bs ? (mem.dev[x] << 8)|mem.dev[x+1] : mem.dev[x]}
|
||||
function DEVW(x, y) {
|
||||
var p, p2
|
||||
if(bs) {
|
||||
p = mem.dev[x]
|
||||
p2 = mem.dev[x+1]
|
||||
mem.dev[x] = y>>8
|
||||
if(x in devWriteHooks)
|
||||
devWriteHooks[x](x, mem.dev[x])
|
||||
devWriteHooks[x](x, mem.dev[x], p)
|
||||
mem.dev[x+1] = y&255
|
||||
if((x+1) in devWriteHooks)
|
||||
devWriteHooks[x+1](x+1, mem.dev[x+1])
|
||||
devWriteHooks[x+1](x+1, mem.dev[x+1], p2)
|
||||
}
|
||||
else {
|
||||
p = mem.dev[x]
|
||||
mem.dev[x] = y
|
||||
if(x in devWriteHooks)
|
||||
devWriteHooks[x](x, y)
|
||||
devWriteHooks[x](x, y, p)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +79,7 @@ function UxnCore() {
|
||||
function uxnstart(startaddr, vmTrace) {
|
||||
pc = startaddr & 65535
|
||||
var instr, src, dst, a, b, c, tmpTrace = !!vmTrace
|
||||
if(!pc || mem.dev[0x0f]) {
|
||||
if(!pc) {
|
||||
this.active = false
|
||||
return 0
|
||||
}
|
||||
@@ -132,7 +131,7 @@ function UxnCore() {
|
||||
case 0x18: /* ADD */ a = POP(src); b = POP(src); PUSH(src, b + a); break;
|
||||
case 0x19: /* SUB */ a = POP(src); b = POP(src); PUSH(src, b - a); break;
|
||||
case 0x1a: /* MUL */ a = POP(src); b = POP(src); PUSH(src, b * a); break;
|
||||
case 0x1b: /* DIV */ a = POP(src); b = POP(src); if(!a) trapout(3); PUSH(src, b / a); break;
|
||||
case 0x1b: /* DIV */ a = POP(src); b = POP(src); if(!a) trapout(3); PUSH(src, 0|(b / a)); break;
|
||||
case 0x1c: /* AND */ a = POP(src); b = POP(src); PUSH(src, b & a); break;
|
||||
case 0x1d: /* ORA */ a = POP(src); b = POP(src); PUSH(src, b | a); break;
|
||||
case 0x1e: /* EOR */ a = POP(src); b = POP(src); PUSH(src, b ^ a); break;
|
||||
|
||||
Reference in New Issue
Block a user