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.
|
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.
|
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 )
|
( subtract #20 from the ASCII code and you get the offset from the nanofont label )
|
||||||
%CHAR-TO-NF { #20 SUB ;nanofont ADD }
|
%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 )
|
( nanofont glyphs for ESOP, courtesy of Michaelangel007 )
|
||||||
|
|
||||||
|
|||||||
+12
-6
@@ -44,13 +44,13 @@ function ESOPExtensions() {
|
|||||||
//setup screen renderer
|
//setup screen renderer
|
||||||
function renderScreen() {
|
function renderScreen() {
|
||||||
var vram = vm.getram(vramOffset, vramSize),
|
var vram = vm.getram(vramOffset, vramSize),
|
||||||
vdata = ctx.getImageData(0,0,width,height),
|
vdata = ctx.createImageData(width,height),
|
||||||
ppos, pval, vbval, i, j
|
ppos, pval, vbval, i, j
|
||||||
for(i=0;i<vRamSize;i++) {
|
for(i=0;i<vramSize;i++) {
|
||||||
vbval = vram[i]
|
vbval = vram[i]
|
||||||
for(j=0;j<8;j++) { //iterate from highest to lowest
|
for(j=0;j<8;j++) { //iterate from highest to lowest
|
||||||
ppos = ((i<<3) + j) << 2
|
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] = pval
|
||||||
vdata.data[ppos+1] = pval
|
vdata.data[ppos+1] = pval
|
||||||
vdata.data[ppos+2] = pval
|
vdata.data[ppos+2] = pval
|
||||||
@@ -129,19 +129,25 @@ function ESOPExtensions() {
|
|||||||
function setupAudio(vm, actx) {
|
function setupAudio(vm, actx) {
|
||||||
var osc = null //keep the existing oscillator reference here
|
var osc = null //keep the existing oscillator reference here
|
||||||
vm.setdev(6,0)
|
vm.setdev(6,0)
|
||||||
vm.setWriteHook(6, function(port, portval) {
|
vm.setWriteHook(6, function(port, portval, prev) {
|
||||||
|
if(portval !== prev) {
|
||||||
if(osc && !portval) { //stop the note
|
if(osc && !portval) { //stop the note
|
||||||
osc.stop()
|
osc.stop()
|
||||||
osc.disconnect()
|
osc.disconnect()
|
||||||
osc = null
|
osc = null
|
||||||
}
|
}
|
||||||
else if(portval < sfl) { //start the note
|
if(portval && portval < sfl) { //start the note
|
||||||
|
if(osc)
|
||||||
|
osc.frequency.value = soundFreqs[portval]
|
||||||
|
else {
|
||||||
osc = actx.createOscillator()
|
osc = actx.createOscillator()
|
||||||
osc.type = 'square'
|
osc.type = 'square'
|
||||||
osc.frequency = soundFreqs[portval]
|
|
||||||
osc.connect(actx.destination)
|
osc.connect(actx.destination)
|
||||||
|
osc.frequency.value = soundFreqs[portval]
|
||||||
osc.start(0)
|
osc.start(0)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
var devCfg = {
|
var devCfg = {
|
||||||
audio: window.audioContext || window.webkitAudioContext,
|
audio: null,
|
||||||
canvas: document.getElementById('C') //JS-specific implementation canvas DOM reference
|
canvas: document.getElementById('C') //JS-specific implementation canvas DOM reference
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13,6 +13,7 @@ function main() {
|
|||||||
rdr.onload = function() {
|
rdr.onload = function() {
|
||||||
var vm = UxnCore()
|
var vm = UxnCore()
|
||||||
var ext = ESOPExtensions()
|
var ext = ESOPExtensions()
|
||||||
|
devCfg.audio = new (window.AudioContext || window.webkitAudioContext)
|
||||||
vm.boot()
|
vm.boot()
|
||||||
ext.setup(vm, devCfg)
|
ext.setup(vm, devCfg)
|
||||||
vm.load(new Uint8Array(rdr.result))
|
vm.load(new Uint8Array(rdr.result))
|
||||||
|
|||||||
+9
-10
@@ -26,14 +26,9 @@ function UxnCore() {
|
|||||||
//helper methods
|
//helper methods
|
||||||
|
|
||||||
function trapout(errcode) { //error reporting with vector execution
|
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.error('Error code: '+errcode+' at instruction #'+pc)
|
||||||
console.log('Working stack: ', mem.wst.dat)
|
console.log('Working stack: ', mem.wst.dat)
|
||||||
console.log('Return stack: ', mem.rst.dat)
|
console.log('Return stack: ', mem.rst.dat)
|
||||||
}
|
|
||||||
pc = 0
|
pc = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,18 +55,22 @@ function UxnCore() {
|
|||||||
function PEEK(x) {return bs ? PEEK16(x) : mem.ram[x]}
|
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 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) {
|
function DEVW(x, y) {
|
||||||
|
var p, p2
|
||||||
if(bs) {
|
if(bs) {
|
||||||
|
p = mem.dev[x]
|
||||||
|
p2 = mem.dev[x+1]
|
||||||
mem.dev[x] = y>>8
|
mem.dev[x] = y>>8
|
||||||
if(x in devWriteHooks)
|
if(x in devWriteHooks)
|
||||||
devWriteHooks[x](x, mem.dev[x])
|
devWriteHooks[x](x, mem.dev[x], p)
|
||||||
mem.dev[x+1] = y&255
|
mem.dev[x+1] = y&255
|
||||||
if((x+1) in devWriteHooks)
|
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 {
|
else {
|
||||||
|
p = mem.dev[x]
|
||||||
mem.dev[x] = y
|
mem.dev[x] = y
|
||||||
if(x in devWriteHooks)
|
if(x in devWriteHooks)
|
||||||
devWriteHooks[x](x, y)
|
devWriteHooks[x](x, y, p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +79,7 @@ function UxnCore() {
|
|||||||
function uxnstart(startaddr, vmTrace) {
|
function uxnstart(startaddr, vmTrace) {
|
||||||
pc = startaddr & 65535
|
pc = startaddr & 65535
|
||||||
var instr, src, dst, a, b, c, tmpTrace = !!vmTrace
|
var instr, src, dst, a, b, c, tmpTrace = !!vmTrace
|
||||||
if(!pc || mem.dev[0x0f]) {
|
if(!pc) {
|
||||||
this.active = false
|
this.active = false
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -132,7 +131,7 @@ function UxnCore() {
|
|||||||
case 0x18: /* ADD */ a = POP(src); b = POP(src); PUSH(src, b + a); break;
|
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 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 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 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 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;
|
case 0x1e: /* EOR */ a = POP(src); b = POP(src); PUSH(src, b ^ a); break;
|
||||||
|
|||||||
Reference in New Issue
Block a user