How to flash the BMC firmware from U-Boot

1) set server ip: 172.31.8.73
2) Protect off all
3) erase all
4) tftpboot 0xb4000000 rom-blade.ima
5) save
6) reset

ip: 172.31.21.11

root

123456

sh coldreset 172.31.0.24

sh coldreset 172.31.10.75

 

scp coldreset 172.31.10.75/root/david

Posted in IPMI | Leave a comment

IPMI commands for CMM

(1) stop the CMM I2C polling:

impitool -H 192.168.100.xxx -U ADMIN -P ADMIN raw 0x30 0x40 6

(2) Read one byte from second blade:

impitool -H 192.168.100.xxx -U ADMIN -P ADMIN raw 0x30 0x37 0x31 0x22 0x01 0x01 0x00 0x01

impitool -H 192.168.100.xxx -U ADMIN -P ADMIN raw 0x30 0x37 0x31 0x22 (slave address) 0x01 (bus#)  0x01 (channel#)  0x00 (offset) 0x01 (how many bytes)

Posted in IPMI | Leave a comment

How to Setup Linpack Testing Program

 

(1) Install Linux OS.
(2) Generate authentication keys for ssh authentication so data can be transferred between two computers without asking for passwords.
On host of 10.31.8.210 (first computer), type:
     ssh-keygen -t dsa
     cd .ssh/
     ls
     scp ./id_dsa.pub 10.31.9.255:/root/.ssh/authorized_keys2
  ssh 10.31.9.255
On host of 10.31.9.255 (second computer), do the same thing as on the first computer:
  ssh-keygen -t dsa
     cd .ssh/
     ls
     scp ./id_dsa.pub 10.31.8.210:/root/.ssh/authorized_keys2

(3) Copy the Linpack testing program to /root directory on these two computers:
Wget http://10.31.7.8/cluster/benchmark/hpl/intel/xhpl_intelx64_ib_static

(4)Run the Linpack testing program:
 
  mpirun –prefix /opt/openmpi-icc/ -np 48 -machinefile mf1 ./xhpl_intelx64_ib_static
(4) The mf1 file is shown as:
10.31.8.210 slots=24
10.31.9.255 slots=24
(5) The HPL.dat is shown as:

HPLinpack benchmark input file
Innovative Computing Laboratory, University of Tennessee
HPL.out      output file name (if any)
6            device out (6=stdout,7=stderr,file)
1            # of problems sizes (N)
100000 30000 40000 50000 60000 39007 39000  20960 364160 359424 276480 138240 115200 23040 354432 236160 95040 9600 20737 16129 16128 Ns
1             # of NBs
768 1024 512 384 640 768 896 960 1024 1152 1280 384 640 960 768 640 256  960 512 768 1152         NBs
0            PMAP process mapping (0=Row-,1=Column-major)
1            # of process grids (P x Q)
4         Ps
12        Qs
16.0         threshold
3            # of panel fact
0 1 2        PFACTs (0=left, 1=Crout, 2=Right)
1            # of recursive stopping criterium
2 8          NBMINs (>= 1)
1            # of panels in recursion
2            NDIVs
3            # of recursive panel fact.
0 1 2        RFACTs (0=left, 1=Crout, 2=Right)
2            # of broadcast
0 2          BCASTs (0=1rg,1=1rM,2=2rg,3=2rM,4=Lng,5=LnM)
2            # of lookahead depth
1 0          DEPTHs (>=0)
1            SWAP (0=bin-exch,1=long,2=mix)
192          swapping threshold
1            L1 in (0=transposed,1=no-transposed) form
1            U  in (0=transposed,1=no-transposed) form
1            Equilibration (0=no,1=yes)
8            memory alignment in double (> 0)
(5) Get CPU and memory information. This information will be needed to setup the parameter of Linpack test.

    cat /proc/cpuinfo
    cat /proc/cpuinfo | grep MHz | wc -l
    ssh 10.31.9.255 “cat /proc/cpuinfo | grep MHz | wc -l”
    ifconfig eth0
    ssh 10.31.9.255 “cat /proc/cpuinfo | grep MHz | wc -l”
    free
    ssh 10.31.9.255 “free”
(6) Before you run the linpack testing program, you need to install openmpi:
tar jxf openmpi-1.4.2.tar.bz2
cd openmpi-1.4.2
  ls
      . set_env
 ./configure –prefix=/opt/openmpi-icc –enable-static –disable-share CC=icc CXX=icpc FC=ifort F77=ifort && make && make install clean

(7) The set_env file is shown as:

_INTEL_COMPILER=/opt/intel/Compiler/11.1/072
_INTEL_MKL=/opt/intel/mkl/10.2.5.035
_OPENMPI=/opt/openmpi-icc
_CUDA_TOOLKIT=/usr/local/cuda
[[ -z $_OPENMPI ]] && { _OPENMPI=/opt/openmpi; }
export PATH=$_OPENMPI/bin:$_INTEL_COMPILER/bin/intel64:$_CUDA_TOOLKIT/bin:$PATH
export LD_LIBRARY_PATH=$_CUDA_TOOLKIT/lib64:$_CUDA_TOOLKIT/lib:$_OPENMPI/lib:$_INTEL_MKL/lib/em64t:$_INTEL_COMPILER/lib/intel64:$LD_LIBRARY_PATH
(8) You need to modify your .bash_profile

Posted in GPU Blade Server | 1 Comment

Linear Regulaor Design

 
Linear Regulator Design Key Notes
James Zou
03/10/2005
The basic properties about linear regulator electric components are discussed in these notes. An electrolytic capacitor model is shown in Figure 1. In this model, it shows the effective series inductance LESL, the effective series resistance RESR, the capacitance C, the dielectric leakage resistance Rleakage.

 
                                            Figure 1. Electrolytic Capacitor Model

Effects of Capacitor Parasitic Parameter
ESR:  The ESR (Equivalent Series Resistance) causes internal heating due to power dissipation as the ripple current flows into and out of the capacitor.  The capacitor can fail if ripple current exceeds maximum ratings. Excessive outputvoltage ripple will result from high ESR, and regulator loop instability is also possible.  ESR is highly dependent on temperature, increasing very quickly at temperatures below about 10 C.
The ESR is the primary cause of regulator loop instability in both linear LDO regulators and switching regulators.

ESL:  The ESL (Effective Series Inductance) limits the high frequency effectiveness of the capacitor.  High ESL is the reason electrolytic capacitors need to be bypassed by film or ceramic capacitors to provide good high frequency performance. The ESR, ESL and C within the capacitor form a resonant circuit, whose frequency of resonance should be as high as possible.  Switching regulators generate ripple voltages on their outputs with very high frequency (>1 MHz) components, which can cause ringing on the output voltage
if the capacitor resonant frequency is low enough to be near these frequencies.
The  ESL limits a capacitors effectiveness at high frequencies, and is the primary reason electrolytic capacitors must be bypassed by good RF capacitors in switching regulator applications (ceramic and film types are often used).

Output Capacitance Affecting Regulator Loop Stability Too
The output capacitor used on an LDO linear regulator can make it oscillate if the
capacitor is not selected correctly.
INPUT CAPACITOR ESL EFFECTS

All of the switching regulators operate as DC-DC converters at a very high frequency.  As the converter switches, it has to draw current pulses from the input source.  The source impedance is extremely important, as even a small amount of inductance can cause significant ringing and spiking on the voltage at the input of the converter. The best practice is to  always provide adequate capacitive bypass as near as possible to the switching converter input.  For best results, an electrolytic is used with a film capacitor (and possibly a ceramic capacitor) in parallel for optimum high frequency bypassing.

OUTPUT CAPACITOR ESR EFFECTS
The primary function of the output capacitor in a switching regulator is filtering.  As the converter operates, current must flow into and out of the output filter capacitor. The ESR of the output capacitor directly affects the performance of the switching regulator.  ESR is specified by the manufacturer on good quality capacitors, but be certain that it is specified at the frequency of intended operation. General-purpose electrolytics usually only specify ESR at 120 Hz, but capacitors intended for high-frequency switching applications will have the ESR guaranteed at high frequency (like 20 kHz to 100 kHz).Some ESR dependent parameters are:
Ripple Voltage:  In most cases, the majority of the output ripple voltage results from the ESR of the output capacitor.  If the ESR increases (as it will at low operating temperatures) the output ripple voltage will increase accordingly.
Efficiency:  As the switching current flows into and out of the capacitor (through the ESR), power is dissipated internally.  This “wasted” power reduces overall regulator efficiency, and can also cause the capacitor to fail if the ripple current exceeds the maximum allowable specification for the capacitor.
Loop Stability:  The ESR of the output capacitor can affect regulator loop stability. Products such as the LM2575 and LM2577 are compensated for stability assuming the ESR of the output capacitor will stay within a specified range.Keeping the ESR within the “stable” range is not always simple in designs that must operate over a wide temperature range.   The ESR of a typical aluminum electrolytic may increase by 40X as the temperature drops from 25C to -40C. In these cases, an aluminum electrolytic must be paralleled by another type of capacitor with a flatter ESR curve (like Tantalum or Film) so that the effective ESR (which is the parallel value of the two ESR’s) stays within the allowable range.
Note:  if operation  below -40C is necessary, aluminum electrolytics are probably not feasible for use.

BYPASS CAPACITORS
High-frequency bypass capacitors are always recommended on the supply pins of IC devices, but if the devices are used in assemblies near switching converters bypass capacitors are absolutely required. The components which perform the high-speed switching (transistors and rectifiers) generate significant EMI that easily radiates into PC board traces and wire leads. To assure proper circuit operation, all IC supply pins must be bypassed to a clean, low-inductance ground (for details on grounding, see next section).

REGULATOR LOOP RESPONSE
The loop response of a typical regulator is shown in Figure 2.  The most important point to realize is that for a stable loop, the gain must cross below 0 dB before the phase angle reaches 180.  A phase angle of 180 means that the signal being fed back around the loop is actually positive feedback, and will cause oscillations to occur.
(Note:  In reality, a phase margin of 45 is usually required for good stability, which means it is advisable to get a 0 dB crossover before the phase angle reaches 135).
In an LDO regulator, the output capacitor is required to force the gain to roll off fast enough to meet the stability requirements (a standard NPN regulator is internally compensated, and usually needs no output capacitor for stability).
As shown in Figure 2, the ESR of the output capacitor causes an unwanted “zero” in the response, which delays the 0 dB crossover point.  If the ESR is large enough, the “zero frequency” gets low enough to cause regulator instability.
The stability requirements for a specific regulator will be listed on the data sheet for the part.  In some cases, a range is given which requires that the ESR be within the minimum and maximum limits.  In the newer parts, only a maximum limit must be met (which makes selecting a capacitor much easier).
 

Figure 2. Loop Gain Plot

TEMPERATURE DEPENDENCE OF ESR
Having now established the necessity of controlling the ESR of the output capacitor on an LDO regulator (to keep the regulator from oscillating), we need to point out one very important thing:  ESR is not constant with temperature.
Figure 3 shows a plot of ESR versus temperature for a typical aluminum electrolytic capacitor.  The most important point to observe is how fast the ESR increases at low temperatures.
In cases where an LDO regulator must be operated below about -10  C, it is sometimes not possible to find an aluminum electrolytic capacitor that can maintain an ESR within the acceptable range.  Also, it is essential that the capacitor is specified to operate over the full temperature range:  some aluminum electrolytics are not usable below -20C (because their electrolyte freezes). If the regulator has only a  maximum limit which the ESR must not exceed, the aluminum electrolytic capacitor can be paralleled with a solid tantalum capacitor (which has a much lower ESR).  When two capacitors are in parallel, the effective ESR is the parallel of the two ESR values, which means the tantalum will help suppress the low-temperature ramp up seen in Figure 3.  As a good rule, the tantalum should be selected so that its capacitance is about 20% of the aluminum electrolytic. If the regulator has both a maximum and minimum limit (the ESR must stay in a specified range), it may be necessary to use a low value carbon film resistor placed in series with a low ESR capacitor (tantalum, film, or ceramic will work). The best type of capacitor to use will depend upon how much total capacitance is required.

Figure 3. Aluminum Electrolytic Capacitor ESR VS Temperature

The Carrot in LDO Regulator Ground Pin Current
Many (but not all) LDO regulators have a characteristic in their ground pin current referred to as the “carrot”.  The carrot is a point in the ground pin current that spikes up as the input voltage is reduced (see Figure 4). The error amplifier in a regulator always tries to force the output to be the right voltage by adjusting the current through the pass device (in this case, the PNP transistor). As the input voltage is reduced (and the voltage across the pass transistor decreases) the current gain of the PNP begins to drop.  To maintain the correct output voltage, the error amplifier has to drive the base of the PNP harder to supply the same load current.  The PNP base drive current leaves the regulator as ground
pin current. As the input voltage drops further, the regulator will approach dropout, causing the error amplifier to drive the PNP base with maximum current (this is the top of the carrot).  This value of current may be 3 or 4 times the maximum ground pin current that is required to drive full rated load current with 5V across the pass transistor.
The carrot is recognized as an undesirable characteristic, since the additional ground pin current must be supplied by the source, but does not power the load (it just heats up the regulator). In the newer LDO regulators, circuitry was built in to prevent this ground pin spike from occurring.  For example, the  ZP2321 (and all of the products in that family) have only a negligible increase in ground pin current as the input voltage crosses through the range where dropout is occurring.
 

Figure 4. LDO regulator with “carrot”

Proper Ground and “skin effect”
The “ground” in a circuit is supposed to be at one potential, but in real life it is not. When ground currents flow through traces which have non-zero resistance, voltage differences will result at different points along the ground path. In DC or low-frequency circuits, “ground management” is comparatively simple:  the only parameter of critical importance is the  DC resistance of a conductor, since that defines the voltage drop across it for a given current.  In high-frequency circuits, it is the inductance of a trace or conductor that is much more important. In switching converters, peak currents flow in high-frequency (> 50 kHz) pulses, which can cause severe problems if trace inductance is high.  Much of the “ringing” and “spiking” seen on voltage waveforms in switching converters is the result of high current being switched through parasitic trace (or wire) inductance. 
Current switching at high frequencies tends to flow near the surface of a conductor (this is called “skin effect”), which means that ground traces must be very wide on a PC board to avoid problems. It also means that even you increase the thickness, it is useless.  It is usually best (when possible) to use one side of the PC board as a ground plane.

PCB Layout

Which one is good?
 


Figure 5. Eliminating Load Regulation Effects
  Selecting the Best Regulator For Your Application

 Maximum Load Current
 Type of Input Voltage Source (Battery or AC)
 Output Voltage Precision (Tolerance)
 Quiescent (Idling) Current
 Special Features (Shutdown Pin, Over current, under voltage, over voltage, timer, retry, etc.)

Posted in LDO Regulator Design | Leave a comment

Switching Regulator Design

Switching Regulator Design
James Zou
10/27/2008
On board level design, we need to pay attention to two most important issues: power and clock. These two issues will decide the board stability and quality. In this paper, we only address the power issue, especially, the switching regulator design. On a regular server motherboard based on Intel chipsets with BMC function, there are about 26 power planes. Among these power planes, there are 10 power planes whose power was supplied by switching regulators. To meet the EUP standard and energy star requirement, more switching regulators are needed to improve the power efficiency.
The older linear regulator required minimum and maximum ESR of the output capacitor. The new linear regulator only required the maximum ESR of the output capacitor to maintain the loop stability. For example, the LT1117 from Linear Technology Inc only required the ESR of output capacitor should be less than 0.5 ohm and a minimum of 10μF of tantalum or 50μF of aluminum electrolytic capacitor. If we chose a linear regulator according to its current requirement and added a big enough output capacitor, we rarely got problem.  Switching regulator design is more complicated. We will start with finding the transferring function. Based on the transferring function,we can make the Bode plots and obtain the stability conditions. Then we will discuss how to choose the capacitors, inductors, and compensation circuit.

Figure 1. Feedback Model of Switching Regulator (Buck Regulator)

Using the current continuity in the energy transfer inductor, we can classify the switching regulator into two modes: Continuous-conduction-mode (CCM) and discontinuous-conduction-mode (DCM). The CCM mode means that the current in the energy transfer inductor never goes to zero between switching cycles. In DCM mode the current goes to zero during part of the switching cycle. From transfer function point, we can say CCM system is a second order system and DCM system is a first order system. On the s-plane, CCM system has a right-half-plane zero and  DCM. does not have a right-half-plane zero. It means DCM system is always stable.
 According to the topologies of circuit, we can name eight classes of  switching regulators: buck, boost, buck-boost, no-inverting buck-boost, bridge, Watkins-Johnson, current-fed bridge and inverse of Watkins-Johnson. The buck DC-DC switching regulator is dominated on modern motherboard design. In this paper, we will only discuss the buck DC-DC converter. A regular feedback model of switching regulator (buck) is shown in Figure 1.
 To expand the detail of buck DC-DC switching regulator, we use Intersil’s ISL6535 as an example, as shown in Figure 2, to deduct the transfer function and analyze the stability.

Figure 2. The block diagram of Intersil’s ISL6535

The detail of modulator in Figure 1 is shown in Figure 3. The input to the modulator is the output of the error amplifier. The output of the modulator is the PHASE node. The transfer function of the modulator is the input voltage to the regulator VIN, divided by the peak-to-peak voltage of the oscillator, ΔVOSC:


The peak to peak voltage of the oscillator can be obtained in data sheet of ISL6535.

Figure 3. The Modulator

The detail of Output filter in Figure 1 is shown in Figure 4. In theory, it should include the resistor of load. To simplify the calculation, we ignore the load resistance. The output filter circuit consists of the output inductor and output capacitors. The parasitic property of the inductor, DCR, and the parasitic property of the capacitors, ESR, play very important roles in the output filter. It will affect the system stability. We include these two parts in the transfer function:

 

Figure 4. The Output Filter

From the equation of the output filter transfer function, we can see there are double poles and one zero on the s-plane. The double poles can be normalized as:

The amplitude and phase plots for G(s) are shown in Figure 5.

 

Figure 5. The amplitude and phase plots for G(s)

If we combine the modulator and output filter together, we got the open loop system as shown in Figure 6. The transfer function of the open loop system can be described as:


Figure 6. The open loop system

In Figure 5, we can see when Q becomes bigger, the amplitude of the gain at the resonant frequency becomes bigger and the phase change at the resonant frequency becomes sharper. It means at high value Q, the open system is hard to be stabilized. The value of Q is determined by the ESR and DCR. If the DCR and ESR are very small, the Q will be very big. From system stabilization point, it is not good to choose too low ESR capacitors and  too low DCR inductors. However, we need to meet the voltage static and transient tolerance of the chipsets. The ESR must be very low. The DCR will affect the power efficiency. To improve the power efficiency, the DCR is the lower, the better. We  choose the ESR and DCR first to meet the ripple and transient tolerance, then we will choose the compensation circuit to stabilize the system. To simplify the analysis of the open loop system, we made the asymptotic Bode plot of the open loop system gain in Figure 7.


Figure 7. The amplitude Bode plot for the open loop system gain

As shown in Figure 1, all the switching regulator system is a feedback system with compensation network. There are three main reasons to add the feedback path: (1) improving the stability, (2) lowering Zout for stiffer V(out) vs. I(out), (3) widening the bandwidth. However, if the feedback system is not properly designed, when the feedback becomes positive, the system will oscillate.
   
In switching regulator design, there are three kinds of compensation as shown in Figure 8, Figure 9 and Figure 10.


Figure 8. Type I Compensation.

Figure 9. Type II Compensation.

Figure 10. Type III Compensation.

In this paper, we only discuss the type II compensation. The transfer function of type II compensation can be described as

Figure 11 shows the asymptotic Bode plot for the type II compensation gain and Figure 12 shows the Bode plot for the type II compensation phase.

Figure 11. Asymptotic Bode plot for type II compensation gain.

Figure 12 Bode plot for type II compensation phase.

From Figure 12, we can see the type II compensation will give a 90 degree boost to the phase. This boost is very important because it will cancel part of the effects of the double poles at the resonant frequency.
The closing loop system with type II compensation is shown in Figure 13.

 

Figure 13. The closing loop with type II compensation.

The transfer function of the closing loop with type II compensation is:
The Bode plot of this closing loop system is shown in Figure 14.

 

Figure 14. The Bode plot for the closing loop system of switching regulator.

A control system is stable if a gain crossing 0 db with close to a –20dB/decade slope and a phase margin greater than 45 ˚ . The crossover frequencies should be in the range of 10% to 30% of the switching frequency, fSW. To explain this stability criterion, we will discuss the stability theory of generic negative feedback amplifier system as shown in Figure 15.

 

Figure 15. A negative feedback amplifier system.

The transfer function of this negative feedback amplifier system can be written as:

 

where AFB is the gain of the amplifier with feedback (the closed-loop gain), β is the feedback factor and AOL is the gain without feedback (the open-loop gain). The gain AOL is a complex function of frequency, with both magnitude and phase. Examination of this relation shows the possibility of infinite gain (interpreted as instability) if the product βAOL =  -1. (That is, the magnitude of  βAOL is unity and its phase is -180°, the so-called Barkhausen stability criterion). Bode plots are used to determine just how close an amplifier comes to satisfying this condition.
Lets define f0dB is the frequency where the magnitude of the product | βAOL | = 1 (in dB, magnitude 1 is 0 dB). The frequency f0dB is determined by the condition:

 

The measurement of proximity to instability is the phase margin. The Bode magnitude plot locates the frequency where the magnitude of |βAOL| reaches unity, denoted here as frequency f0dB. Using this frequency, the Bode phase plot finds the phase of  βAOL. If the phase of  βAOL( f0dB) >  -180°, the instability condition cannot be met at any frequency (because its magnitude is going to be < 1 when f = f180), and the distance of the phase at f0dB in degrees above -180° is called the phase margin. Then the stability criteria can be expressed as: at 0 dB crossing, the f0dB is above –180°. However, this criterion is sufficient to predict stability only for amplifiers satisfying some restrictions on their pole and zero positions (minimum phase systems), as Nyquist criterion described. If we added 45 ˚ phase margin, this stability criterion is sufficient always. This is how the 45˚ Phase margin comes from.
The output capacitor and output inductors together form a low pass filter responsible for smoothing the pulsating voltage at the phase nodes. The output filter must provide the transient energy until the regulator can respond. Because it has a low-bandwidth compared to the switching frequency, the output filter necessarily limits the system transient response. The output capacitor must supply or sink load current while the current in the output inductors increases or decreases to meet the demand.
The table 2-2 and table 2-5 are directly copied from Intel processor specification. From Table 2-2 and Table 2-5, we know:
di/dt = 100A/200ns  = 500 A/μS
 ΔVmax  =  2*19mV + (0.15V-0.07V) = 118 mV
 ΔI = 100A
The filter capacitor must have sufficiently low ESL and ESR so that:
ΔV  < ΔVmax

 

 

Once the output capacitors are selected, the maximum allowable ripple voltage, Vpp(MAX), determines the lower limit on the inductance, as shown in the following Equation:

 

 
……………………………………………………………………..Equation 1.
Where, ESR is the Equivalent Serial Resistance of the output capacitor, Vin is the input voltage, Vout is the output voltage, fs is the switching frequency, Vp-p(MAX) is the maximum allowable ripple voltage.
The current in the switching regulator inductor is shown in Figure 16. The duty cycle can be obtained from Figure 17 as:

 

Figure 16. Switching Regulator Inductor Current.

 
Figure 17. PWM wave form is filtered by LC circuit.

D  = Ton/ Tp  = Vout/Vin         ……………..Equation 2        
During the PWM is on, the voltage on the two ends of the inductor is  ΔV =Vin –Vout. From the differential equation of the inductor, we have:
ΔV   =  L (ΔI/ΔT)                         …………… Equation 3
L  =    ΔV * ΔT/ΔI             ……. Equation 4
ΔT  = D/fs              ………….Equation 5
  so we have:
                        L = (Vin –Vout)Vout/fs VinΔI         ……….Equation 6
here ΔI the current ripple in the inductor. For a constant loading current, the ripple current should be compensated by the capacitors. To meet the ripple voltage requirement, we have:
ΔI = Vp-p(MAX) / ESR           …….Equation 7
Substituting equation 7 into equation 6, we have
L = ESR(Vin –Vout)Vout/fs VinVp-p(MAX)          ………Equation 8               
This is the low limit of the inductor.
The upper limit of inductance is given in the following in-equalities:
The peak-to-peak difference of the inductor current waveform is referred to as the inductor ripple current, and the inductor is typically selected large enough to keep this ripple current less than 20% to 30% of the rated DC current. In summary, we choose the inductor based on:
 Maximum input voltage
 Output voltage
 Switching frequency
 Maximum ripple current
 Duty cycle
 Maximum load current
MOSFET power dissipation depends on the gate-drive voltage (VD), the on-resistance (RDSON), the total gate charge (QGATE), and the gate threshold voltage (VTH).
Switching loss is the major contributor to the high-side MOSFET power dissipation due to the hard switching transition every time it turns on.
The low-side MOSFET power dissipation is mostly attributed to the conduction loss. Switching loss is negligible due to the zero-voltage switching at turn-on and body-diode clamp at turn-off.
The upper-MOSFET switching loss will setup the upper limit for the switching frequency. The lower limit is established by the requirement for the fast transient response and small output-voltage ripple. Choose the lowest switching frequency that allows the regulator to meet the transient response requirement.
The input capacitors are responsible for sourcing the input current flowing into the upper MOSFETS. Their RMS current capacity must be sufficient to handle the current drawn by the upper MOSFETs that is related to duty cycle and the number of active phases.

Posted in Uncategorized | Leave a comment

PS2 Keyboard Interface

.James Zou.
10/25/2010
PS2 Keyboard Interface will disappear soon. However, in the computer history, as one of the main input tool ever, the PS2 keyboard played a very important role. I designed a virtual keyboard many years ago so I understood the ps2 keyboard interface. I will show you how to read the wave form  between the 8042 and the keyboard, then I will list the initial communication sequence of the keyboard initialization. For those who want to know more detail about the PS2 keyboard interface, please read the IBM’s technical reference manual.

(1) When keyboard sends command to the host, the wave form should like the following picture:


               Red: host is driving. Blue: Keyboard is driving. Data is valid at rising edge.
(2) When the host sends command to keyboard, the wave form should like the following picture:

Blue: keyboard is driving. Data is valid at falling edge.
Keyboard inialization sequence:
Host –> KB: FF
KB –> Host: FA AA  00
Host –> KB: F2
KB –> Host: FA 00
Host –> KB: F3
KB –> Host: FA
Host –> KB: 0A
KB –> Host: FA
Host –> KB: F2
KB –> Host: FA 00
Host –> KB: E8
KB –> Host: FA
Host –> KB: 00
KB –> Host: FA
Host –> KB: E6
KB –> Host: FA
Host –> KB: E9
KB –> Host: FA
KB –> HOST: 90
KB –> Host: 02
KB –> Host: C8
Host – KB: E8

Posted in PS2 Keyboard & Mouse Debugging | Leave a comment

Assembly Language Examples

Assembly Language Programming Examples
.James Zou.
10/24/2010

You must be crazy if you are ineresting in reading this kind of stuff here.

Example 1.  
.model small, c
.386
dseg    segment ‘data’
        copy_from       equ     0c000h                  ;copying from c000h segment
        copy_to         equ     8000h                   ;copying to 8000h segment
        n_data_tran     equ     0ffffh                  ;64k
        int_segment     equ     42h                     ;segment for INT 10 (i*4)
        int_offset      equ     40h                     ;offset for INT 10
dseg    ends
sseg    segment stack ‘stack’
        dw 100 dup(“s”)
        top_stack label word
sseg    ends

eseg    segment ‘data’
eseg    ends

cseg    segment ‘code’
        assume cs:cseg, ds:dseg, ss:sseg, es:eseg
start:
        mov     ax,dseg                         ;setup segment registers
        mov     ds,ax

        mov     ax,copy_from                    ;setup c000h segment register
        mov     ds,ax
        mov     ax,copy_to                      ;setup 8000h segment register
        mov     es,ax
        xor     si,si                           ;reset si…
        xor     di,di                           ;…and di

        mov     cx,n_data_tran                  ;set count, number of by to be copy
        rep     movsb

        ;modify INT 10 vector to point to the 8000 segment
        mov     ax,0000h                        ;init ax register for segment change
        mov     es,ax                           ;change the segment to point to the vector table
        mov     bx,int_segment                  ;get the interrupt type segment 8000h
        mov     ax,8000h                        ;address for the segment
        mov     es:[bx],ax                      ;INT 10 point to 8000h segment
.exit
end     start
Example 2.
.model small
 .stack 100h
 .386
 .data
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       Intialization                                                         ;
;                                                                             ;
;…………………………………………………………………..;
        input_request_msg       db ‘Enter CMOS register to read: 00h-8Fh’,0
        hit_any_key_msg         db ‘Hit any key to contiune’,0dh,0ah,'<ESC> to escape’
        nmi_msg                 db ‘NMI is ‘
        on_msg                  db ‘on ‘
        off_msg                 db ‘off ‘
;……………………………………………………………………

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       Control flow:                                                         ;
;       -cls                                                                  ;
;       -get data
;       -display NMI on or off depend on user input
;       -read CMOS location                                                              ;
;       -dipslay result                                                       ;
;       -repeat or exit                                                       ;
;…………………………………………………………………..;

.code
.startup

 control_loop:
        call    clear_scrn_25_x_80       ; clear the screen
        mov     cx, lengthof input_request_msg; set cx for string display
        mov     bp, offset input_request_msg; set pointer for string display
        xor     dx,dx                   ; set cusor position for screen display
        call    print_string_uc         ; display input request message
        call    get_byte_to_8F          ; get byte from user
        jnc     buffer_good             ; jump is user input good
        cmp     al, 27                  ; check for exc key
        je      exit_point              ; if esc pressed, exit program
        call    beep_char               ; any other error, beep and re-prompt
        jmp     control_loop            ; get new data
;…………………………………………………………………..
buffer_good:
        push    ax                      ; preserve input data
        inc     dh                      ; increment display line number
        mov     cx, lengthof nmi_msg    ; prep cx for display
        mov     bp, offset nmi_msg      ; prep pointer for display
        call    print_string_uc         ; print NMI message
        cmp     ah,’8’                  ; test for NMI on or off
        je      nmi_off                 ; skip print on msg
        mov     bp, offset on_msg       ; prep to print off msg
        mov     cx,03h                  ; set string print length
        jmp     nmi_on                  ; skip print on msg
nmi_off:
        mov     bp, offset off_msg      ; prep to print off msg
        mov     cx,04h                  ; set string print length
nmi_on:
        add     dl,07h                  ; set column position for disply
        call    print_string_uc         ; print on or off msg
        pop     ax                      ; restore input data

        call    ascii_byte_to_hex
        or      al,80h                  ; set msn to al
        out     70h,al                  ; send CMOS address
        in      al,71h                  ; read CMOS data into al
        call    hex_byte_to_ascii
        mov     cx,8
        rol     ax,cl                   ; put 1st char in al to be display
        call    print_char_ic           ; display 1st char
        rol     ax,cl                   ; put 2nd char in al to be display
        call    print_char_ic           ; display 2nd char
        inc     dh                      ; increment cursor line number
        inc     dh
        xor     dl, dl                  ; restet cursor to column 0
        mov     bp, offset hit_any_key_msg; prep to display msg
        mov     cx, lengthof hit_any_key_msg; prep to display msg
        call    print_string_uc         ; print ‘hit any key to continue’
        call    read_kbd_char           ; check for keypress
        cmp     al, 27                  ; check for esc key
        je      exit_point              ; exit if escape is pressed
        jmp     control_loop            ; return to begining

 exit_point:
 .exit

;…………………………………………………………………..;

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       clear_scrn_25_x_80                                                    ;
;       this procedure uses no imputs; it assumes a screen starting at 0,0 and;
;       ending at 24,79.  The entire screen is scrolled up using INT 10 06    ;
;                                                                             ;
;       input: nothing                                                        ;
;                                                                             ;
;       output: nothing                                                       ;
;                                                                             ;
;       registers: none                                                       ;
;                                                                             ;
;…………………………………………………………………..;

clear_scrn_25_x_80 proc
        pusha                           ; preserve all registers to make procedure
                                        ; highly portable
        mov     ax,0600h                ; ah=function number for int10 (06)
                                        ; al=number of lines to scroll (00=clear screen)
        mov     bx,700h                 ; bh=color attribute for new lines
        xor     cx,cx                   ; ch=upper left hand line number of window (dec)
                                        ; cl=upper left hand column number of window (dec)
        mov     dx,184fh                ; dh=low right hand line number of window (dec)
                                        ; dl=low right hand column number of window (dec)
        int     10h
        popa                            ; restore resgisters
        ret
clear_scrn_25_x_80 endp
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       position_cursor                                                       ;
;       this procedure uses DX and INT 10 function 02h to position the cursor ;
;       into a desired location on the screen.                                ;
;                                                                             ;
;       input:   dh=line (dec)                                                ;
;                dl=column (dec)                                              ;
;                                                                             ;
;       output: nothing                                                       ;
;                                                                             ;
;       registers: none                                                       ;
;                                                                             ;
;…………………………………………………………………..;

position_cursor proc
        push    ax                      ; preserve ax & bx
        push    bx
        mov     ah, 02h                 ; function number for int10
        mov     bh, 00h                 ; video page number
        int     10h
        pop     bx                      ; restore bx & ax
        pop     ax
        ret
position_cursor endp
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       print_string                                                          ;
;       print_string_uc  (update cursor)                                      ;
;       This procedure prints a string to the screen.                         ;
;                                                                             ;
;       input:  cx=string length                                              ;
;               dh=line number                                                ;
;               dl=column number                                              ;
;               bp=offset to string buffer                                    ;
;               ds=segment for string buffer                                  ;
;                                                                             ;
;       output: nothing                                                       ;
;                                                                             ;
;       registers: DX                                                         ;
;                                                                             ;
;…………………………………………………………………..;

print_string:
        push    ax                      ; preserve ax & bx
        mov     ax, 1300h               ; function number for int 10
        jmp     print_string_common
print_string_uc:
        push    ax                      ; preserve ax & bx
        mov     ax, 1301h               ; function number for int 10
print_string_common:                    ; portion of function common to both routines
        push    bx
        mov     bx, 0007h               ; attribute of charaters in the string
        push    ds                      ; point es to string buffer
        pop     es
        int     10h
        pop     bx                      ; restore bx & ax
        pop     ax
        ret

;……………………………………………………………………
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       read_kbd_char                                                         ;
;       This procedure reads a single character from the keyboard             ;
;                                                                             ;
;       input:   nothing                                                      ;
;                                                                             ;
;       output: ah=scan code                                                  ;
;               al=ASCII code                                                 ;
;                                                                             ;
;       registers: AX                                                         ;
;                                                                             ;
;…………………………………………………………………..;

read_kbd_char proc
        mov     ah,00h
        int     16h                     ; read char from keyboard
        ret
read_kbd_char endp
;……………………………………………………………………
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       beep_char
;       print_char_0ah                                                        ;
;       print_char_0dh                                                        ;
;       print_char_ic                                                         ;
;       print_char                                                            ;
;       these procedures print a single cahracter to the screen.  _0ah and _odh;
;       and beep do not require any input.  _ic incrments the cursor position,;
;       while print_char does not.                                            ;
;                                                                             ;
;       input:          print_char_ic and print_char                          ;
;                       al=ascii of character to be written                   ;
;                                                                             ;
;       output:         nothing                                               ;
;                                                                             ;
;       registers:      none                                                  ;
;                                                                             ;
;…………………………………………………………………..;

beep_char:
        push    ax                      ; save ax
        mov     ax,0e07h                ; ah=function number
                                        ; al=ascii for beep
        jmp     print_char_common

print_char_0ah:
        push    ax                      ; save ax
        mov     ax,0e0ah                ; ah=function number
                                        ; al=ascii for line feed
        jmp     print_char_common
print_char_0dh:
        push    ax                      ; save ax
        mov     ax,0e0dh                ; ah=function number
                                        ; al=ascii for carrage return
        jmp     print_char_common
print_char_ic:
        push    ax                      ; save ax   ***(ah=al)***
        mov     ah,0eh                  ; ah=function number
        jmp     print_char_common
print_char:
        push    ax                      ; save ax
        mov     ah,0ah                  ; ah=function number
print_char_common:
        push    bx                      ; save bx and cx
        push    cx
        mov     bx,01h                  ; indicate white on black
                                        ; text
        mov     cx,1                    ; indicate single execution
        int     10h
        pop     cx                      ; restore ax, bx, cx
        pop     bx
        pop     ax
        ret
;……………………………………………………………………
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       print_0a0d                                                            ;
;       This function performs a carrage return and a line feed               ;
;                                                                             ;
;       input:          nothing                                               ;
;                                                                             ;
;       output:         nothing                                               ;
;                                                                             ;
;       registers:      none                                                  ;
;                                                                             ;
;…………………………………………………………………..;

print_0a0d:
        call    print_char_0ah          ; display line feed char
        call    print_char_0dh          ; display carrage return char
        ret
;……………………………………………………………………
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       validate_number_in_range                                              ;
;       This procedure ensures that the provided ASCII char lies between      ;
;       zero and a range limit (decimal or hex) in ASCII.                     ;
;                                                                             ;
;       input:          ah= range limit  ‘0’-‘9’ or ‘A’-‘F’ (ascii)           ;
;                       al= char to check                                     ;
;                                                                             ;
;       output:         no carry = number within range                        ;
;                       carry = number not within range                       ;
;                                                                             ;
;       registers:      none                                                  ;
;                                                                             ;
;…………………………………………………………………..;

validate_number_in_range:
        cmp     ah, ‘9’                         ; is range limit decimal?
        jbe     numeric_test                    ; test decimal range only
        and     ah, 11011111b                   ; convert to uppercase
        call    validate_hex_char               ; test hex range,
                                                ; carry=not in range
        jnc     number_in_range                 ; number good so ret
        mov     ah, ‘9’                         ; prime ah for numeric test
        clc
numeric_test:
        call    validate_numeric_char           ; test decimal range,
                                                ; carry=not in range
        jnc     number_in_range                 ; number good so return
        stc                                     ; number not in either range
                                                ; so set carry flag
number_in_range:
        ret
;……………………………………………………………………
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       validate_numeric_char                                                 ;
;       This procedure checks if a provided ascii number (al) is between zero ;
;       and a specified range limit (ah) in ASCII.                            ;
;                                                                             ;
;       input:          ah= range limit (decimal ‘0’-‘9’ ascii)               ;
;                       al= ascii number to check                             ;
;                                                                             ;
;       output:         no carry = number within range                        ;
;                       carry = number not within range                       ;
;                                                                             ;
;       registers:      none                                                  ;
;                                                                             ;
;…………………………………………………………………..;

validate_numeric_char:
        clc
        cmp     al, ‘0’                         ; test al below zero
        jb      invalid_numeric                 ; if al is below 0 stc & exit
        cmp     al, ah
        jg      invalid_numeric                 ; if al is greater, stc & exit
        clc                                     ; clear carry; al is good!
        jmp     valid_numeric
invalid_numeric:
        stc                                     ; set carry; al is bad 😦
valid_numeric:
        ret
;……………………………………………………………………
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       validate_hex_char                                                     ;
;       This procedure checks if a provided ascii number (al) is between ‘A’  ;
;       and a specified range limit (ah) in ASCII.                            ;
;                                                                             ;
;       input:          ah= range limit (decimal ‘A’-‘F’ ascii)               ;
;                       al= ascii number to check                             ;
;                                                                             ;
;       output:         no carry = number within range                        ;
;                       carry = number not within range                       ;
;                                                                             ;
;       registers:      none                                                  ;
;                                                                             ;
;…………………………………………………………………..;

validate_hex_char:
        clc
        push    ax
        and     al, 11011111b                   ; convert to uppercase
        cmp     al, ‘A’                         ; test al below ‘A’
        jb      invalid_hex                     ; if below ‘A’ stc & exit
        cmp     al, ah                          ; test al greater then ah
        jg      invalid_hex                     ; if al is greater, stc & exit
        clc                                     ; clear carry, al is good 🙂
        jmp     valid_hex
invalid_hex:
        stc                                     ; set carry, al is bad 😦
valid_hex:
        pop     ax
        ret
;……………………………………………………………………
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       get_byte_to_8F                                              ;
;       This function reads two nibbles from the keyboard and ensures that    ;
;       each is a valid hex number in the range 00-8F.                        ;                                ;
;                                                                             ;
;       input:          ah= range limit (decimal ‘A’-‘F’ ascii)               ;
;                       al= ascii number to check                             ;
;                                                                             ;
;       output:         no carry = data good                                  ;
;                               ah= upper nibble                              ;
;                               al= lower nibble                              ;
;                       carry = data bad                                      ;
;                                                                             ;
;       registers:      ax, bx                                                ;
;                                                                             ;
;…………………………………………………………………..;

get_byte_to_8F:
        push    bx                      ; preserve bx
        clc                             ; clear carry flag to indicate no error
        call    read_kbd_char           ; get one ascii char from keyboard
        mov     ah,’8′                  ; set upper limit for range test
        call    validate_number_in_range; test 1st char is 0-8
        jc      abort_bad_char          ; quit if out of range
        call    print_char_ic           ; print valid char on screen
        mov     bh, al                  ; save char in bh
        call    read_kbd_char           ; get one ascii char from keyboard

        mov     ah,’F’                  ; set upper limit for range test
        call    validate_number_in_range; test 2nd char is 0-F
        jc      abort_bad_char          ; quit if out of range
        call    print_char_ic           ; print 2nd char
        mov     ah, bh                  ; load 1st char in ah
        jmp     all_data_good           ; quit with no carry
abort_bad_char:
        stc                             ; set carry for indicate error
all_data_good:
        pop     bx
        ret
;……………………………………………………………………
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       ascii_byte_to_hex                                                     ;
;                                                                             ;
;       input:          ah=high ascii nibble                                  ;
;                       al=low ascii nibble                                   ;
;                                                                             ;
;       output:         ah=0                                                  ;
;                       al=hex byte                                           ;
;                                                                             ;
;       registers:      none                                                  ;
;                                                                             ;
;       Note: MSN= Most Significant Nibble                                    ;               ;
;             LSN= Least Significant Nibble                                   ;                             ;
;…………………………………………………………………..;

ascii_byte_to_hex:
        push    cx                      ; preserve cx
        push    bx                      ; preserve bx
        push    ax                      ; preserve al (lsn)
        mov     al, ah                  ; mov high ascii nibble to al
        mov     ah,’9′                  ; load ah for ascii range check (0-9)

        call    validate_numeric_char   ; is msn numeric (0-9)?
        jc      msn_alpha               ; msn is aplha (a-f)
        and     al, 0fh                 ; translate ascii to numeric
        jmp     msn_rol                 ; skip alpha translation
msn_alpha:
        sub     al, 39                  ; translate ascii to alpha
        msn_rol:
        mov     cl, 4                   ;
        rol     al, cl                  ; shift msn left by 4 bits
        mov     bl, al                  ; preserve msn in bl
        pop     ax                      ; restore lsn
        mov     ah,’9′                  ; load ah for range check
        call    validate_numeric_char   ; is lsn numeric?
        jc      lsn_alpha               ; lsn is alpha
        and     al, 0fh                 ; translate ascii to numeric
        jmp     msn_lsn                 ; skip alpha translation
lsn_alpha:
        sub     al, 39                  ; translate ascii to alpha
msn_lsn:
        and     al,0fh                  ; keep the lsn in al
        or      al, bl                  ; drop msn into al
        xor     ah,ah                   ; clear ah
        pop     bx                      ; restore bx
        pop     cx                      ; restore cx
        ret

;……………………………………………………………………
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       hex_byte_to_ascii                                                     ;
;       This procedure takes a hex byte in al, translates each nibble into    ;
;       ascii and stores the result in ax.                                    ;
;                                                                             ;
;       input:          al=hex byte data                                      ;
;                                                                             ;
;       output:         ah=upper ascii nibble  (upper case alpha)             ;
;                       al=lower ascii nibble  (upper case alpha)             ;
;                                                                             ;
;       registers:      none                                                  ;
;                                                                             ;
;…………………………………………………………………..;
hex_byte_to_ascii:
        push    cx                      ; preserve bx & cx
        push    bx
        push    ax                      ; preserve lower hex nibble
        and     al, 0f0h                ; mask off lower hex nibble
        mov     cx, 4
        ror     al, cl                  ; shift msn right 4 bits
        cmp     al,9                    ; is msn greater than 9?
        jg      mshexn_alpha            ; if so, translate aplha to ascii
        or      al,30h                  ; translate numeric to ascii
        jmp     get_lshexn              ; skip alpha translation
mshexn_alpha:
        add     al, 37h                 ; translate alpha to ascii (upper case)
get_lshexn:
        mov     bh, al                  ; save msn ascii in bh
        pop     ax                      ; restore lsn
        and     al,0fh                  ; mask off msn
        cmp     al,9                    ; is lsn greater than 9?
        jg      lshexn_alpha            ; if so, translate alpha to ascii
        or      al,30h                  ; translate numeric to ascii
        jmp     hex_to_ascii_done       ; skip alpha translation
lshexn_alpha:
        add     al, 37h                 ; translate alpha to ascii
hex_to_ascii_done:
        mov     ah, bh                  ; restore ms ascii nibble
        pop     bx
        pop     cx
        ret

;……………………………………………………………………
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       print_hex_in_al                                                       ;
;       This routine takes a hex byte in al, translates it into ascii and     ;
;       and displays it to the screen.                                        ;
;                                                                             ;
;       input:          al= byte value in hex                                 ;
;                                                                             ;
;       output:         none                                                  ;
;                                                                             ;
;       registers:      none                                                  ;
;                                                                             ;
;…………………………………………………………………..;
print_hex_in_al:
        push    ax                      ; preserve ax
        call    hex_byte_to_ascii       ; convert hex byte to ascii
        push    ax                      ; preserve lower ascii nibble
        mov     al, ah                  ; move upper ascii nibble to al
        call    print_char_ic           ; display msn
        pop     ax                      ; retrieve lsn
        call    print_char_ic           ; display lsn
        pop     ax                      ; restore ax
        ret
end

.model small
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                               ;
;       Intialization                                                           ;
;                                                                               ;
;…………………………………………………………………….;
dseg    segment ‘data’
        prompt_user     db      “Enter CMOS register to read. ==> “,’$’
        CMOS_address    db      2 dup (0)
        NMI_on          db      “NMI ENABLE ”
        NMI_off         db      “NMI DISABLE ”
        continue        db      “Hit any key to continue”
        exit_press      db      “OR Hit ESC key to exit”
dseg    ends

sseg    segment stack ‘stack’
        dw 100 dup(“s”)
        top_stack label word
sseg    ends

eseg    segment ‘data’
eseg    ends

;……………………………………………………………………..

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       Control flow:                                                           ;
;       -cls                                                                    ;
;       -get data                                                               ;
;       -display NMI on or off depend on user input                             ;
;       -read CMOS location                                                     ;
;       -dipslay result                                                         ;
;       -repeat or exit                                                         ;
;…………………………………………………………………….;

cseg    segment ‘code’
        assume cs:cseg, ds:dseg, ss:sseg, es:eseg
start:
        mov     ax,dseg
        mov     ds,ax
restart:
        mov     ah,00h                  ;Set video mode
        mov     al,03h                  ;set to 640×200
        int     10h
        call    msg_enter_cmos          ;prompt user

        mov     bx,0h                   ;init array index
cmos_add:
        mov     ah,00h                  ;init input for read
        int     16h                     ;get input from keyboard
        mov     CMOS_address[bx],al     ;store user input
        cmp     al,1bh                  ;if user press ESC…
        jz      exit_prog               ;…exit the prog
        mov     ah,0eh                  ;init to display char
        int     10h                     ;display char in AL

        cmp     bx,0h                   ;check for 1st char input…
        jne     second_char             ;…if not then it a second char input
        cmp     al,30h                  ;if al is less then 0 then…
        jl      start                   ;…prompt user again…
        cmp     al,38h                  ;…else if al greater 8 then prompt user again…
        jg      start
        jmp     it_num                  ;go and get the 2nd input
second_char:
        cmp     al,30h                  ;if al is less then 0 then…
        jl      start                   ;…prompt user again…
        cmp     al,39h                  ;…else if al greater 9 then…
        jg      check_alp               ;…check if al is within a-f….
        jmp     it_num
check_alp:
        and     al,11011111b            ;convert to uppercase
        cmp     al,41h                  ;check to see if al is between a-f
        jl      start                   ;….
        cmp     al,46h                  ;if al is between a-f then done…
        jle     it_num
        jmp     start                   ;…else prompt the user again
it_num:
        mov     CMOS_address[bx],al     ;store user input

        inc     bx                      ;inc index
        cmp     bx,2h
        jnz     cmos_add                ;do until get all two numbers

        mov     dx,0100h                ;Set to display in the 2nd line
        call    new_line

        mov     bx,0h                   ;init the index
        mov     ah,CMOS_address[0]      ;get the first number
        cmp     ah,38h                  ;if the first number is greater or equal to 38 then…
        jge     off_nmi                 ;…turn NMI off else…
        jmp     on_nmi                  ;…turn NMI on

off_nmi:                                ;display disable NMI
        mov     ah,0eh                  ;init function
        mov     al,NMI_off[bx]          ;ASCII code of the char to be display
        int     10h                     ;display it
        inc     bx                      ;inc index to the next char in the string
        cmp     bx,11
        jnz     off_nmi                 ;until all of the NMI DISABLE words is display
        jmp     end_off_nmi

on_nmi:                                 ;display disable NMI
        mov     ah,0eh                  ;init function
        mov     al,NMI_on[bx]           ;ASCII code of the char to be display
        int     10h                     ;display it
        inc     bx                      ;inc index to the next char in the string
        cmp     bx,10
        jnz     on_nmi                  ;until all of the NMI ENABLE words is display

end_off_nmi:                            ;done with NMI ENABLE or NMI DISABLE
        mov     dx,0200h                ;set to display in the 3rd line
        call    new_line

        mov     al,CMOS_address[0]      ;get the first number
        call    hex_conversion          ;coverse ascii to hex number
        mov     bx,0h                   ;clear bx
        mov     bl,al                   ;copy the first number in hex
        push    bx                      ;store first number
        mov     al,CMOS_address[1]      ;get the 2nd number
        call    hex_conversion          ;converse ascii to hex number
        pop     bx                      ;restore first number
        mov     cx,4                    ;set positions for shifting
        shl     bl,cl                   ;shift bl 4 bits to the left
        or      al,bl                   ;combine the first and 2nd numbers
        out     70h,al                  ;read CMOS RAM, AL is the address
        in      al,71h                  ;read data from AL address, store infor in AL

        mov     bx,0h                   ;clear bx
        mov     bl,al                   ;copy data from al to bl
        push    bx                      ;store CMOS data
        and     al,0f0h                 ;take the 1st number
        mov     cx,4h                   ;set positions to shifted
        shr     al,cl                   ;shift AL

        call    ascii_conversion        ;converse hex to ascii
        mov     ah,0eh                  ;display the 1st number
        int     10h

        pop     bx                      ;restore CMOS data
        mov     al,bl                   ;copy it to AL
        and     al,0fh                  ;get the 2nd number
        call    ascii_conversion        ;converse hex to ascii
        mov     dx,0201h                ;move cursor one to the right
        call    new_line
        mov     ah,0eh                  ;display the 2st number
        int     10h

        mov     dx,0500h                ;move cursor one to the right
        call    new_line

        mov     bx,0h                   ;array index
cont:                                   ;Prompt the user for CMOS register
        mov     ah,0eh                  ;displaying char
        mov     al,continue[bx]         ;ASCII code of the char to be display
        int     10h                     ;display
        inc     bx                      ;inc the index to the next char in the string
        cmp     bx,23                   ;repeat until the end of the string
        jnz     cont

        mov     dx,0600h                ;move cursor one to the right
        call    new_line

        mov     bx,0h                   ;array index
exit_p:                                 ;Prompt the user for CMOS register
        mov     ah,0eh                  ;displaying char
        mov     al,exit_press[bx]       ;ASCII code of the char to be display
        int     10h                     ;display
        inc     bx                      ;inc the index to the next char in the string
        cmp     bx,22                   ;repeat until the end of the string
        jnz     exit_P

        mov     ah,00h                  ;init input for read
        int     16h                     ;get input from keyboard
        cmp     al,1bh                  ;if user press ESC…
        jz      exit_prog               ;…exit the prog

        jmp     start

exit_prog:
.exit
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       hex_conversion                                                          ;
;       This procedure takes the ascii in al, translates                        ;
;       the ascii into hex and stores the result in al.                         ;
;                                                                               ;
;       input: al = ascii data                                                    ;
;                                                                               ;
;       output: al = hex                                                      ;
;                                                                               ;
;       registers: aL                                                           ;
;                                                                               ;
;…………………………………………………………………….;
hex_conversion          proc    near
        cmp     al,39h                  ;if al is less or egual to 39h then…
        jle     sub_num                 ;…sub 30h to get the num else…
        jmp     sub_alp                 ;…sub 37h to get the alp
sub_num:
        sub     al,30h                  ;converse ascii number to hex
        jmp     hex_done
sub_alp:
        sub     al,37h                  ;converse ascii alp to hex
hex_done:
        ret
hex_conversion  endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       ascii_conversion                                                        ;
;       This procedure takes last hex in al, translates each                    ;
;       nibble into ascii and stores the result in al.                          ;
;                                                                               ;
;       input: al = hex data                                                    ;
;                                                                               ;
;       output: al = ascii                                                      ;
;                                                                               ;
;       registers: aL                                                           ;
;                                                                               ;
;…………………………………………………………………….;
ascii_conversion        proc    near
        cmp     al,9h                   ;if al is less or equal to 9 then…
        jle     add_num                 ;…add num else…
        jmp     add_alp                 ;…add alp
add_num:
        add     al,30h                  ;converse hex number to ascii
        jmp     done_conver
add_alp:
        add     al,37h                  ;converse hex alp to ascii
done_conver:
        ret
ascii_conversion        endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       new_line  (update cursor)                                               ;
;       This procedure position cursor.                                         ;
;                                                                               ;
;       input:  ah = function                                                   ;
;               dh = line number on screen                                      ;
;               dl = column number on screen                                    ;
;                                                                               ;
;       output: nothing                                                         ;
;                                                                               ;
;       registers: ax                                                           ;
;                                                                               ;
;…………………………………………………………………….;
new_line        proc    near
        mov     ah,02h                  ;init the function
        int     10h                     ;place the cursor
        ret
new_line        endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       msg_enter_cmos                                                          ;
;       This procedure display msgs to ask user to enter the                    ;
;       cmos address.                                                           ;
;                                                                               ;
;       input:  none                                                                ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: ax, bx                                                       ;
;                                                                               ;
;…………………………………………………………………….;
msg_enter_cmos  proc    near
        mov     bx,0h                   ;array index
prompt:                                 ;Prompt the user for CMOS register
        mov     ah,0eh                  ;displaying char
        mov     al,prompt_user[bx]      ;ASCII code of the char to be display
        int     10h                     ;display
        inc     bx                      ;inc the index to the next char in the string
        cmp     bx,33                   ;repeat until the end of the string
        jnz     prompt
        ret
msg_enter_cmos  endp
end     start

Example 3.
.model small
 .stack 100h
 .386
 .data
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       Intialization                                                           ;
;                                                                               ;
;…………………………………………………………………….;
        msg_1                   db      ‘Standard CMOS:’
        msg_2                   db      ‘Extended Memory size from inside the CMOS checksum.’
        msg_3                   db      ‘Extended Memory size from outside the CMOS checksum.’
        msg_4                   db      ‘CMOS checksum: ‘
        msg_5                   db      ‘Interrupt Vector:’
        msg_6                   db      ‘Extended Memory size: ‘
        msg_7                   db      ‘Base Memory size: ‘
        hit_any_key_msg         db      ‘Hit any key to contiune’,0dh,0ah,'<ESC> to EXIT’
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       Control flow:                                                           ;
;       -cls screen                                                             ;
;       -display msg_1                                                          ;
;       -display standard CMOS (all 128kb)                                      ;
;       -display msg_2                                                          ;
;       -read the extended memory size from inside the CMOS checksum            ;
;       -convert the hex numbers to dec numbers                                 ;
;       -display extended memory size from inside the CMOS checksum             ;
;       -display msg_3                                                          ;
;       -read the extended memory size from outside the CMOS checksum           ;
;       -convert the hex numbers to dec numbers                                 ;
;       -display extended memory size from outside the CMOS checksum            ;
;       -wait (prompt user)                                                     ;
;       -calculate the cmos, convert hex to dec, and display it                 ;
;       -use INT to get the extrended memory and display it                     ;
;       -use INT to get the base memory and display it                          ;
;…………………………………………………………………….;

.code
.startup

 control_loop:
        call    clear_scrn_25_x_80              ; clear the screen
        mov     cx, lengthof msg_1              ; set cx for string display
        mov     bp, offset msg_1                ; set pointer for string display
        xor     dx,dx                           ; set cusor position for screen display
        call    print_string_uc                 ; display input request message

        call    new_line                        ; down one line
        mov     cx,0h                           ; init counter
problem_1:
        mov     al,cl                           ; set cmos register number
        call    read_and_display                ; read cmos location and display it the screen
        push    cx                              ; store counter
        and     cl,0fh                          ; get the last nibble
        cmp     cl,0fh                          ; if register number not equal to Fh then …
        jne     cont                            ; …continue else…
        call    new_line                        ; …start from the next line
cont:
        pop     cx                              ; restore counter
        inc     cx                              ; inc counter
        cmp     cx,8fh                          ; if counter greater than 128kb then…
        jg      problem_2                       ; …do problem 2….
        jmp     problem_1                       ; …continue do problem 1
problem_2:
        call    new_line                        ; start from the next line
        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msg_2              ; set cx for string display
        mov     bp, offset msg_2                ; set pointer for string display
        call    print_string_uc                 ; display input request message
        call    new_line                        ; start from the next line

        mov     al,18h                          ; init to read extend memory (high byte)
        call    read_cmos_location              ; read the extend memory high byte
        mov     ah,al                           ; copy the high byte to ah
        mov     al,17h                          ; init to read extend memory (low byte)
        call    read_cmos_location              ; read the extend memory low byte
        call    hex_to_dec                      ; convert hex to dec and display it
problem_3:
        call    new_line                        ; start from the next line
        call    new_line                        ; start from the next line
        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msg_3              ; set cx for string display
        mov     bp, offset msg_3                ; set pointer for string display
        call    print_string_uc                 ; display input request message
        call    new_line                        ; start from the next line

        mov     al,31h                          ; init to read extend memory (high byte)
        call    read_cmos_location              ; read the extend memory high byte
        mov     ah,al                           ; copy the high byte to ah
        mov     al,30h                          ; init to read extend memory (low byte)
        call    read_cmos_location              ; read the extend memory low byte
        call    hex_to_dec                      ; convert hex to dec and display it
        call    new_line                        ; start from the next line

problem_4:
        call    new_line                        ; start from the next line
        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msg_4              ; set cx for string display
        mov     bp, offset msg_4                ; set pointer for string display
        call    print_string_uc                 ; display input request message

        mov     dx,0h                           ; clear register for checksum
        mov     cx,10h                          ; init counter
continue_4:
        mov     al,cl                           ; init cmos register number
        call    read_cmos_location              ; read cmos location
        mov     ah,0h                           ; clear ah register
        add     dx,ax                           ; checksum = checksum + ax
        inc     cx                              ; inc counter
        cmp     cx,2eh                          ; if counter not equal to 2eh (cmos register number) then…
        jne     continue_4                      ; …counter do the checksum

        mov     ax,dx                           ; set to al with hex nibble to convert to ascii
        call    hex_to_dec                      ; convert hex to dec and display it
        call    new_line                        ; start from the next line
        call    exit_or_continue                ; hold the display
problem_5:
        call    new_line                        ; start from the next line
        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msg_5              ; set cx for string display
        mov     bp, offset msg_5                ; set pointer for string display
        call    print_string_uc                 ; display input request message
        call    new_line                        ; start from the next line

        mov     dx,0h                           ; clear register
        mov     bx,0h                           ; init index
continue_5:
        push    ds                              ; store the segment
        mov     ds,dx                           ; set segment address to 0
        mov     al,ds:[bx]                      ; read 00:[bx] location
        pop     ds                              ; restore the segment
        call    hex_to_ascii                    ; convert to ascii
        call    display_hex                     ; display it
        push    bx                              ; store index
        and     bl,0fh                          ; get the last nibble
        cmp     bl,0fh                          ; if register number not equal to Fh then …
        jne     no_new_line_5                   ; …continue else…
        call    new_line                        ; …start from the next line
no_new_line_5:
        pop     bx                              ; restore index
        inc     bx                              ; inc index
        cmp     bx,02ffh                        ; if the offset is greater than 768b then…
        jg      problem_6                       ; …do problem 6 else…
        jmp     continue_5                      ; …continue reading the interrupt vector

problem_6:
        call    new_line                        ; start from the next line
        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msg_6              ; set cx for string display
        mov     bp, offset msg_6                ; set pointer for string display
        call    print_string_uc                 ; display input request message

continue_6:
        mov     ah, 88h                         ; get the extrended memory function
        int     15h                             ; get the size of extrended memory
        call    hex_to_dec                      ; convert hex to dec and display it

problem_7:
        call    new_line                        ; start from the next line
        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msg_7              ; set cx for string display
        mov     bp, offset msg_7                ; set pointer for string display
        call    print_string_uc                 ; display input request message
        int     12h                             ; get the size of base memory
        call    hex_to_dec                      ; convert hex to dec and display it
exit_point:
.exit
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       hex_to_dec                                                              ;
;       the procedure convert hex to dec and display it on the screen           ;
;                                                                               ;
;       input: ax = hex numbers                                                 ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: ax                                                           ;
;                                                                               ;
;…………………………………………………………………….;
hex_to_dec      proc    near
        push    bx                      ; store register
        push    cx
        push    dx

        mov     bx,0h                   ; init the counter
        mov     dx,0h                   ; clear dx for remainder
        mov     cx,10                   ; set to be divided
next_div:
        div     cx                      ; ax/cx
        inc     bx                      ; inc counter
        push    dx                      ; store the remainder
        mov     dx,0h                   ; clear dx for the next remainder
        cmp     ax,0h                   ; stop dividing if the quotient is zero
        jne     next_div                ; else continue

do_pop:
        pop     dx                      ; restore the remainder
        mov     al,dl                   ; al take the remainder
        call    hex_to_ascii            ; convert the 2nd nibble into ascii
        mov     ah,0eh                  ; function code for display on the screen
        int     10h                     ; display it
        dec     bx                      ; dec the counter
        cmp     bx,0h                   ; if the counter reach zero then done restore…
        jne     do_pop                  ; …all remainder else continue getting the remainder

        pop    dx                       ; restore the register
        pop    cx
        pop    bx
        ret
hex_to_dec      endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       exit_or_continue                                                        ;
;       the procedure prompt the user to press any to continue or               ;
;       press <esc> to exit the program                                         ;
;                                                                               ;
;       input: none                                                             ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;

exit_or_continue        proc    near
        pusha
        call    new_line                        ; start from the next line
        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof hit_any_key_msg    ; set cx for string display
        mov     bp, offset hit_any_key_msg      ; set pointer for string display
        call    print_string_uc                 ; display input request message
        call    new_line                        ; start from the next line

        call    read_kbd_char                   ; wait to user to press a button
        cmp     al, 27                          ; check for exc key
        je      exit_point                      ; if esc pressed, exit program
        popa
        ret
exit_or_continue        endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       read_and_display                                                        ;
;       read_cmos_location (read cmos location)                                 ;
;       hex_to_ascii       (convert hex to ascii)                               ;
;       display_hex        (display ascii char to screen)                       ;
;                                                                               ;
;       input: al = cmos register number                                        ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
 read_and_display       proc    near
        call    read_cmos_location              ; read the cmos location
        call    hex_to_ascii                    ; convert hex into ascii code
        call    display_hex                     ; display to the screen
        ret
 read_and_display       endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       new_line                                                                ;
;       this procedure uses no imputs; it will position the cursor to a         ;
;       new line.                                                               ;
;                                                                               ;
;       input: none                                                             ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
new_line        proc    near
        pusha
        mov     ah,0eh
        mov     al,0dh
        int     10h
        mov     ah,0eh
        mov     al,0ah
        int     10h
        popa
        ret
new_line        endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       display_hex                                                             ;
;       this procedure will print two character to the screen.  One from ah     ;
;       another from al.                                                        ;
;                                                                               ;
;       input: ax = ascii of character to be written                            ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
display_hex     proc    near
        push    cx                      ; store register
        push    ax
        mov     cx,8h
        shr     ax,cl                   ; get the 1st nibble
        mov     ah,0eh                  ; function code for displaying char
        int     10h                     ; display the 1st nibble
        pop     ax                      ; restore data
        mov     ah, 0eh                 ; function code for displaying char
        int     10h                     ; display the 2nd nibble
        mov     ah,0eh                  ; function code for displaying char
        mov     al,20h                  ; display a space
        int     10h                     ; display it

        pop     cx                      ; restore register
        ret
display_hex     endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       hex_to_ascii                                                            ;
;       this procedure will convert hex character to ascii.                     ;
;                                                                               ;
;       input:  al = 1st and 2nd nibble to be convert to ascii                  ;
;                                                                               ;
;       output: ah = 1st nibble in ascii number                                 ;
;               al = 2nd nibble in ascii number                                 ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
hex_to_ascii   proc    near
        push    bx                      ; store register
        push    cx
        push    ax
        mov     cx,4                    ; set for shifting
        shr     al,4                    ; get the 1st hex number
        cmp     al,9                    ; compare to see if it a number or alp
        jg      alp1                    ; if alp go to alp1 else…
        add     al,30h                  ; …convert to ascii
        jmp     second_nibble
alp1:
        add     al,37h                  ; …convert to ascii
second_nibble:
        mov     bl,al                   ; store the 1st nibble
        pop     ax                      ; retore the hex numbers
        and     al,0fh                  ; get the 2nd hex number
        cmp     al,9                    ; compare to see if it a number or alp
        jg      alp2                    ; if alp go to alp2 else…
        add     al,30h                  ; …convert to ascii
        jmp     done_nibble
alp2:
        add     al,37h                  ; …convert to ascii
done_nibble:
        mov     ah,bl                   ;
        pop     cx
        pop     bx
        ret
hex_to_ascii   endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       read_cmos_location                                                      ;
;       this procedure uses al as an register number, then read the           ;
;       CMOS location and return the data in al register.                     ;
;                                                                               ;
;       input: al                                                               ;
;                                                                               ;
;       output: al                                                              ;
;                                                                               ;
;       registers: ax                                                           ;
;                                                                               ;
;…………………………………………………………………….;
read_cmos_location      proc    near
        out     70h,al
        in      al,71h
        ret
read_cmos_location      endp
;…………………………………………………………………..;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       clear_scrn_25_x_80                                                      ;
;       this procedure uses no imputs; it assumes a screen starting at 0,0 and  ;
;       ending at 24,79.  The entire screen is scrolled up using INT 10 06      ;
;                                                                               ;
;       input: nothing                                                          ;
;                                                                               ;
;       output: nothing                                                         ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
clear_scrn_25_x_80 proc
        pusha                           ; preserve all registers to make procedure
                                        ; highly portable
        mov     ax,0600h                ; ah=function number for int10 (06)
                                        ; al=number of lines to scroll (00=clear screen)
        mov     bx,700h                 ; bh=color attribute for new lines
        xor     cx,cx                   ; ch=upper left hand line number of window (dec)
                                        ; cl=upper left hand column number of window (dec)
        mov     dx,184fh                ; dh=low right hand line number of window (dec)
                                        ; dl=low right hand column number of window (dec)
        int     10h
        popa                            ; restore resgisters
        ret
clear_scrn_25_x_80 endp
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       current_cursor_position                                               ;
;       this procedure reads the current cursor position on the               ;
;       specified video page and return it in dx.                             ;
;                                                                             ;
;       input:  ah = function                                                ;
;               bh = video page number                                       ;
;                                                                             ;
;       output: ch = beginning line of the blinking cursor                    ;
;               cl = ending lin of the blinking cursor                        ;
;               dh = line on screen                                           ;
;               dl = column on screen                                         ;
;                                                                             ;
;       registers: none                                                       ;
;                                                                             ;
;…………………………………………………………………..;
current_cursor_position         proc
        push    ax                      ; preserve ax & bx
        push    bx
        mov     ah, 03h                 ; function number for int10
        mov     bh, 00h                 ; video page number
        int     10h
        pop     bx                      ; restore bx & ax
        pop     ax
        ret
current_cursor_position         endp
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       print_string                                                          ;
;       print_string_uc  (update cursor)                                      ;
;       This procedure prints a string to the screen.                         ;
;                                                                             ;
;       input:  cx=string length                                              ;
;               dh=line number                                                ;
;               dl=column number                                              ;
;               bp=offset to string buffer                                    ;
;               ds=segment for string buffer                                  ;
;                                                                             ;
;       output: nothing                                                       ;
;                                                                             ;
;       registers: DX                                                         ;
;                                                                             ;
;…………………………………………………………………..;
print_string:
        push    ax                      ; preserve ax & bx
        mov     ax, 1300h               ; function number for int 10
        jmp     print_string_common
print_string_uc:
        push    ax                      ; preserve ax & bx
        mov     ax, 1301h               ; function number for int 10
print_string_common:                    ; portion of function common to both routines
        push    bx
        mov     bx, 0007h               ; attribute of charaters in the string
        push    ds                      ; point es to string buffer
        pop     es
        int     10h
        pop     bx                      ; restore bx & ax
        pop     ax
        ret
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       read_kbd_char                                                         ;
;       This procedure reads a single character from the keyboard             ;
;                                                                             ;
;       input:   nothing                                                      ;
;                                                                             ;
;       output: ah=scan code                                                  ;
;               al=ASCII code                                                 ;
;                                                                             ;
;       registers: AX                                                         ;
;                                                                             ;
;…………………………………………………………………..;

read_kbd_char   proc      near
        mov     ah,00h
        int     16h                     ; read char from keyboard
        ret
read_kbd_char   endp
end                                     ; end of file
Example 4.
We will read the PCI configuration space specification and develop an algorithm followed by an assembly language program to detect the number of PCI devices present in a system. A PCI device might be a multi function device as well. When a PCI device is detected, determine if the PCI device is a multi or a single function device. If it is a multi function device, determine how many functions present in that particular PCI device.

.model small
 .stack 100h
 .486p
 .data
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       Intialization                                                           ;
;                                                                               ;
;…………………………………………………………………….;
        msgs_on_pci_bus         db      ‘On PCI Bus ‘
        msgs_device_present     db      ‘ device(s) present’
        msgs_device_no          db      ‘Device No. ‘
        msgs_has                db      ‘h has ‘
        msgs_function           db      ‘ function(s) ‘
        hit_any_key_msg         db      ‘Hit any key to contiune’,0dh,0ah,'<ESC> to EXIT’
        device_no               db      0
        function_no             db      0
        device_function         db      32 dup(0)
        div_ten                 db      10
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       Control flow:                                                           ;
;       -cls screen                                                             ;
;       -Detect PCI device                                                      ;
;       -Determine if the PCI device has mult function or a single function     ;
;       -Determine how many functions present in a particular PCI device
;       -Display the inform has found for the Bus                               ;
;…………………………………………………………………….;
.code
.startup

zz control_loop:
        call    clear_scrn_25_x_80              ; clear the screen
        mov     cx, lengthof msgs_on_pci_bus    ; set cx for string display
        mov     bp, offset msgs_on_pci_bus      ; set pointer for string display
        xor     dx,dx                           ; set cusor position for screen display
        call    print_string_uc                 ; display input request message

        xor     bx, bx                          ; clear counter for Bus number
        mov     ah,0eh                          ; function to write to the screen
        mov     al, bl                          ; take the counter
        add     al, 30h                         ; convert the number into ascii number
        int     10h                             ; display it to the screen
        call    new_line                        ; down one line

        mov     eax, 80000000h                  ; Bus 0, PCI device 0, function 0, offset 0
search_next_bus:
        call    init_data                       ; init all the data to 0
        call    search_device                   ; search for the device
        call    display_device_function         ; display all of the device and function
                                                ; that has been found
        add     eax, 00010000h                  ; inc the configuration of the next Bus
        inc     bx                              ; inc the counter for Bus
        cmp     bl, 6                           ; if bus != 6 then
        jne     con_bus_search                  ; search the next bus
        jmp     exit_point                      ; else exit the program

con_bus_search:
        call    new_line                        ; down one line
        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msgs_on_pci_bus    ; set cx for string display
        mov     bp, offset msgs_on_pci_bus      ; set pointer for string display
        call    print_string_uc                 ; display input request message

        push    eax                             ; save the PCI configuration
        mov     ah,0eh                          ; function to write to the screen
        mov     al, bl                          ; take the counter
        add     al, 30h                         ; convert the number into ascii number
        int     10h                             ; display the number to the screen
        call    new_line                        ; down one line

        pop     eax                             ; restore the PCI configuration
        jmp     search_next_bus

exit_point:
.exit
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       init_data                                                               ;
;       the procedure init all of the data                                      ;
;                                                                               ;
;       input:  none                                                            ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
init_data       proc    near
        pusha                                   ; store all register
        mov     device_no, 0                    ; init device number
        mov     function_no, 0                  ; init device function
        xor     bx, bx                          ; clear index
init_data_continue:
        mov     device_function[bx], 0h         ; clear all of the data in the array
        inc     bx                              ; inc the index
        cmp     bx, 32                          ; if index != 32 then
        jne    init_data_continue               ; clear the next element in the array
        popa                                    ; restore all register
        ret
init_data       endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       search_device                                                           ;
;       the procedure search for all of the PCI device                          ;
;                                                                               ;
;       input:  eax = pci configuration numbers                                 ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
search_device   proc    near
        pusha                                   ; store all register

        xor     bx, bx                          ; clear counter for device
detect_device:                                  ; search of number of device in Bus 0
        push    eax                             ; save pci configuration
        mov     dx, 0cf8h                       ; get the address port
        out     dx, eax                         ; Write eax to address port
        mov     dx, 0cfch                       ; get the data port
        in      eax, dx                         ; Read from data port
        cmp     ax, 00h                         ; if read in data == 0 or ffffh
        je      no_device_found                 ;
        cmp     ax, 0ffffh                      ;
        je      no_device_found                 ; then not device is found

add_device_no:                                  ; found a device
        mov     al, device_no                   ; get the device number
        add     al, 1                           ; inc the device nubmer
        daa                                     ; convert the device number into dec
        mov     device_no, al                   ; save the device number
        pop     eax                             ; restore the PCI configuration
        call    search_function                 ; search for function
        mov     dl, function_no                 ; get the function number
        mov     device_function[bx], dl         ; save the function number into the device index
        push    eax                             ; save the PCI configuration
no_device_found:
        pop     eax                             ; restore the PCI configuration
        add     ah, 8h                          ; inc device, PCI configuration
        inc     bx                              ; inc the device index
        cmp     bx, 32                          ; if device != 32 then
        jne     detect_device                   ; continue detecting next device

        popa                                    ; restore all register
        ret
search_device   endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       display_device_function                                                 ;
;       the procedure display all of the device numbers that has a function     ;
;       and number of functions                                                 ;
;                                                                               ;
;       input:  none                                                            ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
display_device_function         proc    near
        pusha

        mov     al, device_no                   ; get the device number
        call    hex_to_ascii                    ; convert the number into ascii number
        mov     ah, 0eh                         ; function to write to the screen
        int     10h                             ; display it to the screen
        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msgs_device_present; set cx for string display
        mov     bp, offset msgs_device_present  ; set pointer for string display
        call    print_string_uc                 ; display input request message

        call    new_line                        ; down one line

        xor     bx, bx                          ; clear the index for device
display_next_device:
        mov     al, device_function[bx]         ; get the function number for precific device
        cmp     al, 0                           ; if function == 0
        je      counter_inc                     ; then check for the next device

        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msgs_device_no     ; set cx for string display
        mov     bp, offset msgs_device_no       ; set pointer for string display
        call    print_string_uc                 ; display input request message

        mov     al, bl                          ; get the index for device
        call    hex_to_ascii                    ; convert it into ascii number
        mov     dl, al                          ; save the 2nd nibble
        mov     al, ah                          ; get the 1st nibble to be display
        mov     ah, 0eh                         ; function to write to the screen
        int     10h                             ; display it to the screen

        mov     al, dl                          ; get the 2nd nibble to be display
        mov     ah, 0eh                         ; function to write to the screen
        int     10h                             ; display it to the screen

        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msgs_has           ; set cx for string display
        mov     bp, offset msgs_has             ; set pointer for string display
        call    print_string_uc                 ; display input request message

        mov     al, device_function[bx]         ; get the function for a precific device
        call    hex_to_ascii                    ; convert it to ascii number
        mov     ah, 0eh                         ; function to write to the screen
        int     10h                             ; display it to the screen

        call    current_cursor_position         ; get the current cursor position
        mov     cx, lengthof msgs_function      ; set cx for string display
        mov     bp, offset msgs_function        ; set pointer for string display
        call    print_string_uc                 ; display input request message

        call    new_line                        ; down one line
counter_inc:
        inc     bx                              ; inc the index for device
        cmp     bx, 32                          ; if the index device != 32
        jne     display_next_device             ; then continue to display else exit the loop
        popa                                    ; register all register
        ret
display_device_function         endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       search_function                                                         ;
;       the procedure search the all of the function for the pci device         ;
;                                                                               ;
;       input:  eax = pci configuration number                                  ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
search_function         proc    near
        push    eax                             ; store all register
        push    bx
        push    cx
        push    dx

        push    eax                             ; save the pci configuration
        mov     function_no, 0h                 ; set the function number to 0
        add     al, 0ch                         ; set the pci configuration to point to
                                                ; read bist, header type, latency timer,
                                                ; and cache line size
        mov     dx, 0cf8h                       ; set the address port
        out     dx, eax                         ; Write eax to address port
        mov     dx, 0cfch                       ; set the data port
        in      eax, dx                         ; Read from data port
        shr     eax, 23                         ; get the msb in the header type
        mov     bl, al                          ; save it in bl
        pop     eax                             ; restore the pci configuration
        cmp     bl, 1                           ; if bl == 1 then is a mult function
        je      mult_function_found
single_function_found:                          ; else is a single function
        mov     al, function_no                 ; get the function number
        add     al, 1                           ; inc function number
        daa                                     ; convert it to dec number
        mov     function_no, al                 ; save it
        jmp     done_function_search

mult_function_found:                            ; for mult function
        mov     cx, 7                           ; init the counter
search_next_function:
        push    eax                             ; save the pci configuration
        mov     dx, 0cf8h                       ; set up the address port
        out     dx, eax                         ; Write eax to address port
        mov     dx, 0cfch                       ; set up the data port
        in      eax, dx                         ; Read from data port

        cmp     ax, 00h                         ; if the vendor id == 0 or ffffh
        je      no_function_found               ;
        cmp     ax, 0ffffh                      ;
        je      no_function_found               ; then there is no function
add_function_no:
        mov     al, function_no                 ; get the function number
        add     al, 1                           ; inc the function number
        daa                                     ; convert it to dec number
        mov     function_no, al                 ; save it
no_function_found:
        pop     eax                             ; restore the pci configuration
        add     ah, 1h                          ; inc the function for pci configuration
        loop    search_next_function

done_function_search:
        pop     dx                              ; restore all register
        pop     cx
        pop     bx
        pop     eax
        ret
search_function         endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       new_line                                                                ;
;       this procedure uses no imputs; it will position the cursor to a         ;
;       new line.                                                               ;
;                                                                               ;
;       input: none                                                             ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
new_line        proc    near
        pusha                                   ; store all register
        mov     ah,0eh                          ; function to write to the screen
        mov     al,0dh                          ; carry return
        int     10h                             ; display it
        mov     ah,0eh                          ; function to write to the screen
        mov     al,0ah                          ; line feed
        int     10h                             ; display it
        popa                                    ; store all register
        ret
new_line        endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       hex_to_ascii                                                            ;
;       this procedure will convert hex character to ascii.                     ;
;                                                                               ;
;       input:  al = 1st and 2nd nibble to be convert to ascii                  ;
;                                                                               ;
;       output: ah = 1st nibble in ascii number                                 ;
;               al = 2nd nibble in ascii number                                 ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
hex_to_ascii   proc    near
        push    bx                              ; store register
        push    cx
        push    ax
        mov     cx,4                            ; set for shifting
        shr     al,4                            ; get the 1st hex number
        cmp     al,9                            ; compare to see if it a number or alp
        jg      alp1                            ; if alp go to alp1 else…
        add     al,30h                          ; …convert to ascii
        jmp     second_nibble
alp1:
        add     al,37h                          ; …convert to ascii
second_nibble:
        mov     bl,al                           ; store the 1st nibble
        pop     ax                              ; retore the hex numbers
        and     al,0fh                          ; get the 2nd hex number
        cmp     al,9                            ; compare to see if it a number or alp
        jg      alp2                            ; if alp go to alp2 else…
        add     al,30h                          ; …convert to ascii
        jmp     done_nibble
alp2:
        add     al,37h                          ; …convert to ascii
done_nibble:
        mov     ah,bl                           ; get the 1st nibble
        pop     cx                              ; restore register
        pop     bx
        ret
hex_to_ascii   endp
;…………………………………………………………………..;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       clear_scrn_25_x_80                                                      ;
;       this procedure uses no imputs; it assumes a screen starting at 0,0 and  ;
;       ending at 24,79.  The entire screen is scrolled up using INT 10 06      ;
;                                                                               ;
;       input: nothing                                                          ;
;                                                                               ;
;       output: nothing                                                         ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
clear_scrn_25_x_80 proc
        pusha                                   ; preserve all registers to make procedure
                                                ; highly portable
        mov     ax, 0600h                       ; ah=function number for int10 (06)
                                                ; al=number of lines to scroll (00=clear screen)
        mov     bx, 700h                        ; bh=color attribute for new lines
        xor     cx, cx                          ; ch=upper left hand line number of window (dec)
                                                ; cl=upper left hand column number of window (dec)
        mov     dx, 184fh                       ; dh=low right hand line number of window (dec)
                                                ; dl=low right hand column number of window (dec)
        int     10h
        popa                                    ; restore resgisters
        ret
clear_scrn_25_x_80 endp
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       current_cursor_position                                               ;
;       this procedure reads the current cursor position on the               ;
;       specified video page and return it in dx.                             ;
;                                                                             ;
;       input:  ah = function                                                 ;
;               bh = video page number                                        ;
;                                                                             ;
;       output: ch = beginning line of the blinking cursor                    ;
;               cl = ending lin of the blinking cursor                        ;
;               dh = line on screen                                           ;
;               dl = column on screen                                         ;
;                                                                             ;
;       registers: none                                                       ;
;                                                                             ;
;…………………………………………………………………..;
current_cursor_position         proc
        push    ax                              ; preserve ax & bx
        push    bx
        mov     ah, 03h                         ; function number for int10
        mov     bh, 00h                         ; video page number
        int     10h
        pop     bx                              ; restore bx & ax
        pop     ax
        ret
current_cursor_position         endp
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       print_string                                                          ;
;       print_string_uc  (update cursor)                                      ;
;       This procedure prints a string to the screen.                         ;
;                                                                             ;
;       input:  cx=string length                                              ;
;               dh=line number                                                ;
;               dl=column number                                              ;
;               bp=offset to string buffer                                    ;
;               ds=segment for string buffer                                  ;
;                                                                             ;
;       output: nothing                                                       ;
;                                                                             ;
;       registers: DX                                                         ;
;                                                                             ;
;…………………………………………………………………..;
print_string:
        push    ax                              ; preserve ax & bx
        mov     ax, 1300h                       ; function number for int 10
        jmp     print_string_common
print_string_uc:
        push    ax                              ; preserve ax & bx
        mov     ax, 1301h                       ; function number for int 10
print_string_common:                            ; portion of function common to both routines
        push    bx
        mov     bx, 0007h                       ; attribute of charaters in the string
        push    ds                              ; point es to string buffer
        pop     es
        int     10h
        pop     bx                              ; restore bx & ax
        pop     ax
        ret
end                                             ; end of file

        mov     consonant, 0                    ; set 1st letter for consonant to not
        mov     vowel, 0                        ; set 1st letter for consonant to not
        mov     space, 1                        ; set the spacing to yes
        jmp     write_next                      ; go write the char to file

check_space:
        cmp     space, 1                        ; check for the spacing between word
        jne     write_next                      ; if no spacing between word then write it to the file
        call    vowel_characters                ; else check for vowel in the 1st char
        jnc     check_space_con                 ; if not a vowel then check for consonant
        mov     consonant, 0                    ; set 1st letter for consonant to not
        mov     vowel, 1                        ; set 1st letter for vowel to yes
        mov     space, 0                        ; set the spacing to no
        jmp     write_next                      ; go write the char to file
check_space_con:
        call    consonant_characters            ; check for the consonant
        jnc     write_next                      ; if not a consonant then go write it to the file
        mov     dl, inbuff                      ; take the char
        mov     first_letter, dl                ; store it in file_letter
        mov     consonant, 1                    ; set 1st letter for consonant to yes
        mov     vowel, 0                        ; set 1st letter for vowel to not
        mov     space, 0                        ; set the spacing to yes
        jmp     next_char                       ; go get the the next char
write_next:
        call    write_character                 ; write to file_B
        jmp     next_char                       ; go read the next character

end_read_file:
        call    close_files                     ; close file_A and file_B

        mov     bx, 21h                         ; init the starting point
        mov     cx, 0h
to_screen:

        mov     al, array_alps[bx]              ; get the sum of the char
        cmp     al, 0
        je      cont

        mov     ah, 0eh                         ; function to write to the screen
        mov     al, bl                          ; al take the ascii to display the char
        int     10h
        mov     ah,0eh                          ; function to write to the screen
        mov     al, ‘=’                         ; display =
        int     10h
        mov     al, array_alps[bx]              ; get the sum of the char
        add     al, 30h                         ; convert it to ascii
        mov     ah,0eh                          ; function to write to the screen
        int     10h

        mov     ah,0eh                          ; function to write to the screen
        mov     al, ‘ ‘                         ; display a space
        int     10h
        mov     ah,0eh                          ; function to write to the screen
        mov     al, ‘ ‘                         ; display a space
        int     10h
        inc     cx                              ; init the display counter
        mov     ax, cx                          ; copy it
        and     ax, 0fh                         ; get the 2nd nibble
        cmp     ax, 05h                         ; if it equal to f then
        je      next_line                       ; print set the cursor to the next line
        jmp     cont                            ; else continue
next_line:
        call    new_line                        ; set cursor to the new line
        mov     cx, 0h                          ; reset the display counter
cont:
        inc     bx                              ; inc the ascii code
        cmp     bx, 07fh                        ; display until 7f
        jne     to_screen

exit_point:
.exit
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       open_file                                                               ;
;       the procedure will open file_A and create a new file call file_B        ;
;                                                                               ;
;       input:          none                                                    ;
;                                                                               ;
;       output:         none                                                    ;
;                                                                               ;
;       registers:      none                                                    ;
;                                                                               ;
;…………………………………………………………………….;
open_file       proc    near
        pusha
        mov     al, 02h                         ; open file_A for read
        lea     dx, file_A                      ;
        mov     ah, 3dh
        int     21h
        mov     handle_A, ax                    ; save the handle

        lea     dx, file_B                      ; delete file_B
        mov     ah, 41h
        int     21h

        mov     cx, 0020h                       ; attributes of a new file
        lea     dx, file_B                      ; create file_B
        mov     ah, 5bh
        int     21h
        mov     handle_B,ax                     ; save the handle
        popa
        ret
open_file       endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       write_character                                                         ;
;       the procedure count the number of occurences of each character          ;
;                                                                               ;
;       input:          none                                                    ;
;                                                                               ;
;       output:         none                                                    ;
;                                                                               ;
;       registers:      none                                                    ;
;                                                                               ;
;…………………………………………………………………….;
characters_counter      proc    near
        pusha
        mov     bx,0h                           ; clear bx
        mov     bl, inbuff                      ; get the data from inbuff, use it as index
        mov     al, array_alps[bx]              ; get the contain
        inc     al                              ; inc the sum
        mov     array_alps[bx], al              ; write the sum back to memory
        popa
        ret
characters_counter      endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       write_character                                                         ;
;       the procedure write a character in inbuff to file_B                     ;
;                                                                               ;
;       input:          none                                                    ;
;                                                                               ;
;       output:         none                                                    ;
;                                                                               ;
;       registers:      none                                                    ;
;                                                                               ;
;…………………………………………………………………….;
write_character proc    near
        pusha                                   ; store register
        mov     bx, handle_B                    ; write to file_B
        mov     cx, 1                           ; number of char
        lea     dx, inbuff                      ; data to be writen
        mov     ah, 40h                         ; function for write
        int     21h
        popa                                    ; retore the register
        ret
write_character endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       write_ay                                                                ;
;       the procedure write the 1st char in a word and the word ay to file_B    ;
;                                                                               ;
;       input:          none                                                    ;
;                                                                               ;
;       output:         none                                                    ;
;                                                                               ;
;       registers:      none                                                    ;
;                                                                               ;
;…………………………………………………………………….;
write_ay     proc    near
        pusha
        mov     bx, handle_B                    ; write to file_B
        mov     cx, 1                           ; number of char
        lea     dx, first_letter                ; data to be writen
        mov     ah, 40h                         ; function for write
        int     21h

        mov     bx, handle_B                    ; write to file_B
        mov     cx, 2                           ; number of char
        lea     dx, ay                          ; data to be writen
        mov     ah, 40h                         ; function for write
        int     21h
        popa
        ret
write_ay     endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       write_way                                                               ;
;       the procedure write the word way to file_B                              ;
;                                                                               ;
;       input:          none                                                    ;
;                                                                               ;
;       output:         none                                                    ;
;                                                                               ;
;       registers:      none                                                    ;
;                                                                               ;
;…………………………………………………………………….;
write_way     proc    near
        pusha                                   ; store register
        mov     bx, handle_B                    ; write to file_B
        mov     cx, 3                           ; number of char
        lea     dx, way                         ; data to be writen
        mov     ah, 40h                         ; function for write
        int     21h
        popa                                    ; store register
        ret
write_way     endp

;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       init_data                                                               ;
;       the procedure init the data for an array of alps, number, and other     ;
;       consonant alps is set to 2 and vowel alps is set to 1 and all other     ;
;       is set to 0                                                             ;
;                                                                               ;
;       input:          none                                                    ;
;                                                                               ;
;       output:         none                                                    ;
;                                                                               ;
;       registers:      none                                                    ;
;                                                                               ;
;…………………………………………………………………….;
init_data       proc    near
        pusha                                   ; store register
        mov     bx, 0                           ; init counter
        mov     ax, 0
init_all:                                       ; vowel = 1, consonant = 2, other = 0
        mov     con_vowel_other[bx], al         ; init everything to 0
        inc     bl                              ; inc counter
        inc     bl                              ; inc counter
        cmp     bl, 0feh
        jne     init_all

        mov     bl, ‘A’                         ; starting point
        mov     al, 2
init_consonant:
        mov     con_vowel_other[bx], al         ; init all consonants in uper case to 2
        inc     bl                              ; inc counter
        cmp     bl, ‘Z’
        jne     init_consonant

        mov     bl, ‘a’                         ; starting point
init_consonant_lower:
        mov     con_vowel_other[bx], al         ; init consonants in lower case to 2
        inc     bl                              ; inc counter
        cmp     bl, ‘z’
        jne     init_consonant_lower

init_vowel:
        mov     al, 1                           ; init all the vowel to 1
        mov     bl, ‘a’
        mov     con_vowel_other[bx], al
        mov     bl, ‘A’
        mov     con_vowel_other[bx], al
        mov     bl, ‘e’
        mov     con_vowel_other[bx], al
        mov     bl, ‘E’
        mov     con_vowel_other[bx], al
        mov     bl, ‘i’
        mov     con_vowel_other[bx], al
        mov     bl, ‘I’
        mov     con_vowel_other[bx], al
        mov     bl, ‘o’
        mov     con_vowel_other[bx], al
        mov     bl, ‘O’
        mov     con_vowel_other[bx], al
        mov     bl, ‘u’
        mov     con_vowel_other[bx], al
        mov     bl, ‘U’
        mov     con_vowel_other[bx], al
        popa                                    ; restore the register
        ret
init_data       endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       consonant_characters                                                    ;
;       the procedure find if the character in inbuff is a consonant or not     ;
;       if the character is a consonant, the number counter of the character    ;
;       by one.                                                                 ;
;                                                                               ;
;       input:          none                                                    ;
;                                                                               ;
;       output:         carry flag = 0 if not a consonant                       ;
;                       carry flag = 1 if is a consonant                        ;
;                                                                               ;
;       registers:      none                                                    ;
;                                                                               ;
;…………………………………………………………………….;
consonant_characters    proc    near
        pusha                                   ; store register
        mov     bx, 0h                          ; clear bx
        mov     bl, inbuff                      ; get the data from inbuff
        and     bl, 11011111b                   ; convert to uppercase
        mov     al, con_vowel_other[bx]         ; vowel = 1, consonant = 2, other = 0
        cmp     al, 2                           ; 1 for vowel, check for consonant
        je      find_consonant                  ; if its a consonant
        jmp     not_consonant                   ; if its not a consonant
find_consonant:
        ;mov     bx,0h                           ; clear bx
        ;mov     bl, inbuff                      ; get the data from inbuff, use it as index
        ;mov     al, array_alps[bx]              ; get the contain
        ;inc     al                              ; inc the sum
        ;mov     array_alps[bx], al              ; write the sum back to memory
        stc                                     ; set carry flay
        jmp     done_consonant
not_consonant:
        clc                                     ; clear carry flag
done_consonant:
        popa                                    ; restore register
        ret
consonant_characters    endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       vowel_characters                                                        ;
;       the procedure find if the character in inbuff is a vowel or not         ;
;       if the character is a vowel, the number counter of the character        ;
;       by one.                                                                 ;
;                                                                               ;
;       input:          none                                                    ;
;                                                                               ;
;       output:         carry flag = 0 if not a vowel                           ;
;                       carry flag = 1 if is a vowel                            ;
;                                                                               ;
;       registers:      none                                                    ;
;                                                                               ;
;…………………………………………………………………….;
vowel_characters proc    near
        pusha                                   ; store register
        mov     bx, 0h                          ; clear bx
        mov     bl, inbuff                      ; get the data from inbuff
        and     bl, 11011111b                   ; convert it to uppercase
        mov     al, con_vowel_other[bx]         ; vowel = 1, consonant = 2, other = 0
        cmp     al, 1                           ; 1 for vowel, check for vowel
        je      find_vowel                      ; if its a vowel
        jmp     not_vowel                       ; if not a vowel
find_vowel:
        ;mov     bx,0h                           ; clear bx
        ;mov     bl, inbuff                      ; get the data from inbuff, use it as index
        ;mov     al, array_alps[bx]              ; get the contain
        ;inc     al                              ; inc the sum
        ;mov     array_alps[bx], al              ; write the sum back to memory
        stc                                     ; set carry flay
        jmp     done_vowel
not_vowel:
        clc                                     ; clear carry flag
done_vowel:
        popa                                    ; restore register
        ret
vowel_characters endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       close_files                                                             ;
;       the procedure will close the file_A and file_B                          ;
;                                                                               ;
;       input:  none                                                            ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
close_files     proc    near
        pusha                                   ; store the register
        mov     bx, handle_A                    ; close file_A
        mov     ah, 3eh                         ; function for closing
        int     21h

        mov     bx, handle_B                    ; close file_B
        mov     ah, 3eh                         ; function for closing
        int     21h
        popa                                    ; restore the register
        ret
close_files     endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       new_line                                                                ;
;       this procedure uses no imputs; it will position the cursor to a         ;
;       new line.                                                               ;
;                                                                               ;
;       input: none                                                             ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
new_line        proc    near
        pusha
        mov     ah,0eh
        mov     al,0dh
        int     10h
        mov     ah,0eh
        mov     al,0ah
        int     10h
        popa
        ret
new_line        endp
;…………………………………………………………………..;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       clear_scrn_25_x_80                                                      ;
;       this procedure uses no imputs; it assumes a screen starting at 0,0 and  ;
;       ending at 24,79.  The entire screen is scrolled up using INT 10 06      ;
;                                                                               ;
;       input: nothing                                                          ;
;                                                                               ;
;       output: nothing                                                         ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
clear_scrn_25_x_80 proc
        pusha                           ; preserve all registers to make procedure
                                        ; highly portable
        mov     ax,0600h                ; ah=function number for int10 (06)
                                        ; al=number of lines to scroll (00=clear screen)
        mov     bx,700h                 ; bh=color attribute for new lines
        xor     cx,cx                   ; ch=upper left hand line number of window (dec)
                                        ; cl=upper left hand column number of window (dec)
        mov     dx,184fh                ; dh=low right hand line number of window (dec)
                                        ; dl=low right hand column number of window (dec)
        int     10h
        popa                            ; restore resgisters
        ret
clear_scrn_25_x_80 endp
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       current_cursor_position                                               ;
;       this procedure reads the current cursor position on the               ;
;       specified video page and return it in dx.                             ;
;                                                                             ;
;       input:  ah = function                                                 ;
;               bh = video page number                                        ;
;                                                                             ;
;       output: ch = beginning line of the blinking cursor                    ;
;               cl = ending lin of the blinking cursor                        ;
;               dh = line on screen                                           ;
;               dl = column on screen                                         ;
;                                                                             ;
;       registers: none                                                       ;
;                                                                             ;
;…………………………………………………………………..;
current_cursor_position         proc
        push    ax                      ; preserve ax & bx
        push    bx
        mov     ah, 03h                 ; function number for int10
        mov     bh, 00h                 ; video page number
        int     10h
        pop     bx                      ; restore bx & ax
        pop     ax
        ret
current_cursor_position         endp
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       print_string                                                          ;
;       print_string_uc  (update cursor)                                      ;
;       This procedure prints a string to the screen.                         ;
;                                                                             ;
;       input:  cx = string length                                            ;
;               dh = line number                                              ;
;               dl = column number                                            ;
;               bp = offset to string buffer                                  ;
;               ds = segment for string buffer                                ;
;                                                                             ;
;       output: nothing                                                       ;
;                                                                             ;
;       registers: DX                                                         ;
;                                                                             ;
;…………………………………………………………………..;
print_string:
        push    ax                      ; preserve ax & bx
        mov     ax, 1300h               ; function number for int 10
        jmp     print_string_common
print_string_uc:
        push    ax                      ; preserve ax & bx
        mov     ax, 1301h               ; function number for int 10
print_string_common:                    ; portion of function common to both routines
        push    bx
        mov     bx, 0007h               ; attribute of charaters in the string
        push    ds                      ; point es to string buffer
        pop     es
        int     10h
        pop     bx                      ; restore bx & ax
        pop     ax
        ret
end                                     ; end of file
Example 6.
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
; This Program is to fulfill the following:                                     ;
;       1. Clear the screen                                                     ;
;       2. Init the gdt table                                                   ;
;       3. Go into protected mode and write to memory and read back             ;
;       4. Switch back to real mode                                             ;
;       5. Compare the value read from protected mode with test pattern         ;
;       6. Display the memory location to the screen                            ;
;       7. Update the ES entry in the GDT                                       ;
;       8. Continue 3-7 until end of memory                                     ;
;…………………………………………………………………….;
.model small
.stack 100h
.386

gdt_table       struc
        limit           dw      0h
        lower_address   dw      0h
        upper_address   db      0h
        access_rights   db      0h
        zeros           dw      0h
gdt_table       ends

.data
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       Intialization                                                           ;
;                                                                               ;
;…………………………………………………………………….;
        hit_any_key_msg         db      ‘Hit any key to contiune’,0dh,0ah,'<ESC> to EXIT’
        msg_display             db      ‘Extended Memory Found at:’, 0dh, 0ah
        test_pattern_write      dw      5a5ah
        test_pattern_read       dw      5a5ah
        stack_segment           dw      ?
        stack_pointer           dw      ?
        counter                 db      0

        dummy_descriptor        gdt_table       <0h, 0, 0, 00h, 00h>
        gdt_descriptor          gdt_table       <40h, ?, ?, 93h, 00h>
        idt_descriptor          gdt_table       <0h, 0, 0, 00h, 00h>
        ds_descriptor           gdt_table       <0ffffh, ?, ?, 93h, 00h>
        es_descriptor           gdt_table       <0ffffh, 00h, 10h, 93h, 00h>
        ss_descriptor           gdt_table       <0ffffh, ?, ?, 93h, 00h>
        cs_descriptor           gdt_table       <0ffffh, ?, ?, 9bh, 00h>
        temp_cs_descriptor      gdt_table       <0h, 0, 0, 00h, 00h>
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       Control flow:                                                           ;
;       -cls screen                                                             ;
;       -display extended memory found at: on to the screen                     ;
;       -calculate the physical address for gdt, ds, ss and cs descriptor       ;
;       -set the return address                                                 ;
;       -init soft shutdown                                                     ;
;       -save the ss segment                                                    ;
;       -switch to protected mode                                               ;
;       -write and read from memory                                             ;
;       -reset the CPU                                                          ;
;…………………………………………………………………….;
.code
.startup
control_loop:
        call    clear_scrn_25_x_80              ; clear the screen
        mov     cx, lengthof msg_display        ; set cx for string display
        mov     bp, offset msg_display          ; set pointer for string display
        xor     dx, dx                          ; set cusor position for screen display
        call    print_string_uc                 ; display input request message
        call    new_line                        ; down one line

        mov     ax, seg dummy_descriptor        ; get the gdt table address
        shl     ax, 4                           ; shift 4 bits to the left on the segment
        add     ax, offset dummy_descriptor     ; add the segment and offset address to
        mov     gdt_descriptor.lower_address, ax; physical address and store it to the lower address
        mov     ax, seg dummy_descriptor        ; get the segment addresss
        shr     ax, 12                          ; shift 12 bits to the right to get the upper address
        adc     ax, 0h                          ; and add the carry if any
        mov     gdt_descriptor.upper_address, al; and store it in the ss descriptor uppper address

        push    ds                              ; push ds
        pop     ax                              ; get the ds segment
        shl     ax, 4                           ; shift 4 bits to the left to get calculate
        mov     ds_descriptor.lower_address, ax ; physical address and store it to the lower address
        push    ds                              ; push ds
        pop     ax                              ; get the ds segment
        shr     ax, 12                          ; shift 12 bits to the right to get the upper address
        mov     ds_descriptor.upper_address, al ; and store it in the ss descriptor uppper address

        push    ss                              ; push ss
        pop     ax                              ; get the ss segment
        shl     ax, 4                           ; shift 4 bits to the left to get calculate
        mov     ss_descriptor.lower_address, ax ; physical address and store it to the lower address
        push    ss                              ; push ss
        pop     ax                              ; get the ss segment
        shr     ax, 12                          ; shift 12 bits to the right to get the upper address
        mov     ss_descriptor.upper_address, al ; and store it in the ss descriptor uppper address

        push    cs                              ; push cs
        pop     ax                              ; get the cs segment
        shl     ax, 4                           ; shift 4 bits to the left to get calculate
        mov     cs_descriptor.lower_address, ax ; physical address and store it to the lower address
        push    cs                              ; push cs
        pop     ax                              ; get the cs segment
        shr     ax, 12                          ; shift 12 bits to the right to get the upper address
        mov     cs_descriptor.upper_address, al ; and store it in the ss descriptor uppper address

next_address:
        mov     dx, 40h                         ; set the es segment to 40h
        mov     es, dx                          ;

        mov     es:[69h], seg return_address    ; take the segment of the return
        mov     es:[67h], offset return_address ; offset address after return to real mode

        mov     al, 8fh                         ; write 05h to cmos location 0fh
        out     70h, al                         ; for CPU shutdown
        mov     al, 05h                         ;
        out     71h, al                         ;

        pushf                                   ; save the flag register
        cli                                     ; clear interrupt flag
        mov     ah, 89h                         ; switch from real mode into pretected mode
        xor     bx, bx                          ; with offset to interrupt desciptor table
                                                ; to zero
        push    seg dummy_descriptor            ; setting up the address of descriptor table
        pop     es                              ; getting the segment address and
        mov     si, offset dummy_descriptor     ; the offset address

        push    ss                              ; push the ss segment to the stack
        pop     stack_segment                   ; pop ss segment into the stack_segment
        push    sp                              ; push the ss pointer to the stack
        pop     stack_pointer                   ; pop ss pointer into the stack_pointer
        int     15h                             ; switching mode

        xor     di, di                          ; clear di
        mov     ax, test_pattern_write          ; setup the test pattern
        mov     es:[di], ax                     ; write the test pattern to mem
        mov     ax, es:[di]                     ; and read back from the mem
        mov     test_pattern_read, ax           ; save the test pattern

        mov     al, 0feh                        ; resetting the CPU to return to real mode
        out     64h, al                         ;
return_address:
        xor     ax, ax                          ; write to programmable interrupt controller
        out     21h, ax                         ; to enable all of the operation
        mov     ax, @data                       ; reinit the data segment
        mov     ds, ax                          ;

        push    stack_segment                   ; push the stack_segment to stack
        pop     ss                              ; restore the ss segment
        push    stack_pointer                   ; push the stack_pointer to the stack
        pop     sp                              ; restore the ss pointer
        popf                                    ; restore all flag

        mov     ax, test_pattern_read           ; get the test pattern from mem
        cmp     test_pattern_write, ax          ; if write == read then continure
        jne     exit_point                      ; else exit the program

        inc     counter                         ; init the counter to set new line
        cmp     counter, 6h                     ; if the counter != 6 then
        jne     no_line                         ; continue display to the screen
        mov     counter, 1h                     ; else reset counter
        call    new_line                        ; and set new line
no_line:
        mov     ax, es_descriptor.zeros         ; get the es lower address
        call    hex_to_ascii                    ; convert hex number into ascii number
        call    display_hex                     ; display hex number to the screen

        mov     al, es_descriptor.upper_address ; get the es lower address
        call    hex_to_ascii                    ; convert hex number into ascii number
        call    display_hex                     ; display hex number to the screen
        mov     al, 0h
        call    hex_to_ascii                    ; convert hex number into ascii number
        call    display_hex                     ; display hex number to the screen
        mov     al, 0h
        call    hex_to_ascii                    ; convert hex number into ascii number
        call    display_hex                     ; display hex number to the screen
        call    display_test_pattern            ; display the memory location to the screen

        clc
        add     es_descriptor.upper_address, 1h ; inc the upper address
        jc      add_the_zeros                   ; if uppter addres > ffh then add_the_zeros
        jmp     no_add_zeros                    ; else do nothing
add_the_zeros:
        inc     es_descriptor.zeros             ; inc the zeros
no_add_zeros:
        mov     test_pattern_read, 0h           ; clear the test pattern read
        jmp     next_address                    ; continue test the mem

exit_point:
        xor     ax, ax                          ; write to programmable interrupt controller
        out     21h, ax                         ; to enable all of the operation
.exit
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       display_hex                                                             ;
;       this procedure display the test pattern to the screen                   ;
;                                                                               ;
;       input: al = number to be display to the screen                          ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
display_test_pattern    proc    near
        push    bx                              ; store the register
        push    cx                              ;
        push    dx                              ;

        mov     ah,0eh                          ; function code for displaying char
        mov     al,20h                          ; display a space
        int     10h                             ; display it

        mov     ax, test_pattern_write          ;
        mov     dx, ax                          ; copy the test pattern
        mov     al, ah                          ; get the ah to be display first
        call    hex_to_ascii                    ; convert hex number into ascii number
        call    display_hex                     ; display hex number to the screen
        mov     al, dl                          ; setup the al
        call    hex_to_ascii                    ; convert hex number into ascii number
        call    display_hex                     ; display hex number to the screen

        mov     ah,0eh                          ; function code for displaying char
        mov     al,20h                          ; display a space
        int     10h                             ; display it
        mov     ah,0eh                          ; function code for displaying char
        mov     al,20h                          ; display a space
        int     10h                             ; display it

        pop     dx                              ; restore teh register
        pop     cx                              ;
        pop     bx                              ;
        ret
display_test_pattern    endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       display_hex                                                             ;
;       this procedure will print two character to the screen.  One from ah     ;
;       another from al.                                                        ;
;                                                                               ;
;       input: ax = ascii of character to be written                            ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
display_hex     proc    near
        push    cx                              ; store register
        push    ax
        mov     cx,8h
        shr     ax,cl                           ; get the 1st nibble
        mov     ah,0eh                          ; function code for displaying char
        int     10h                             ; display the 1st nibble
        pop     ax                              ; restore data
        mov     ah, 0eh                         ; function code for displaying char
        int     10h                             ; display the 2nd nibble

        pop     cx                              ; restore register
        ret
display_hex     endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       hex_to_ascii                                                            ;
;       this procedure will convert hex character to ascii.                     ;
;                                                                               ;
;       input:  al = 1st and 2nd nibble to be convert to ascii                  ;
;                                                                               ;
;       output: ah = 1st nibble in ascii number                                 ;
;               al = 2nd nibble in ascii number                                 ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
hex_to_ascii   proc    near
        push    bx                              ; store register
        push    cx
        push    ax
        mov     cx,4                            ; set for shifting
        shr     al,4                            ; get the 1st hex number
        cmp     al,9                            ; compare to see if it a number or alp
        jg      alp1                            ; if alp go to alp1 else…
        add     al,30h                          ; …convert to ascii
        jmp     second_nibble
alp1:
        add     al,37h                          ; …convert to ascii
second_nibble:
        mov     bl,al                           ; store the 1st nibble
        pop     ax                              ; retore the hex numbers
        and     al,0fh                          ; get the 2nd hex number
        cmp     al,9                            ; compare to see if it a number or alp
        jg      alp2                            ; if alp go to alp2 else…
        add     al,30h                          ; …convert to ascii
        jmp     done_nibble
alp2:
        add     al,37h                          ; …convert to ascii
done_nibble:
        mov     ah,bl                           ;
        pop     cx                              ; restore the resgister
        pop     bx                              ;
        ret
hex_to_ascii   endp

;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       new_line                                                                ;
;       this procedure uses no imputs; it will position the cursor to a         ;
;       new line.                                                               ;
;                                                                               ;
;       input: none                                                             ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
new_line        proc    near
        pusha
        mov     ah,0eh
        mov     al,0dh
        int     10h
        mov     ah,0eh
        mov     al,0ah
        int     10h
        popa
        ret
new_line        endp
;…………………………………………………………………..;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       clear_scrn_25_x_80                                                      ;
;       this procedure uses no imputs; it assumes a screen starting at 0,0 and  ;
;       ending at 24,79.  The entire screen is scrolled up using INT 10 06      ;
;                                                                               ;
;       input: nothing                                                          ;
;                                                                               ;
;       output: nothing                                                         ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
clear_scrn_25_x_80 proc
        pusha                                   ; preserve all registers to make procedure
                                                ; highly portable
        mov     ax,0600h                        ; ah=function number for int10 (06)
                                                ; al=number of lines to scroll (00=clear screen)
        mov     bx,700h                         ; bh=color attribute for new lines
        xor     cx,cx                           ; ch=upper left hand line number of window (dec)
                                                ; cl=upper left hand column number of window (dec)
        mov     dx,184fh                        ; dh=low right hand line number of window (dec)
                                                ; dl=low right hand column number of window (dec)
        int     10h
        popa                                    ; restore resgisters
        ret
clear_scrn_25_x_80 endp
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       current_cursor_position                                               ;
;       this procedure reads the current cursor position on the               ;
;       specified video page and return it in dx.                             ;
;                                                                             ;
;       input:  ah = function                                                 ;
;               bh = video page number                                        ;
;                                                                             ;
;       output: ch = beginning line of the blinking cursor                    ;
;               cl = ending lin of the blinking cursor                        ;
;               dh = line on screen             7                              ;
;               dl = column on screen                                         ;
;                                                                             ;
;       registers: none                                                       ;
;                                                                             ;
;…………………………………………………………………..;
current_cursor_position         proc
        push    ax                              ; preserve ax & bx
        push    bx
        mov     ah, 03h                         ; function number for int10
        mov     bh, 00h                         ; video page number
        int     10h
        pop     bx                              ; restore bx & ax
        pop     ax
        ret
current_cursor_position         endp
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       print_string_uc  (update cursor)                                      ;
;       This procedure prints a string to the screen.                         ;
;                                                                             ;
;       input:  cx = string length                                            ;
;               dh = line number                                              ;
;               dl = column number                                            ;
;               bp = offset to string buffer                                  ;
;               ds = segment for string buffer                                ;
;                                                                             ;
;       output: nothing                                                       ;
;                                                                             ;
;       registers: DX                                                         ;
;                                                                             ;
;…………………………………………………………………..;
print_string_uc proc    near
        push    ax                              ; preserve ax & bx
        mov     ax, 1301h                       ; function number for int 10
        mov     bx, 0007h                       ; attribute of charaters in the string
        push    ds                              ; point es to string buffer
        pop     es                              ;
        int     10h                             ;
        pop     ax
        ret
print_string_uc endp
end                                             ; end of file
Example 7.

.model small
.stack 100h
.486p
descriptor      struct
        limit           dw      0h
        lower_address   dw      0h
        upper_address   db      0h
        access_rights   db      0h
        zeros           dw      0h
descriptor      ends
.data
        msgs_extend_memory      db      ‘Extended Memory found at: ‘
        current_position        dw      0h
        test_pattern_write      dw      5a5ah

        gdt_begin       label           word
        dummy           descriptor      <0,0,0,0,0>
        gdt_des         descriptor      <20h,?,?,93h,0>
        es_4gig_des     descriptor      <0ffffh,0,0,93h,8fh>
        es_64k_des      descriptor      <0ffffh,0,0,93h,0>

.code
.startup
start:
        call    clear_scrn_25_x_80              ; clear the screen
        mov     cx, lengthof msgs_extend_memory ; set cx to get the string length
        mov     bp, offset msgs_extend_memory   ; set pointer for string display
        xor     dx,dx                           ; set cusor position for screen display
        call    print_string_uc                 ; display input request message
        call    current_cursor_position         ; get the cursor position
        mov     current_position, dx            ; save it

        call    enable_gate_a20                 ; enable the a20 address line
        mov     dx, 10h                         ; for load a segment
        call    flat_and_real                   ; go into flat mode

        mov     esi, 100000h                    ; start point 1Mb
memory_testing:
        mov     dx, test_pattern_write          ; get the test pattern
        mov     es:[esi], dx                    ; write to memory location
        mov     dx, es:[esi]                    ; read test pattern
        cmp     dx, test_pattern_write          ; if read test pattern != write test pattern
        jne     done_mem_test                   ; then memory test is done else continue

        mov     dx, current_position            ; get the cursor position
        mov     ah, 02h                         ; function to set the cursor position
        int     10h                             ; set the cursor position
        call    time_delay                      ; delay time

        mov     eax, esi                        ; copy the memory location
        call    calculate_display_dec           ; display the memory location to the screen
        add     esi, 010000h                    ; inc memory location by 64k
        jmp     memory_testing

done_mem_test:
        call    disable_gate_a20                ; enable the a20 address line
        mov     dx, 18h                         ; loading a segment
        call    flat_and_real                   ; switch from flat to real mode
.exit
;……………………………………………………………………

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       current_cursor_position                                               ;
;       this procedure reads the current cursor position on the               ;
;       specified video page and return it in dx.                             ;
;                                                                             ;
;       input:  none                                                          ;
;                                                                             ;
;       output: dh = line on screen                                           ;
;               dl = column on screen                                         ;
;                                                                             ;
;       registers: none                                                       ;
;                                                                             ;
;…………………………………………………………………..;
current_cursor_position         proc
        push    ax                      ; preserve ax & bx
        push    bx
        mov     ah, 03h                 ; function number for int 10
        mov     bh, 00h                 ; video page number
        int     10h
        pop     bx                      ; restore bx & ax
        pop     ax
        ret
current_cursor_position         endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       time_delay                                                              ;
;       this procedure will delay the time                                      ;
;                                                                               ;
;       input:  none                                                            ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
time_delay      proc    near
        pusha                                   ; store all register
        mov     cx, 0ffffh                      ; init the counter for delay
delay:
        nop                                     ; delay
        nop                                     ; delay
        loop    delay                           ; continue until cx = 0
        popa                                    ; restore all register
        ret
time_delay      endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       calculate_display_dec                                                   ;
;       this procedure display the test pattern to the screen                   ;
;                                                                               ;
;       input:  eax = in hex to be convert to dec                               ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
calculate_display_dec   proc    near
        push    edx                             ; restore 32 bits register
        push    ecx
        push    ebx

        mov     cx, 0h                          ; init the counter
        mov     ebx, 10                         ; init the divider

next_dec:
        xor     edx, edx                        ; clear the remainder
        div     ebx                             ; eax / 10
        push    dx                              ; save the remainder
        inc     cx                              ; inc the counter
        cmp     eax, 0                          ; if eax != 0
        jne     next_dec                        ; then continue do the divide

        sub     cx, 3                           ; no to display the last 3 digit
next_display_dec:
        pop     dx                              ; restore the remainder
        mov     al, dl                          ; copy remainder into al for convertion
        call    hex_to_ascii                    ; convert hex number into ascii number
        mov     ah,0eh                          ; function code for displaying char
        int     10h                             ; display it
        dec     cx                              ; dec counter
        jnz     next_display_dec                ; continue if not cx != 0

        mov     ah,0eh                          ; function code for displaying char
        mov     al, ‘K’                         ; k on the screen
        int     10h                             ; display it
        mov     ah,0eh                          ; function code for displaying char
        mov     al, ‘b’                         ; b on the screen
        int     10h                             ; display it

        pop     dx                              ; restore 3 last remainders
        pop     dx                              ;
        pop     dx                              ;

        pop     ebx                             ; restore all register
        pop     ecx
        pop     edx
        ret
calculate_display_dec   endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       hex_to_ascii                                                            ;
;       this procedure will convert hex character to ascii.                     ;
;                                                                               ;
;       input:  al = 1st and 2nd nibble to be convert to ascii                  ;
;                                                                               ;
;       output: ah = 1st nibble in ascii number                                 ;
;               al = 2nd nibble in ascii number                                 ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
hex_to_ascii   proc    near
        push    bx                              ; store register
        push    cx
        push    ax
        mov     cx,4                            ; set for shifting
        shr     al,4                            ; get the 1st hex number
        cmp     al,9                            ; compare to see if it a number or alp
        jg      alp1                            ; if alp go to alp1 else…
        add     al,30h                          ; …convert to ascii
        jmp     second_nibble
alp1:
        add     al,37h                          ; …convert to ascii
second_nibble:
        mov     bl,al                           ; store the 1st nibble
        pop     ax                              ; retore the hex numbers
        and     al,0fh                          ; get the 2nd hex number
        cmp     al,9                            ; compare to see if it a number or alp
        jg      alp2                            ; if alp go to alp2 else…
        add     al,30h                          ; …convert to ascii
        jmp     done_nibble
alp2:
        add     al,37h                          ; …convert to ascii
done_nibble:
        mov     ah,bl                           ;
        pop     cx                              ; restore the resgister
        pop     bx                              ;
        ret
hex_to_ascii   endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       flat_and_real                                                           ;
;       this procedure uses dx as an input for loading a segment register       ;
;       (selector) ES.                                                          ;
;                                                                               ;
;       input:  dx = selector for es_4gig_des or es_64k_des                     ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
flat_and_real   proc    near
        pusha                                   ; store all register
                                                ; initialize the gdt descriptor
        mov     ax, ds                          ; get the ds address
        movzx   eax, ax                         ; make the bits 16-31 all zeros
        shl     eax, 4                          ; shift 4 bits to the left
        add     eax, offset gdt_begin           ; calculate the physical address
        mov     gdt_des.lower_address, ax       ; save the lower address
        shr     eax, 16                         ; calculate the upper address
        mov     gdt_des.upper_address, al       ; save the upper address

        mov     al, 80h                         ; disable NMI
        out     70h, al

        lgdt    ds:fword ptr gdt_begin+8        ; load the global descriptor table descriptor

        mov     eax, cr0                        ; get the cr0 register
        or      al, 1                           ; or to set the pe bit in cr0 register
        mov     cr0, eax                        ; set the pe bit in cr0 register
        jmp     $+2                             ; clear the prefetch queue

        mov     ax, dx                          ; dx = 16 for flat and 18 for real
        mov     es, ax

        mov     eax, cr0                        ; get the cr0 register
        and     al, 0feh                        ; and to clear the pe bit in cr0 register
        mov     cr0, eax                        ; clear pe bit in cr0 register
        jmp     $+2                             ; clear teh prefetch queue

        popa                                    ; restore all register
        ret
flat_and_real   endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       clear_scrn_25_x_80                                                      ;
;       this procedure uses no imputs; it assumes a screen starting at 0,0 and  ;
;       ending at 24,79.  The entire screen is scrolled up using INT 10 06      ;
;                                                                               ;
;       input: nothing                                                          ;
;                                                                               ;
;       output: nothing                                                         ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
clear_scrn_25_x_80 proc
        pusha                                   ; preserve all registers to make procedure
                                                ; highly portable
        mov     ax,0600h                        ; ah=function number for int10 (06)
                                                ; al=number of lines to scroll (00=clear screen)
        mov     bx,700h                         ; bh=color attribute for new lines
        xor     cx,cx                           ; ch=upper left hand line number of window (dec)
                                                ; cl=upper left hand column number of window (dec)
        mov     dx,184fh                        ; dh=low right hand line number of window (dec)
                                                ; dl=low right hand column number of window (dec)
        int     10h
        popa                                    ; restore resgisters
        ret
clear_scrn_25_x_80 endp
;…………………………………………………………………….;

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                             ;
;       print_string_uc                                                       ;
;       This procedure prints a string to the screen.                         ;
;                                                                             ;
;       input:  cx=string length                                              ;
;               dh=line number                                                ;
;               dl=column number                                              ;
;               bp=offset to string buffer                                    ;
;               ds=segment for string buffer                                  ;
;                                                                             ;
;       output: nothing                                                       ;
;                                                                             ;
;       registers: DX                                                         ;
;                                                                             ;
;…………………………………………………………………..;
print_string_uc         proc    near
        push    ax                              ; preserve ax & bx
        mov     ax, 1301h                       ; function number for int 10
print_string_common:                            ; portion of function common to both routines
        push    bx
        mov     bx, 0007h                       ; attribute of charaters in the string
        push    ds                              ; point es to string buffer
        pop     es
        int     10h
        pop     bx                              ; restore bx & ax
        pop     ax
        ret
print_string_uc         endp
;…………………………………………………………………….;

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                                                                               ;
;       enable / disable gate A20                                               ;
;                                                                               ;
;       input:  none                                                            ;
;                                                                               ;
;       output: none                                                            ;
;                                                                               ;
;       registers: none                                                         ;
;                                                                               ;
;…………………………………………………………………….;
enable_gate_a20:
        push    ax                                      ; store ax register
        mov     ah, 0dfh                                ; command to enable a20 gate
        jmp     ed_1

disable_gate_a20:
        push    ax                                      ; store ax register
        mov     ah, 0ddh                                ; command to disable a20 gate
ed_1:
        mov     al, 0d1h                                ; command for write to output port
        out     64h, al                                 ;
ed_2:
        jcxz    $+2
        in      al, 64h                                 ; read status byte
        test    al, 2                                   ; check whether input buffer is full
        jnz     ed_2                                    ; some byte still in the input buffer
        mov     al, ah                                  ; pass data byte for controller command
        out     60h, al                                 ;
ed_3:
        in      al, 64h                                 ; read status byte
        test    al, 00000010b                           ; check whether input buffer is full
        jnz     ed_3                                    ; some byte still in the input buffer
        pop     ax                                      ; restore ax register
        ret

end                                                     ; end of program

Posted in Assembly Language | Leave a comment