From c48e530cbe66934909daf9bd4f898cf1f813d131 Mon Sep 17 00:00:00 2001 From: Josh Dersch Date: Wed, 2 Mar 2016 17:31:19 -0800 Subject: [PATCH] Finished up configuration UI. Config is now persisted to a configuration file. Small fixes to UDP encapsulation to ignore packets coming from the same host. Small fix for PInvoke for high res timer. --- Contralto/AltoSystem.cs | 21 +- Contralto/Configuration.cs | 43 ++- Contralto/Disk/allgames.dsk | Bin 2601648 -> 2601648 bytes Contralto/Disk/diag.dsk | Bin 2601648 -> 2601648 bytes Contralto/ExecutionController.cs | 11 +- Contralto/HighResTimer.cs | 2 +- Contralto/IO/EthernetController.cs | 48 ++-- Contralto/IO/HostEthernet.cs | 281 +++++++++++++++++++ Contralto/IO/HostEthernetEncapsulation.cs | 4 +- Contralto/IO/Keyboard.cs | 3 +- Contralto/IO/UDPEncapsulation.cs | 17 +- Contralto/Program.cs | 22 +- Contralto/UI/AlternateBootWindow.Designer.cs | 142 +++++++--- Contralto/UI/AlternateBootWindow.cs | 67 +++-- Contralto/UI/AltoWindow.Designer.cs | 57 ++-- Contralto/UI/AltoWindow.cs | 55 ++-- Contralto/UI/Debugger.cs | 12 +- Contralto/UI/SystemOptions.Designer.cs | 16 +- Contralto/UI/SystemOptions.cs | 107 ++++--- 19 files changed, 701 insertions(+), 207 deletions(-) create mode 100644 Contralto/IO/HostEthernet.cs diff --git a/Contralto/AltoSystem.cs b/Contralto/AltoSystem.cs index fd6eb10..c262144 100644 --- a/Contralto/AltoSystem.cs +++ b/Contralto/AltoSystem.cs @@ -65,10 +65,7 @@ namespace Contralto _cpu.Reset(); _ethernetController.Reset(); - UCodeMemory.Reset(); - - // Force the boot keys on reset. - PressBootKeys(); + UCodeMemory.Reset(); } /// @@ -126,18 +123,20 @@ namespace Contralto _diskController.Drives[drive].UnloadPack(); } - public void PressBootKeys() + public void PressBootKeys(AlternateBootType bootType) { - // - // Press bootkeys if the user has specified a boot combination. - // - if (Configuration.EthernetBootEnabled) + switch(bootType) { - _keyboard.PressBootKeys(Configuration.BootAddress, true); + case AlternateBootType.Disk: + _keyboard.PressBootKeys(Configuration.BootAddress, false); + break; + + case AlternateBootType.Ethernet: + _keyboard.PressBootKeys(Configuration.BootFile, true); + break; } } - public AltoCPU CPU { get { return _cpu; } diff --git a/Contralto/Configuration.cs b/Contralto/Configuration.cs index ac99029..0e05b39 100644 --- a/Contralto/Configuration.cs +++ b/Contralto/Configuration.cs @@ -41,6 +41,18 @@ namespace Contralto /// Encapsulate frames inside UDP datagrams on the host interface. /// UDPEncapsulation, + + /// + /// No encapsulation; sent packets are dropped on the floor and no packets are received. + /// + None, + } + + public enum AlternateBootType + { + None, + Disk, + Ethernet, } /// @@ -53,8 +65,9 @@ namespace Contralto // Initialize things to defaults. HostAddress = 0x22; - EthernetBootEnabled = false; + AlternateBootType = AlternateBootType.Disk; BootAddress = 0; + BootFile = 0; SystemType = SystemType.TwoKRom; @@ -98,18 +111,23 @@ namespace Contralto /// /// The type of interface to use to host networking. /// - public static PacketInterfaceType HostPacketInterfaceType; + public static PacketInterfaceType HostPacketInterfaceType; /// - /// Whether to enable Ethernet boot at reset + /// The type of Alternate Boot to apply /// - public static bool EthernetBootEnabled; + public static AlternateBootType AlternateBootType; /// - /// The address/file to boot at reset + /// The address to boot at reset for a disk alternate boot /// public static ushort BootAddress; + /// + /// The file to boot at reset for an ethernet alternate boot + /// + public static ushort BootFile; + /// /// Whether to render the display "interlaced" or not. /// @@ -140,7 +158,7 @@ namespace Contralto while (!configStream.EndOfStream) { lineNumber++; - string line = configStream.ReadLine().ToLowerInvariant().Trim(); + string line = configStream.ReadLine().Trim(); if (string.IsNullOrEmpty(line)) { @@ -161,7 +179,7 @@ namespace Contralto try { - switch (parameter) + switch (parameter.ToLowerInvariant()) { case "drive0image": Drive0Image = value; @@ -187,14 +205,18 @@ namespace Contralto HostPacketInterfaceType = (PacketInterfaceType)Enum.Parse(typeof(PacketInterfaceType), value, true); break; - case "ethernetbootenabled": - EthernetBootEnabled = bool.Parse(value); + case "alternateboottype": + AlternateBootType = (AlternateBootType)Enum.Parse(typeof(AlternateBootType), value, true); break; case "bootaddress": BootAddress = Convert.ToUInt16(value, 8); break; + case "bootfile": + BootFile = Convert.ToUInt16(value, 8); + break; + case "interlacedisplay": InterlaceDisplay = bool.Parse(value); break; @@ -251,8 +273,9 @@ namespace Contralto } configStream.WriteLine("HostPacketInterfaceType {0}", HostPacketInterfaceType); - configStream.WriteLine("EthernetBootEnabled {0}", EthernetBootEnabled); + configStream.WriteLine("AlternateBootType {0}", AlternateBootType); configStream.WriteLine("BootAddress {0}", Conversion.ToOctal(BootAddress)); + configStream.WriteLine("BootFile {0}", Conversion.ToOctal(BootFile)); configStream.WriteLine("InterlaceDisplay {0}", InterlaceDisplay); configStream.WriteLine("ThrottleSpeed {0}", ThrottleSpeed); } diff --git a/Contralto/Disk/allgames.dsk b/Contralto/Disk/allgames.dsk index b33f0be0681dc71e48732a135401d104bce6079e..aa6e380f51fbbf67966e21e55d6e10802e081865 100644 GIT binary patch delta 1292 zcmZvcT}V@57{}jpI&Np@ocXzyuFa;I=0_(tGFGH*Svt_tma8zbmRng(r!(n`Ladk< zM%F_aQCjq6WzYw8Zn_AHl0G233M#~)@+uO%=%S$KcuL+@7r%4(|M!2M|2tl`JD>WQ zJ1Rx2GddeJEC%n5&egRA%wK@9?9q1P~%u9 z7gu|T3|4(B4C<>*0!AVjVaNniu5XSs%5pPI>MNj?v%*r|0zI77Bx2|w?kB`&sNna9 zeexPVT;qJX=nzs&+{BJ=mQ|}dgCs=i`AV_e2{m{^aL7}>i(f6&c^ux~$8Rt!GppTLU5f|6 z)iZvV!#P7e2tp8!3O@LlPyjvpbdYq5VMHkD`*}mkhc2B3S_Ctk*R4-IGu6B)sm>6J z%Deqo4qtUS*`!LGvUD8Vah!Qz4JCw zTAM9|D|z=Q_X0f1cT-wRt%8xlvy}S)#uv<|w3@oKF#cO6IccW@3KliR&9oV9;9mTg za*xA$S1qNr{t^f;9i-f=(6!7(X)RR+XUa}ZyA#Xlb}bQtrz`eNC$zhMy^_uyf^QXD z;}T*)I&fXTY~%&H?cf6V4*5LU7I zXWUf;C;r|vl(!Nmu;QLbs3{zlBOOs=-vpbGr?`jpBTVdbGKVA}Iz*4~hyf805s?rh zl87WB$w&&4s(emPyY_-p|8JDucWEZpa8pN!1B-L}QZ}<5<;{n*A*RnhE^)E`(KN(_ z%tXw{EF>MtKrF~?#H#d<+D@G`lra&hX-_y5QIfvrd|_ht_Dp0BVn?!&Y-BEygUmy6 K6?=PL@A6-wFsx(% delta 1491 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 z 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

