|
Post by Malban on Sept 30, 2017 13:11:32 GMT -5
Hi, as some of you might now - I am currently working on Vide 2.0 - which will support the language "C". As an experiement I programmed a few BIOS functions in "C" to be not dependend on the BIOS. Results look quite well I think.
This does not mean, that this is the path we will finally take - but I think they are "cool"
void cMoveto_d(signed int y, signed int x) { VIA_port_a = y; // y pos to dac VIA_cntl = (int)0xce; // disable zero, disable all blank VIA_port_b = 0; // mux enable, dac to -> integrator y (and x) VIA_shift_reg = 0; // all output is BLANK VIA_port_b++; // mux disable, dac only to x VIA_port_a = x; // dac -> x VIA_t1_cnt_hi=0; // start timer while ((VIA_int_flags & 0x40) == 0); // wait till timer finishes } Is translated to:
_cMoveto_d: stb >VIA_port_a ; y ldb #$CE stb >VIA_cntl clr >VIA_port_b clr >VIA_shift_reg inc >VIA_port_b ldb >VIA_port_b ldb <<$02,s ; x stb >VIA_port_a clr >VIA_t1_cnt_hi L2: ldb >VIA_int_flags andb #$40 beq L2 rts
void cDraw_VLc(signed char *vList) { int count = *(vList++); // count in list do { VIA_port_a = *(vList++); // first y coordinate to dac VIA_port_b = 0; // mux enable, dac to -> integrator y (and x) VIA_port_b++; // mux disable, dac only to x VIA_port_a = *(vList++); // dac -> x VIA_shift_reg = (int)0xff; // full "unblank" output VIA_t1_cnt_hi = 0; // start timer while ((VIA_int_flags & 0x40) == 0); // wait till timer finishes VIA_shift_reg = 0; // output full blank } while (--count >=0); // loop thru all vectors } To:
_cDraw_VLc: leas <<-$01,s ldb ,x+ stb ,s ; count L8: ldb ,x ; D.1223,* vList.83 stb >VIA_port_a clr >VIA_port_b inc >VIA_port_b ldb >VIA_port_b ldb <<$01,x ; temp.84 stb >VIA_port_a ; temp.84 leax <<$02,x ; vList.83,, vList.83 ldb #$FF stb >VIA_shift_reg clr >VIA_t1_cnt_hi L7: ldb >VIA_int_flags andb #$40 beq L7 clr >VIA_shift_reg dec ,s ; count bpl L8 leas <<$01,s rts
Malban
|
|
|
Post by gauze on Oct 5, 2017 9:01:57 GMT -5
I was going to ask the obvious question about having better drawing routines in the "Vectrex C stdlib" or whatever you want to call it. It is a really obvious idea to have more efficient drawing routines vs the general ones in the BIOS, since you aren't taking up ROM space with them you can have as many different versions of drawing routines as you want as well.
|
|
|
Post by gtoal on Oct 7, 2017 10:53:32 GMT -5
You know how in the packet routines you have a byte code for move, line, and end. What would be useful would be an extra code to invoke Reset0Ref that could be placed in a draw list. (OR a tunable parameter to call that at fixed intervals or after a move command so that there isn't an obvious gap?)
Also to consider if writing replacement routines - versions that use absolute coordinates rather than delta offsets. Easier to work with and if you did implement the Reset0Ref addition, it would be necessary to keep track of the accumulated x,y value anyway in order to return to expected position after the implicit move to 0,0 that it does.
What I can do to help with this project if you want, is construct some single-feature small test programs, so that if someone wants to, for example, draw an array of dots, then they look at the example code for that procedure which would be a complete minimal program that just filled an array and drew it.
Graham
|
|
|
Post by gauze on Oct 7, 2017 12:12:21 GMT -5
gtoal, Malban actually has some draw code like that let me see if I can find it ...
well what the heck i can't find the source file that describes it but I find it in VIDE jar only
$ grep -ir "Draw sync list" * Binary file Vide.jar matches
that's it! run VIDE open up "vecci" click on "export" tab, then mouse over "Draw sync list" to see the tool tip describing the format.
|
|
|
Post by gtoal on Oct 9, 2017 3:19:48 GMT -5
that's it! run VIDE open up "vecci" click on "export" tab, then mouse over "Draw sync list" to see the tool tip describing the format. Thanks - as soon as I see how bad the drift is on the current code, I'll start on inserting those sync calls.
|
|
|
Post by gtoal on Oct 20, 2019 13:06:57 GMT -5
I did eventually find this but it wasn't as integrated as I expected, unless as usual I'm looking in the wrong place. (Sorry Malban, your documentation is extensive but finding it and finding things in it is often quite tricky). Here's the test program I put together (with the .h and .s files included inline since I don't know how to do attachments here.)
It's a useful procedure - is there a way to just link to it without having to have a local copy in your working Vide directory? Is it part of a library somewhere and I just haven't worked out how to invoke it? Having a local copy like this means I won't be able to take advantage of any improvements or upgrades that may appear later in Vide.
// Example program using drawSyncList. Stitched together from
// various parts of Vide examples. Please tell me if there
// are better ways of doing this...
#include <vectrex.h>
#include "printSyncList.h"
// can't use <> includes... doesn't appear to be available as a standard header.
// also had to link the .s file in from the local folder,
// it was not present in the standard library environment
// The .asm file this is based on had to be converted
// to gcc format, so not sure how drawSyncList is supposed
// to be accessed in standard Vide environment?
#ifdef NEVER // this is printSyncList.h, included for completeness
extern unsigned long draw_synced_list;
#define __ass asm volatile
#define __PRINT_SYNC_LIST draw_synced_list
#define __MC6809_jsrSync_abxu__y(args...) __mc6809_jsrSync_abxu__y(args)
#define asm_drawSyncList(D, X, U) __MC6809_jsrSync_abxu__y(D, X, U, __PRINT_SYNC_LIST, PRINT_SYNC_LIST, d, x, u)
#ifdef OMMIT_FRAMEPOINTER
#define __mc6809_jsrSync_abxu__y(d,x,u, func, name, regs...) { \
__ass( \
"ldd %[D]\n\t" \
"ldx %[X]\n\t" \
"ldu %[U]\n\t" \
"jsr " #func "; " #name "\n\t" \
:: [D] "m" (d),[X] "m" (x),[U] "m" (u) \
: "memory","d", "u", "x","y","cc"); \
}
#else
#define __mc6809_jsrSync_abxu__y(d,x,u, func, name, regs...) { \
__ass( \
"pshs u\n\t" \
"ldd %[D]\n\t" \
"ldx %[X]\n\t" \
"ldu %[U]\n\t" \
"jsr " #func "; " #name "\n\t" \
"puls u\n\t" \
:: [D] "m" (d),[X] "m" (x),[U] "m" (u) \
: "memory","d", "x","y","cc"); \
}
#endif
// U = address of vectorlist
// X = (y,x) position of vectorlist (this will be point 0,0), positioning on screen
// A = scalefactor "Move" (after sync)
// B = scalefactor "Vector" (vectors in vectorlist)
__INLINE void drawSyncList(
void* volatile u,
signed int y,
signed int x,
unsigned int scaleMove,
unsigned int scaleList)
{
unsigned long xReg = ((unsigned long)(((unsigned long)y)<<8)+(((unsigned long)x)&0xff));
unsigned long dReg = ((unsigned long)(((unsigned long)scaleMove)<<8)+(((unsigned long)scaleList)&0xff));
asm_drawSyncList(
dReg,
xReg,
((unsigned long)u)
);
}
#endif
/*
0x00 moverel (relative to current position in object)
0x01 sync and moverel (relative to initial origin parameter)
0FFX drawrel (relative to current position in object)
0x02 end
Note: there is no 'move abs' (relative to initial origin parameter)
so positioning without a sync uses draw scale, not move scale,
and every disjoint object automatically gets a sync.
(Also there's no line pattern (any other value than the 4 above fails))
*/
const signed char Test[]=
{
// synched:
// bottom right
(signed char) 0x01, -0x40, 0x00, // sync and move to y, x
(signed char) 0xFF, -0x3f, +0x7f, // draw, y, x
(signed char) 0xFF, +0x3f, +0x7f, // draw, y, x
(signed char) 0xFF, +0x3f, -0x7f, // draw, y, x
(signed char) 0xFF, -0x3f, -0x7f, // draw, y, x
// top right
(signed char) 0x01, +0x40, 0x00, // sync and move to y, x
(signed char) 0xFF, -0x3f, +0x7f, // draw, y, x
(signed char) 0xFF, +0x3f, +0x7f, // draw, y, x
(signed char) 0xFF, +0x3f, -0x7f, // draw, y, x
(signed char) 0xFF, -0x3f, -0x7f, // draw, y, x
// vs unsynched:
// top left
(signed char) 0x00, 0x00, -0x7f, // moverel to y, x at draw scale
(signed char) 0x00, 0x00, -0x7f, // moverel to y, x at draw scale
(signed char) 0xFF, -0x3f, +0x7f, // draw, y, x
(signed char) 0xFF, +0x3f, +0x7f, // draw, y, x
(signed char) 0xFF, +0x3f, -0x7f, // draw, y, x
(signed char) 0xFF, -0x3f, -0x7f, // draw, y, x
// bottom left
(signed char) 0x00, -0x7f, 0x00, // move to y, x
(signed char) 0xFF, -0x3f, +0x7f, // draw, y, x
(signed char) 0xFF, +0x3f, +0x7f, // draw, y, x
(signed char) 0xFF, +0x3f, -0x7f, // draw, y, x
(signed char) 0xFF, -0x3f, -0x7f, // draw, y, x
(signed char) 0x02 // endmarker
};
int main(void)
{
for (;;) {
Wait_Recal();
Intensity_5F();
// right-hand objects are fully synched, left-hand are not
// objects in top to bottom order:
drawSyncList(&Test,127,-31,127,16);
drawSyncList(&Test,63,-31,127,63);
drawSyncList(&Test,-63,31,127,63);
drawSyncList(&Test,-127,31,127,16);
// y x moveScale drawScale
}
return 0;
}
#ifdef NEVER // this is the accompanying assembly code in printSyncList.s
;***************************************************************************
; DEFINE SECTION
;***************************************************************************
; load vectrex bios routine definitions
.module printSyncList
.area .text
music1 = 0xFD0D
VIA_port_b = 0xD000 ;VIA port B data I/O register
VIA_port_a = 0xD001 ;VIA port A data I/O register (handshaking)
VIA_t1_cnt_lo = 0xD004 ;VIA timer 1 count register lo (scale factor)
VIA_t1_cnt_hi = 0xD005 ;VIA timer 1 count register hi
VIA_shift_reg = 0xD00A ;VIA shift register
VIA_cntl = 0xD00C ;VIA control register
VIA_int_flags = 0xD00D ;VIA interrupt flags register
Intensity_5F = 0xF2A5 ;
Wait_Recal = 0xF192 ;
Mov_Draw_VLc_a = 0xF3AD ;count y x y x ...
Moveto_d = 0xF312 ;
;***************************************************************************
; HEADER SECTION
;***************************************************************************
; The cartridge ROM starts at address 0
; CODE
;***************************************************************************
; SUBROUTINE SECTION
;***************************************************************************
;ZERO ing the integrators takes time. Measures at my vectrex show e.g.:
;If you move the beam with a to x = -127 and y = -127 at diffferent scale values, the time to reach zero:
;- scale $ff -> zero 110 cycles
;- scale $7f -> zero 75 cycles
;- scale $40 -> zero 57 cycles
;- scale $20 -> zero 53 cycles
ZERO_DELAY = 7 ; delay 7 counter is exactly 111 cycles delay between zero SETTING and zero unsetting (in moveto_d)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;U = address of vectorlist
;X = (y,x) position of vectorlist (this will be point 0,0), positioning on screen
;A = scalefactor "Move" (after sync)
;B = scalefactor "Vector" (vectors in vectorlist)
;
; mode, rel y, rel x,
; mode, rel y, rel x,
; . . .
; . . .
; mode, rel y, rel x,
; 0x02
; where mode has the following meaning:
; negative draw line
; 0 move to specified endpoint
; 1 sync (and move to list start and than to place in vectorlist)
; 2 end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.globl draw_synced_list
draw_synced_list:
pshs a ; remember out different scale factors
pshs b
; first list entry (first will be a sync + moveto_d, so we just stay here!)
lda ,u+ ; this will be a "1"
sync:
deca ; test if real sync - or end of list (2)
bne drawdone ; if end of list -> jump
; zero integrators
ldb #0xCC ; zero the integrators
stb VIA_cntl ; store zeroing values to cntl
ldb #ZERO_DELAY ; and wait for zeroing to be actually done
; reset integrators
clr VIA_port_a ; reset integrator offset
lda #0x82 ; %10000010
; wait that zeroing surely has the desired effect!
zeroLoop:
sta VIA_port_b ; while waiting, zero offsets
decb
bne zeroLoop
inc VIA_port_b
; unzero is done by moveto_d
lda 1,s ; scalefactor move
sta VIA_t1_cnt_lo ; to timer t1 (lo=
tfr x,d ; load our coordinates of "entry" of vectorlist
jsr Moveto_d ; move there
lda ,s ; scale factor vector
sta VIA_t1_cnt_lo ; to timer T1 (lo)
moveTo:
ldd ,u++ ; do our "internal" moveto d
beq nextListEntry ; there was a move 0,0, if so
jsr Moveto_d
nextListEntry:
lda ,u+ ; load next "mode" byte
beq moveTo ; if 0, than we should move somewhere
bpl sync ; if still positive it is a 1 pr 2 _> goto sync
; now we should draw a vector
ldd ,u++ ;Get next coordinate pair
STA VIA_port_a ;Send Y to A/D
CLR VIA_port_b ;Enable mux
LDA #0xff ;Get pattern byte
INC VIA_port_b ;Disable mux
STB VIA_port_a ;Send X to A/D
LDB #0x40 ;B-reg = T1 interrupt bit
CLR VIA_t1_cnt_hi ;Clear T1H
STA VIA_shift_reg ;Store pattern in shift register
setPatternLoop:
BITB VIA_int_flags ;Wait for T1 to time out
beq setPatternLoop ; wait till line is finished
CLR VIA_shift_reg ; switch the light off (for sure)
bra nextListEntry
drawdone:
puls d ; correct stack and go back
rts
#endif
|
|