'******************************************************************************************** ' Displaylisted PSRAM HDMI for P2 Retromachine ' Version 0.07 alpha - 20220328 ' 1 cog, 1024x576 32 bpp graphics with sprites ' (c) 2012-2022 Piotr Kardasz pik33@o2.pl ' MIT license '******************************************************************************************** '' WARNING! If you want to use this with a BRK debugger, set con debugger to anything different than 0 '' It will prevent the driver from using the last 16 kB of HUB RAM ' ' You can capture the FlexBasic print by open SendRecvDevice(@this_object.putchar, nil, nil) as #0 for any mode ' Colors are in format $rrggbb00 - if the color code is <=255, the color will be loaded frot the Atari 8bit type palette ' rrggbb00 is needed by a streamer/HDMI as non-zero lower nibble can switch HDMI to direct 10bit mode ' using a palette for low color# makes the driver compatible with 8-bit drivers ' ' Available functions: ' ' - Starting and mode setting ' 'pub start(base,mb) - start the driver at pins 'base' with PSRAM mailbox at mb 'pub makedl() - make a standard display list for the mode, called from setmode ' ' - Graphics function for graphics modes 'pub putpixel(x,y,c) - set pixel at x,y to the color c 'pub fastline(x1,x2,y,c) - draw a horizontal line fast 'pub draw(x1,y1,x2,y2,c) - draw a line 'pub line(x1,y1,x2,y2,c) - alias for draw 'pub fcircle(x0,y0,r,c) - draw a filled circle 'pub circle(x0,y0,r,c) - draw an empty circlev 'pub frame(x1,y1,x2,y2,c) - draw an empty rectangle 'pub box(x1,y1,x2,y2,c) - draw a filled rectangle 'pub putcharxycf(x,y,achar,f) - draw the character, don't change the background 'pub putcharxycg(x,y,achar,f,b) - draw the character on the opaque background color 'pub putcharxycg8(x,y,achar,f,b) - draw a 8x8 character 'pub putcharxycz(x,y,achar,f,b,xz,yz) - draw a zoomed character 'pub outtextxycg(x,y,text,f,b) - output a string 'pub outtextxycg8(x,y,text,f,b) - output 8x8 string 'pub outtextxycf(x,y,text,f) - output a string, don't change the background 'pub outtextxycz(x,y,text,f,b,xz,yz) - output a zoomed string '- font functions ' 'pub setfontfamily(afontnum) - set a font offset, 0=vga, 4=ST, 8=Atari 8bit. To be removed in the next version 'pub defchar(fn,ch,b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15) - redefine a character ' '- cursor functions ' 'pub setcursorpos(x,y) - set the (x,y) position of cursor ' '- vblank functions ' 'pub waitvbl(amount) - wait for start of vblank. Amount=delay in frames 'pub waitvblend(amount) - wait for end of vblank. Amount=delay in frames ' '- color functions ' 'pub getpalettecolor(color): get a color from the palette 'pub setwritecolors(ff,bb) - set colors for putchar, write and writeln 'pub setcolor(c,r,g,b) -set color #c in palette to r,g,b ' '- text functions ' 'pub cls(fc,bc) - clear the screen, set its foreground/background color 'pub putcharxy(x,y,achar) - cutput a char at x,y, don't change colors and cursor position 'pub putchar(achar) - output a char at the cursor position, move the cursor, also works in graphics modes, reacts to tab and cr 'pub putchar2(achar) - output a char at the cursor position, move the cursor, also works in graphics modes, doesn't reacts to tab and cr 'pub write(text) - output a string at the cursor position, move the cursor 'pub writeln(text) - output a string at the cursor position x,y, move the cursor to the next line 'pub scrollup() - scroll the screen one line up 'pub scrolldown() - scroll the screen one line down 'pub crlf() - set cursor at the first character in a new line, scroll if needed 'pub bksp() - backspace. Move the cursor back, clear a character ' '- converting ' 'pub inttostr(i) - convert a integer to dec string, return a pointer 'pub inttostr2(i,d) - convert unsigned integer to dec string with d digits, return a pointer 'pub inttohex(i,d) - convert unsigned integer to hex string with d digits, return a pointer ' '----------------------------------------------------------------------------------------------------------------------- ' Available standard graphic modes: ' - 1024x576@50 Hz borderless ' The display list ' The display list controls every line of the display. When the driver starts or setmode function is called, the new DL is created for this mode. ' At every moment the user can create a new display list and point the driver to it. ' The DL command list '' - display a line from memory list %0000_0000_aaaa_aaaa_aaaa_aaaa_aaaa_0000 a - pointer to the memory list for the line TODO '' - display a graphic line %aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_0010 a- PSRAM address '' - repeat %nnnn_nnnn_nnnn_qqqq_mmmm_mmmm_mmmm_0001 repeat the next dl line n times, after q lines add offset m longs to the address ''----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- CON hdmi_base = 0 'must be a multiple of 8 _clkfreq = 336956522 'this is the retromachine standard main clock, PAL color frequency * 95 debugger = 1 'set this to non-zero value if you want to use BRK debugger ''--------- VGA DOS color definition constants. c_black = $00000000 c_blue = $0000AA00 c_green = $00AA0000 c_cyan = $00AAAA00 c_red = $AA000000 c_magenta = $AA00AA00 c_brown = $AA550000 c_lightgray = $AAAAAA00 c_darkgray = $55555500 c_lightblue = $5555FF00 c_lightgreen = $55FF5500 c_lightcyan = $55FFFF00 c_lightred = $FF555500 c_lightmagenta = $FF55FF00 c_yellow = $FFFF5500 c_white = $FFFFFF00 ''---------- A constant to add to timing values for the streamer timingsxxt = $70810000 ' streamer imm->pins var long buf_ptr 'initial main buffer pointer long font_ptr 'initial font definition pointer long border_ptr 'border colors buffer pointer long cursor_ptr 'cursor position pointer '---------- A pointer block, these pointers will be passed to the cog long vblank_ptr 'vblank signalling variable pointer long mode_ptr 'timings pointer long palette_ptr '256-color palette pointer; bit 31 set: do not read long dl_ptr 'display list pointer long hdmibase 'HDMI pin# long mailbox_ptr 'PSRAM mailbox pointer. If zero, no PSRAM long sprite_ptr '---------- Variables. Todo: check if all of these are still needed in the current version of the driver long cog 'driver cog# long bordercolor 'border color long buflen 'buffer length in longs byte cursor_x 'X cursor position in text modes byte cursor_y 'Y cursor position byte cursor_sh 'cursor shape, 0 to 15, 0=full rectangle..15-one line, >=16 no cursor byte dummyalign 'alignment dummy byte long write_color 'character color for write/writeln long write_background 'background color for write/writeln long vblank 'vblank signalling byte n_string[12] 'string buffer for inttostr and hextostr 'long timings[16] 'graphic mode timings long cpl 'char/pixels per line long cpl1 long lines 'screen text lines count long fontnum 'offset to font long streamer[6] 'streamer constants long colors[16] 'vga colors long graphmode long font_family long customtimings[16] long ppl 'pixel per line '---------- Temporary variables for accessing different parts of the complex screen long s_buf_ptr long s_font_ptr long s_lines long s_cpl long s_buflen long s_cpl1 long s_ppl long s_debug long t_lines long st_lines long xzoom, yzoom, azoom long spr1ptr word spr1x word spr1y word spr1w word spr1h long spr2ptr word spr2x word spr2y word spr2w word spr2h long spr3ptr word spr3x word spr3y word spr3w word spr3h long spr4ptr word spr4x word spr4y word spr4w word spr4h long spr5ptr word spr5x word spr5y word spr5w word spr5h long spr6ptr word spr6x word spr6y word spr6w word spr6h long spr7ptr word spr7x word spr7y word spr7w word spr7h long spr8ptr word spr8x word spr8y word spr8w word spr8h long spr9ptr word spr9x word spr9y word spr9w word spr9h long spr10ptr word spr10x word spr10y word spr10w word spr10h long spr11ptr word spr11x word spr11y word spr11w word spr11h long spr12ptr word spr12x word spr12y word spr12w word spr12h long spr13ptr word spr13x word spr13y word spr13w word spr13h long spr14ptr word spr14x word spr14y word spr14w word spr14h long spr15ptr word spr15x word spr15y word spr15w word spr15h long spr16ptr word spr16x word spr16y word spr16w word spr16h long mailbox0 long displaylist[12] ' now 8 longs is sufficient for a DL for simple modes long emptydl[2] byte pixelbuf long ccc[8] obj ram: "psram.spin2" '**************************************************************************************************************** ' * ' A dummy start function if someone runs this driver alone rev 20220320 * ' * '**************************************************************************************************************** pub dummy() '' this is not a main program. '**************************************************************************************************************** ' * 'Start the driver at pins 'base' with mailbox mb rev 20220801 * ' * ' * ' base - HDMI base pin * ' mb - PSRAM mailbox pointer, 32-bit PSRAM is mandatory here * ' * '**************************************************************************************************************** pub start(base,mb):result '--------------------------- initialize pointers and variables hdmibase:=base ' HDMI base pin, 8*n mailbox_ptr:=mb mailbox0:=mb ' PSRAM mailbox pointer sprite_ptr:=@spr1ptr spr1y:=600 ' spr2y:=600 ' spr3y:=600 ' spr4y:=600 ' spr5y:=600 ' spr6y:=600 ' spr7y:=600 ' spr8y:=600 ' spr9y:=600 ' spr10y:=600 ' spr11y:=600 ' spr12y:=600 ' spr13y:=600 ' spr14y:=600 ' spr15y:=600 ' spr16y:=600 ' emptydl[0]:=%0100_0000_0000_0000_0000_0000_0000_0111 emptydl[1]:=0 '---------------------------- the mode has to be set here to enable computing the buffer length s_debug:=debugger ' check if debug mode defined (eats 16 kB upper RAM so don't use it) ' if s_debug<>0 s_debug:=16384 ' the buffers adresses will be corrected to not interfere with the debugger setmode() ' set the mode, see below vblank_ptr:=@vblank ' set pointers before starting the driver cursor_ptr:=@cursor_x fontnum:=0 ' start with a PC type font longmove(@colors,@vgacolors,16) ' prepare standard DOS VGA colors '---------------------------- initialize a cursor (MSDOS type) cursor_x:=0 ' place the cursor at 0:0 cursor_y:=0 '---------------------------- start the cog cog:=coginit(16,@hdmi, @vblank_ptr) ' start the driver cog waitms(40) ' wait for stabilize return cog ' return the driver's cog # '**************************************************************************************************************** ' * ' Simple standard mode setting rev. 20220319 * ' Mode number - see start() above or bits below * ' * '**************************************************************************************************************** pub setmode() | i dl_ptr:=@emptydl[0] if cog>0 waitvbl(1) ' if the driver is active, wait for vblank to set the new mode and DL ppl:=(timings[3]) cpl:=timings[7]<<3 ' now cpl is longs per line cpl1:=cpl '' todo remove palette_ptr:=@ataripalette ' use 256-colors palettr repeat i from 0 to 3 timings[i]:=timings[i]+hdmibase<<17+ timingsxxt ' add a streamer config (imm->pins) to horizontal timings clkfreq:=timings[9] ' set the clock frequency for the mode 'hubset(timings[10]) waitms(1) ' wait for stabilization lines:=timings[11] t_lines:=lines/16 buflen:=cpl*lines ' framebuffer length in longs buf_ptr:=$2000000-4*buflen ' todo: get a PSRAM real himem mode_ptr:=@timings ' set pointers to timings makedl() ' make a DL for the mode s_buf_ptr:=buf_ptr ' secondary copies of main framebuffer parameters s_font_ptr:=font_ptr s_lines:=lines s_buflen:=buflen s_cpl:=cpl s_cpl1:=cpl st_lines:=t_lines ppl:=ppl/xzoom s_ppl:=ppl waitms(20) ' wait '**************************************************************************************************************** ' * ' Make a display list for simple standard modes rev.20220319 * ' * '**************************************************************************************************************** pub makedl() |i,psbuf,lines2 psbuf:=$80000-s_debug-1024 ' HUB line buffer on the top of HUB RAM (-16 kB if debug enabled) repeat i from 0 to 11 ' clear DL displaylist[i]:=0 ' displaylist[0]:=lines<<20+(0)<<16+%0001+ $4000 displaylist[1]:=buf_ptr<<4+%10 dl_ptr:=@displaylist[0] ' tell the driver where to find the DL '**************************************************************************************************************** ' * ' Graphic primitives * ' * '**************************************************************************************************************** ''---------- putpixel - put a pixel on the screen - a mother of all graphic functions --------------------------- pub putpixel(x,y,c) if (c<<24)<>0 c:=long[palette_ptr+4*(c & $FF)] if ((x>=0) & (x<4*s_cpl) & (y>=0) & (y0 c:=long[palette_ptr+4*(c & $FF)] if y<0 return if x1>x2 x1,x2:=x2,x1 ram.fill(s_buf_ptr+(4*s_cpl1*y+4*x1),c,1+x2-x1,0,4) pub line(x1,y1,x2,y2,c) ' this is a "draw" alias draw(x1,y1,x2,y2,c) pub draw(x1,y1,x2,y2,c) | d,dx,dy,ai,bi,xi,yi,x,y ' I had to rename the function for BASIC if (y1==y2) fastline(x1,x2,y1,c) else if (c<<24)<>0 c:=long[palette_ptr+4*(c & $FF)] x:=x1 y:=y1 if (x1dy) ai:=(dy-dx)*2 bi:=dy*2 d:= bi-dx repeat while (x<>x2) if (d>=0) x+=xi y+=yi d+=ai else d+=bi x+=xi putpixel(x,y,c) else ai:=(dx-dy)*2 bi:=dx*2 d:=bi-dy repeat while (y<>y2) if (d>=0) x+=xi y+=yi d+=ai else d+=bi y+=yi putpixel(x, y,c) '-- A filled circle ----------------------------------------------------- pub fcircle(x0,y0,r,c) | d,x,y,da,db d:=5-4*r x:=0 y:=r da:=(-2*r+5)*4 db:=3*4 repeat while (x<=y) fastline(x0-x,x0+x,y0-y,c) fastline(x0-x,x0+x,y0+y,c) fastline(x0-y,x0+y,y0-x,c) fastline(x0-y,x0+y,y0+x,c) if d>0 d+=da y-=1 x+=1 da+=4*4 db+=2*4 else d+=db x+=1 da+=2*4 db+=2*4 '-- A circle ------------------------------------------------------------ pub circle(x0,y0,r,c) | d,x,y,da,db d:=5-4*r x:=0 y:=r da:=(-2*r+5)*4 db:=3*4 repeat while (x<=y) putpixel(x0-x,y0-y,c) putpixel(x0-x,y0+y,c) putpixel(x0+x,y0-y,c) putpixel(x0+x,y0+y,c) putpixel(x0-y,y0-x,c) putpixel(x0-y,y0+x,c) putpixel(x0+y,y0-x,c) putpixel(x0+y,y0+x,c) if d>0 d+=da y-=1 x+=1 da+=4*4 db+=2*4 else d+=db x+=1 da+=2*4 db+=2*4 '-- A frame (an empty rectangle) --------------------------------------- pub frame(x1,y1,x2,y2,c) fastline(x1,x2,y1,c) fastline(x1,x2,y2,c) line(x1,y1,x1,y2,c) line(x2,y1,x2,y2,c) '-- A box (a filled rectangle) ---------------------------------------- pub box(x1,y1,x2,y2,c) |yy repeat yy from y1 to y2 fastline(x1,x2,yy,c) '**************************************************************************************************************** ' * ' Characters on graphic screen * ' * '**************************************************************************************************************** ' ------ Transparent character pub putcharxycf(x,y,achar,f) |xx, yy, bb repeat yy from 0 to 15 bb:=byte[@vga_font+font_family<<10+achar<<4+yy] repeat xx from 0 to 7 if (bb&(1<0 putpixel(xx+x,yy+y,f) ' ------ Opaque character pub putcharxycg(x,y,achar,f,b) |xx, yy,bb repeat yy from 0 to 15 bb:=byte[@vga_font+font_family<<10+achar<<4+yy] repeat xx from 0 to 7 if (bb&(1<0 putpixel(xx+x,yy+y,f) else putpixel(xx+x,yy+y,b) pub putcharxycgf(x,y,achar,f,b) |xx,yy,bb,c0 c0:=@ccc if (f<<24)<>0 f:=long[palette_ptr+4*(f & $FF)] if (b<<24)<>0 b:=long[palette_ptr+4*(b & $FF)] repeat yy from 0 to 15 bb:=byte[@vga_font+font_family<<10+achar<<4+yy] asm testb bb,#0 wz if_z mov $1e0,f if_nz mov $1e0,b testb bb,#1 wz if_z mov $1e1,f if_nz mov $1e1,b testb bb,#2 wz if_z mov $1e2,f if_nz mov $1e2,b testb bb,#3 wz if_z mov $1e3,f if_nz mov $1e3,b testb bb,#4 wz if_z mov $1e4,f if_nz mov $1e4,b testb bb,#5 wz if_z mov $1e5,f if_nz mov $1e5,b testb bb,#6 wz if_z mov $1e6,f if_nz mov $1e6,b testb bb,#7 wz if_z mov $1e7,f if_nz mov $1e7,b setq #7 wrlong $1e0,c0 endasm long[mailbox0][2]:=32 long[mailbox0][1]:=@ccc long[mailbox0]:= s_buf_ptr+((y+yy)<<12+x<<4)+$f0000000 repeat while long[mailbox0] < 0 ' ------ Opaque 8x8 character pub putcharxycg8(x,y,achar,f,b) |xx, yy,bb repeat yy from 0 to 7 bb:=byte[@vga_font+font_family<<10+achar<<3+yy] repeat xx from 0 to 7 if (bb&(1<0 putpixel(xx+x,yy+y,f) else putpixel(xx+x,yy+y,b) '' ------ Opaque zoomed 8x16 character pub putcharxycz(x,y,achar,f,b,xz,yz) |xx,xxx,yy,yyy,bb repeat yy from 0 to 15 bb:=byte[@vga_font+font_family<<10+achar<<4+yy] repeat xx from 0 to 7 if (bb&(1<0 repeat yyy from 0 to yz-1 repeat xxx from 0 to xz-1 putpixel(xz*xx+xxx+x,yz*yy+yyy+y,f) else repeat yyy from 0 to yz-1 repeat xxx from 0 to xz-1 putpixel(xz*xx+xxx+x,yz*yy+yyy+y,b) '' ----- String output using above pub outtextxycg(x,y,text,f,b) | iii,c repeat iii from 0 to strsize(text)-1 putcharxycg(x+8*iii,y,byte[text+iii],f,b) pub outtextxycg8(x,y,text,f,b) | iii,c repeat iii from 0 to strsize(text)-1 putcharxycg8(x+8*iii,y,byte[text+iii],f,b) pub outtextxycf(x,y,text,f) | iii,c repeat iii from 0 to strsize(text)-1 putcharxycf(x+8*iii,y,byte[text+iii],f) pub outtextxycz(x,y,text,f,b,xz,yz) | iii,c repeat iii from 0 to strsize(text)-1 putcharxycz(x+8*xz*iii,y,byte[text+iii],f,b,xz,yz) '**********************************************************************r*** ' * ' Font related functions * ' * '************************************************************************* ''--------- Set a font offset. TODO: remove, use byte#1 instead pub setfontfamily(afontnum) font_family:=afontnum 'if afontnum==8 ' font_ptr:=@amiga_font if afontnum==4 font_ptr:=@st_font if afontnum==0 font_ptr:=@vga_font ''--------- Get a pointer to a font definition pub getfontaddr(num) if num==1 return @vga_font if num==2 return @st_font if num==3 return @a8_font ''--------- Redefine a character pub defchar(fn,ch,b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15) :s s:=@st_font+fn+ch*16 byte[s+00]:=b0 byte[s+01]:=b1 byte[s+02]:=b2 byte[s+03]:=b3 byte[s+04]:=b4 byte[s+05]:=b5 byte[s+06]:=b6 byte[s+07]:=b7 byte[s+08]:=b8 byte[s+09]:=b9 byte[s+10]:=b10 byte[s+11]:=b11 byte[s+12]:=b12 byte[s+13]:=b13 byte[s+14]:=b14 byte[s+15]:=b15 '************************************************************************* ' * ' Cursor functions * ' * '************************************************************************* pub setcursorpos(x,y) ''---------- Set the (x,y) position of cursor cursor_x:=x cursor_y:=y '************************************************************************* ' * ' VBlank functions * ' * '************************************************************************* pub waitvbl(amount) | i ''---------- Wait for start of vblank. Amount=delay in frames repeat i from 1 to amount repeat until vblank==0 waitus(100) repeat until vblank==1 waitus(100) pub waitvblend(amount) | i ''---------- Wait for end of vblank. Amount=delay in frames repeat i from 1 to amount repeat until vblank==1 waitus(100) repeat until vblank==0 waitus(100) '************************************************************************* ' * ' Color functions * ' * '************************************************************************* ''---------- Get a VGA color code pub getvgacolor(color):r return colors[color] pub getpalettecolor(color):r return long[palette_ptr+4*color] ''---------- Set the border color pub setbordercolor(r,g,b) | color color:=r<<24+g<<16+b<<8 bordercolor:=color pub setbordercolor2(color) bordercolor:=color ''---------- Set colors for putchar, write and writeln pub setwritecolors(ff,bb) write_color:=ff write_background:=bb ''---------- Set color #c in palette to r,g,b pub setcolor(c,r,g,b) |cc cc:=r<<24+g<<16+b<<8 long[palette_ptr+4*c]:=cc '************************************************************************* ' * ' Text functions * ' * '************************************************************************* pub getcolor(c) :r return long[@ataripalette+4*c] ''---------- Clear the screen, set its foreground/background color pub cls(fc,bc):c c:=bc ram.fill(s_buf_ptr,c,4*buflen,0,4) setwritecolors(fc,bc) cursor_x:=0 cursor_y:=0 return c ''---------- Output a char at the cursor position, move the cursor pub putchar(achar) | c,x,y,l,newcpl if achar==10 crlf() if achar==9 cursor_x:=(cursor_x& %11110000)+16 if (achar<>9) && (achar<>10) putcharxycgf(cursor_x,16*cursor_y,achar,write_color,write_background) cursor_x+=2 if cursor_x>=256 cursor_x:=0 cursor_y+=1 if cursor_y>st_lines-1 scrollup() cursor_y:=st_lines-1 ''---------- Output a char at the cursor position, move the cursor, don't react for tab or lf pub putchar2(achar) | c,x,y,l,newcpl putcharxycgf(cursor_x,16*cursor_y,achar,write_color,write_background) cursor_x+=2 if cursor_x>=256 cursor_x:=0 cursor_y+=1 if cursor_y>st_lines-1 scrollup() cursor_y:=st_lines-1 ''--------- Output a string at the cursor position, move the cursor pub write(text) | iii,c,ncx,ncy repeat iii from 0 to strsize(text)-1 putchar2(byte[text+iii]) '--------- Output a string at the cursor position x,y, move the cursor to the next line - pub writeln(text) write(text) cursor_x:=0 cursor_y+=1 if (cursor_y>st_lines-1) scrollup() cursor_y:=st_lines-1 ''----------- Scroll the screen one line up pub scrollup() | i repeat i from 0 to 559 ram.read1($80000-16384-4096-s_debug, s_buf_ptr+(i+16)*4096, 4096) ram.write($80000-16384-4096-s_debug, s_buf_ptr+i*4096, 4096) repeat i from 560 to 575 fastline(0,1023,i,write_background) ''----------- Scroll the screen one line down pub scrolldown() | i repeat i from 559 to 0 ram.read1($80000-16384-4096-s_debug, s_buf_ptr+i*4096, 4096) ram.write($80000-4096-1024-s_debug, s_buf_ptr+(i+16)*4096, 4096) repeat i from 0 to 15 fastline(0,1023,i,write_background) ''----------- Set cursor at the first character in a new line, scroll if needed pub crlf() cursor_x:=0 cursor_y+=1 if cursor_y>st_lines-1 scrollup() cursor_y:=st_lines-1 ''---------- Backspace. Move the cursor back, clear a character pub bksp() cursor_x-=1 if cursor_x==255 cursor_x:=s_cpl-1 cursor_y-=1 if cursor_y==255 cursor_y:=0 scrollup() outtextxycg(cursor_x,cursor_y,string(" "),write_color,write_background) '************************************************************************* ' * ' Conversions * ' * '************************************************************************* ''---------- Convert a integer to dec string, return a pointer pub inttostr(i):result |q,pos,k,j j:=i pos:=10 k:=0 if (j==0) n_string[0]:=48 n_string[1]:=0 else if (j<0) j:=0-j k:=45 n_string[11]:=0 repeat while (pos>-1) q:=j//10 q:=48+q n_string[pos]:=q j:=j/10 pos-=1 repeat while n_string[0]==48 bytemove(@n_string,@n_string+1,12) if k==45 bytemove(@n_string+1,@n_string,12) n_string[0]:=k q:=@n_string return q ''---------- Convert a integer to dec string using d digits, return a pointer pub inttostr2(i,d):result |q,pos,k,j j:=i pos:=d-1 k:=0 n_string[d]:=0 repeat k from 0 to d-1 n_string[k]:=48 if (j<>0) repeat while (pos>-1) q:=j+//10 q:=48+q n_string[pos]:=q j:=j+/10 pos-=1 q:=@n_string return q ''---------- Convert unsigned integer to hex string with d digits, return a pointer pub inttohex(i,d):result |q,pos,k,j j:=i pos:=d-1 k:=0 n_string[d]:=0 repeat k from 0 to d-1 n_string[k]:=48 if (j<>0) repeat while (pos>-1) q:=j+//16 if (q>9) q:=q+7 q:=48+q n_string[pos]:=q j:=j+/16 pos-=1 q:=@n_string return q pub setpalette(colors) if colors==256 palette_ptr:=@ataripalette '********************************************************************************** ' ' Blitting ' '********************************************************************************** pub blit(f,x1a,y1a,x2a,y2a,s1,t,x1b,y1b,s2) | y '' bit 30 set=psram if ((f & $40000000) <>0) && ((t & $40000000)<>0) ' todo: check if the fields overlap and reorder the move f:=f & $FFFFFFF t:=t & $FFFFFFF if (f+s1*y1a+4*x1a)>(t+s2*y1b+4*x1b) repeat y from y1a to y2a ram.read1($80000-16384*debugger-16384-4096, f+(y)*s1+4*x1a, 4*(x2a-x1a+1)) ram.write($80000-16384*debugger-16384-4096, t+(y1b-y1a+y)*s2+4*x1b, 4*(x2a-x1a+1)) else repeat y from y2a to y1a ram.read1($80000-16384*debugger-16384-4096, f+(y)*s1+4*x1a, 4*(x2a-x1a+1)) ram.write($80000-16384*debugger-16384-4096, t+(y1b-y1a+y)*s2+4*x1b, 4*(x2a-x1a+1)) if ((f & $40000000) <>0) && ((t & $40000000)==0) f:=f & $FFFFFFF repeat y from y1a to y2a ram.read1(t+(y1b-y1a+y)*s2+4*x1b,f+(y)*s1+4*x1a,4*(x2a-x1a+1)) if ((f & $40000000) == 0) && ((t & $40000000)<>0) t:=t & $FFFFFFF repeat y from y1a to y2a ram.write(f+(y)*s1+4*x1a,t+(y1b-y1a+y)*s2+4*x1b,4*(x2a-x1a+1)) if ((f & $40000000) <>0) && ((t & $40000000)<>0) repeat y from y1a to y2a bytemove (f+(y)*s1+4*x1a,t+(y1b-y1a+y)*s2+4*x1b,4*(x2a-x1a+1)) '********************************************************************************** ' ' Fonts and palettes ' '********************************************************************************** dat vga_font file "vgafont.def" st_font file "st4font.def" a8_font file "atari8.fnt" ataripalette file "ataripalettep2.def" '********************************************************************************** ' ' Timings and colors definitions ' '********************************************************************************** ' bf.hs, hs, bf.vis visible, up p., vsync, down p., cpl, total lines, clock, hubset scanlines ud bord mode reserved timings long 14, 80, 14, 1024, 6, 8, 6, 128, 576, 336956522, %1_101101__11_0000_0110__1111_1011, 576, 0, 192, 0, 0 vgacolors long $00000000,$0000AA00,$00AA0000,$00AAAA00,$AA000000,$AA00AA00,$AA550000,$AAAAAA00,$55555500,$5555FF00,$55FF5500,$55FFFF00,$FF555500,$FF55FF00,$FFFF5500,$FFFFFF00 '********************************************************************************** ' ' PASM driver code ' '********************************************************************************** DAT org ''-------- Initialization ---------------------------------------------------------------- hdmi setq #6 rdlong vblankptr, ptra ' read pointers setq #8 rdlong m_bs,modeptr ' read timings bitl hbase, #31 wcz ' if pin 31 is set, use full strength for Adafruit Pico HDMI board setcmod #$100 ' enable HDMI mode mov t1,#448 ' 7 << 6 add t1,hbase drvl t1 ' #7<<6 + hdmi_base ' enable HDMI pins if_z wrpin #0, t1 '#7<<6 + hdmi_base ' for Adafruit breakout board - full logic as in Pico, the board has 220 Ohm resistors on it if_nz wrpin ##%10110_1111_0111_10_00000_0, t1 ' #7<<6 + hdmi_base ' a '123 ohm BITDAC for Parallax breakout board setxfrq ##$0CCCCCCC+1 ' set streamer freq to 1/10th clk ' mov t1,hbase ' shl t1,#17 ' add immg32,t1 ' add the pin base to he streamer constant sub i_upporch,#2 ' the driver will call 2 blank lines itself to preload the buffer, so sub #2 from up porch time cogid t1 ' get a cogid mul t1, #12 ' compute the offset to PSRAM mailbox add mailbox, t1 ' add offset to find this COG's mailbox ''-------- frame rendering main loop --------------------------------------------------- p101 setq #3 rdlong vblankptr,ptra setq #47 ' read sprite data rdlong sprite1pointer,spriteptr mov spriteline,#0 ' init the sprite line variable mov dlinum, #0 add frames,#1 ' increment the frame counter mov dlptr2,dlptr ' init the temporary DL pointer mov linenum,#0 ' init the current line # mov rcnt,#0 ' init the DL repeat counter mov rcnt2a,affffffff ' why?! '' ----- up porch (before the picture) mov hsync0,sync_000 ' init constants for sync mov hsync1,sync_001 callpa i_upporch ,#blank ' call the porch line i_upporch (-2) times wrlong #0,vblankptr ' the vblank time ends here xcont m_bs,hsync0 ' horizontal sync xzero m_sn,hsync1 call #dli ' call DL interpreter for line #0 at line #(-2) - 2 lines earlier, so it can start preloading data from PSRAM xcont m_bv,hsync0 xcont m_vi,hsync0 rdfast #256,buf1d ' prepare the HUB buffer for 4 scanlines xcont m_bs,hsync0 ' horizontal sync xzero m_sn,hsync1 call #dli xcont m_bv,hsync0 xcont m_vi,hsync0 call #sprite ' sprites for line #0 '' ------- the main screen drawing starts here p301 xcont m_bs,hsync0 ' make a right porch xzero m_sn,hsync1 ' make hsync call #dli ' process the DL for line+2 xcont m_bv,hsync0 xcont immg32,#0 ' display the line call #sprite ' process sprites for line+1 add linenum,#1 ' increment the current line number cmp linenum,i_totalvis wz ' check if all lines displayed if_nz jmp #p301 ' if not, display the next line ' ---------------- All visible lines displayed now, start vblank p112 wrlong #1,vblankptr ' tell the system that the vblank started callpa i_downporch ,#blank ' bottom blanks mov hsync0,sync_222 ' vsync on mov hsync1,sync_223 callpa i_vsync,#blank ' vertical sync blanks jmp #p101 ' return to the main loop '' --------------- END of frame rendering loop --------------------------------------------------------------------------- '' --------------- Display list interpreter --------------------------------------------------------------------------- dli cmp rcnt,#0 wz ' check the DL repeat counter if_z rdlong dl,dlptr2 if_z add dlptr2,#4 if_z jmp #p307 ' no repeat, goto read and interpret the next DL entry sub rcnt,#1 wz ' decrement the repeat counter if_nz mov dl,rdl ' restore repeating DL entry from temporary buffer incmod rcnt2a,rcnt2 wcz ' address update counter if_c add dl,roffset ' if it rollovers, add the offset to the data address mov rdl,dl ' save the result p307 mov framebuf2,dl wcz ' move this to framebuf2. If normal DL entry, the frame buffer start will be extracted from this getnib t1,dl,#0 cmp t1,#%0010 wz ' 0010 - display a normal graphics line, preload it from the PSRAM if_z jmp #preload cmp t1,#%0000 wz ' 0000 - display a line from a PSRAM list if_z jmp #preload2 cmp t1,#%0001 wz ' 0001 - repeat if_z jmp #p390 p308 ret p390 rdlong rdl,dlptr2 ' read the next DL entry to repeat getword rcnt,framebuf2,#1 ' read the repeat count shr rcnt,#4 ' from 12 upper bits mov rcnt2a,affffffff ' I still don't know why? getnib rcnt2,framebuf2,#4 ' read the pointer update counter getword roffset,framebuf2,#0 ' read the offset to add shr roffset,#4 ' clean the command field from offset shl roffset,#6 ' and make it ready to add to the DL entry (address=20 upper bits) jmp #dli ' now start repeating '' --------------- A display list interpreter end ------------------------------------------------------------------------ '' --------------- Blank and vsync procedures called via callpa have to be in the middle of the code --------------------- blank xcont m_bs,hsync0 ' horizontal sync xzero m_sn,hsync1 xcont m_bv,hsync0 xcont m_vi,hsync0 _ret_ djnz pa,#blank '' -------------- Preload a line from PSRAM preload mov buf1c,dlinum ' preload a line buffer #dlinum (0..3) shl buf1c,#12 ' 4096 bytes per line add buf1c,buf1d ' add the start address (himem-debug-4096) : Todo: debug variable! mov buf1,buf1c incmod dlinum,#3 shr framebuf2,#4 ' get the PSRAM start address from DL - Todo: use new DL format mov buf2,a4096 mov cmd,framebuf2 ' set the address setnib cmd, #%1011, #7 ' attach the command - read burst from the external memory setq #2 ' write 3 longs to the mailbox _ret_ wrlong cmd,mailbox ' read the PSRAM preload2 ' incmod dlinum,#3 shr framebuf2,#4 mov cmd,affffffff mov buf1,framebuf2 setq #1 _ret_ wrlong cmd,mailbox '' -------------- Draw sprites sprite mov spritenum,#15 ' 16 sprites. Todo: this should be a parameter p802 mov t5,spritenum ' prepare a pointer to load sprite data mul t5,#3 ' one sprite data set needs 3 longs alts t5,#sprite1xy getword sprite_y,0-0,#1 ' get a sprite y signx sprite_y,#15 ' they can be negative alts t5,#sprite1xy getword sprite_x,0-0,#0 ' and x signx sprite_x,#15 shl sprite_x,#2 ' now these are longs alts t5,#sprite1wh getword sprite_h,0-0,#1 ' get a sprite height sub sprite_h,#1 alts t5,#sprite1wh getword sprite_w,0-0,#0 ' and width shl sprite_w,#2 cmps sprite_x,a4096 wcz if_ge jmp #p801 cmps sprite_x,##-128 wcz if_le jmp #p801 mov t2,linenum ' display line # to check if sprite has to be displayed subs t2,sprite_y wcz ' check if the sprite has to be displayed if_c jmp #p801 ' if not, go out cmp t2,sprite_h wcz ' we have now the sprite line #, check, if it is not >= sprite height if_gt jmp #p801 ' if yes, go out mov t3,spriteline ' compute the line buffer addres where to put the sprite line shl t3,#12 ' =4096*spriteline where spriteline=0..3 ' add t3,buf1d ' line buffer addr testb sprite_x,#31 wc ' check if sprite pos <0 if_nc add t3,sprite_x ' if not, add xpos, else xpos=0 - now we have the address to where wmlong the sprite mul t2,sprite_w ' compute the offset to the sprite line data if_c add sprite_w,sprite_x ' if sprite_x negative, shotren the width if_c sub t2,sprite_x ' and add the offset (sub negative) to the sprite data offset alts t5,#sprite1pointer ' get the pointer to the sprite (3 longs per sprite data) add t2,0-0 ' then add the offset if_c jmp #p899 mov t4,sprite_x ' add t4,sprite_w sub t4,a4096 wcz ' check if the sprite goes right off the screen if_nc sub sprite_w,t4 ' if yes, make it narrower p899 mov t6,sprite_w shr t6,#2 ' bytes to longs sub t6,#1 ' longs to move for the full sprite width, -1 (setq adds 1) setq t6 rdlong 368,t2 ' read sprite data to the cog setq t6 ' write the sprite data to the line buffer wmlong 368,t3 p801 djnf spritenum,#p802 ' get the next sprite incmod spriteline,#3 ' prepare to fill the next line ret '' -------------- Graphics line ------------------------------------------------------------ '' consts and vars sync_000 long %1101010100_1101010100_1101010100_10 ' sync_001 long %1101010100_1101010100_0010101011_10 ' hsync sync_222 long %0101010100_0101010100_0101010100_10 'vsync sync_223 long %0101010100_0101010100_1010101011_10 'vsync + hsync border long %00000000_00011010_00101100_00000000 '------ these longs will be set by setmode function m_bs long 0 'blanks before sync m_sn long 0 'sync m_bv long 0 'blanks before visible m_vi long 0 'visible pixels # i_upporch long 0 'up porch lines i_vsync long 0 'vsync lines i_downporch long 0 'down porch lines i_cpl long 0 'chars/longs per line i_totalvis long 0 '------------------------------------- linenum long 0 frames long 0 dlinum long 0 lutg8 long $70880400 ' 0111_0000_1000_1000 immg32 long $B0810400 ' 1011_0000_1000_0001 vblankptr long 0 modeptr long 0 paletteptr long 0 dlptr long 0 hbase long 1 mailbox long 0 spriteptr long 0 cmd long 0 buf1 long $80000-16384-16384 buf2 long 1024 dlptr2 long 1 dl long 1 buf1c long 0 buf1d long $80000-16384-16384 framebuf2 long 1 hsync0 long 1 hsync1 long 1 t1 long 1 t2 long 0 t3 long 0 t4 long 0 rcnt long 0 'dl repeat count rcnt2 long 0 rcnt2a long 0 roffset long 0 rdl long 0 'dl repeat line dlc long 0 'dl command affffffff long $ffffffff sprite1pointer long 0 sprite1xy long 0 sprite1wh long 0 sprite2pointer long 0 sprite2xy long 0 sprite2wh long 0 sprite3pointer long 0 sprite3xy long 0 sprite3wh long 0 sprite4pointer long 0 sprite4xy long 0 sprite4wh long 0 sprite5pointer long 0 sprite5xy long 0 sprite5wh long 0 sprite6pointer long 0 sprite6xy long 0 sprite6wh long 0 sprite7pointer long 0 sprite7xy long 0 sprite7wh long 0 sprite8pointer long 0 sprite8xy long 0 sprite8wh long 0 sprite9pointer long 0 sprite9xy long 0 sprite9wh long 0 sprite10pointer long 0 sprite10xy long 0 sprite10wh long 0 sprite11pointer long 0 sprite11xy long 0 sprite11wh long 0 sprite12pointer long 0 sprite12xy long 0 sprite12wh long 0 sprite13pointer long 0 sprite13xy long 0 sprite13wh long 0 sprite14pointer long 0 sprite14xy long 0 sprite14wh long 0 sprite15pointer long 0 sprite15xy long 0 sprite15wh long 0 sprite16pointer long 0 sprite16xy long 0 sprite16wh long 0 spritenum long 0 spriteline long 0 sprite_x long 900 sprite_y long 0 sprite_w long 16 sprite_h long 64 l2 long 0 t5 long 0 t6 long 0 t7 long 0 t8 long 0 t9 long 0 preloadaddr long 0 preloadlineaddr long 0 a1024 long 1024 a4096 long 4096 a1023 long 1023 fit 368