?N>@yr0hh zunwmcdPzm6^@kOTZfo)}qom26`&(hhOYk+A?K7QYLSeAyb8&DlqLA8^TE;Tgf=E;1 zXoFLAYC>annsg8+_Jo7A5d$%=WTy=rgsre6*)&ShI1TCI5+{=HG}TjV#uZwV<^EWw zI$gWanW;K~{-){ICXJ!Rq0Ka)--6B{80)o8g8{Q$b0JJugyslz`?1bQgZ72(7RgV- z9VX3S^J1-KaL2H4B!uE!R9;%H6PZqJ(29=lbV75U)*^6SCJty!7q4OoEv;8mLd|Y% zsih@0U!AU7=(MQlfID_rkx~e8d*nw~Vi4Y_*JkTa2~D|bzmVNkN5XeakzI+g2D|E1 zL|rxxh?0qDO3)14i-Zm|$)7IKXQFl^2WJ9`-o%~7ja4zo*#G)NOZZ=YWT2*=S|kmA=!lxpc~EP>Kdx8HW}AK#CbZ(m zBJ=`y^e!mVtg%Fy_$M4`v|s|~`g;L`5{u%NjEdF0RC$|btPv-O;OH8B} znp^Unu=EKQMBto^i%-7Vj|d*la|p&dtVE1$hBkpkuv~5O*E!GQtI-Zzk$$6M2{5#r z*e-mwBCHRHEqPApC9%25#Px>Z1gLQ*=~Ux>iu6m=q*oj6!jU9+?6Slm0Zu$nPy`mS zWha{7jyxow$z&Cc;T%{k{_?S^%A|Ys;a|kCWt?eX7)@XywUCYr>z(7&!gmbBCZQf*+@TLi z34Yo4w-E_)=OQdL#T98-&#cfWP-4nK(UeT`Z)fVq_^Rx$;08Q9ap26=>cr6%*l#x>TaZP*&wWf^@&cKRfL`bPb7Y?5-)_V!^|a#qe0Z+H(K> z&QhbKcB)mlfzHIui4@zeHD$KO3Z<6&A7g3x-28dQ=dlP%aLb6zy|`G6igh?MV^1^* zmix)(OXs;s{*lgv!N>B{^ILXoH+?3lx2vVn<4LAiVY~Ec`$&_;7#nG_v^*w68e@-b zw|wev5^!gUADW9r(Bh1T*3`1YVUi@ZLoFH9R#U9#kYeM}Q5j>krZ{NTM!GAAt@AbE zX_&+;FL{)g6S!^oeqJDUT4LLAZx3;)BBn&wH6a;vN>(m+Cx%iN=&wo!_LBVCGX25mFMGZbzub$oOHZ;M=4ro_F3QdG^pA(Wyk389 zzWA#A=g0KprTAj`>&Nu_lG23-8mm6+>!<9}Zzn?UVZ|XL_`@#{j=)ke_;ZtAdR+gE z`uB|wG|Kf)=(95)XpB2K@r`J~4!IreRlvx~1-fp1@Ap7s-pOezA85>i%|~ka;uHD= z9YuzKWlk-g-gBsvy(740h?XuSEP_Kk+uzfO3dk-miok7P*1L0|1jFB`1; zTBu%4wqFZ(pA>}~v*LuC{OeYKEfnP4b@J|$d)7Q4KYu_UZ>nD1eR6fy*FyLAjJi)2 z=M4>sxKY9=>*ojbUyjrpXZ$=3muI2%W&h5ezV*HF;lhJrQ9a&Nxu%V}=Q# zGj~ew<3Rh84<)w}8+OVJ*{LQbJCr6R?;|4YSQ)aNPa4+Ai=K;^9lHH)sZxwflhTaI zhsY#>o#lr$N2L3XMN9}K-XonCjcLX-OBz+6;$#_78+TFEfHTvKM1=h-<8@50AvILk zBE1P!W?D{~g~+gPWgOS>a>Ue7E7L+^!_JS99{>F;J=JOTX=Ox&eIG-%XWxXWq2mv-L)NFY zrd1OgzK;j%KW0b{oqk9k_qg-v_omF#9BCe;J6_@ zq}?Z-274%7O4~yT2ZcMkNOT>oVAwxEH zKa*L~Gt-SkOjcx}^v4;InVyqwAtFg3?)zw>B~)=hI)~_T(hJiwi3~f4MgAP`MwEt* zJ|zXg7N(b_=MWoqn+kTq6Y+_mdk^9j-WYJz>4n6GU1uKFi11A-i4*0$znCy9bmEY7 z98pxK*Qb|}QP_(j(z~aZC96KYHNBdMuoFEHy@wgmngg8EX}cJz zx;AEpS{wGD0_Gdf=vzabFGzQZqw$1$zmoQY&CJiqw-6g%O%L|DS0}6sz4(gs2-uwb!u(8P!z-$hiCce7nE+e{ zXDT3O@EUA>l@Vq6)%k@)gx6CdzJn2C;zGYXDGegN>iqirGGfC^>cF0A8tD!hPDz;A z4X!nxl}vb971#&-BYzp%`G&LvY-|3${Cd)cm)20s^&90|+(DHL5BdwwAGtz))ERYI}`G<&|$Mcc;Cdmqn1(pJdi12i1#OFB6 z2und`fsu&tY*-N2yv>Nrf}8>i5e^G%>I+&6s)=xM;>`~j(OR&t zpq_|DoEW^wh{VR*=9Q85(5Amjr$nRM=(e~eVwZ4sa7tuesQDk#QLq+wrrSvD)jZ~P|D*%~&T(6a z$mg<>U8>B`BVSR+2(HkbN$gTCyX#*}R_HEs=Mb@s6J6gjqRd_GE+k?(kMFgO=K1nP zwd#xZ4^*d&pzGabWKh7B{i2FeQtxhcR}-;<6X#TnXm#&%*Ar35qdZtRCLv^qP+de4 z_qh+bTZvuCWieXF#=8#{OYVI{xE11!g4?1*;hv~HQ7ds59UpQ=sc&@`hplr72wQbBN3}OF<(0|L6lD|i5x3;#H!vf!XT&E zLMGw&;y4q!4o8*A>G_eT390hO@v8ks z7?l<0kl7l3EPu?zF`|6+W1~mPr>;<)HNv2}xR6Z3FSOBk4TX`JqC7Z;j#FJ+UtC6P z36J2^KosSozPPoxnuxXkMzj|1E3PME9VZ6HsuD#x(WJUC9^9egR$|vH?DA``*Neif z`lt2lSlP}nv$8!@A{Fl=yHXxY+9WEy5~;*ke29n*oXD{;!dPM{k%%bcL~#-$EG3yG zMj|$HVoM4mGD~twEJS!X5x9~OIVFW9nM9Ox;(;lQC@d)}$suABCk{?yL|I97Ng)x} zapL6+MpT#7my{7vp%8M{cyY3vZy2MO51K_|$YfXH<_uP?CDmlNncK}Zj+rk1b8f=) zQ1J}a9+?^4!lk2%j^DFB4p+(uMm%;8UIaJb0>eN+tVch98~FO^D-C5OoFMjpYE`ILoHW2vQ7B4P_CN*#=_lxCJ1iMWXq zH|H=SvoxpFLPQlOb~+i6Q(9P>NksVFIojI3MT{scEi26-qFPbNudRqk4V}wV;r;yB5FAC^)g1ZmhLO9C*o#K7*>Et1bnEp zm584xL}K-z4ws>*1yORwTHWZ-qLr+e4tb=~ePmb5BbZx6F?%GBvGfoTw{W6x6(fuu zi$@~jR!&r`W`xC)=`j-VQ-zTI<*L!4wrf?GLj*3zV25G!hYh z4+0{pjuDxiIh__F!h`Z4Om{FMr?ap#lZajX;4>N+QP^45nL|V~C-NH^QPx@ASx7_+ zC(3p(qPnxbvy6yVPSoDbi2Baf&T1ldbE5g5(rcoOEAyx-0UW0$2%BBFy6-^h%x zbY*rKiMXE=#s?UY*_G2}A>si}BzH0*r>n3llZXd7F@Fyu3cJd>a){_u2synisx|a} zm#SJcf~)Q-B=#XLyM7;&RrhChl@YOr6aFBG#?Nmvgg(D5_G4{KS2fWO^H}rs2`579 z9#zd1jr}?Oh5alsU0i%%KgHT#=v~>*60=t!?u$)09IAZ+1>0!4Cl-I``0p7ND2VFQ zz?(6;nUB?S)tj*n*Fgeu@&U_v!4W+J5sz>py${5A zz`c6B$PlDQ72>u%>s6v~lWM!_5q9C(6rvtg-)m6ogJid#M^N$$irJtx#OZs9cuXPW z=6j60Q8Lg!wh`$TXagOk{&xNP88Oy)6o4Q?WS&WSHxVT9KZFnEYK$m7dTj7@Z`Dp#h&5g;%aEW1=Kc z+0(~);{tIWvX;2P*>)JHh7H={f^h*dP!B`FxZXIHOAXgd=!7Oh3_13UiI$?(32|}A z4rc2zBuk08C#oOdU95}d^AIpRt1Cb$V1!4J}isv{nF43B(CWE+P z$eL(RWI2iFn%kd+X7sRuGtr%BC(RYy;PDq=kihqjy@b6n!{*+^K%$4t$8v*laqKWM?5C4$xVojE8ck=OvKJj^wOZB0r*Xt;wOd&}rf|isPoS8}d8gHF zwUc5RLr?_iobp(`RyR=@9PwHMRu3VW3L<~|6(XC?`8I3N8X(@zk)XBL%CeB9Angmr z>ZBQB$S`Uwoe9Zt)?O0KR1oQ`L z;)pjbkmey|30I6rgW_t=x1|Ns0>tNYB$(El#`3Y0E0$+Mu}ln^T&x<>vQ*|}r0)Y3{G!B7q&aC7rOdRw}e%!?R;GQNgW z!SvpAmbO(K>9woVgJfLH&)UkRW22Zp-!(eg*sPRV+hj z?6>)#*sAPB$IZ3QRTE#$5$jz0T$Yb*T=9GZ6kg6d=epu4jskt4lMwIfJKlNcK85m62I^gyvg*^7>IT4}0>fFb%Y zA8mEooh%=BbH(c+D0Xt*>2y2oq__vjFUFz>?&Xxn>2e-CW^20Yw|GV!uQ3qt$tF&R$ZqD~S9=KluANZ_Tsk#St%a z#GdEGj1?dqT=CHxP~6XXcb&T$J<+Wl!&pb6eeNGWg{%WOdu!EECUg&Bx=QIXZ0Mbi3Vl z(mcxz#+qR89N$Z~VDI^1bFVw#_K^88Zcs8A1}_X7w7G-s02#bE33{M*o&RTR#KeciV-uR_%-L<#hzj( z@xS4Sr`TKUCgfGFSUwMme$EGq+lsx!pTt|g1ym8QaVl8cTiiy}>m2DVQ5OdZIfd(V zKWj@RamBra{FWneCDsx(A#ZTRT4FDWBjk4+v6nbYST;^`#M$O7v6Id36{PXX!f~N1 z3lrCsM6wM10X^ZM1!vrY2NQMDACnY9sEBzZ|$;o#S#A{N9#kZUfbhUMPNpXqu(dzL!X^8W|uHLRT;?Z%1Q{5X> zcLfO%rO-j+cvQpEC@3UlFFG!04XTM(al{(52U$MwQa`NNWq?A%d1ufaw38x&A*hB( zPI-dfpqnTyN4&v6&_jq$LF8}8BC;sXw*`a20P)cr2?l$EEDL(BSYU=?gcK?*pF}4@ ze_XJa6fp`Cy1_Pn#kF|gN;H~}k{y5?dVL*N-YJyIRRaj@gyWdW%kpK+Qlyvty zX@6AMpwS#V0e=(mX9}5P%|E?I+wUemP6~H6^3S`>Iw@WX`9GqrM^hSK(ntJg1(E+8 z1b+qRZKYYIG_hSu;7C@ftJFrw7_J!q1QcUAUsPIN>LPv|N6JfUN{a|dkn% zLuq?y4e=8=e|I1FiJb2)?JI33-o%kUkEXPn5VNEVHuXPaj*=|Op57DhDfeJN6|-Ly zDD>s?<}$5h9k!_PGL z>_x{{+A1}~&*X@$GOLp1BbzHGeh$Sf&bum$Dziv2n;|HIIh-o5tf?#_YA#1=DjV>* z8zA!(M84+|BAd_o_R8+c2I3cRq`R`Ol4Zfc6|bu;I%y#?L}QNnDos^^%3gH5*XGp_znmjB zZdl2hg08ZS${n=?iH5-Gto6 zGo=q8Q@8V62jT;^fQAfw!;meI6^JLu&o#^Lf~IcRz!fM8WRXEVH@Nj)7~H}4nwzl~ z7&fm7Gz7}Yyn!1WZG*v`!v^hv?mz<>G!8@EfxZCCNfXyxdH|Xoxb8m0Dx)br&_|NH z7=p^Un^U%?tR|NHogB$(ay8k=_#Oq3Z|p{~-OKr+rt&5i@w+%u-c-|6L`XAN{QLd@JYw{B!WTIp5vX*VImY8%O$fYMQzUX~$*vIqH|jABN&SWiL8@r){T( zc$p)%omo3sK03H!{ZT0H=e%oY(atPVJirhX!GoMC-&wP>h^S7E)a-27Sx(493L>9; z8IkSbeEZJsoeji4%#rS$eLGney0~KGNhtR6Dr(j=$M5VT$v$31vww>!`WfFV_#O6w z!{%Adu4WsVcXNa7e}us!!v;mo<;^ZKcyt&lZ?0)(`Pk1j&%FiBW5Wgw&F#%Kq2DgJCB_M!`6Lmn&xh@eo|7N+@@SWmY!1fqT}0aZ5rZ#&JkN%R$DwF2f5;= zkD=({ysNFKEsOX=3_%?{&8hOXnl_g9UXIkXHMEtJai4<7Z+(f#4s*V}t-Gy(_z*|B z+xptt2|2WC-)C`Yn7Tpcz-p5=;r zbWl9U`J#^U4j1vybELeZri10<7+1VL5{ef%-_X(CQA3Isfy7Qi5xm5y?vB2WcA}1R zq_0!c(M`y&B>osU7LmQI>_x|S+B!AFzrqn)XI3Z6!U?YMnV|SJ=Utseomrdvz(BVT=7vV6t8iY@mpN5 z*|VUgE55Uj6mKYqd~Fu^-*Mj7mDLqb{ArG4b-B81g#4Z>9-0HiA2?ssRo>+y{*N3f z@2cry`8dNB?<|DkPn>V)YVWEc#hcP$=cE`(+r{$mXU=zb^>wuqf0iSCK}}aTA#dTz z9ex(fM~rVPd(rVhTTny%I~=hEvw|!i16;AI5Q=v>?+O+Lvq*7{^UquZ{yol@2Wx^w z#GmI#O|T(YPRL)l;@c7^-sgOKusg`|@mG#?2m6979~Zb{!A2o0owr$ z8T@k?vK`1ez;f~>*X#*E^VP6{>p;o5rD22i1KkH2$Y5v~>ORnSfaOF`DNl{d+My9up(>f4%ryt&5A=~lVhAci#VOmt ztb;81YK~+bbRD#ju|`4UXCFqfMR308VEI88@sS)UKUj0Hh!8DT40S`H<9x%x_JcLV zM{)kj$H7N)zWZR`!FJ;H9O>)T9PB1!ger9E2(lpGco2#hWiL9u*Vd~cek4b1y;;31 z9|o@Y`C%wxIq&K%>dhjBks&C8QJgC8t?4ZyDvl#Hy$!wPgv2X|JpKhlHk$M8z1_VH z#9zUY?%uv$mW2eaSpNzXV^pE^H(3oFiSO+r#aIQA?|v2hIL_OSWF3hoK9M6?M_fm2 zgpB8klfQ*x0_Tg4lpk>sKanHlM{16+e3-am`q$VqS`lInjZAUd^kTeY0j%FQYnMmfE=Pp2#GHl>FT68pv zG^yO+gNrb@QrWxj6YQi7Th|Z#q{W>pQMF#xiYJg$5I?XmNDD`tVQggiFILq){1(E03 z5ZOG=w;%65&hk5-Bi+aQj?6gGMV*g}OZ@2}}EB6g($)buy>mlNPt%$Kf$d6B}l_jmU< z5POXRbocl5v&64b%y+GYd9f-~TE&X~RD6FQ*{@a*`I!yi*Kpo;D(h4{@z-)B>y+!1 zjgS(q`1U#|)^fh+RQV|v@#{EJeyZja%ffoDSg-|(QqDJ=YCly&iVX}w(U)w>icc1Ay(@y+PInsAlbEcb+ z?L0$AA4i66<2gPXf7W(ZLk71GL$M8KHESBcMe0{XZy~woHTOHQ!hZ%gsb99tRe>D z&-RgI2SZR1cX7%#kTt-Pe>X?623!L+GTx~m^7wuf+dZ5w8Ymxd5q~d7$_Hu&iU`@o z73<%CqM7pz1MLGf#J6z%?mvKU<$U)*-#|O@yE)Q#UNg{5NE@zzb87ZLR!M{3SDoG&M& zQ$gh0K0;&r z@8i7fLe_gL;Pb5K`}hesqPDX7utz>f+KwwH5a-GIl!CM*%(`t^dxV07vnG5E^5f& zsbR==G3#PHK|kl33GvVz95!%WEV`IQ20h$h$ruU};Q!OZ*~dvy*KvG1hH2rJ*m9XxU3IIyVZ#+R z+ncsnVXeJ!i&aNk#zN7gZZHKk?50c+N^jD9>cN{$GqH!8N`dI%=1M{k6-7Vqe`hLgXXa4-X-=ELC_WS#>ue}3)+r$20klvBLk(o?Zqp?V%#v1tkk%5su z_KyUF4q`3T;KC2AMpDfew~wpvN(Bb3(JLIhq6OLe$mlZU#d!gyb^zuC+2jR@R(9tAdqfq~{=v!4S`hiI@l z)C?xsjLz;0sPoJye^zh~tqIK`Zfs#dTd-A#u2y#|cGxpRv+7!gk3q0>~>)XTSKh@wmSqEYL9LW zGT4bB+6!oiU6`^xq21LU&4Jw^>S}klg8}xSGwoXH>gF*JAbNCkO92hkmzm0cajwtOR zuDlTt+Wt48)QA@0FH`Aw3q*_P5&kl+j)Q_UX5U4db_m{#Sd<`t7{rR$5tGT=Xe_yh z8YA#d#H9rJf5LCLkNgpMFXB^z{J%haNsf3-n)D0nG8&;VZjc)P7OPH0QYk_HKOm~4 zNx>ZdMdREDsnLShB~#M4@lHT!3;qXXNw#FNItpS-j$|=u3({CML=Srx-jzJbVgDY8 zC;3t^!Z9?Ct)xao692jwm7|K}bL9g9H72d0BkI7ayp~p@!nhXIqbkQG1m>-y!00ew zMy;sM0Xalg)Q$#od=Q=G8>tfw15VV9+T0lvA~)*M?KnbX(HYrFoz5`e$KQ%V3H~5 zoSddkUJ@5@g+WT zD`_W9CZ9oLbDkPScqi#5ZT6p)hDT24gZLbjm-Le^tEnJ&uFoJpN>7|>H@O5@I%2t3e3fzM;L<}6x$A&lE8CuMQGg22HU z6zB;9ZpuqJ9MD7LrTkPd$yw-3KA$>ONnF68FTzjxT=^oAI&Z?4pwzUMR#?pd(b9Ta zWl|HQ@ym;7N6&^g(^gt%e-4P1w$mn)bJ5r{hZ+XFlXlZK`}5#C=aN4k-b?#wm;IMP z{EVFTnA9a)z?n~tnPSzcWYmnz-ULxIS|*s|0yOTth8kai*E42DxAcsKdW;k~S%b=hA5;^*Y7$7G&_YdA}&F<-1Ym7JQB*b6(D2Z-aO_KNpPf9W>7M zsqtM&+`y6ZO3vrTwSqLRdx-q^;MKgASJ+<%qUH6x%H(=9R;{7NLU=Q8<#qNqfLM7u zAIz}`jbrPmu^8UTyLp=%-zT!3|0MnZ%FFwCm(`6RenHNAOm4zEd)^j$XZPc+Ur-8a zLFRxHBDJ6uf+2p0&hl;4xj78z1+$=W=N1IE@1Vesuo~G#t6RgkU2qB($8SR*wT}X~ zhXJ?X6&w!S5hAbP7lKLdMCalI)cG-eUi z>K7n>NiKR!?hOW_ACeZ1nn-_%AXc49NiE6j?*mawS}7P|2^y=%P~(1hy=0a&Zu|=V zt#Rak4R4j~lF9xzAa=|lSB4(84BjkTWu5(U5UXsLgAx9S#wn*# zV+FiZcFQ(5{scc`3i&_7du6}uvi}Q+Uy;imlfTl(`TLi2x~VZFR-H;kt;p|K{(;6BIyF|oyA`kEuzwiD ztN4{*j@4)^s!?MNecS~%b>ym2@wxGcG<^R#d<<)$)T&lhSUn1&RrRXMQ-%TtcSnwQu0s1dsV;cvflvW*W{|lWTPZ5 z>CC0VruP?}N=>cFY@ZfDt!cGjh|MCtXFkQB5mv96HI3t2B>!q2eyb2x&90d&o)y5Z zIW>#Ha{@Ruw`MbVUI4e|)f@&d2;kNHn#*9D0KOsDf|vdxeNqRPb!0=S`5bu(L@`t& z7+^byYG{VSnH?aSp&Kfboglhl8XA*bAf{m%I+NWXmSGzvlRY4|;TRT^y&#U^8a9)c zL0rQ#947lfJi|9!Ca-|_b=mNkyc)dK>A$E*0s9AXn%;b zx?Wcq9SD(LH|rXsH$r6At-8+WO@SJDZ{paFx59v3cj^`g4u;5yMCvx7$RUA-7c8AP GP5wW|w^t_s delta 73092 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

g1|g3T@<)Vx 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 dt$FCVb)GGr)#Mt~^!FdZh7_#dHD{sz{{a /// Runs the input state machine. This runs periodically (as scheduled by the Scheduler) and: - /// 1) Drops incoming packets if the interface is off + /// 1) Ignores incoming packets if the receiver is off. /// 2) Pulls incoming packets from the queue if the interface is active /// 3) Reads words from incoming packets into the controller's FIFO ///

