From afcb3392240f6502cd75ee9cdfbc09bafedf113c Mon Sep 17 00:00:00 2001 From: starfrost013 Date: Sun, 13 Apr 2025 18:36:48 +0100 Subject: [PATCH] Get rid of useless "reserved" stuff and also implement 8bpp indexed mode using CLUT. --- doc/nvidia_notes/status.xlsx | Bin 15992 -> 15953 bytes .../86box/nv/classes/vid_nv3_classes.h | 92 ++--------------- src/include/86box/nv/render/vid_nv3_render.h | 9 +- src/include/86box/nv/vid_nv3.h | 21 +++- src/video/nv/nv3/nv3_core.c | 75 ++++++++------ src/video/nv/nv3/nv3_core_arbiter.c | 22 ++-- src/video/nv/nv3/render/nv3_render_core.c | 97 ++++++++++++------ src/video/nv/nv3/subsystems/nv3_pramdac.c | 48 ++++++++- 8 files changed, 203 insertions(+), 161 deletions(-) diff --git a/doc/nvidia_notes/status.xlsx b/doc/nvidia_notes/status.xlsx index 4e02b672cb00475d41b8a9e3411d5ca4a9365291..b73941d31dae703054ddc6f338acef9f0a12bcd4 100644 GIT binary patch delta 5487 zcmZ8l2Q(bqvtMPEjkZBT5S{2{NtDGZ(R&TiB6?k-x7Arh*wssPi7p7DM(?XciS|YB zHHgmh&w1y4@BHV?xp(fJ-?{gmGjr$6%(?%Vf7KEmu$-Cxry+VBj}swFVBZJ|v*p^; z*PGjGl`ElzhvyLMmX0|Dim4!rhxi#m?RGYF6}$WXgvd*BodT1cv0QiNRR5R@NhG&2Yj)h)X~73sN06N&I=jG>j9k)TE5Rd@Rm9EBQOnYBUjCG z)T=Ru_fKyV5$I`u>wawyW{>P=I9@)MzCZsi4nvjZo8H0(1ETk4NeAeHeK1 zlc++@GHlxuGF;3uD-B;BkdA*NE-nR=Q( zN(<3!kzsuvv{@httfd@zaG^`*`*^=|EI4tyu# zc1}P#w+d#qh~R2gdWueJW-F-`(^A_LG7U^wynU!UbS?-YZ#8=aHGBSApa1tL{Nl3dxRUg$S?zp3GH7b*<=Mg8I9rKCJqqyYkvdX=kO zUPVCH+p1Z|5nK@&LWZYQ@iY0K1j&F)SJ97$y*$ z4D+xVhIlKBp{s)6b5#kIPo`Ql=*fA&+0q5*T%Os1cO<&3mh8?Vrj+WbXXEhdZvEzH zIDIC!-g*V?6YHmz_{K=$;v+uD9r_&_&KYeTs@Bo&NH%2=*L8%R7I8(8D%tU995IG}08s zW=@kilAdN#5hAU!g=uY^66dokN9~rGrhF+o$6LN)vDpW|N=E{08YfR&eKVHL&|p$J zgu=2^(fP@ad1u3|SnLjjv6rSgj`VF;CV6l21`CxNUf(yy)DF3LIVP%}*{xp`Z<-_x1ugH&rMqo^^#!U6@gL&+LQ(A<3B8@;^N9l=m1L7C-@_nl3 zmWS7DM=6C(!wOU^jtXg0rtFp$(U`v)l`yeT!jfV~pwNGR@$^FT`Q%_tslgk$CC+|B zUeOOIW_gMVROTA$_?f81e>S_tp9kjqCDIBE);!mxu1#@DTH$VM2D;M<XRe*q z2Sqa%8TxogH@PJ(a~mLxVclTn*>_1x+%Jq_onU4{FV0S@#w6AM$RGo1%#p)9$%v>x z9z1D@_8!sl@Q09bx%v;d`dKKN26OV$)u%6Dx?q~RZi};9w4x!%ja}YtG)vhvEh6r1 zhWeA(^5zER8)nf@DB~i=r>E+%wtJlY-^5X}E#&vdD`D7N`-wk$S;+BxN|+x@SatO6 z9dFgvx)?~wPK+@S9%Q##^ayA=#YaaoIDq1pj~AwJ001uHzkav~Ccs9#i3{N;3$K*% z4Jr)HnP5Qn#E>O-neEF*HThj-B`a@@reo-3Pu~9Ho_bbA?b69_(p2n_(L1g2M}&}U z=6qp6p;_z^Qt~!}&s$nI%3Q<zt#PFu7eoO2wfwgb<{MsQ+NNQ`4!)jxG4M&0mR?Pu9=!L+x4XaW(`lW-Fsg)- z8ufBYN895Z>K9RMjjRS4Nbr}~C+ogHF@oIBP%Wh*%Y@TJnEcat3q^-y#S}STdHBwJ zo_NNI>=)8P7t?_F^{PdxL6Ps zjLe;nX~(?7BoshgEpY2Z^D=YGJbmLSG8qK;39Xdqi^8Yy@u`ttLdaS1inb??zg>+S zkpcjBcK`qYoxorTQawd7p55D}@ULCahm`n;nYavoiiiWQQ@Z$rndzK(EjHDOZ>5c< z;yt)rR627rx~B^pRMo0U_K9)0Kh2MC?hMT@;fv*8^R)%WDEqvimSb^I(H=Y40e5w^ z5KE5tO`!U`e4vXI=pD&Uz~G!rf}uzA9MwkVRE;p9Tz z?guM-HF)A0#1w zzQsGQv^`i+s3;J(26?{(9@MP%KGugL!ov^3SRbbSH?WoT1^#dmWhf})Gq=(X_VCShKWTz^1_|*==va%daJ`UeKp_un zdPvjEF~{k3&L;w+>uCmT9Wpo{sB**R>)PlTBD+v; z?1{_ko0q#%T6NAsee&vLvY(3#es90hewm{rJx55C67`4y{#67*Pjf;g8Eb7=n1S7$ zi|%$!wB*oCluYjlHQ_2bK~YOq_vzcUBjT=Z$URo2yYZgJUj6W0KTk-Z(lD5%!F~1v z7IY-nmnm{8bLY~L706JIL)=47j99+H-zSze_lJG=mXSLQy*wCV*-&MF zt6BK?-g*9d(A`~PvWasjKT%L+h+B~KIfoNak?VvZit)5K17u%6H=?d+`;bf7)F@19 zd?eXvmb>1^G}4u>Y5nL%`6wl*O^x zYNKrR`C&5ymwo;kmx?JkwRugb@6|=}Ww1UcQ)0YulD&!&I1v>Ke1`SVnAP$|Pdm&u zp@kqX29FvSVzP?jB}bgRts<|!732tUN3{b!$%c_v7oml@TbLBtsfpkv%$f1RSq(ge zWZKGjI0bQF?LH%IKb5GWElL^Xe)FIS4jGW4%D_ixc)a%O(Vt<^eDN$Bum$#?k!<Z+?G{s(xYg@?fHdm&q0TTD<~Nn$Vgtp`UHvt>RJ&SG`|1C0fc{JYZ%=H7D5FS z%1;KXWDb((>Qh^OW&slPJs+Q|^$X~ww zFi#jf$&eh??t~rG)_`^1)f2P(2vL1nG^C=qs8$_5^YBtDbE0sm}Y zKc<|+-@~toW>_F5Y_za2@xTKBD$#IWdc+e2vH%Ue+uTl-s0TIzd$wdb`q=7WCpqVEp-B1p zl_^j&OmNx4*XSGl*_jdLXaq8m>z;z%(?$}TR0Mwu zpALl(B!TlyL~Dti$tRFuflU+}a))@tVT!!xB~T`fPme8-s#Zn^-t>7@~G2UqsT;S^TN@q-WRu5J=K#?_Z}J^7dyI*W_CrLC>Hyp z(p(J!N)<0&(@Ql6^*6W>$*kNErAL^p_lBU!aMX!+xGxU7t&lMPc$J80J7TabN;3gX z%ks>9GlW9ByR*$WcD8qvh6Ml75UgKRETOuNx{qM#XcAQ7sYfg(7_+6@Z*sjSvpK+G z6@d?3w?4hoybi>MURVNV|4nbVx1#j2sjfHdivp+(s=>C&Oa z&qF~;)VNl7Z_=c7t%F$cS`DnLAh^$MFRkELR`=sQn_t|sxP(s%VVY>##D+4V4 zqGy#?vINz|=vOV$G`wAj54hJm0L&Qe;>;{k-!3{(uGrH*5r|&cDKXEO_`D}GaW>py zaPR7@nkA^!f)H=UQpS4Hv~9(4d^j;#$ZPuP$?Ss5g5R`7k!8msc||6wBUXBCbiHK} zOn-nt=Hz~a52oqF}&C&yYRU;TWb+Zf~A!3Aens>;^zF@6;gc``{`D`nO zBJ2p`6Uf7sMp)qnkG1Lc2LW}tKF9VP>Bm>3Mn9VJWSlgfh7BV7+tAlJ+dCiKd3Nh` zN|Z5Z-pJ06IHz!-+iS`?wf8dNF&@P_4aF9kdQ=0&i|PCCNf_o*ESDo=dbqmNa3-nr zI)E`t4|)U(#Pphd_%fL1M=NnjGHqtgU`cT1Up;P12;&o`HO6^2ux2r@v#QZ%w631( zd2oy(uMkvh!1Ah8DeZJNF;WUXZA34VRL4fQC|d6ix%1u`YBk=p^&w&mS9H$I0)eqajpw3s+4Qq!3ZpHJn}H#> zha_TWDf!FD0(P%w#lPsiRDUK4L#1!n-gu;Q@G4zAESq?(`ZnDPFAf?NuZ@`cF=W{~*Haz znY!4lQfa+TPi*`0WFlHeZPk7bORUQ`^_P^* z2LczVu(8=>R5uau)%bN!cX2&S_!`XNtP$`_9-CLEBaI-e%M_+bF10;GNHZ5hx04t? zfymdYDb$j9vlgpN#WVl(&6mV?z9kG^a`V+2UP`952bz=b($VXr>1bYwS?lk%?P?XIps9l1Vju#Ng+ZiLYB+@1un=Y{o%|HtzkqGB{WVUPHVg8$ z;&4HKID?3m|AYPoeMfY>TvMRm59iWJLP@rbc{9v6me;h~16R0C${cPKK*rxN{(hA& zgJZ|mYadvn=sVA7&iAXc0;j)tjMjlULPDwJSVHBwn*E7 zd|m8dk66$;sLI>T+6VN$5$P6wHBemGfOBcjkVlTH!77$?pTrUA)RZRfctQ&V-~KTg z{d(~($3Py_SX=IvrS976h>2TXluUKwf38L@q(tAj_Tg~na;dm-J0)+95=YlE6I>K* zR2*}a-1)vfQAROqDPff7OI}aKLTf$i;oP5;vzOXl^Q}E#lKFS-eP4PEeUy^DGAKEh z`PFauk5;_Nhx;t$$5+e!ZhQS7pLlC!%Ur8uo+mJ?D+#jOi7|b|dKtkdsc;0WNq7-} z^S?bsa&c`eL$tLx5ADA#5CDMc-T?nnB@sFpN{Q|gr=cOOTqcj$I83Y!1RR=@xN#lKI!mlV(#33l4QzJmn-*kJIt$yFhVwDNu_76t_hdEAA9`r|gS61&Tw_EybZo zk;~ip=llM-H5x| zvxfAVh}OHPL>NWCn;eD*GtNE+o=ufq(2yr`P15loS$bL5ow_rrJS$9*W%jrBsQzOq{58)-lmZ?CF51e>!okWxu(gHP3*dnrAgOq#zY%9Ox1=FPhw zjkGgS>>DX!4H$I`jVw%Xen@NCO7Lz@)vaV;qSyV=(m{NZ}hR5}TPypi3w2nnJt@zaG~^<2f|Tsk07n&)d_M;e}8WMeSS%0(^qTn zoIkP$r6?V=I7~2jM4^f2Cxbe*i)-PL=!cvgO4;^a_q`$_>v{?%woJC3#;5`MxCRNs zd`LaRKEe0QK^*Q0hnG5dtvFQ#{)L%yXOStu3Mo0$^v^zSZQ>`d2AYfdjh`NtsTe=3 zAzDB(*BBr*y>11%u<%|b#{PiQYL_pFIyRGp_tL!+7)t2j52f6nlpZ!7tN!#KyVrpP z8jgz$HakLS^D&F2zRLv{8YFe!ai&og+=JO|M{qS?DXMJJD?>@)N%^7_x06D!+Y5Jz zyon1~5qoJ+n|y{^4ll_};`dXRji|VfMu+d9(~=WrEd@-JV@EEz zS^Y+*?3gzl?w?SGQVWe>yF$$fN6@1WbD*uwP3oRGxq(9@cq14oxQr_64k@H~Bfu0~ zl6U4SKG%@u)~p>gInOotEaVM(GV{sv=tx__cf3)>%cYC*_AeSx#p&bQPUN@5pWKnf zSo6OsJGts=j|x>&f02)4H+{?LC8%>`^+}sSk*tO!YfI7V3Moy4?YZKawWWQ*E^M8S zZ+{0;S}pHNNBGQ1#>B%MGMD%Uzj3_M7Upby`(jqh6&{6CJDa@)3BEWGv0g4&ylYZ5 z;FxqD`ru9dl4Qy-ZASqAz0wFVQ$?qq3hx|ILJHHf_|6Y!RT=gMwO^yY>ZLTAdeX8e zJ*&eaHpa5Anb9ymerXI+<8gV=MptK(X_%uVWa)l^N+RaPu zKyHH?EbVG?5*I8W&pW+Fu?d^bKdNor!n9 z45NO%LO{W`5KW(lvp-MbaS!f`K?aOEj3zHS#&!HpW-2)Gt<{HS)nO zj#E9MoQ-6e_|!u$x)3mY>Yc$a)@P{>WokUi9npusHaR|-`2hdZnmv|E#~cj zpM)kxx?j3W4Pb8;hhrNF1mfhL%+o-HkaPS(-b=Cn6nhrsC5yJeQTR#SymsDx1 ztp9orU1b*J;fc2Jx^P;{93-iNqmg0=D{g>CihB_9SWxdoir{Lb8^S8LYeO295+F2g zNJvOeP%UBy?EYfV{nN8q%AU=_09i@M<|m3g;ku$pIuWBoVYf}gkMHo+OI%EN*^e{$ z&F58gWlzA6Ov)GSFSBVOFTV#qNq-K#9Y}6n5KN1Su94~4W{CBX*R5Uw9;_@j=Q64~ zuIjY`Xn3ZhIWOz{o?L^8Jj-5yo6$dN0Lo`NrpyeIBR#9BXXXg(oEXFw+#y`8H9uMY znLj0QTkE?Z$*@@{NKP6HpeU@NEGVH5&;UuwGP~4cJXKnCi_eL+V-D4?9tC7$t)p5G z7?-|5B{Ry|d9$LS+~vq{QbcEEO~XQsoU>(Q=NDWAr%aZOHU`P~C{48@>|OV)JsH;a zAmoFIrYd=v9Gd_@*F*}P1;nr)0PG=7H?_3uwC%Ci3l07<=a62L(x;KJR7CT|uH?bc zF1p*C^~_nnrcj6-QuI%kwWbv`jm6O{za$TGD!0SCCx;qjf0=I{#}hAN;h-8_O8~dc*D%a=+Em1Whr*-Q(MX6EbICu(_1ERI3|prF+N?e}cLX$OX8xU0N%@34yWoBuv*rvknHVVW=p^y8 zaomSqY~QU9hQzZ6B7Cxb(}=KWlaua`erJJ+an?hC+>e|OH) z-y${L%r%@JFQhh1w2%IttekxoM-t0gIp}9;*z(cuM$(idxa^2(?5Wb-l84&LuGG}? zBVn^B)w?lsLDDE{96UILVz4ieaLi@ecg@E&h`7Ikh>VX3NpITSC8v2TYTS&oNqI*% ziiY)}_*&4Yj=lQu-bKJ=T#x^>f)aXQ#wZxw&r&%k@5-xPhND8SlE!gxELb9tifx{} z+pKl2@88YLf4e*jthdg%i`E}SO-&L`#j zB*`wM%<}YSmu6sbu!PZStA~&^q^Aa*Gs}Xb^FNWPqE?Fr2Huc`8Mh0XoGn_0K74e& z^cGfRlU-*^8W>X2WN2D?HP<~ZTPp4~)UkHKhEp&BN4YdVf9!I>y>a#(zO+BS@tv%) zcJRFhBq2T%t>hj&VLtu6P#e!FEl_bxzK6dte?GoJ*ni)5Z<t%i(Lu2OugAJk z#dKCW(L2zLQpvR*b^8_9kO5}{UD+z&iRtOA5fT9%cTSIYa>Zqd-ty#d8j&H*k7%-0 zUZfjUioUGxAChxrA-~siK44d%*4{I%yAd&s!2?)X!>ToiB7$OvB4^WaLWjl_QVB=Lg}2PEGi(=!G9ME zIx0Z~od=LMVlceH$1d1QC5^>ELK=gb^U^_nC=vy|(R(ZyP*o0#XAUs>bzXuLdi2ZM z6c{k3>clL}A0braponpwT08P-S9O-@`&BxIzDi}6T_&Ra3UTbUOul$16v{RZ$oSE) zMGL~0As&In-oD*l^Y;Gc5;Cg>=T1i9qoUG{Kdd_G?bHOLegXV!sGk-GxwYyw^`$~8 zY%&Y-Gc(6^N)hj*+^V>hfK}*)8qk(~(OjR=HU}AI+ycZZL9Pkbqf%)2TGXL%4KG=5 z$FxCWd5pY8)78AfN?agino0p;eLhoa@ui)=7L6~>iT6Xt+?NChOroc~vp1AgCkZ%% zasZuslf?onoThlvHJcTCzffjYCJqUd&iv}y`crq&V}WMKc!rNmP0R6Ig!=W@;VK27 zpg5@n;UIU}p={IbX4WfjxcHb_z|!B0x$ZgZAQ~{c<1oFxfQ}9%0oK{6NTOz{|ZI zW?XC>nhyF1-K*2Emn?(F<#Neyl zKVvPHE(GsK3*SzDO){w<;}(Im7vER&26P2%cy;qyy~fHjurE{Nsj@+hu|!YUmW}ae zIN~{ByB?5>?UIX?I`P-GcQ>{_t(?r)u|MsY%r~)j*SGKciT71JynK?rMzHS%>SBeU zCV$m`=dZ_y2S$9W)JC!a>sL&TrP4o5 zvhiX}Rk8wp#XqcXUiX7mtdqx5`>9q9h2TwttDMazXn8L5&={&wR$7Q63Gf54;~2=M z1v{BDp)Wm|wdojwS@oNnNcJ0^9rvuaPUWdA$$QSYs?tz3V!Ocjm&rIxg-hs}XH&+!1(BbsmMqzT;jaC4yo_3ZVgW*@xRMKwVi$H^Tf$)HZ^{f^=S| zZab+aiXFoUv&0lVdD{vDiqMB2St4%s3K6XP<6%xQA4VbQs+*Fm0*tOz>#Ka}Sl5?a z5u}Gkdy>=4tHZ6)rbgs6b`oKjyt0MYKL?BRTvej=K1sV1kEMkrre`fZIca+ZC!U{D z9WOh99cCAbX{Zm=EhZp=b#~Gg2hKqR#1Sf#fiIonet%TR&up1D9w@PK%cJT;Pj!;r zHkJcx@0>yot>Avznt^)i8WK#kcZxj9R%mhv-V6TNS(We+vO8uYGL8rB&>4L8m-M?H zIrPIux9VD0g>5YYd@^c)U8u_B`U+w98)Rp|h{HM7gRjWzEBV=c%x{ZsbcAZK)OiVo zE4{Ck)x+(~&1!Yp(gJTB(j7&;=oP_YHe6$|()Ey!LpvBR9E01A)N5;NdG1~BJDKQ$ zKTAB~g_2)R70kp6L1a(0c$&w{yA)?Xx}$;(;{;o79rQ9hZ)x7+E+6PKIRF3#bF$M6 zg9E9S-sB49>|Hgye0;L=Ir8-yEYVL9iqWR?6QuyloRQMAiv@Qblh8{FL2O~W6zbWynNnTRlA;+;L%E1W25ucri zow@vFJ$BinM`3r%*~|xY zt@FJ_idb*9L=3bS=~GeFL>uWqRMbK_x$vc-5cV`jpk6494q9sRG0ToqM zTJ;C`JG@PLyp~bP#p$M4p%J#_7vMkq4kRhD1_kA)|`;*qy zGDkzv`KHZ5k+~N3I)1h@r;TAcgrMl=&s4AZE2lX+o0>;tXgz=oJ+m*y65NO^%!&*# zQyt)^h&Vxik{fAuxvLk$cEQw$Bqu;)i}7Xn&U zXkq4AI+xgnrm!m_E0_AQw4(c)^9@ju87i@qHK%Ci1G%#@GRVc|K60QYDmwDlpiudx zG<`&%9OcZR*^K$nm&bR>`Fj+_|bOh=F0-)66LC@#`&`msaC>e-| z`ahpld?X}_XJ_}nsh0RJaT^4n{?FIx|B!kCe@Pq?d?=Tcf1#TMfcn3_+W!`+L-Uu^ z{LJ5{e}*qoBso!7n4o-2fPdA2YDvC8E`~Zw(o_A%bs * @@ -727,8 +727,16 @@ extern const device_config_t nv3_config[]; #define NV3_PRAMDAC_END 0x680FFF #define NV3_PDAC_END 0x680FFF // OPTIONAL external DAC -#define NV3_VGA_DAC_START 0x6813C6 -#define NV3_VGA_DAC_END 0x6813C9 + +#define NV3_USER_DAC_START 0x681200 +#define NV3_USER_DAC_PALETTE_START 0x6813C6 +#define NV3_USER_DAC_PIXEL_MASK 0x6813C6 +#define NV3_USER_DAC_READ_MODE_ADDRESS 0x6813C7 //bit0=read/write mode? +#define NV3_USER_DAC_WRITE_MODE_ADDRESS 0x6813C8 +#define NV3_USER_DAC_PALETTE_DATA 0x6813C9 +#define NV3_USER_DAC_PALETTE_SIZE 768 +#define NV3_USER_DAC_PALETTE_END 0x6813C9 +#define NV3_USER_DAC_END 0x681FFF #define NV3_USER_START 0x800000 // Mapping for the area where objects are submitted into the FIFO (up to 0x880000?) #define NV3_USER_END 0xFFFFFF @@ -1065,6 +1073,11 @@ typedef struct nv3_pramdac_s uint32_t htotal; // horizontal total lines uint32_t hequ_width; // horizontal equ width (not sure what this is) uint32_t hserr_width; // horizontal sync error width + + uint8_t user_pixel_mask; // pixel mask for DAC lookup + uint32_t user_read_mode_address; // user read mode address + uint32_t user_write_mode_address; // user write mode address + uint8_t palette[NV3_USER_DAC_PALETTE_SIZE]; // Palette Info/CLUT - 256 entriesxr,g,b = 768 bytes } nv3_pramdac_t; /* Holds DMA channel context information */ @@ -1133,7 +1146,7 @@ typedef struct nv3_pgraph_status_s } nv3_pgraph_status_t; /* All of this B* stuff is registers at 400630..40065c and 4006a8 in reality, easier to implement it like this - BPixel = Internal Binary Representation of the pixel within the architecture + BPixel = Buffer Pixel Format */ #define NV3_BPIXEL_FORMAT 0 #define NV3_BPIXEL_FORMAT_IS_VALID 2 diff --git a/src/video/nv/nv3/nv3_core.c b/src/video/nv/nv3/nv3_core.c index 14788dcb3..e8456814f 100644 --- a/src/video/nv/nv3/nv3_core.c +++ b/src/video/nv/nv3/nv3_core.c @@ -49,9 +49,9 @@ void nv3_svga_write(uint16_t addr, uint8_t val, void* priv); bool nv3_is_svga_redirect_address(uint32_t addr) { - return (addr >= NV3_PRMVIO_START && addr <= NV3_PRMVIO_END) // VGA - || (addr >= NV3_PRMCIO_START && addr <= NV3_PRMCIO_END) // CRTC - || (addr >= NV3_VGA_DAC_START && addr <= NV3_VGA_DAC_END); // Legacy RAMDAC support(?) + return (addr >= NV3_PRMVIO_START && addr <= NV3_PRMVIO_END) // VGA + || (addr >= NV3_PRMCIO_START && addr <= NV3_PRMCIO_END) // CRTC + || (addr >= NV3_USER_DAC_START && addr <= NV3_USER_DAC_END); // Note: 6813c6-6813c9 are ignored somewhere else } // All MMIO regs are 32-bit i believe internally @@ -65,6 +65,14 @@ uint8_t nv3_mmio_read8(uint32_t addr, void* priv) // Some of these addresses are Weitek VGA stuff and we need to mask it to this first because the weitek addresses are 8-bit aligned. addr &= 0xFFFFFF; + // We need to specifically exclude this particular set of registers + // so we can write the 4/8bpp CLUT + if (addr >= NV3_USER_DAC_PALETTE_START && addr <= NV3_USER_DAC_PALETTE_END) + { + // Throw directly into PRAMDAC + return nv3_mmio_arbitrate_read(addr); + } + if (nv3_is_svga_redirect_address(addr)) { // svga writes are not logged anyway rn @@ -143,6 +151,15 @@ void nv3_mmio_write8(uint32_t addr, uint8_t val, void* priv) { addr &= 0xFFFFFF; + // We need to specifically exclude this particular set of registers + // so we can write the 4/8bpp CLUT + if (addr >= NV3_USER_DAC_PALETTE_START && addr <= NV3_USER_DAC_PALETTE_END) + { + // Throw directly into PRAMDAC + nv3_mmio_arbitrate_write(addr, val); + return; + } + // This is weitek vga stuff // If we need to add more of these we can convert these to a switch statement if (nv3_is_svga_redirect_address(addr)) @@ -474,7 +491,7 @@ void nv3_pci_write(int32_t func, int32_t addr, uint8_t val, void* priv) break; default: - + break; } } @@ -493,31 +510,6 @@ void nv3_recalc_timings(svga_t* svga) svga->ma_latch += (svga->crtc[NV3_CRTC_REGISTER_RPC0] & 0x1F) << 16; - // should these actually use separate values? - // i don't we should force the top 2 bits to 1... - - // required for VESA resolutions, force parameters higher - // only fuck around with any of this in VGAmode? - - if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VDT10)) svga->vtotal += 0x400; - if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VRS10)) svga->vblankstart += 0x400; - if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VBS10)) svga->vsyncstart += 0x400; - if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_HBE6)) svga->hdisp += 0x400; - if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VDE10)) svga->dispend += 0x400; - - if (svga->crtc[NV3_CRTC_REGISTER_HEB] & 0x01) - svga->hdisp += 0x100; // large screen bit - - /* - if (pixel_mode == NV3_CRTC_REGISTER_PIXELMODE_VGA) - { - if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VDT10)) svga->vtotal += 0x400; - if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VRS10)) svga->vblankstart += 0x400; - if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VBS10)) svga->vsyncstart += 0x400; - if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_HBE6)) svga->hdisp += 0x400; - - } - */ /* Turn off override if we are in VGA mode */ svga->override = !(pixel_mode == NV3_CRTC_REGISTER_PIXELMODE_VGA); @@ -698,7 +690,7 @@ void nv3_svga_write(uint16_t addr, uint8_t val, void* priv) addr ^= 0x60; uint8_t crtcreg = nv3->nvbase.svga.crtcreg; - uint8_t old_value; + uint8_t old_value = 0x00; // todo: // Pixel formats (8bit vs 555 vs 565) @@ -747,12 +739,33 @@ void nv3_svga_write(uint16_t addr, uint8_t val, void* priv) case NV3_CRTC_REGISTER_RMA: nv3->pbus.rma.mode = val & NV3_CRTC_REGISTER_RMA_MODE_MAX; break; + /* Handle some large screen stuff */ + case NV3_CRTC_REGISTER_PIXELMODE: + if (val & 1 << (NV3_CRTC_REGISTER_FORMAT_VDT10)) + nv3->nvbase.svga.vtotal += 0x400; + if (val & 1 << (NV3_CRTC_REGISTER_FORMAT_VRS10)) + nv3->nvbase.svga.vblankstart += 0x400; + if (val & 1 << (NV3_CRTC_REGISTER_FORMAT_VBS10)) + nv3->nvbase.svga.vsyncstart += 0x400; + if (val & 1 << (NV3_CRTC_REGISTER_FORMAT_HBE6)) + nv3->nvbase.svga.hdisp += 0x400; + + /* Make sure dispend and vblankstart are right if we are displaying above 1024 vert */ + if (nv3->nvbase.svga.crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VDE10)) + nv3->nvbase.svga.dispend += 0x400; + + break; + case NV3_CRTC_REGISTER_HEB: + if (val & 0x01) + nv3->nvbase.svga.hdisp += 0x100; + break; case NV3_CRTC_REGISTER_I2C_GPIO: uint8_t scl = !!(val & 0x20); uint8_t sda = !!(val & 0x10); // Set an I2C GPIO register i2c_gpio_set(nv3->nvbase.i2c, scl, sda); break; + } /* Recalculate the timings if we actually changed them @@ -763,7 +776,7 @@ void nv3_svga_write(uint16_t addr, uint8_t val, void* priv) // and in the words of an ex-Rendition/3dfx/NVIDIA engineer, "VGA was basically an undocumented bundle of steaming you-know-what. // And it was essential that any cores the PC 3D startups acquired had to work with all the undocumented modes and timing tweaks (mode X, etc.)" if (nv3->nvbase.svga.crtcreg < 0xE - && nv3->nvbase.svga.crtcreg > 0x10) + || nv3->nvbase.svga.crtcreg > 0x10) { nv3->nvbase.svga.fullchange = changeframecount; nv3_recalc_timings(&nv3->nvbase.svga); diff --git a/src/video/nv/nv3/nv3_core_arbiter.c b/src/video/nv/nv3/nv3_core_arbiter.c index 2bb3ef8b4..99aebb5e7 100644 --- a/src/video/nv/nv3/nv3_core_arbiter.c +++ b/src/video/nv/nv3/nv3_core_arbiter.c @@ -58,9 +58,10 @@ uint32_t nv3_mmio_arbitrate_read(uint32_t address) uint32_t ret = 0x00; - // note: some registers are byte aligned not dword aligned - // only very few are though, so they can be handled specially, using the register list most likely - address &= 0xFFFFFC; + // Ensure the addresses are dword aligned. + // I don't know why this is needed because writepriv32 is always to dword align, but it crashes if you don't do this. + if (!(address >= NV3_USER_DAC_PALETTE_START && address <= NV3_USER_DAC_PALETTE_END)) + address &= 0xFFFFFC; // gigantic set of if statements to send the write to the right subsystem if (address >= NV3_PMC_START && address <= NV3_PMC_END) @@ -97,7 +98,8 @@ uint32_t nv3_mmio_arbitrate_read(uint32_t address) ret = nv3_prmcio_read(address); else if (address >= NV3_PVIDEO_START && address <= NV3_PVIDEO_END) ret = nv3_pvideo_read(address); - else if (address >= NV3_PRAMDAC_START && address <= NV3_PRAMDAC_END) + else if ((address >= NV3_PRAMDAC_START && address <= NV3_PRAMDAC_END) + || (address >= NV3_USER_DAC_PALETTE_START && address <= NV3_USER_DAC_PALETTE_END)) //clut ret = nv3_pramdac_read(address); else if (address >= NV3_VRAM_START && address <= NV3_VRAM_END) ret = nv3_dfb_read32(address & nv3->nvbase.svga.vram_mask, &nv3->nvbase.svga); @@ -121,9 +123,12 @@ void nv3_mmio_arbitrate_write(uint32_t address, uint32_t value) // Some of these addresses are Weitek VGA stuff and we need to mask it to this first because the weitek addresses are 8-bit aligned. address &= 0xFFFFFF; - // note: some registers are byte aligned not dword aligned - // only very few are though, so they can be handled specially, using the register list most likely - address &= 0xFFFFFC; + + // Ensure the addresses are dword aligned. + // I don't know why this is needed because writepriv32 is always to dword align, but it crashes if you don't do this. + // Exclude the 4bpp/8bpp CLUT for this purpose + if (!(address >= NV3_USER_DAC_PALETTE_START && address <= NV3_USER_DAC_PALETTE_END)) + address &= 0xFFFFFC; // gigantic set of if statements to send the write to the right subsystem if (address >= NV3_PMC_START && address <= NV3_PMC_END) @@ -158,7 +163,8 @@ void nv3_mmio_arbitrate_write(uint32_t address, uint32_t value) nv3_prmcio_write(address, value); else if (address >= NV3_PVIDEO_START && address <= NV3_PVIDEO_END) nv3_pvideo_write(address, value); - else if (address >= NV3_PRAMDAC_START && address <= NV3_PRAMDAC_END) + else if ((address >= NV3_PRAMDAC_START && address <= NV3_PRAMDAC_END) + || (address >= NV3_USER_DAC_PALETTE_START && address <= NV3_USER_DAC_PALETTE_END)) //clut nv3_pramdac_write(address, value); else if (address >= NV3_VRAM_START && address <= NV3_VRAM_END) nv3_dfb_write32(address, value, &nv3->nvbase.svga); diff --git a/src/video/nv/nv3/render/nv3_render_core.c b/src/video/nv/nv3/render/nv3_render_core.c index fc4bce4d9..6eb1f50c1 100644 --- a/src/video/nv/nv3/render/nv3_render_core.c +++ b/src/video/nv/nv3/render/nv3_render_core.c @@ -88,6 +88,7 @@ nv3_color_expanded_t nv3_render_expand_color(uint32_t color, nv3_grobj_t grobj) break; case nv3_pgraph_pixel_format_y8: + /* Indexed mode */ color_final.a = (color >> 8) & 0xFF; // yuv @@ -143,11 +144,11 @@ uint32_t nv3_render_downconvert_color(nv3_grobj_t grobj, nv3_color_expanded_t co packed_color |= (color.g << 20); packed_color |= (color.b << 10); break; - case nv3_pgraph_pixel_format_y8: - warning("nv3_render_downconvert: Y8 not implemented"); + case nv3_pgraph_pixel_format_y8: /* i think this is just indexed mode. since r=g=b we can just take the indexed from the r */ + packed_color = nv3_render_get_palette_index((color.r >> 2) & 0xFF); break; case nv3_pgraph_pixel_format_y16: - //warning("nv3_render_downconvert: Y16 not implemented"); + warning("nv3_render_downconvert: Y16 not implemented"); break; default: warning("nv3_render_downconvert_color unknown format %d", format); @@ -189,15 +190,24 @@ uint32_t nv3_render_to_chroma(nv3_color_expanded_t expanded) return !!expanded.a | (expanded.r << 30) | (expanded.b << 20) | (expanded.a << 10); } -/* Convert a rgb10 colour to a pattern colour */ -uint32_t nv3_render_set_pattern_color(nv3_color_expanded_t pattern_colour, bool use_color1) +/* Get a colour for a palette index. (The colours are 24 bit RGB888 with a 0xFF alpha added for some purposes.) */ +uint32_t nv3_render_get_palette_index(uint8_t index) +{ + uint32_t red_index = index * 3; + uint32_t green_index = red_index + 1; + uint32_t blue_index = red_index + 2; + + uint8_t red_colour = nv3->pramdac.palette[red_index]; + uint8_t green_colour = nv3->pramdac.palette[green_index]; + uint8_t blue_colour = nv3->pramdac.palette[blue_index]; + + /* Alpha is always 0xFF */ + return (0xFF << 24) | ((red_colour) << 16) | ((green_colour) << 8) | blue_colour; +} + +/* Convert a rgb10 colour to a pattern colour */ +void nv3_render_set_pattern_color(nv3_color_expanded_t pattern_colour, bool use_color1) { - /* reset the colour */ - if (!use_color1) - nv3->pgraph.pattern_color_0_rgb.r = nv3->pgraph.pattern_color_0_rgb.g = nv3->pgraph.pattern_color_0_rgb.b = 0x00; - else - nv3->pgraph.pattern_color_1_rgb.r = nv3->pgraph.pattern_color_1_rgb.g = nv3->pgraph.pattern_color_1_rgb.b = 0x00; - /* select the right pattern colour, _rgb is already in RGB10 format, so we don't need to do any conversion */ if (!use_color1) @@ -359,7 +369,6 @@ uint32_t nv3_render_read_pixel_32(nv3_position_16_t position, nv3_grobj_t grobj) /* Plots a pixel. */ void nv3_render_write_pixel(nv3_position_16_t position, uint32_t color, nv3_grobj_t grobj) { - uint8_t alpha = 0xFF; // PFB_0 is always set to hardcoded "NO_TILING" value of 0x1114. // It seems, you are meant to @@ -372,12 +381,6 @@ void nv3_render_write_pixel(nv3_position_16_t position, uint32_t color, nv3_grob uint32_t framebuffer_bpp = nv3->nvbase.svga.bpp; // maybe y16 too?z - /* doesn't seem*/ - nv3_color_argb_t color_data = *(nv3_color_argb_t*)&color; - - if (framebuffer_bpp == 32) - alpha = color_data.a; - int32_t clip_end_x = nv3->pgraph.clip_start.x + nv3->pgraph.clip_size.x; int32_t clip_end_y = nv3->pgraph.clip_start.y + nv3->pgraph.clip_size.y; @@ -507,7 +510,8 @@ void nv3_render_write_pixel(nv3_position_16_t position, uint32_t color, nv3_grob /* Ensure the correct monitor size */ void nv3_render_ensure_screen_size(void) { - bool changed = false; //doesn't check if the res is the same? + /* First check if hdisp == xsize and dispend == ysize. */ + bool changed = false; if (nv3->nvbase.svga.hdisp != nv3->nvbase.svga.monitor->mon_xsize) { @@ -521,9 +525,13 @@ void nv3_render_ensure_screen_size(void) nv3->nvbase.svga.monitor->mon_ysize = nv3->nvbase.svga.dispend; } + /* + if either changed: + -> set resolution + -> set refresh rate - this is just a rough estimation right now. we need it as we only blit what changes + */ if (changed) { - /* set refresh rate - this is just a rough estimation right now. we need it as we only blit what changes */ nv3->nvbase.refresh_time = 1 / (nv3->nvbase.pixel_clock_frequency / (double)ysize / (double)xsize); // rivatimers count in microseconds set_screen_size(xsize, ysize); } @@ -534,7 +542,15 @@ void nv3_render_ensure_screen_size(void) /* Blit to the monitor from DFB, 8bpp */ void nv3_render_current_bpp_dfb_8(uint32_t address) { + nv3_size_16_t size = {0}; + size.w = size.h = 1; + nv3_position_16_t pos = nv3_render_get_dfb_position(address); + + uint32_t* p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; + uint32_t data = *(uint32_t*)&(nv3->nvbase.svga.vram[address]); + + *p = nv3_render_get_palette_index(data & 0xFF); } /* Blit to the monitor from DFB, 15/16bpp */ @@ -545,8 +561,6 @@ void nv3_render_current_bpp_dfb_16(uint32_t address) nv3_position_16_t pos = nv3_render_get_dfb_position(address); - //pos.x >>= 1; - uint32_t* p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; uint32_t data = *(uint32_t*)&(nv3->nvbase.svga.vram[address]); @@ -623,8 +637,8 @@ void nv3_render_current_bpp(svga_t *svga, nv3_position_16_t pos, nv3_size_16_t s switch (nv3->nvbase.svga.bpp) { case 4: - /* Uh we should never be here because we're in the SVGA mode */ - fatal("NV3 - Tried to render 4bpp in NV mode"); + /* Uh we should never be here because we're in the SVGA mode(?) */ + fatal("NV3 - 4bpp not implemented (not even sure if it's SVGA only)"); break; case 8: nv3_render_8bpp(pos, size, grobj); @@ -648,7 +662,36 @@ void nv3_render_current_bpp(svga_t *svga, nv3_position_16_t pos, nv3_size_16_t s void nv3_render_8bpp(nv3_position_16_t pos, nv3_size_16_t size, nv3_grobj_t grobj) { - + if (!nv3) + return; + + uint32_t vram_base; //acquired for the start of each line + uint32_t* p; + uint32_t data; + uint32_t start_x = pos.x; + + p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; + + for (uint32_t y = 0; y < size.h; y++) + { + /* re-set the vram address because we are basically "jumping" halfway across a line here */ + vram_base = nv3_render_get_vram_address(pos, grobj) & nv3->nvbase.svga.vram_display_mask; + + for (uint32_t x = 0; x < size.w; x++) + { + p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; + data = *(uint32_t*)&nv3->nvbase.svga.vram[vram_base]; + + /* should just "tip over" to the next line */ + *p = nv3_render_get_palette_index(data & 0xFF); + + vram_base++; + pos.x++; + } + + pos.x = start_x; + pos.y++; + } } /* @@ -675,7 +718,6 @@ void nv3_render_15bpp(nv3_position_16_t pos, nv3_size_16_t size, nv3_grobj_t gro for (uint32_t x = 0; x < size.w; x++) { p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; - data = *(uint32_t*)&nv3->nvbase.svga.vram[vram_base]; /* should just "tip over" to the next line */ @@ -714,7 +756,6 @@ void nv3_render_16bpp(nv3_position_16_t pos, nv3_size_16_t size, nv3_grobj_t gro for (uint32_t x = 0; x < size.w; x++) { p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; - data = *(uint32_t*)&nv3->nvbase.svga.vram[vram_base]; /* should just "tip over" to the next line */ @@ -750,11 +791,9 @@ void nv3_render_32bpp(nv3_position_16_t pos, nv3_size_16_t size, nv3_grobj_t gro /* re-get the vram address because we are basically "jumping" halfway across a line here */ vram_base = nv3_render_get_vram_address(pos, grobj) & nv3->nvbase.svga.vram_display_mask; - for (uint32_t x = 0; x < size.w; x++) { p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; - data = *(uint32_t*)&nv3->nvbase.svga.vram[vram_base]; /* should just "tip over" to the next line */ diff --git a/src/video/nv/nv3/subsystems/nv3_pramdac.c b/src/video/nv/nv3/subsystems/nv3_pramdac.c index 5597e2f73..f9f8b670c 100644 --- a/src/video/nv/nv3/subsystems/nv3_pramdac.c +++ b/src/video/nv/nv3/subsystems/nv3_pramdac.c @@ -225,6 +225,10 @@ nv_register_t pramdac_registers[] = { NV3_PRAMDAC_HTOTAL, "PRAMDAC - Total Horizontal Lines", NULL, NULL}, { NV3_PRAMDAC_HEQU_WIDTH, "PRAMDAC - HEqu End", NULL, NULL}, { NV3_PRAMDAC_HSERR_WIDTH, "PRAMDAC - Horizontal Sync Error", NULL, NULL}, + { NV3_USER_DAC_PIXEL_MASK, "PRAMDAC - User DAC Pixel Mask", NULL, NULL}, + { NV3_USER_DAC_READ_MODE_ADDRESS, "PRAMDAC - User DAC Read Mode Address", NULL, NULL}, + { NV3_USER_DAC_WRITE_MODE_ADDRESS, "PRAMDAC - User DAC Write Mode Address", NULL, NULL}, + { NV3_USER_DAC_PALETTE_DATA, "PRAMDAC - User DAC Palette Data", NULL, NULL}, { NV_REG_LIST_END, NULL, NULL, NULL}, // sentinel value }; @@ -301,6 +305,21 @@ uint32_t nv3_pramdac_read(uint32_t address) case NV3_PRAMDAC_HSERR_WIDTH: ret = nv3->pramdac.hserr_width; break; + case NV3_USER_DAC_PIXEL_MASK: + ret = nv3->pramdac.user_pixel_mask; + break; + case NV3_USER_DAC_READ_MODE_ADDRESS: + ret = nv3->pramdac.user_read_mode_address; + break; + case NV3_USER_DAC_WRITE_MODE_ADDRESS: + ret = nv3->pramdac.user_write_mode_address; + break; + case NV3_USER_DAC_PALETTE_DATA: + /* I doubt NV actually read this in their drivers, but it's worth doing anyway */ + /* Bit 1 is listed as "read or write mode" and 7:0 as "Write-only address", but NV only ever set this to 0 too, so i think this should be fine for now */ + ret = nv3->pramdac.palette[nv3->pramdac.user_read_mode_address]; + nv3->pramdac.user_read_mode_address++; + break; } } @@ -390,8 +409,31 @@ void nv3_pramdac_write(uint32_t address, uint32_t value) nv3->pramdac.hequ_width = value; break; case NV3_PRAMDAC_HSERR_WIDTH: - nv3->pramdac.hserr_width = value; + break; + case NV3_USER_DAC_PIXEL_MASK: + nv3->pramdac.user_pixel_mask = value; + break; + case NV3_USER_DAC_READ_MODE_ADDRESS: + nv3->pramdac.user_read_mode_address = value; + break; + case NV3_USER_DAC_WRITE_MODE_ADDRESS: + + /* + This seems to get reset to 0 after 256 writes, but, the palette is 768 bytes in size. + Clearly there's some mechanism here, but I'm not sure what it is. So let's just reset if we reach 768. + */ + if (nv3->pramdac.user_write_mode_address >= NV3_USER_DAC_PALETTE_SIZE) + nv3->pramdac.user_write_mode_address = value; + + break; + case NV3_USER_DAC_PALETTE_DATA: + /* I doubt NV actually read this in their drivers, but it's worth doing anyway */ + /* Bit 1 is listed as "read or write mode" and 7:0 as "Write-only address", but NV only ever set this to 0 too, so i think this should be fine for now */ + nv3->pramdac.palette[nv3->pramdac.user_write_mode_address] = value; + + nv3->pramdac.user_write_mode_address++; + break; } } @@ -407,7 +449,3 @@ void nv3_pramdac_write(uint32_t address, uint32_t value) } } -uint32_t nv3_pramdac_read_clut(void) //4bpp/8bpp -{ - -} \ No newline at end of file