@@ -379,13 +388,16 @@ namespace Contralto.IO switch(_inputState) { case InputState.ReceiverOff: - // Receiver is off, if we have any incoming packets, drop the first. + // Receiver is off, if we have any incoming packets, they are ignored. + // TODO: would it make sense to expire really old packets (say more than a couple of seconds old) + // so that the receiver doesn't pick up ancient history the next time it runs? + // We already cycle out packets as new ones come in, so this would only be an issue on very quiet networks. + // (And even then I don't know if it's really an issue.) _receiverLock.EnterReadLock(); if (_nextPackets.Count > 0) { - _nextPackets.Dequeue(); - Log.Write(LogComponent.EthernetPacket, "Receiver is off, dropped incoming packet from packet queue."); + Log.Write(LogComponent.EthernetPacket, "Receiver is off, ignoring incoming packet from packet queue."); } _receiverLock.ExitReadLock(); break; diff --git a/Contralto/IO/HostEthernet.cs b/Contralto/IO/HostEthernet.cs new file mode 100644 index 0000000..f6a9617 --- /dev/null +++ b/Contralto/IO/HostEthernet.cs @@ -0,0 +1,281 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using PcapDotNet.Base; +using PcapDotNet.Core; +using PcapDotNet.Core.Extensions; +using PcapDotNet.Packets; +using PcapDotNet.Packets.Ethernet; +using System.IO; +using Contralto.Logging; +using System.Threading; + +namespace Contralto.IO +{ + + public struct EthernetInterface + { + public EthernetInterface(string name, string description, MacAddress macAddress) + { + Name = name; + Description = description; + MacAddress = macAddress; + } + + public static List EnumerateDevices() + { + List interfaces = new List(); + + foreach (LivePacketDevice device in LivePacketDevice.AllLocalMachine) + { + interfaces.Add(new EthernetInterface(device.Name, device.Description, device.GetMacAddress())); + } + + return interfaces; + } + + public string Name; + public string Description; + public MacAddress MacAddress; + } + + public delegate void ReceivePacketDelegate(MemoryStream data); + + /// + /// Implements the logic for encapsulating a 3mbit ethernet packet into a 10mb packet and sending it over an actual + /// interface controlled by the host operating system. + /// + /// This uses PCap.NET to do the dirty work. + /// + public class HostEthernet + { + public HostEthernet(EthernetInterface iface) + { + AttachInterface(iface); + } + + public HostEthernet(string name) + { + // Find the specified device by name + List interfaces = EthernetInterface.EnumerateDevices(); + + foreach (EthernetInterface i in interfaces) + { + if (name == i.Name) + { + AttachInterface(i); + return; + } + } + + throw new InvalidOperationException("Specified ethernet interface does not exist."); + } + + public void RegisterReceiveCallback(ReceivePacketDelegate callback) + { + _callback = callback; + + // Now that we have a callback we can start receiving stuff. + Open(true /* promiscuous */, int.MaxValue); + BeginReceive(); + } + + + /// + /// Sends an array of bytes over the ethernet as a 3mbit packet encapsulated in a 10mbit packet. + /// + /// + /// + public void Send(ushort[] packet, int length) + { + // Sanity check. + if (length < 1) + { + throw new InvalidOperationException("Raw packet data must contain at least two bytes for addressing."); + } + + + // + // Outgoing packet contains 1 extra word (2 bytes) containing + // the prepended packet length (one word) + byte[] packetBytes = new byte[length * 2 + 2]; + + // + // First two bytes include the length of the 3mbit packet; since 10mbit packets have a minimum length of 46 + // bytes, and 3mbit packets have no minimum length this is necessary so the receiver can pull out the + // correct amount of data. + // + packetBytes[0] = (byte)(length); + packetBytes[1] = (byte)((length) >> 8); + + // + // Do this annoying dance to stuff the ushorts into bytes because this is C#. + // + for (int i = 0; i < length; i++) + { + packetBytes[i * 2 + 2] = (byte)(packet[i]); + packetBytes[i * 2 + 3] = (byte)(packet[i] >> 8); + } + + // + // Grab the source and destination host addresses from the packet we're sending + // and build 10mbit versions. + // + byte destinationHost = packetBytes[3]; + byte sourceHost = packetBytes[2]; + + Log.Write(LogComponent.HostEthernet, "Sending packet; source {0} destination {1}, length {2} words.", + Conversion.ToOctal(sourceHost), + Conversion.ToOctal(destinationHost), + length); + + MacAddress destinationMac = Get10mbitDestinationMacFrom3mbit(destinationHost); + MacAddress sourceMac = new MacAddress((UInt48)(_10mbitMACPrefix | Configuration.HostAddress)); + + // Build the outgoing packet; place the source/dest addresses, type field and the raw data. + EthernetLayer ethernetLayer = new EthernetLayer + { + Source = sourceMac, + Destination = destinationMac, + EtherType = (EthernetType)_3mbitFrameType, + }; + + PayloadLayer payloadLayer = new PayloadLayer + { + Data = new Datagram(packetBytes), + }; + + PacketBuilder builder = new PacketBuilder(ethernetLayer, payloadLayer); + + // Send it over the 'net! + _communicator.SendPacket(builder.Build(DateTime.Now)); + + Log.Write(LogComponent.HostEthernet, "Encapsulated 3mbit packet sent."); + } + + private void ReceiveCallback(Packet p) + { + // + // Filter out packets intended for the emulator, forward them on, drop everything else. + // + if ((int)p.Ethernet.EtherType == _3mbitFrameType && // encapsulated 3mbit frames + ((p.Ethernet.Destination.ToValue() & 0xffffffffff00) == _10mbitMACPrefix || // addressed to any emulator OR + p.Ethernet.Destination.ToValue() == _10mbitBroadcast) && // broadcast + (p.Ethernet.Source.ToValue() != (UInt48)(_10mbitMACPrefix | Configuration.HostAddress))) // and not sent by this emulator + { + Log.Write(LogComponent.HostEthernet, "Received encapsulated 3mbit packet."); + _callback(p.Ethernet.Payload.ToMemoryStream()); + } + else + { + // Not for us, discard the packet. + } + } + + private void AttachInterface(EthernetInterface iface) + { + _interface = null; + + // Find the specified device by name + foreach (LivePacketDevice device in LivePacketDevice.AllLocalMachine) + { + if (device.Name == iface.Name && device.GetMacAddress() == iface.MacAddress) + { + _interface = device; + break; + } + } + + if (_interface == null) + { + throw new InvalidOperationException("Requested interface not found."); + } + + Log.Write(LogComponent.HostEthernet, "Attached to host interface {0}", iface.Name); + } + + private void Open(bool promiscuous, int timeout) + { + _communicator = _interface.Open(65536, promiscuous ? PacketDeviceOpenAttributes.MaximumResponsiveness | PacketDeviceOpenAttributes.Promiscuous : PacketDeviceOpenAttributes.MaximumResponsiveness, timeout); + + // Set this to 1 so we'll get packets as soon as they arrive, no buffering. + _communicator.SetKernelMinimumBytesToCopy(1); + + Log.Write(LogComponent.HostEthernet, "Host interface opened and receiving packets."); + } + + /// + /// Begin receiving packets, forever. + /// + private void BeginReceive() + { + // Kick off receive thread. + _receiveThread = new Thread(ReceiveThread); + _receiveThread.Start(); + } + + private void ReceiveThread() + { + // Just call ReceivePackets, that's it. This will never return. + // (probably need to make this more elegant so we can tear down the thread + // properly.) + Log.Write(LogComponent.HostEthernet, "Receiver thread started."); + _communicator.ReceivePackets(-1, ReceiveCallback); + } + + private MacAddress Get10mbitDestinationMacFrom3mbit(byte destinationHost) + { + MacAddress destinationMac; + + if (destinationHost == _3mbitBroadcast) + { + // 3mbit broadcast gets translated to 10mbit broadcast + destinationMac = new MacAddress(_10mbitBroadcast); + } + else + { + // Check addressing table for external (non emulator) addresses; + // otherwise just address other emulators + // TODO: implement table. Currently hardcoded address 1 to test IFS on dev machine + // + if (destinationHost == 1) + { + destinationMac = new MacAddress((UInt48)(_ifsTestMAC)); + } + else + { + destinationMac = new MacAddress((UInt48)(_10mbitMACPrefix | destinationHost)); // emulator destination address + } + + } + + return destinationMac; + } + + private LivePacketDevice _interface; + private PacketCommunicator _communicator; + private ReceivePacketDelegate _callback; + + + // Thread used for receive + private Thread _receiveThread; + + private const int _3mbitFrameType = 0xbeef; // easy to identify, ostensibly unused by anything of any import + + /// + /// On output, these bytes are prepended to the Alto's 3mbit (1 byte) address to form a full + /// 6 byte Ethernet MAC. + /// On input, ethernet frames are checked for this prefix + /// + private UInt48 _10mbitMACPrefix = 0x0000aa010200; // 00-00-AA is the Xerox vendor code, used just to be cute. + + private UInt48 _10mbitBroadcast = (UInt48)0xffffffffffff; + private const int _3mbitBroadcast = 0; + + // Temporary; to be replaced with an external address mapping table + private UInt48 _ifsTestMAC = (UInt48)0x001060b88e3e; + } +} diff --git a/Contralto/IO/HostEthernetEncapsulation.cs b/Contralto/IO/HostEthernetEncapsulation.cs index f045381..3ff7821 100644 --- a/Contralto/IO/HostEthernetEncapsulation.cs +++ b/Contralto/IO/HostEthernetEncapsulation.cs @@ -65,7 +65,7 @@ namespace Contralto.IO foreach (EthernetInterface i in interfaces) { - if (name == i.Name) + if (name == i.Description) { AttachInterface(i); return; @@ -183,7 +183,7 @@ namespace Contralto.IO // Find the specified device by name foreach (LivePacketDevice device in LivePacketDevice.AllLocalMachine) { - if (device.Description == iface.Name) + if (device.Description == iface.Description) { _interface = device; break; diff --git a/Contralto/IO/Keyboard.cs b/Contralto/IO/Keyboard.cs index 1d34665..d9c25f5 100644 --- a/Contralto/IO/Keyboard.cs +++ b/Contralto/IO/Keyboard.cs @@ -119,8 +119,7 @@ namespace Contralto.IO // If we had been holding boot keys, release them now that a real user is pressing a key. if (_bootKeysPressed) { - Reset(); - _bootKeysPressed = false; + Reset(); } AltoKeyBit bits = _keyMap[key]; diff --git a/Contralto/IO/UDPEncapsulation.cs b/Contralto/IO/UDPEncapsulation.cs index fc571e1..3ced3ee 100644 --- a/Contralto/IO/UDPEncapsulation.cs +++ b/Contralto/IO/UDPEncapsulation.cs @@ -21,6 +21,8 @@ namespace Contralto.IO { _udpClient = new UdpClient(_udpPort, AddressFamily.InterNetwork); _udpClient.EnableBroadcast = true; + _udpClient.Client.Blocking = true; + _udpClient.Client.MulticastLoopback = false; // // Grab the broadcast address for the interface so that we know what broadcast address to use @@ -31,7 +33,7 @@ namespace Contralto.IO IPInterfaceProperties props = null; foreach(NetworkInterface nic in nics) { - if (nic.Description.ToLowerInvariant() == interfaceName.ToLowerInvariant()) + if (nic.Description == interfaceName) { props = nic.GetIPProperties(); break; @@ -49,7 +51,8 @@ namespace Contralto.IO // go with it. if (unicast.Address.AddressFamily == AddressFamily.InterNetwork) { - _broadcastEndpoint = new IPEndPoint(GetBroadcastAddress(unicast.Address, unicast.IPv4Mask), _udpPort); + _thisIPAddress = unicast.Address; + _broadcastEndpoint = new IPEndPoint(GetBroadcastAddress(_thisIPAddress, unicast.IPv4Mask), _udpPort); break; } } @@ -173,8 +176,12 @@ namespace Contralto.IO // TODO: sanitize data before handing it off. - Log.Write(LogComponent.HostNetworkInterface, "Received UDP-encapsulated 3mbit packet."); - _callback(new System.IO.MemoryStream(data)); + // Drop our own UDP packets. + if (!groupEndPoint.Address.Equals(_thisIPAddress)) + { + Log.Write(LogComponent.HostNetworkInterface, "Received UDP-encapsulated 3mbit packet."); + _callback(new System.IO.MemoryStream(data)); + } } } @@ -204,5 +211,7 @@ namespace Contralto.IO private UdpClient _udpClient; private IPEndPoint _broadcastEndpoint; + // The IP address (unicast address) of the interface we're using to send UDP datagrams. + private IPAddress _thisIPAddress; } } diff --git a/Contralto/Program.cs b/Contralto/Program.cs index b52c998..224e2f7 100644 --- a/Contralto/Program.cs +++ b/Contralto/Program.cs @@ -21,12 +21,28 @@ namespace Contralto if (!String.IsNullOrEmpty(Configuration.Drive0Image)) { - system.LoadDrive(0, Configuration.Drive0Image); + try + { + system.LoadDrive(0, Configuration.Drive0Image); + } + catch(Exception e) + { + Console.WriteLine("Could not load image '{0}' for drive 0. Error '{1}'.", Configuration.Drive0Image, e.Message); + system.UnloadDrive(0); + } } if (!String.IsNullOrEmpty(Configuration.Drive1Image)) { - system.LoadDrive(1, Configuration.Drive1Image); + try + { + system.LoadDrive(1, Configuration.Drive0Image); + } + catch (Exception e) + { + Console.WriteLine("Could not load image '{0}' for drive 1. Error '{1}'.", Configuration.Drive1Image, e.Message); + system.UnloadDrive(1); + } } AltoWindow mainWindow = new AltoWindow(); @@ -57,7 +73,7 @@ namespace Contralto catch { Console.WriteLine("WARNING: WinPCAP does not appear to be properly installed."); - Console.WriteLine(" Ethernet functionality is disabled."); + Console.WriteLine(" Raw Ethernet functionality will be disabled."); Console.WriteLine(" Please install WinPCAP from: http://www.winpcap.org/"); Configuration.HostRawEthernetInterfacesAvailable = false; diff --git a/Contralto/UI/AlternateBootWindow.Designer.cs b/Contralto/UI/AlternateBootWindow.Designer.cs index d4bf01e..cc2c973 100644 --- a/Contralto/UI/AlternateBootWindow.Designer.cs +++ b/Contralto/UI/AlternateBootWindow.Designer.cs @@ -28,45 +28,41 @@ /// private void InitializeComponent() { - this.EthernetBootEnabled = new System.Windows.Forms.CheckBox(); - this.BootFileGroup = new System.Windows.Forms.GroupBox(); + this.EthernetBootFileGroup = new System.Windows.Forms.GroupBox(); this.label1 = new System.Windows.Forms.Label(); this.BootFileComboBox = new System.Windows.Forms.ComboBox(); this.OKButton = new System.Windows.Forms.Button(); this.CancelButton = new System.Windows.Forms.Button(); - this.BootFileGroup.SuspendLayout(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.EthernetBootRadioButton = new System.Windows.Forms.RadioButton(); + this.DiskBootRadioButton = new System.Windows.Forms.RadioButton(); + this.DiskBootGroupBox = new System.Windows.Forms.GroupBox(); + this.DiskBootAddressTextBox = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.EthernetBootFileGroup.SuspendLayout(); + this.groupBox1.SuspendLayout(); + this.DiskBootGroupBox.SuspendLayout(); this.SuspendLayout(); // - // EthernetBootEnabled + // EthernetBootFileGroup // - this.EthernetBootEnabled.AutoSize = true; - this.EthernetBootEnabled.Location = new System.Drawing.Point(7, 12); - this.EthernetBootEnabled.Name = "EthernetBootEnabled"; - this.EthernetBootEnabled.Size = new System.Drawing.Size(133, 17); - this.EthernetBootEnabled.TabIndex = 0; - this.EthernetBootEnabled.Text = "Ethernet Boot Enabled"; - this.EthernetBootEnabled.UseVisualStyleBackColor = true; - this.EthernetBootEnabled.CheckedChanged += new System.EventHandler(this.OnCheckChanged); - // - // BootFileGroup - // - this.BootFileGroup.Controls.Add(this.label1); - this.BootFileGroup.Controls.Add(this.BootFileComboBox); - this.BootFileGroup.Location = new System.Drawing.Point(4, 35); - this.BootFileGroup.Name = "BootFileGroup"; - this.BootFileGroup.Size = new System.Drawing.Size(397, 62); - this.BootFileGroup.TabIndex = 1; - this.BootFileGroup.TabStop = false; - this.BootFileGroup.Text = "Boot File"; + this.EthernetBootFileGroup.Controls.Add(this.label1); + this.EthernetBootFileGroup.Controls.Add(this.BootFileComboBox); + this.EthernetBootFileGroup.Location = new System.Drawing.Point(4, 106); + this.EthernetBootFileGroup.Name = "EthernetBootFileGroup"; + this.EthernetBootFileGroup.Size = new System.Drawing.Size(397, 62); + this.EthernetBootFileGroup.TabIndex = 1; + this.EthernetBootFileGroup.TabStop = false; + this.EthernetBootFileGroup.Text = "Ethernet Boot File"; // // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(6, 16); + this.label1.Location = new System.Drawing.Point(3, 16); this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(359, 13); + this.label1.Size = new System.Drawing.Size(356, 13); this.label1.TabIndex = 1; - this.label1.Text = "Select a standard boot file number below, or enter a custom value in octal. "; + this.label1.Text = "Select a standard boot file number below, or enter a custom value in octal:"; // // BootFileComboBox // @@ -81,7 +77,7 @@ // // OKButton // - this.OKButton.Location = new System.Drawing.Point(245, 103); + this.OKButton.Location = new System.Drawing.Point(245, 174); this.OKButton.Name = "OKButton"; this.OKButton.Size = new System.Drawing.Size(75, 23); this.OKButton.TabIndex = 2; @@ -91,7 +87,7 @@ // // CancelButton // - this.CancelButton.Location = new System.Drawing.Point(326, 103); + this.CancelButton.Location = new System.Drawing.Point(326, 174); this.CancelButton.Name = "CancelButton"; this.CancelButton.Size = new System.Drawing.Size(75, 23); this.CancelButton.TabIndex = 3; @@ -99,35 +95,105 @@ this.CancelButton.UseVisualStyleBackColor = true; this.CancelButton.Click += new System.EventHandler(this.CancelButton_Click); // + // groupBox1 + // + this.groupBox1.Controls.Add(this.EthernetBootRadioButton); + this.groupBox1.Controls.Add(this.DiskBootRadioButton); + this.groupBox1.Location = new System.Drawing.Point(4, 9); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(397, 43); + this.groupBox1.TabIndex = 4; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Alternate Boot Type"; + // + // EthernetBootRadioButton + // + this.EthernetBootRadioButton.AutoSize = true; + this.EthernetBootRadioButton.Location = new System.Drawing.Point(86, 20); + this.EthernetBootRadioButton.Name = "EthernetBootRadioButton"; + this.EthernetBootRadioButton.Size = new System.Drawing.Size(90, 17); + this.EthernetBootRadioButton.TabIndex = 1; + this.EthernetBootRadioButton.TabStop = true; + this.EthernetBootRadioButton.Text = "Ethernet Boot"; + this.EthernetBootRadioButton.UseVisualStyleBackColor = true; + + // + // DiskBootRadioButton + // + this.DiskBootRadioButton.AutoSize = true; + this.DiskBootRadioButton.Location = new System.Drawing.Point(9, 20); + this.DiskBootRadioButton.Name = "DiskBootRadioButton"; + this.DiskBootRadioButton.Size = new System.Drawing.Size(71, 17); + this.DiskBootRadioButton.TabIndex = 0; + this.DiskBootRadioButton.TabStop = true; + this.DiskBootRadioButton.Text = "Disk Boot"; + this.DiskBootRadioButton.UseVisualStyleBackColor = true; + + // + // DiskBootGroupBox + // + this.DiskBootGroupBox.Controls.Add(this.DiskBootAddressTextBox); + this.DiskBootGroupBox.Controls.Add(this.label2); + this.DiskBootGroupBox.Location = new System.Drawing.Point(4, 58); + this.DiskBootGroupBox.Name = "DiskBootGroupBox"; + this.DiskBootGroupBox.Size = new System.Drawing.Size(397, 42); + this.DiskBootGroupBox.TabIndex = 2; + this.DiskBootGroupBox.TabStop = false; + this.DiskBootGroupBox.Text = "Disk Boot Address"; + // + // DiskBootAddressTextBox + // + this.DiskBootAddressTextBox.Location = new System.Drawing.Point(186, 13); + this.DiskBootAddressTextBox.Name = "DiskBootAddressTextBox"; + this.DiskBootAddressTextBox.Size = new System.Drawing.Size(94, 20); + this.DiskBootAddressTextBox.TabIndex = 2; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(3, 16); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(177, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Enter the octal disk address to boot:"; + // // AlternateBootOptions // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(403, 128); + this.ClientSize = new System.Drawing.Size(406, 201); + this.Controls.Add(this.DiskBootGroupBox); + this.Controls.Add(this.groupBox1); this.Controls.Add(this.CancelButton); this.Controls.Add(this.OKButton); - this.Controls.Add(this.BootFileGroup); - this.Controls.Add(this.EthernetBootEnabled); + this.Controls.Add(this.EthernetBootFileGroup); this.Name = "AlternateBootOptions"; this.ShowIcon = false; this.ShowInTaskbar = false; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "Ethernet Boot Options"; - this.BootFileGroup.ResumeLayout(false); - this.BootFileGroup.PerformLayout(); + this.Text = "Alternate Boot Options"; + this.EthernetBootFileGroup.ResumeLayout(false); + this.EthernetBootFileGroup.PerformLayout(); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.DiskBootGroupBox.ResumeLayout(false); + this.DiskBootGroupBox.PerformLayout(); this.ResumeLayout(false); - this.PerformLayout(); } #endregion - - private System.Windows.Forms.CheckBox EthernetBootEnabled; - private System.Windows.Forms.GroupBox BootFileGroup; + private System.Windows.Forms.GroupBox EthernetBootFileGroup; private System.Windows.Forms.Label label1; private System.Windows.Forms.ComboBox BootFileComboBox; private System.Windows.Forms.Button OKButton; private System.Windows.Forms.Button CancelButton; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.RadioButton EthernetBootRadioButton; + private System.Windows.Forms.RadioButton DiskBootRadioButton; + private System.Windows.Forms.GroupBox DiskBootGroupBox; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox DiskBootAddressTextBox; } } \ No newline at end of file diff --git a/Contralto/UI/AlternateBootWindow.cs b/Contralto/UI/AlternateBootWindow.cs index cf5bbc8..9b65f7c 100644 --- a/Contralto/UI/AlternateBootWindow.cs +++ b/Contralto/UI/AlternateBootWindow.cs @@ -14,16 +14,22 @@ namespace Contralto { public AlternateBootOptions() { - InitializeComponent(); - + InitializeComponent(); + LoadBootEntries(); - BootFileGroup.Enabled = EthernetBootEnabled.Checked = Configuration.EthernetBootEnabled; - - SelectBootFile(Configuration.BootAddress); - - } + if (Configuration.AlternateBootType == AlternateBootType.Disk) + { + DiskBootRadioButton.Checked = true; + } + else + { + EthernetBootRadioButton.Checked = true; + } + SetBootAddress(Configuration.BootAddress); + SelectBootFile(Configuration.BootFile); + } private void LoadBootEntries() { @@ -55,18 +61,33 @@ namespace Contralto } } + private void SetBootAddress(ushort address) + { + DiskBootAddressTextBox.Text = Conversion.ToOctal(address); + } + private void BootFileComboBox_SelectedIndexChanged(object sender, EventArgs e) { - _selectedBoot = ((BootFileEntry)BootFileComboBox.SelectedItem).FileNumber; - } + _selectedBootFile = ((BootFileEntry)BootFileComboBox.SelectedItem).FileNumber; + } private void OKButton_Click(object sender, EventArgs e) { + try + { + _selectedBootAddress = Convert.ToUInt16(DiskBootAddressTextBox.Text, 8); + } + catch + { + MessageBox.Show("The disk boot address must be an octal value between 0 and 177777."); + return; + } + if (BootFileComboBox.SelectedItem == null) { try { - _selectedBoot = Convert.ToUInt16(BootFileComboBox.Text, 8); + _selectedBootFile = Convert.ToUInt16(BootFileComboBox.Text, 8); } catch { @@ -76,11 +97,20 @@ namespace Contralto } else { - _selectedBoot = ((BootFileEntry)BootFileComboBox.SelectedItem).FileNumber; + _selectedBootFile = ((BootFileEntry)BootFileComboBox.SelectedItem).FileNumber; } + + Configuration.BootAddress = _selectedBootAddress; + Configuration.BootFile = _selectedBootFile; - Configuration.BootAddress = _selectedBoot; - Configuration.EthernetBootEnabled = _bootEnabled; + if (DiskBootRadioButton.Checked) + { + Configuration.AlternateBootType = AlternateBootType.Disk; + } + else + { + Configuration.AlternateBootType = AlternateBootType.Ethernet; + } this.Close(); } @@ -88,12 +118,7 @@ namespace Contralto private void CancelButton_Click(object sender, EventArgs e) { this.Close(); - } - - private void OnCheckChanged(object sender, EventArgs e) - { - BootFileGroup.Enabled = _bootEnabled = EthernetBootEnabled.Checked; - } + } private BootFileEntry[] _bootEntries = new BootFileEntry[] { @@ -118,8 +143,8 @@ namespace Contralto - private ushort _selectedBoot; - private bool _bootEnabled; + private ushort _selectedBootFile; + private ushort _selectedBootAddress; } diff --git a/Contralto/UI/AltoWindow.Designer.cs b/Contralto/UI/AltoWindow.Designer.cs index 1777900..c27cdf9 100644 --- a/Contralto/UI/AltoWindow.Designer.cs +++ b/Contralto/UI/AltoWindow.Designer.cs @@ -44,7 +44,7 @@ this.loadToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.unloadToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.Drive1ImageName = new System.Windows.Forms.ToolStripMenuItem(); - this.enableAlternateBootToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.AlternateBootToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.SystemEthernetBootMenu = new System.Windows.Forms.ToolStripMenuItem(); this.optionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.SystemShowDebuggerMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -88,7 +88,7 @@ this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.exitToolStripMenuItem}); this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; - this.fileToolStripMenuItem.Size = new System.Drawing.Size(35, 20); + this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); this.fileToolStripMenuItem.Text = "File"; // // exitToolStripMenuItem @@ -105,12 +105,12 @@ this.SystemResetMenuItem, this.drive0ToolStripMenuItem, this.drive1ToolStripMenuItem, - this.enableAlternateBootToolStripMenuItem, + this.AlternateBootToolStripMenuItem, this.SystemEthernetBootMenu, this.optionsToolStripMenuItem, this.SystemShowDebuggerMenuItem}); this.settingsToolStripMenuItem.Name = "settingsToolStripMenuItem"; - this.settingsToolStripMenuItem.Size = new System.Drawing.Size(54, 20); + this.settingsToolStripMenuItem.Size = new System.Drawing.Size(57, 20); this.settingsToolStripMenuItem.Text = "System"; // // SystemStartMenuItem @@ -118,7 +118,7 @@ this.SystemStartMenuItem.Name = "SystemStartMenuItem"; this.SystemStartMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Alt) | System.Windows.Forms.Keys.S))); - this.SystemStartMenuItem.Size = new System.Drawing.Size(210, 22); + this.SystemStartMenuItem.Size = new System.Drawing.Size(223, 22); this.SystemStartMenuItem.Text = "Start"; this.SystemStartMenuItem.Click += new System.EventHandler(this.OnSystemStartMenuClick); // @@ -128,7 +128,7 @@ this.SystemResetMenuItem.Name = "SystemResetMenuItem"; this.SystemResetMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Alt) | System.Windows.Forms.Keys.R))); - this.SystemResetMenuItem.Size = new System.Drawing.Size(210, 22); + this.SystemResetMenuItem.Size = new System.Drawing.Size(223, 22); this.SystemResetMenuItem.Text = "Reset"; this.SystemResetMenuItem.Click += new System.EventHandler(this.OnSystemResetMenuClick); // @@ -139,7 +139,7 @@ this.unloadToolStripMenuItem1, this.Drive0ImageName}); this.drive0ToolStripMenuItem.Name = "drive0ToolStripMenuItem"; - this.drive0ToolStripMenuItem.Size = new System.Drawing.Size(210, 22); + this.drive0ToolStripMenuItem.Size = new System.Drawing.Size(223, 22); this.drive0ToolStripMenuItem.Text = "Drive 0"; // // loadToolStripMenuItem1 @@ -147,14 +147,14 @@ this.loadToolStripMenuItem1.Name = "loadToolStripMenuItem1"; this.loadToolStripMenuItem1.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Alt) | System.Windows.Forms.Keys.L))); - this.loadToolStripMenuItem1.Size = new System.Drawing.Size(167, 22); + this.loadToolStripMenuItem1.Size = new System.Drawing.Size(172, 22); this.loadToolStripMenuItem1.Text = "Load..."; this.loadToolStripMenuItem1.Click += new System.EventHandler(this.OnSystemDrive0LoadClick); // // unloadToolStripMenuItem1 // this.unloadToolStripMenuItem1.Name = "unloadToolStripMenuItem1"; - this.unloadToolStripMenuItem1.Size = new System.Drawing.Size(167, 22); + this.unloadToolStripMenuItem1.Size = new System.Drawing.Size(172, 22); this.unloadToolStripMenuItem1.Text = "Unload..."; this.unloadToolStripMenuItem1.Click += new System.EventHandler(this.OnSystemDrive0UnloadClick); // @@ -162,7 +162,7 @@ // this.Drive0ImageName.Enabled = false; this.Drive0ImageName.Name = "Drive0ImageName"; - this.Drive0ImageName.Size = new System.Drawing.Size(167, 22); + this.Drive0ImageName.Size = new System.Drawing.Size(172, 22); this.Drive0ImageName.Text = "Image Name"; // // drive1ToolStripMenuItem @@ -172,20 +172,20 @@ this.unloadToolStripMenuItem, this.Drive1ImageName}); this.drive1ToolStripMenuItem.Name = "drive1ToolStripMenuItem"; - this.drive1ToolStripMenuItem.Size = new System.Drawing.Size(210, 22); + this.drive1ToolStripMenuItem.Size = new System.Drawing.Size(223, 22); this.drive1ToolStripMenuItem.Text = "Drive 1"; // // loadToolStripMenuItem // this.loadToolStripMenuItem.Name = "loadToolStripMenuItem"; - this.loadToolStripMenuItem.Size = new System.Drawing.Size(134, 22); + this.loadToolStripMenuItem.Size = new System.Drawing.Size(142, 22); this.loadToolStripMenuItem.Text = "Load..."; this.loadToolStripMenuItem.Click += new System.EventHandler(this.OnSystemDrive1LoadClick); // // unloadToolStripMenuItem // this.unloadToolStripMenuItem.Name = "unloadToolStripMenuItem"; - this.unloadToolStripMenuItem.Size = new System.Drawing.Size(134, 22); + this.unloadToolStripMenuItem.Size = new System.Drawing.Size(142, 22); this.unloadToolStripMenuItem.Text = "Unload..."; this.unloadToolStripMenuItem.Click += new System.EventHandler(this.OnSystemDrive1UnloadClick); // @@ -193,27 +193,28 @@ // this.Drive1ImageName.Enabled = false; this.Drive1ImageName.Name = "Drive1ImageName"; - this.Drive1ImageName.Size = new System.Drawing.Size(134, 22); + this.Drive1ImageName.Size = new System.Drawing.Size(142, 22); this.Drive1ImageName.Text = "Image Name"; // - // enableAlternateBootToolStripMenuItem + // AlternateBootToolStripMenuItem // - this.enableAlternateBootToolStripMenuItem.Name = "enableAlternateBootToolStripMenuItem"; - this.enableAlternateBootToolStripMenuItem.Size = new System.Drawing.Size(210, 22); - this.enableAlternateBootToolStripMenuItem.Text = "Enable Alternate Boot"; + this.AlternateBootToolStripMenuItem.Name = "AlternateBootToolStripMenuItem"; + this.AlternateBootToolStripMenuItem.Size = new System.Drawing.Size(223, 22); + this.AlternateBootToolStripMenuItem.Text = "Start with Alternate Boot"; + this.AlternateBootToolStripMenuItem.Click += new System.EventHandler(this.OnStartWithAlternateBootClicked); // // SystemEthernetBootMenu // this.SystemEthernetBootMenu.Name = "SystemEthernetBootMenu"; - this.SystemEthernetBootMenu.Size = new System.Drawing.Size(210, 22); + this.SystemEthernetBootMenu.Size = new System.Drawing.Size(223, 22); this.SystemEthernetBootMenu.Text = "Alternate Boot Options..."; this.SystemEthernetBootMenu.Click += new System.EventHandler(this.OnAlternateBootOptionsClicked); // // optionsToolStripMenuItem // this.optionsToolStripMenuItem.Name = "optionsToolStripMenuItem"; - this.optionsToolStripMenuItem.Size = new System.Drawing.Size(210, 22); - this.optionsToolStripMenuItem.Text = "Options..."; + this.optionsToolStripMenuItem.Size = new System.Drawing.Size(223, 22); + this.optionsToolStripMenuItem.Text = "System Configuration..."; this.optionsToolStripMenuItem.Click += new System.EventHandler(this.OnSystemOptionsClick); // // SystemShowDebuggerMenuItem @@ -221,7 +222,7 @@ this.SystemShowDebuggerMenuItem.Name = "SystemShowDebuggerMenuItem"; this.SystemShowDebuggerMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Alt) | System.Windows.Forms.Keys.D))); - this.SystemShowDebuggerMenuItem.Size = new System.Drawing.Size(210, 22); + this.SystemShowDebuggerMenuItem.Size = new System.Drawing.Size(223, 22); this.SystemShowDebuggerMenuItem.Text = "Show Debugger"; this.SystemShowDebuggerMenuItem.Click += new System.EventHandler(this.OnDebuggerShowClick); // @@ -230,13 +231,13 @@ this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.aboutToolStripMenuItem}); this.helpToolStripMenuItem.Name = "helpToolStripMenuItem"; - this.helpToolStripMenuItem.Size = new System.Drawing.Size(40, 20); + this.helpToolStripMenuItem.Size = new System.Drawing.Size(44, 20); this.helpToolStripMenuItem.Text = "Help"; // // aboutToolStripMenuItem // this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem"; - this.aboutToolStripMenuItem.Size = new System.Drawing.Size(103, 22); + this.aboutToolStripMenuItem.Size = new System.Drawing.Size(107, 22); this.aboutToolStripMenuItem.Text = "About"; this.aboutToolStripMenuItem.Click += new System.EventHandler(this.OnHelpAboutClick); // @@ -256,19 +257,19 @@ // CaptureStatusLabel // this.CaptureStatusLabel.Name = "CaptureStatusLabel"; - this.CaptureStatusLabel.Size = new System.Drawing.Size(102, 17); + this.CaptureStatusLabel.Size = new System.Drawing.Size(109, 17); this.CaptureStatusLabel.Text = "CaptureStatusLabel"; // // SystemStatusLabel // this.SystemStatusLabel.Name = "SystemStatusLabel"; - this.SystemStatusLabel.Size = new System.Drawing.Size(98, 17); + this.SystemStatusLabel.Size = new System.Drawing.Size(105, 17); this.SystemStatusLabel.Text = "SystemStatusLabel"; // // DiskStatusLabel // this.DiskStatusLabel.Name = "DiskStatusLabel"; - this.DiskStatusLabel.Size = new System.Drawing.Size(82, 17); + this.DiskStatusLabel.Size = new System.Drawing.Size(89, 17); this.DiskStatusLabel.Text = "DiskStatusLabel"; // // AltoWindow @@ -328,6 +329,6 @@ private System.Windows.Forms.ToolStripStatusLabel SystemStatusLabel; private System.Windows.Forms.ToolStripStatusLabel DiskStatusLabel; private System.Windows.Forms.ToolStripMenuItem SystemEthernetBootMenu; - private System.Windows.Forms.ToolStripMenuItem enableAlternateBootToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem AlternateBootToolStripMenuItem; } } \ No newline at end of file diff --git a/Contralto/UI/AltoWindow.cs b/Contralto/UI/AltoWindow.cs index 41e5597..25acab9 100644 --- a/Contralto/UI/AltoWindow.cs +++ b/Contralto/UI/AltoWindow.cs @@ -47,8 +47,8 @@ namespace Contralto _controller.ErrorCallback += OnExecutionError; // Update disk image UI info - Drive0ImageName.Text = _system.DiskController.Drives[0].IsLoaded ? System.IO.Path.GetFileName(_system.DiskController.Drives[0].Pack.PackName) : _noImageLoadedText; - Drive1ImageName.Text = _system.DiskController.Drives[1].IsLoaded ? System.IO.Path.GetFileName(_system.DiskController.Drives[1].Pack.PackName) : _noImageLoadedText; + Drive0ImageName.Text = _system.DiskController.Drives[0].IsLoaded ? Path.GetFileName(_system.DiskController.Drives[0].Pack.PackName) : _noImageLoadedText; + Drive1ImageName.Text = _system.DiskController.Drives[1].IsLoaded ? Path.GetFileName(_system.DiskController.Drives[1].Pack.PackName) : _noImageLoadedText; } /// @@ -58,21 +58,25 @@ namespace Contralto /// private void OnSystemStartMenuClick(object sender, EventArgs e) { - // Disable "Start" menu item - SystemStartMenuItem.Enabled = false; + StartSystem(AlternateBootType.None); + } - // Enable "Reset" menu item - SystemResetMenuItem.Enabled = true; + private void OnStartWithAlternateBootClicked(object sender, EventArgs e) + { + if (_controller.IsRunning) + { + _controller.Reset(Configuration.AlternateBootType); + } + else + { + StartSystem(Configuration.AlternateBootType); + } - _controller.StartExecution(); - - SystemStatusLabel.Text = _systemRunningText; - - } + } private void OnSystemResetMenuClick(object sender, EventArgs e) { - _controller.Reset(); + _controller.Reset(AlternateBootType.None); } private void OnSystemDrive0LoadClick(object sender, EventArgs e) @@ -90,6 +94,7 @@ namespace Contralto CommitDiskPack(0); _system.LoadDrive(0, path); Drive0ImageName.Text = System.IO.Path.GetFileName(path); + Configuration.Drive0Image = path; } catch(Exception ex) { @@ -104,6 +109,7 @@ namespace Contralto CommitDiskPack(0); _system.UnloadDrive(0); Drive0ImageName.Text = _noImageLoadedText; + Configuration.Drive0Image = String.Empty; } private void OnSystemDrive1LoadClick(object sender, EventArgs e) @@ -121,6 +127,7 @@ namespace Contralto CommitDiskPack(1); _system.LoadDrive(1, path); Drive1ImageName.Text = System.IO.Path.GetFileName(path); + Configuration.Drive1Image = path; } catch (Exception ex) { @@ -135,17 +142,13 @@ namespace Contralto CommitDiskPack(1); _system.UnloadDrive(1); Drive1ImageName.Text = _noImageLoadedText; + Configuration.Drive1Image = String.Empty; } private void OnAlternateBootOptionsClicked(object sender, EventArgs e) { AlternateBootOptions bootWindow = new AlternateBootOptions(); - bootWindow.ShowDialog(); - - // - // Apply settings to system. - // - _system.PressBootKeys(); + bootWindow.ShowDialog(); } private void OnSystemOptionsClick(object sender, EventArgs e) @@ -206,6 +209,9 @@ namespace Contralto CommitDiskPack(0); CommitDiskPack(1); + // Commit current configuration to disk + Configuration.WriteConfiguration(); + this.Dispose(); Application.Exit(); } @@ -268,6 +274,19 @@ namespace Contralto } } + private void StartSystem(AlternateBootType bootType) + { + // Disable "Start" menu item + SystemStartMenuItem.Enabled = false; + + // Enable "Reset" menu item + SystemResetMenuItem.Enabled = true; + + _controller.StartExecution(bootType); + + SystemStatusLabel.Text = _systemRunningText; + } + // // Display handling // diff --git a/Contralto/UI/Debugger.cs b/Contralto/UI/Debugger.cs index 73f0401..f67d78e 100644 --- a/Contralto/UI/Debugger.cs +++ b/Contralto/UI/Debugger.cs @@ -718,7 +718,7 @@ namespace Contralto { _execType = ExecutionType.Step; SetExecutionState(ExecutionState.SingleStep); - _controller.StartExecution(); + _controller.StartExecution(AlternateBootType.None); } private void OnAutoStepButtonClicked(object sender, EventArgs e) @@ -729,7 +729,7 @@ namespace Contralto // _execType = ExecutionType.Auto; SetExecutionState(ExecutionState.AutoStep); - _controller.StartExecution(); + _controller.StartExecution(AlternateBootType.None); } private void RunButton_Click(object sender, EventArgs e) @@ -740,14 +740,14 @@ namespace Contralto // _execType = ExecutionType.Normal; SetExecutionState(ExecutionState.Running); - _controller.StartExecution(); + _controller.StartExecution(AlternateBootType.None); } private void RunToNextTaskButton_Click(object sender, EventArgs e) { _execType = ExecutionType.NextTask; SetExecutionState(ExecutionState.Running); - _controller.StartExecution(); + _controller.StartExecution(AlternateBootType.None); } /// @@ -762,7 +762,7 @@ namespace Contralto { _execType = ExecutionType.NextNovaInstruction; SetExecutionState(ExecutionState.Running); - _controller.StartExecution(); + _controller.StartExecution(AlternateBootType.None); } @@ -775,7 +775,7 @@ namespace Contralto private void ResetButton_Click(object sender, EventArgs e) { - _controller.Reset(); + _controller.Reset(AlternateBootType.None); Refresh(); } diff --git a/Contralto/UI/SystemOptions.Designer.cs b/Contralto/UI/SystemOptions.Designer.cs index 7df345f..fe1b9a4 100644 --- a/Contralto/UI/SystemOptions.Designer.cs +++ b/Contralto/UI/SystemOptions.Designer.cs @@ -48,6 +48,7 @@ this.InterlaceDisplayCheckBox = new System.Windows.Forms.CheckBox(); this.OKButton = new System.Windows.Forms.Button(); this.CancelButton = new System.Windows.Forms.Button(); + this.NoEncapsulationRadioButton = new System.Windows.Forms.RadioButton(); this.tabControl1.SuspendLayout(); this.tabPage1.SuspendLayout(); this.tabPage2.SuspendLayout(); @@ -142,6 +143,7 @@ // // groupBox1 // + this.groupBox1.Controls.Add(this.NoEncapsulationRadioButton); this.groupBox1.Controls.Add(this.RawEthernetRadioButton); this.groupBox1.Controls.Add(this.UDPRadioButton); this.groupBox1.Location = new System.Drawing.Point(10, 30); @@ -154,7 +156,7 @@ // RawEthernetRadioButton // this.RawEthernetRadioButton.AutoSize = true; - this.RawEthernetRadioButton.Location = new System.Drawing.Point(77, 16); + this.RawEthernetRadioButton.Location = new System.Drawing.Point(63, 16); this.RawEthernetRadioButton.Name = "RawEthernetRadioButton"; this.RawEthernetRadioButton.Size = new System.Drawing.Size(186, 17); this.RawEthernetRadioButton.TabIndex = 1; @@ -271,6 +273,17 @@ this.CancelButton.UseVisualStyleBackColor = true; this.CancelButton.Click += new System.EventHandler(this.CancelButton_Click); // + // NoEncapsulation + // + this.NoEncapsulationRadioButton.AutoSize = true; + this.NoEncapsulationRadioButton.Location = new System.Drawing.Point(255, 16); + this.NoEncapsulationRadioButton.Name = "NoEncapsulation"; + this.NoEncapsulationRadioButton.Size = new System.Drawing.Size(51, 17); + this.NoEncapsulationRadioButton.TabIndex = 2; + this.NoEncapsulationRadioButton.TabStop = true; + this.NoEncapsulationRadioButton.Text = "None"; + this.NoEncapsulationRadioButton.UseVisualStyleBackColor = true; + // // SystemOptions // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -320,5 +333,6 @@ private System.Windows.Forms.GroupBox groupBox1; private System.Windows.Forms.RadioButton RawEthernetRadioButton; private System.Windows.Forms.RadioButton UDPRadioButton; + private System.Windows.Forms.RadioButton NoEncapsulationRadioButton; } } \ No newline at end of file diff --git a/Contralto/UI/SystemOptions.cs b/Contralto/UI/SystemOptions.cs index 2288b80..dc4eacd 100644 --- a/Contralto/UI/SystemOptions.cs +++ b/Contralto/UI/SystemOptions.cs @@ -54,55 +54,82 @@ namespace Contralto.UI { // If PCAP isn't installed, the RAW Ethernet option is not available. RawEthernetRadioButton.Enabled = false; - UDPRadioButton.Checked = true; - } - else - { - if (Configuration.HostPacketInterfaceType == PacketInterfaceType.UDPEncapsulation) - { - UDPRadioButton.Checked = true; - } - else - { - RawEthernetRadioButton.Checked = true; - } - } - PopulateNetworkAdapterList(UDPRadioButton.Checked); + // Ensure the option isn't set in the configuration. + if (Configuration.HostPacketInterfaceType == PacketInterfaceType.EthernetEncapsulation) + { + Configuration.HostPacketInterfaceType = PacketInterfaceType.None; + } + } + + switch(Configuration.HostPacketInterfaceType) + { + case PacketInterfaceType.UDPEncapsulation: + UDPRadioButton.Checked = true; + break; + + case PacketInterfaceType.EthernetEncapsulation: + RawEthernetRadioButton.Checked = true; + break; + + case PacketInterfaceType.None: + NoEncapsulationRadioButton.Checked = true; + break; + } + + PopulateNetworkAdapterList(Configuration.HostPacketInterfaceType); } - private void PopulateNetworkAdapterList(bool udpEncapsulation) + private void PopulateNetworkAdapterList(PacketInterfaceType encapType) { // // Populate the list with the interfaces available on the machine, for the // type of encapsulation being used. - // + // + HostInterfaceGroupBox.Enabled = encapType != PacketInterfaceType.None; + EthernetInterfaceListBox.Items.Clear(); - NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces(); - + // Add the "Use no interface" option EthernetInterfaceListBox.Items.Add( new EthernetInterface("None", "No network adapter")); - foreach (NetworkInterface iface in interfaces) + + switch (encapType) { // For UDP we show all interfaces that support IPV4, for Raw Ethernet we show only Ethernet interfaces. - if (udpEncapsulation) - { - if (iface.Supports(NetworkInterfaceComponent.IPv4)) + case PacketInterfaceType.UDPEncapsulation: { - EthernetInterfaceListBox.Items.Add(new EthernetInterface(iface.Name, iface.Description)); + NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces(); + + foreach (NetworkInterface iface in interfaces) + { + if (iface.Supports(NetworkInterfaceComponent.IPv4)) + { + EthernetInterfaceListBox.Items.Add(new EthernetInterface(iface.Name, iface.Description)); + } + } } - } - else - { - if (iface.NetworkInterfaceType == NetworkInterfaceType.Ethernet) + break; + + // Add all interfaces that PCAP knows about. + case PacketInterfaceType.EthernetEncapsulation: { - EthernetInterfaceListBox.Items.Add(new EthernetInterface(iface.Name, iface.Description)); - } - } - } + List ifaces = EthernetInterface.EnumerateDevices(); + + foreach (EthernetInterface iface in ifaces) + { + EthernetInterfaceListBox.Items.Add(iface); + } + } + break; + + case PacketInterfaceType.None: + // Add nothing. + break; + } + // // Select the one that is already selected (if any) @@ -115,7 +142,7 @@ namespace Contralto.UI { EthernetInterface iface = (EthernetInterface)EthernetInterfaceListBox.Items[i]; - if (iface.Description.ToLowerInvariant() == Configuration.HostPacketInterfaceName.ToLowerInvariant()) + if (iface.Description == Configuration.HostPacketInterfaceName) { EthernetInterfaceListBox.SelectedIndex = i; break; @@ -146,12 +173,16 @@ namespace Contralto.UI { _selectedInterfaceType = PacketInterfaceType.UDPEncapsulation; } - else + else if (RawEthernetRadioButton.Checked) { _selectedInterfaceType = PacketInterfaceType.EthernetEncapsulation; } + else + { + _selectedInterfaceType = PacketInterfaceType.None; + } - PopulateNetworkAdapterList(UDPRadioButton.Checked); + PopulateNetworkAdapterList(_selectedInterfaceType); } private void OKButton_Click(object sender, EventArgs e) @@ -180,14 +211,14 @@ namespace Contralto.UI // // First warn the user of changes that require a restart. // - if (Configuration.HostPacketInterfaceName.ToLowerInvariant() != iface.Description.ToLowerInvariant() || + if (Configuration.HostPacketInterfaceName != iface.Description || Configuration.HostPacketInterfaceType != _selectedInterfaceType || Configuration.SystemType != _selectedSystemType) { MessageBox.Show("Changes to CPU or Ethernet configuration will not take effect until ContrAlto is restarted."); } - //System + // System Configuration.SystemType = _selectedSystemType; // Ethernet @@ -197,9 +228,7 @@ namespace Contralto.UI // Display Configuration.InterlaceDisplay = InterlaceDisplayCheckBox.Checked; - Configuration.ThrottleSpeed = ThrottleSpeedCheckBox.Checked; - - Configuration.WriteConfiguration(); + Configuration.ThrottleSpeed = ThrottleSpeedCheckBox.Checked; this.Close();