Sie sind auf Seite 1von 70

Memory Addressed

Display
A-LEVEL ELECTRONICS PROJECT

Dharmesh Malam
AUGUST 2002

www.dharmeshmalam.com
2 Memory Addressed Display

CONTENTS

Summary ................................................................................................................................................................. 5

Specification ........................................................................................................................................................... 6

General ............................................................................................................................................................... 6

Systems .............................................................................................................................................................. 6

Microprocessor .............................................................................................................................................. 6

Display Driver ................................................................................................................................................. 7

Display Multiplexer ........................................................................................................................................ 8

Display ............................................................................................................................................................ 8

Display power supply ..................................................................................................................................... 9

Sound ............................................................................................................................................................. 9

Input............................................................................................................................................................... 9

System Design....................................................................................................................................................... 10

Microprocessor ................................................................................................................................................ 10

General......................................................................................................................................................... 10

Clock ............................................................................................................................................................. 12

Ram .............................................................................................................................................................. 14

IO.................................................................................................................................................................. 16

Human Interface .............................................................................................................................................. 18

Control Pad .................................................................................................................................................. 18

Display Driver ................................................................................................................................................... 20

Video RAM ................................................................................................................................................... 20

Summary of steps needed to refresh video ram ......................................................................................... 24

Row Tristates ............................................................................................................................................... 24

Column Multiplexer ..................................................................................................................................... 26


3 Memory Addressed Display

Display .............................................................................................................................................................. 29

LEDs .............................................................................................................................................................. 29

Power supply to LEDs ................................................................................................................................... 32

PCB ................................................................................................................................................................... 37

Art Work ...................................................................................................................................................... 37

Construction ................................................................................................................................................ 39

Sound System: ................................................................................................................................................. 41

Alternate Solutions ............................................................................................................................................... 42

LCD screen ........................................................................................................................................................ 42

Pros .............................................................................................................................................................. 42

Cons ............................................................................................................................................................. 42

Input System: ................................................................................................................................................... 43

Pro ................................................................................................................................................................ 43

Cons ............................................................................................................................................................. 43

Replace Display Driver with Software: ........................................................................................................... 44

Pros .............................................................................................................................................................. 44

Cons ............................................................................................................................................................. 44

Software ............................................................................................................................................................... 45

Summary .......................................................................................................................................................... 45

Memory ............................................................................................................................................................ 45

More Abstractions ........................................................................................................................................... 46

Pixels to Pictures.............................................................................................................................................. 49

Other Routines ............................................................................................................................................. 51

Software Summary .......................................................................................................................................... 51

Routine Rom Table....................................................................................................................................... 51

Ram address’ ............................................................................................................................................... 52

Helper Subroutine Summary ...................................................................................................................... 52

Diary...................................................................................................................................................................... 54
4 Memory Addressed Display

Week 1,2: The Z80 ........................................................................................................................................... 54

Week 2,3 .......................................................................................................................................................... 54

Week 2,3,4: The PCB ........................................................................................................................................ 54

Week ,3,4: Other systems ............................................................................................................................... 55

Resources.............................................................................................................................................................. 56

Time Spent on Project: .................................................................................................................................... 56

Money Spent on Project: (APPROX)................................................................................................................ 56

Evaluation ............................................................................................................................................................. 57

Acknowledgements .............................................................................................................................................. 58

General ............................................................................................................................................................. 58

Books ................................................................................................................................................................ 58

Internet ............................................................................................................................................................ 58

Other ................................................................................................................................................................ 58

Software ........................................................................................................................................................... 58

Appendix ............................................................................................................................................................... 59

Hardware ......................................................................................................................................................... 59

Software........................................................................................................................................................... 60
5 Memory Addressed Display

SUMMARY

The aim of this project was to design and construct a memory mapped display system, consisting of a
large matrix of 860 LEDs. This is multiplexed and constantly refreshed by a hardware driver, which in turn is
under control and refreshed by a Z80 based microprocessor system. The display is completely general and ab-
stracted to software as a range in memory, which is ‘drawn’ to. This is then outputted to the hardware display
driver which outputs to the display LEDs. Both input ports are connect to control pads which each have eight
push buttons, and are used to interface with the system. The software creates a menu, which allows selection
of programs. A screensaver and sound test program was coded. A simple sound system was also connected
and allows basic noises.

The aim was fully satisfied by the finished project, which showed reliable operation.
6 Memory Addressed Display

SPECIFICATION

GENERAL

The project must be built on a breadboard and a PCB using standard analogue and digital components, such as
74xx, 40xx, Z80, etc, but no use of ‘all in one’ systems.

The project must be completed in three weeks within the feasibility of the equipment requirements.

The system will allow execution of different programs from a menu displayed. There will be a ‘Screen Saver’
program which scrolls user inputted text, at random points across the screen. There should be an introductory
screen.

A ‘Sound Test’ program should also be coded, which should create different sounds depending on which but-
ton is pressed on the pad.

SYSTEMS

MICROPROCESSOR

o A Zilog Z80 based microprocessor system will be constructed on a breadboard. The Z80 will be clocked at
4-MHz from a crystal oscillator.

o The Z80 will interface with four 8-bit output ports, and 2 * 8-bit input ports, i.e. 32-bits of output and
16-bits of input.

o The output ports will be addressed as output port 0, port 1, port 2, and port 3. Additional IO, and address
decode hardware consisting of a 74LS42, and OR Gates will insure that the right port is selected. The out-
put ports are 74LS374 8-bit D-type flip-flops, which are clocked at specific times by the IO decode hard-
ware. This latches the data bus, and therefore has the correct bits as output.

o The input ports will be addressed input port 0 and input port 1. Each is 8-bits wide, and consists of
74LS244 8-bit tristates. Their output enables (/OE) pins are pulsed low by the IO decode hardware, ‘letting
through’ the output from the control pads to the data bus. This is then read by the Z80.

o The Z80 has a ROM and a RAM. The ROM is actually a RAM, but backed by a battery, so its contents are
not lost. It is wired as a standard 2k x 8 EPROM (2716). This memory is pre-built on a mini PCB and fits into
a ZIF socket. It can easily be removed, and inserted into a ‘program loader’ which allows editing of its
contents. The contents are the opcodes and data that the Z80 executes, and processes. This ZIF arrange-
ment allows quick editing and testing.

o The Z80 is also equipped with a 6116 2Kx8 RAM. This gives 2 Kilobytes of memory locations for temporary
storage. The control pins are connected to the memory decoder, which enables the ROM or RAM de-
pending on need.

o The memory decoder consists of a 74LS42, which has pins /MEMRQ, /RD and A11 from the Z80 connected
to inputs C, B, A respectively. Outputs /0 and /1 are connected to /OE pins on the ROM and RAM, so that
when /MEMRQ, /RD, and A11 are all low, /OE to the ROM goes low, thus reading from ROM. When A11 is
high, /OE on the RAM goes low, hence reading from the RAM. /MEMRQ is also connected to the chip en-
able pin (/CE) on the RAM, and /WR from the Z80 is connected to /WR on the RAM. This ensures that
7 Memory Addressed Display

when /MEMRQ and /WR go low, the RAM is written to.

o A relaxation oscillator creates an uneven clock at about 100Hz which is shaped to be mainly high, but
spikes instantly to low by a 4017, is connect to the Maskable Interrupt (/INT) pin on the Z80. This means
the interrupt service routine is called every one hundredth of a second. This routine contains housekeep-
ing functions, such as checking for a pause, and resetting the sound system.

DISPLAY DRIVER

o This sub-system has the role of outputting the right data, from the frame-buffer RAM, to the multiplexer
system. It must also reset the right counters and multiplexers at the right time, and generate the Master
Display Clock. It is refreshed by the Z80 microprocessor system when needed by software, i.e. under pro-
grammer control. This also implements double buffering, which is described later.

o This sub-system is the go between the Z80 and the display. This system controls and outputs to the display
static frames, one bit per LED at any time. To make the simplest scene, like a flashing dot, requires the Z80
to refresh the RAM. This refreshing is controlled by output ports 0, 1, and 2.

o Two 6116 RAMs are connected in parallel, with address and control lines (/WR, /OE) commoned. The data
lines are parallel, so a 16 x 2k RAM is created. The 16 parallel data lines are connected to the display bus,
which in turn are connected to output ports 0 and 1, and also the row tristates. The display bus is either
allowing data from the Z80 to be written to the frame buffer RAM, or allowing data from this RAM to be
outputted to the row tristates on the PCB.

o The address lines on the 6116 RAM are commoned and connected to a 4024 7-bit binary counter. Address
pins A0 to A6 on the RAMs are connected to Q0 to Q6 on 4024. A7 to A10 are connected to 0V. This gives
128 (2^7) memory locations of which 56 are needed. 56 because the display is multiplexed 16 LEDs (half a
row) at a time, and there are 28 rows, therefore 56 (2 * 28) separate 16-bit wide locations are needed.
This is because there is a one to one mapping between bits in the frame-buffer RAM and LEDs on the on
the display.

o The 4024 is an asynchronous binary counter, which here is configured to count from 0000000B to
1110000B, i.e. 0 to 56. It is reset on 56 by a triple input AND gate (74LS11) connected to Q6, Q5, and Q4.
We can clearly see from the binary representation of 56 (1110000B) why this works, as the most signifi-
cant bits only go high on 56. The output of the AND gate is fed through an OR gate (74LS32) to the reset
pin on the 4024. The other input to the OR gate is connected to a pin on output port 3. This is needed by
the refresh routine, as discussed later. The 4024 is clocked by the Master Display Clock (MDC), through an
OR gate (74LS32). The other input is used by the Z80 to refresh the frame buffer. This arrangement of the
4024 makes the RAM output the memory locations 0 to 55 continuously, which are dots seen by the dis-
play.

o The Master Display Clock (MDC) is what clocks the 4024, column multiplexer and the row tristates. This
ensures that the whole display is in sync, as 56 separate clock cycles are needed to display one frame, and
over 50 frames a second are needed display a flicker free image. The MDC consist of a 555 timer circuit
configured to operate at around 3 KHz, as 56 * 50 gives 2800. The two resistors, Ra, and Rb, where Rb is a
5K potentiometer allowing fine tuning of the display clock to give best performance. The enable pin on
the 555 is connected to a pin on output port, which is used by the refresh routine (called OUTRAM).
8 Memory Addressed Display

DISPLAY MULTIPLEXER

o The display and its associated multiplexing system are built on a double sided PCB. The multiplexing sys-
tems are divided into two parts. They are the row tristates which energize 16-LEDs at a time, the same
width at the display bus, and the column multiplexer which energies row after row, from top to bottom.
Since each row has 30 LEDs, and the display bus is 16-bits wide, two energizes are needed to display one
row. I.e. the first 16 LEDs are energized first and then the last 14 are.

o The row tristates consists of 30 tristates on 4 74LS240 chips. Each chip contains 8 inverting three-state
buffers, all connected to one active low output enable (/OE). Thus the first two 74LS240 have their /OE
pins commoned, and the second two have their /OE pins commoned. The four chips contain 32 tristates,
but there are only 30 LEDs per row, so the last 2 tristates on the fourth chip are not needed. The outputs
of the tristates are all connected through PNP emitter followers to the cathodes of the display LEDs. Thus
the first tristate is connected to 28 LED cathodes, as the display is 30x28. The 16 parallel inputs of the first
16 tristates are connected to the display bus, as are the 16 parallel inputs of the last 16 tristates. The 2
commoned output enables are connected to output 1, and output 2 of a 4017, which is configured to re-
set on 3. The 4017 is a decoded decade counter, and is clocked by the MDC. This means on the first cycle
of the MDC, output 1 goes high, while the other outputs are low. This enables the first 2 74LS240s, and
disables the other 2. On the next cycle, the opposite occurs, and on the next, it resets. There is also a
manual reset, which is connected to output port 3, allowing the microprocessor to reset it.

o The display reset pin is what clocks the column multiplexer, as it goes high every 2 cycles of the MDC, and
as the next row must be selected. This system consists of 2 analogue switches configured as a multi-
plexer. Each multiplexer has 16 outputs, and there are 28 rows so the last 4 outputs on the second multi-
plexer are not needed. A 4024, 7-bit binary counter, is configured to count from 0 to 28, (0000000B, to
0011100B). This is done by resetting through a triple AND gate, which has outputs C, D, and E of the 4024
as inputs. The 4067 have four inputs, forming a 4-bit binary number. Both 4067s have the inputs com-
moned and connected to the Least Significant Bits of the 4024 counter. To select the right multiplexer,
the /EN pin on the first 4067 is connected to output E on the counter, and a NOTted E is connected to /EN
on the second multiplexer. There is also a manual reset, which is connected to output port 3, so the mi-
croprocessor can reset it.

DISPLAY

o The display consists of 24 * 17.3 mm 5x7 dot matrix displays. There are arranged in a 6 x 4 grid. There-
fore we have 6 * 5 dots on the x-axis, and 4 * 7 dots on the y-axis. Hence 30 x 28 dots giving a total of 840
dots. This gives the display a high pixel density.

o Each 5x7 dot matrix display has all its anodes and all its cathodes connected. Every display has its cath-
odes connected to the cathodes of the display above and below it, and its anodes connected to the dis-
play left and right of it. This tiling results in one large 30 x 28 display. Since the displays have equal bor-
ders on each side, the geometry of the display is not distorted.

o This resultant display is driven through PNP emitter followers for the columns, and NPN emitter followers
for the rows. The PNPs are connected to the row tristates, and the NPNs are connected to the column
multiplexer. The PNPs are ZTX550 Bipolar transistors, with a base resistor or 3R9, same as the NPNs which
are ZTX 455s. Both are in an ELINE package, and can source over an amp.
9 Memory Addressed Display

DISPLAY POWER SUPPLY

o The emitters in the NPN are connected to their very own power supply. This means the 5V power supply
to the logic is not overloaded and individual adjustment of the brightness can be done.

o A LM317 voltage regulator circuit is used, with de-spiking on the input by a 0.1uF capacitor, and smooth-
ing on the output by a 220uF capacitor. The adjust is controlled by a 10k potentiometer connected to a
knob. This allows adjustment of the voltage, hence the brightness. The input voltage can be varied from
4V to 20V, depending on availability. Even very high voltages, such as 30V, will not damage the display as
the voltage regulator ‘burns’ this off as heat, which is dissipated through a heat sink. The smoothing en-
sures that if suddenly all the LEDs come on, there is enough instantaneous current to light them brightly.

SOUND

o This system allows various sounds to be created when needed in software. A 555 timer clocks a 74LS93
binary counter. This gives us various frequencies. Three different frequencies, plus one at total 5V are put
into tristates. The outputs of the tristates are commoned, and connected to a pizeo buzzer. The 4 input
enables are connected to the first four outputs of output port 3. Different combinations of the output will
create different sounds.

INPUT

o 2 pads made of 8 push-switches are used to interface with the system. They are made on a small PCB.
They connect to the input ports, and usually give a low. The resort to a high when a button is pressed.
10 Memory Addressed Display

SYSTEM DESIGN

MICROPROCESSOR

GENERAL

The Z80 is an 8-bit CISC CPU which can interface with a variety of memories, input and output de-
vices. In the design of this project, a system with 4 output ports and 2 input ports was needed. A 2KB ROM
and a 2KB RAM was also used.

The Z80 has two sets of 6 8-bit general purpose registers, two sets of accumulator and flag registers,
as well as 2 index registers, and other special purpose registers. This is summarised in figure 1 below.

This large register file is used thoroughly in the software, and so is the feature of combining two 8-bit
registers to form a 16-bit register. These registers and the vast instruction set give the programmer the ability
to write complex programs especially if written in assembler as opposed to machine code. The ZIF socket used
to interface the ROM allows quick changes, but the program loader can be tedious to use.
11 Memory Addressed Display

The above diagram shows the pins on the Z80. Address lines A0-A11 were used to access the memo-
ries and address the ports. Pins A12-A15 are not used. Data lines D0-D7 form the data bus which is linked to
the ROM, RAM and the input and output ports.

/CLK was connected to a crystal oscillator circuit shown below in figure 3, which oscillates at 4MHz.
Such a high clock is needed to make sure that the very complex blitting operation (drawing to memory) occurs
instantly with respect to display driver.

The CPU bus control pin /BUSRQ is pulled high as it is not needed. CPU control lines /WAIT and /NMI,
the non maskable interrupt, are pulled high. /RESET is connect to a RC de-bounced switch with also pulses high
on power up to reset the CPU. The maskable interrupt /INT, is connected to a shaped clock, which spikes to
low.

System control pins /MREQ, /IORQ, /WR, /RW all feed the memory and IO decode circuits described
below. /M1, /RFSH, /HALT, and /BUSACK are all disconnected as they are not needed.
12 Memory Addressed Display

CLOCK

The above diagram shows the series resonant crystal oscillator circuit used to clock the Z80. The cir-
cuit is also designed to use the fundamental frequency of the crystal, which here is 4 MHz. The inverter per-
forms a 180-degree phase shift in a series resonant oscillator circuit. The 330 Ohm resistors provide the nega-
tive feedback to bias the inverter in their linear region. The crystal provides a very accurate clock. This allows
accurate estimations of the time taken to execute instructions and a list of the T-states (clock cycles, needed
by each instruction is given in the appendix. Also it means routines are executed extremely fast allowing very
complex routine to be written.

Originally the circuit was built as above, but the Z80 would not clock from it. Testing with a frequency
counter showed it was oscillating at 4MHz. Further testing with an oscilloscope showed the waveform was not
clean enough. This was corrected by sticking a Schmitt trigger (74LS14) on the output. This buffered and
sharpened up the signal.

For testing and construction of the Z80 CPU, a 60 KHz relaxation oscillator was used. This had to be
replaced with a crystal as 60 KHz was to slow and it would not scale over a few hundred kilohertz.
13 Memory Addressed Display

A NOR relaxation oscillator creates the clock signal to /INT. The relaxation oscillator creates a pulse
at about 100Hz. This is used to clock a 4017 decoded decade counter which is configured to reset at 9. The
reset signal is fed into a Schmitt inverter, which is then fed into the /INT pin. This means we get a pulse shape
and so the interrupt service routine is triggered every 100th of a second. Originally a clock which had about
equal mark space was fed in. This was discovered to not be satisfactory as since the Z80 is being clocked at a
high speed the interrupt service routine was being executed extremely fast. This meant that the routine was
finished before the clock could go low again triggering the interrupt again. This happens a few hundred times
before the clock goes high. So instead of triggering the interrupt once, it is triggered half the time the Z80 does
anything. This is inefficient and hence the spiking solution above was used. Note the interrupt service routine
is triggered at best once and at worst a few times.
14 Memory Addressed Display

RAM

The Z80 was equipped with a non-volatile RAM, wired to behave as a ROM, which had 2K locations, as
well as a 6116 2k x 8 RAM. Memory decode circuitry was used to interface the memories to the Z80. We can
see a block diagram in figure 5 below which shows the memory decode and IO refresh circuitry.
15 Memory Addressed Display
16 Memory Addressed Display

Address pins A0 to A10 are connected to A0 to A10 on the ROM and RAM. Data lines D0 to D7 are
connect to D0 - D7 on the ROM and RAM. The memory decode circuit shown above is used. The 74LS24 is used
to enable the right component.

The table below shows the possible output

0v /MREQ/RD A11 | /OE ROM /OE RAM


D C B A | /0 /1
0 1 X X |1 1
0 X 1 X |1 1
0 0 0 0 |0 1
0 0 0 1 |1 0

This means when the Z80 wants to read RAM or ROM, /MREQ and /RD go low. A11 is then used to
select the ROM or RAM. Therefore addresses 0H to 800H are ROM, as 2^11 = 2048 = 800h, and 800h to 1000h
are RAM.

/WR is connected to /WR on the RAM, and /MREQ is also connected to /CE, (chip enable). This
means when the CPU wants to write to RAM, /MREQ and /WR goes low, thus selecting the RAM.

IO

Figure 4 also shows IO decode circuit. The Z80 puts a binary code on its address bus corresponding to
which port it wants to talk to. It also puts /IORQ low, when IO operations are needed, and /RD or /WR low
depending on weather it want to read the input port, or write to the output port. The IO decode circuitry
works all this out and enables the right port.
17 Memory Addressed Display

A 74LS42 is again used, with /IOREQ going into input D, and A0, A1, A2 going into inputs A, B, C on
the 74LS42 respectively. This gives 2^3 =8 possible input and output ports. The outputs /0 - /3 go into an OR
gate, which has its other input as either /WR or /RD depending weather this is an input or output port. This
makes sure the right port is selected

The table below shows the possible selections.

/IORQ A2 A1 A0 | /0 /1 /2 /3
1 X X X 1 1 1 1
0 0 0 0 0 1 1 1
0 0 0 1 1 0 1 1
0 0 1 0 1 1 0 1
0 0 1 1 1 1 1 0

Because of the OR gates, if /0 is low, and /RD is low then input port 0 is selected. If /WR was low then
output port 0 would be selected, etc.

This IO decode circuitry gives us 2 inputs ports and 4 output ports, with which the rest of the system is
controlled.
18 Memory Addressed Display

HUMAN INTERFACE

CONTROL PAD

The control pads are the human interface to the system. The microprocessor reads them and uses
them to select and control what is happening in the program. Each one is simply 8 push switches which are
normally pulled low, but go high when pushed. They are constructed on a PCB, using 1K resistors. Each switch
is connected to an 8-bit wide input port. Therefore if no switches are pressed then, all input lines are low, and
if one is pressed, then the corresponding line goes high. The software checks which bit is high or low and does
the corresponding action.
19 Memory Addressed Display

The above diagram shows the circuit used. It was constructed on PCB, shown in the photo below.
There are two pads for a maximum of 2 users.

Originally the switches were not de-bounced. This gave huge problems when testing the software.
Because the CPU polls the input port to see if any bit is high, and the CPU is running at a very high clock speed,
every press would trigger the CPU hundreds of times. This made using it impossible.

There were too problems, first is the bouncing of the switch, when it closes and opens, which may
trigger the CPU a few times, instead of once. The debouncing is normally solved by using a RC network. This
was tried but it did not work as there is also another problem, the very high clock speed. The switch is proba-
bly pressed down for a hundredth of a second, but the input port is polled, maybe a thousand times a second.
This means, the first high triggers the action, then a few microseconds later the action is finished, and the
software looks at the input port again. But the switch is still pressed, therefore the action happens again. So
the end result is that the action occurs a few hundred times, when the user expects it to occur once.

Therefore even though the switch is de-bounced, the RC discharge still triggers the action a few hun-
dred times. To solve this infuriating problem in hardware was nearly impossible. A software solution was
needed.

At first it was wrongly assumed that there was only a denouncing problem, therefore software
de-bouncer was created. The CPU would poll the input port until a bit went high, it would then wait a few mil-
liseconds, and then check if the port was still high, if it was then the action was committed. This de-bounced
the switch, but it still did not work. This was when the other problem was discovered. The solution was to do
the action on the very first high, but then wait for a few tenths of a second until the end of the action and the
return to polling the port. This solved both problems in one go and all in software.
20 Memory Addressed Display

DISPLAY DRIVER

VIDEO RAM

The diagram above shows the display driver. At its heart are 2 * 6116 RAMs wired up to give a 16 x 2k
RAM. It is connected to a 4024 binary counter configured to counter from 0 to 56, reset and then restart. The
16 parallel data lines are connected to the display bus, which is then connected to the row tristates, and out-
put ports 0 and 1. The whole system is controlled by output port 2.
21 Memory Addressed Display

In normal mode, the MDC is enabled, output port 0 and 1 are disabled, and the RAMs are put into
read mode (/WR = high, /RD = low). This make the system output 56 separate 16-bit wide chunks of data
synchronised with the master display clock. The multiplexer circuitry on the PCB decodes this and puts the
right data to the display.

Port 2 is used to control this system. The RAMs contain the data with which display is multiplexed
with. So at address 0000000, there is 16 bits of data, which correspond to the first 16 LEDs on row 1. Address
0000001, has the data for the next 14 LEDs on row 1, the next address has the data for the first 16 LEDs on row
2, and so on until address 55. These can only contain static data, i.e. not moving. To change something, or to
actually put anything in the RAMs, they need to be refreshed with the internal video RAM. To do this the
OUTRAM routine is called. This routine first stops the MDC, by outputting a low on port 2, output pin 1. This
freezes the display. It then resets the 4024 which increments the RAM, by pulsing pin 3. This makes the RAM
be on address 0. Also the /RD goes high, so nothing is outputted, and /EN2 goes high, which disconnects the
column multiplexers so the display is disabled. It then loads the data for the first 16-LEDS, on row 1 to ports 0
and 1, which are on the display bus, hence connected to the data lines on the rams. It then puts a low to /OE
on ports 0 and 1. This means the data for address 0 is on the bus. This is written in by pulsing /WR. So now the
data for the first 16 LEDs have been written in. The clock to the 4024 is pulsed, making the RAMs point to ad-
dress 1. The whole process is repeated until all 112 bytes have been loaded into the RAMs. Then it resets the
4024 and the column and row multiplexers so everything is on the first address. The output enables on ports 0
and 1 are made high, so the display bus is not connected to the ports. /RD is made low now, the MDC is en-
abled and /EN2 goes low enabling the display. This puts the system back into normal mode, but with a com-
pletely refreshed frame buffer.

This sequence of events has to occur every time something changes on the screen, i.e. something
moves or flashes. It also has to be unnoticeable, hence the need for a very fast clock. If there was a slower
clock the display would go blank when the ram is refreshed, but with a 4MHz clock the process is invisible. This
is crucial because it allows very smooth movement with no artefacts.
22 Memory Addressed Display
23 Memory Addressed Display
24 Memory Addressed Display

SUMMARY OF STEPS NEEDED TO REFRESH VIDEO RAM

1. Stop MDC (EN on 555 goes low) and disable display (/EN2 goes high).

2. Reset column / row logic and RAM counter.

3. Make /RD on RAM high.

4. Load data from internal Z80 RAM onto ports 0 and 1.

5. Enable the ports (/OE on ports goes low).

6. Pulse /WR on RAMS to save data.

7. Pulse clock to 4024 to get to next address.

8. Repeat until all RAM is updated.

9. Disable ports 0, 1 (/OE goes high).

10. Reset row/column logic and ram counter.

11. Make /RD low.

12. Restart MDC (EN on 555 goes high).

The speed of the MDC is crucial for the display. If it is too slow then the multiplexing is visible and the
screen flickers. If it is too fast the system can not keep up and therefore the screen loses synchronization. This
leads to ghosting. To fine tune this frequency, two 10k potentiometers replaced the Ra and Rb resistors on the
555 timer allowing the frequency to be tuned.

ROW TRISTATES

The above diagram shows the row tristate system which is what feeds the LED rows through transis-
25 Memory Addressed Display

tor drivers. It is constructed on a PCB as seen in the photo. It is inputted by the display bus from the PCB. The
74240 are inverting tristates. They invert because otherwise a low on the display bus would light a LED up as
the cathodes are connected to the row tristates. Because they invert, a high on the display bus will light up a
led. This is done purely to make the software easier to write.

Two 74LS240s are connected to form two pairs of 16 tristates which can be enabled alternatively. This
is done by the 4017, which is clocked by the MDC (master display clock). The transistor NOT gates are needed
because the 74240 have active low enables. The 4017 either enables the first two 74240s or the last two. This
means that the display bus is connected to either the first 16 LEDs, or the last 14 LEDs. This arrangement is
clocked by the MDC, so on every increment of the RAMs, the active pair changes. There is also a manual reset,
which is needed by the OUTRAM routine. The divided clock goes to the column multiplexer which energizes
the next column every time the 4017 resets. This ensures that the right 16 LEDs are always lit, in synchronisa-
tion with the video RAMs.

With the above arrangement there were ghosting problems due to the switching occurring too slow
which respect to the RAMs. This meant data for the first 16 LEDs were showing up on the next 14. This was
found to be the fault of the transistor NOT gates due to them not switching cleanly enough. A simple change in
the circuitry solved the problem. The diagram below shows the difference

Figure 8

Figure 9
26 Memory Addressed Display

We can see the transistor NOT gates have been removed, and the lines have simply been swapped
around. This is the equivalent of inverting them, as the 4017 only counts to 2, then resets. The repair work can
be seen in the photo below.

COLUMN MULTIPLEXER

In the above diagram we can see the column multiplexer, whose job is to energise row after row, and
27 Memory Addressed Display

reset keeping synchronisation with the master display clock. After a full reset the first pulse energises row one,
because the 4024 outputs 0000000B. Since the 4 least significant bits are connected to the inputs on the 4067
multiplexer, both select their first output Q1. But since output Q4 on the 4024 is low, then the first 4067 is
enabled and the second one is disabled.

The 4067 is a analogue switch which connects the selected output to input W. Here W is connected to
5V, so the outputs Q0 - Q15 are either disconnected, or connected to 5V, when selected via a 4-bit binary
code. There is a 200R resistance between W and Qx which is part of base resister to the NPN transistors.

The 4024 binary counter is designed to reset on 28, as this is how many rows there are. This done by a
triple AND gate on a 7411 (28 = 11100B) therefore the AND is connected to Q4, Q3, Q2. An OR gate is used,
with the input connected to port 2, this allows the CPU to reset the multiplexer, needed by the OUTRAM rou-
tine.

/EN2 is used to disable both multiplexers, and hence the display, it is normally low but goes high
when the video ram is being refreshed.

The MDC, divided by two, is used to clock the 4027 binary counter. Therefore a new row is energised,
every two memory address. This keeps synchronisation.

The transistor NOT gate also has problems switching cleanly. This lead to problem with the first row
being ghosted to row 16, as the transistor has not switched. But since they ghosting is slight, and replacing it is
not trivial the transistor NOT gate was kept. A simple was to reduce this problem was to make sure that most
text and graphics displayed start at row 2, thereby stopping the ghosting and using row 1 to a minimum.
28 Memory Addressed Display
29 Memory Addressed Display

DISPLAY

LEDS

In the above diagram we can the basic diagram for the display. In each individual display there are 5 *
7 = 35 dots with all the anodes connected and all the cathodes connected. These can be tiled to form a larger
matrix. Here 24 displays, six on the x-axis and 4 on the y-axis, are stacked giving a 30 x 28 display.

The displays have an equal border of 0.1’’ all the way round and hence can be easily tiled with no dis-
tortion. The aspect ratio of the display is 30:28 which equals 15:14, slightly widescreen.

Using 17.3 mm (height) matrices allows the display to have a very high pixel density and also a high
resolution. The display is 3.1’’ by 2.9’’ (~77.3mm x 71.3mm). The LEDs are High Intensity Red, and have a lu-
minance of about 20mC, bright enough for a display, especially when there are 860 of them.
30 Memory Addressed Display
31 Memory Addressed Display
32 Memory Addressed Display

POWER SUPPLY TO LEDS

The above diagram shows how the LEDs were connected to each other and to the transistors. Each
LED ideally drops about 2V across it and has about 20mA through it. Because of the multiplexing system there
can be a maximum of 16 LEDs on at any time. Therefore at full capacity, one NPN has to source 16 x 20mA
=320mA, but the PNPs have to sink only 20mA, as each LED has its ‘own’ one. This maximum of 320mA is only
an instantaneous need and is only sustained if every LED is on all 840. The transistors can easily source 1 amp,
so this no problem. Normally a half to a quarter of the LEDs are on in any frame. If the display was not multi-
plexed and all of the LEDs were on then 840 x 20mA = 14.8 Amps is needed which is not practical. Also every
LED would need its own line

Even though the maximum current needed is relatively low sourcing this from the 5V, 1Amp power
supply that feeds the rest of the system would mean overloading the system. Hence the LEDs were supplied
with their own power source from a separate variable power supply. This allowed them not to interfere with
the other circuitry and also adjust the voltage for optimum performance. The power supply was not fed
straight into the emitters of the NPN transistors. It went through a voltage regulator circuit, which first made
sure that the system cannot be over-volted and therefore damaged. It also gives a brightness adjustment, by
means of a 10k potentiometer is connected to the adjust. It de-spikes the voltage in, and smoothes the voltage
out, by using 0.1uF and 220uF capacitors respectively. The smoothing, acts like a power reserve when suddenly
all the LEDs come on and a lot more instantaneously current is needed

The diagram below shows the circuit used.

The 10K potentiometer is connected to a soft touch knob, which is used to adjust the brightness. The
1K resistor splits the adjust voltage, so that the output can never be too high. A heat sink is used, to cool the
LM317, when it is dropping a high voltage.

Maximum Power used by display:


33 Memory Addressed Display

I: 16 x 20mA = 320mA

V: 4V - 10V

P = 1.92 W = 3.2W

This includes the power lost as heat in the LM317 voltage regulator and switching the transistors.

A blue power LED is also wired to the output of the LM317, with its brightness proportional to the
voltage out of the regulator.
34 Memory Addressed Display
35 Memory Addressed Display
36 Memory Addressed Display
37 Memory Addressed Display

PCB

ART WORK

The diagrams below show the PCB silk screens used for making the display. This is a two sided PCB, so
green is on the component side (top) and red is on the solder side (bottom). A doubled sided PCB means sol-
dering on both sides, at least where there is a connection. This can be very tricky, especially with the displays.
SILL sockets were soldered in, and then the display was pushed into the socket. This means they can be re-
moved, if needed.
38 Memory Addressed Display
39 Memory Addressed Display

CONSTRUCTION

In the photo below we can see connections from the PCB to the Breadboard. First there is the LSB
and MSB of the Display Bus. Theses go to the row tristates. Then there is the control bus, which has +5V and
GND for the logic on the board. It has Vled for the Display, and also GNDled, a separate ground for the LEDs.
Then there is CLK, which is the Master Display Clock, RES, which resets the column multiplexer, and row
tristates, and finally /EN2, which can disable the display. The last 2 are used by the OUTRAM routine to re-
fresh the display.
40 Memory Addressed Display
41 Memory Addressed Display

SOUND SYSTEM:

Below is a block diagram of the sound system.

A 555 clocks a 7493 binary counter which create a set of frequencies. These are tristated, with control
from output port 3. The tristate outputs are commoned and connected to a piezo buzzer through a potenti-
ometer which acts as a volume control. This arrangement allows various sounds to be heard, through software
control.
42 Memory Addressed Display

ALTERNATE SOLUTIONS

There are a few ways in which this project could have been built otherwise. The display system could
have been build not using LED matrixes but with a LCD matrix. The input system could have been changed, and
the hardware display driver could have been replaced with a software one.

LCD SCREEN

It is possible to buy many LCD screens which could be interfaced with the CPU. This would have
meant a complete different way of driving the display. To achieve similar functionality as the dot-matrix LEDs
i.e. the ability to turn on and off individual pixels would require a matrix LCD screen. These are very expensive,
therefore a cheaper solution would be fixed LCD screen, (16 x 2). Theses work like an ASCII printer, in which a
ASCII code is serially sent to the screen, which using its own decode circuitry turns into text. This means only
text can be shown, and typically because of cost reasons only 2 lines, with 16 characters per line. This is not
satisfactory as with the LEDs we can address single pixels, have graphics, and a much higher resolution. Also
the screen can be built to any dimensions, whereas the LCD is preassembled to an oblong design suited for
text.

The LEDs are also much brighter, and can have a display driver built for its specific purposes. Here to
offload the multiplexing from the Z80 to hardware, giving the CPU more time to work.

Also the LCD typically have a serial interface, which means a method is needed for parallel to serial
conversion from the Z80 ports. This adds complications to the circuitry.

PROS

o Can have pre-built displays, which are compact.

o Already have drivers built in, therefore the computation of display text is offloaded from the CPU.

CONS
43 Memory Addressed Display

o A similar general memory mapped display, with similar resolution would be very expensive (>£100).

o Interfacing is hard, need parallel to serial conversion.

o Not big enough, can ‘t change length/width ratio.

o Cannot address individual pixels easily, therefore hard to do arbitrary graphics.

o Not very bright.

The LEDs were chosen because they can be easily tiled to large sizes, and are relatively easy to multi-
plex and address. This mean anything can be displayed, as the CPU only needs to adjust memory and output.
The LCD, since it is rebuilt with its own driver, would require working around it instead of have the display fit
the CPUs need. The LCD would be smaller, harder to interface, and harder to do arbitrary graphics.

INPUT SYSTEM:

The current input system used control pads which are wired straight into the input ports, as shown on
figure 6. These have terrible bouncing problems, but are corrected in software. The input port polls (repeat-
edly checks the input port) to see if anything has changed.

An alternative to this is to use a switch decoder chip. Up to 16 buttons are wired to this chip on both
pads. This chip automatically de-bounces the switches. It also outputs a 4 bit binary word depending on which
switch is pressed, and it can also trigger an interrupt if any switched is pressed.

Initially it would seen that this chip would be a quick and neat way of interfacing the pads, as it would
de-bounce, allows interfacing 2 pads with only one port, and trigger an interrupt.

The problem is that first, de-bouncing in software is even easier and neater than using a separate
chip. Secondly, as it outputs a binary code depending on which switch is pressed, it is impossible to know if
two switches are pressed at the same time. This is knowledge is lost, but is needed by the software. Triggering
the interrupt for every press is more efficient, but the interrupt is already being used anyway.

PRO

o Reduces wire count.

o De-bounce in hardware.

o Can trigger interrupt.

CONS

o De-bouncing in software is easier, and quicker.

o Cannot tell if 2 buttons are pressed at same time.

o Extra chip, with complicated wiring, loses simplicity.

Event though the chip is novel, its extra complicity and the loss of the ability to see if two or more
44 Memory Addressed Display

switches are pressed at the same time means that the simplest option actually is the best. Wiring the buttons
straight into the input ports, and de-bouncing in software is simple and works.

REPLACE DISPLAY DRIVER WITH SOFTWARE:

It is entirely possible to replace the display driver and its video RAM by directly connecting the display
bus to the CPU output ports. This would have reduced the chip count considerably.

This would require the CPU to constantly multiplex the display, thereby outputting the data, and cre-
ating the Master display clock. The problems occur as this puts a huge amount of effort on the Z80. 90% of its
time would be spent multiplexing, therefore a clock increase would be needed. But also multiplexing has to be
regular, i.e. the display must be scanned at least 50 times a second, every second. The rate must be exactly the
same, or the brightness of the display will vary. Also if the display tries to do something else, like creating the
contents, then in that time the screen will not be updated. This is not satisfactory, as the screen will temporal-
ity flicker, or even go blank.

PROS

o Reduces chip count, hardware is simpler.

CONS

o Too much work for the CPU, trying to do 2 things simultaneously.

o Flicker, and variable brightness, as multiplexing speed changes depending on CPU workload.

o Software must be very carefully written, as it might stall the multiplexing, (eg time wasting routines would
give a blank screen).

The hardware system was chosen, as it puts the repetitive, but non-trivial task of multiplexing the
display out of the way of the CPU. Once it is built, the programmer can forget how it works, as it will always
display the frame. The software solution would require significant consideration during programming, and
would reduce the total throughput of the Z80.
45 Memory Addressed Display

SOFTWARE

SUMMARY

A major part of the system is the software. The hardware is designed to be general; it allows turning
on and off individual pixels dynamically. This means the software is under total control of each of the 860 LEDs.

Thinking about individual dots is no way to write a program as it’s too cumbersome - the display
needs to be abstracted by software. This is done by memory mapping the LEDs to the graphics memory.

MEMORY

The Z80 is configured with a 2K ROM and a 2K RAM. ROM is from address 0000H to 07FFH, while
RAM is from 0800H to 0FFFH. A stack is initialised at address 0FFFH and works its way down. Maskable inter-
rupts are enabled, and the interrupt service routine starts at 0038H. Reusable helper routines are stored from
address 0400H, all the way to the end of ROM. 0 to 0037H, contains the initialisation code. Programs are from
0044H to 03FF. The diagram below shows a memory map of the system.

Basics:

The display driver has its own 16-bit wide RAM which has a bit corresponding to every LED. This is the
frame buffer and contains the currently displayed frame. To change what is being shown, the RAM needs to be
written to. This is done via the system OUTRAM routine and not directly from user code. Normal software ed-
its bits in the internal frame buffer, which is then refreshed to the external RAM. The OUTRAM routine is very
important, as its job is to update the external RAMs with the internal representation.

As user software does not interface with the display driver RAM, it needs to Blit (draw) to aa internal
buffer starting at address 0800H and ending at 0870H. This is 70H address or 112 bytes (4 bytes per row * 28
rows). As one byte has 8 bits therefore 4 * 8 = 32 possible bits per row. This correspond the LEDs but since
there are only 30 LEDs the last 2 bits are not connected on the row tristates. This area of memory is the inter-
46 Memory Addressed Display

nal frame buffer and contains a bit by bit representation of the LEDs. This is how the display is abstracted to
the software. The software doesn’t need to know about the implementation of the display, only this RAM.
When the display RAM is refreshed from this internal frame buffer (by calling OUTRAM) the display will
change. This is the basis of how anything is drawn.

To simple make the first 8 LEDs come on requires the following steps.

1. Clear VIDRAM (0800H - 0870H) - ie write 00H to every byte.

2. Write FFH to address 0800H.

3. Call OUTRAM.

This pseudo program shows the basic steps in displaying pixels. When the Z80 is first turned on the
VIDRAM cannot be assumed to be clear, hence it needs to be zeroed. FFH is 11111111B, this is written to the
first byte. The one mean the corresponding LED dot will turn on while a zero is the opposite. Therefore writing
FFH to 0800H will turn on the first 8 LEDs.

OUTRAM needs to be called to refresh the external RAMs with the internal representation. Now the first 8
LEDs are turned on.

Writing 01H (00000001B) to address 0800H + 4 (0804H) would result in the 8th LED on the second
row being turned on. Writing the same 01H to address 0805H would result in the 16th LED on the second row
being turned on. The table below shows how the memory maps to the display.

Vidram 0 1 2 3
0800H |7 ...... 0| |7 ...... 0| |7 ...... 0| |7 .......0|
0804H |7 ...... 0| |7 ...... 0| |7 ...... 0| |7 ...... 0|
0808H |7 ...... 0| |7 ...... 0| |7 ...... 0| |7 ...... 0|
080CH |7 ...... 0| |7 ...... 0| |7 ...... 0| |7 ...... 0|
0810H |7 ...... 0| |7 ...... 0| |7 ...... 0| |7 ...... 0|
0814H |7 ...... 0| |7 ...... 0| |7 ...... 0| |7 ...... 0|
… to 0870J

Each “|7 ...... 0|” refers to one byte of memory and 4 bytes represent one row on the display. This
line of RAM is what the software blits to, and it must work out which bit and byte refer to which LED on the
display. The last 3 bits on column 2 do not represent any LEDs (32 bits cf 30 dots) so can be ignored.

MORE ABSTRACTIONS

It can be seen that writing different combinations to different address in VIDRAM, and calling
OUTRAM mean any possible combination can be displayed. However writing specific bytes to memory loca-
tions is not an easy way to program. It is fine if a static frame needs to be created, but any animation requires
rewriting to VIDRAM. This means the program has to work out the exact bytes for every frame, put them in a
lookup table and copy to VIDRAM. This is very inefficient and time consuming, as each frame would require
112 bytes. Also the dynamic features of having a general purpose CPU are not being utilised. To make life eas-
ier for the programmer, more abstractions are needed.

The Z80 needs to be programmed to automatically create frames from simple instructions. For exam-
ple, the programmer should simple say, ‘I want the string “HELLO” to be placed at co-ordinates (0,4) and the
system should takes care of the rest. To create such a simple programmer API very complex helper
47 Memory Addressed Display

sub-routines are needed.

First we need to make more abstractions. Addressing the display as a memory range is very general
and versatile from the Z80s point of view but not user friendly for the programmer. To abstract further, the
display is refereed as a grid with a coordinate system. The origin is to the top left and the first pixel is (0, 0).
The units are discrete and 0 based. On the x-axis we have 0 - 27, representing the 28 columns, and on the
y-axis 0 - 29, representing the 30 rows. Negative co-ordinates are allowed coded using two-complement. The
diagram below shows this setup.

This is much more user friendly for the programmer, as they display can be referred to in a more
natural way. The way this is implemented is by the FIND_PIXEL routine. To use it, register B and C are loaded
with the desired X and Y co-ordinates. When the routine returns it has HL pointing to the right byte in VIDRAM
and the Accumulator has a bit mask which corresponds to the individual LED.

For example the, following assembler is executed

LD B,0

LD C,0

CALL FIND_PIXEL

-----------------------
48 Memory Addressed Display

This is what A and HL are returned with

A = 10000000B

HL = 0800H

Ie the very first pixel: HL points to the byte in VIDRAM, and A has a mask, with 7 zeros and 1 one, the location
of the 1 depends on where the pixel is.

If the co-ordinates were (9,3), the 9th pixel on row 3

then A= 01000000b

and HL = 08009h

The algorithm is as follows:

HL = Int (X DIV 8) + (4*Y) + (0800H) (offset)

Since there are 4 bytes per row, we multiply the Y value by 4. So if Y = 0, then we could possibly have the first 4
bytes, 0800H - 08003H; if Y=1, then the possibilities are 08004H-08007H. The division tells us if it is the first,
second, third or fourth byte. If X is between 0-7, Int(X DIV 8) evaluates to 0, if X is between 8 and 15 it evalu-
ates to 1 and so on.

A = X AND 00000111

The masking gives a number between 0 and 7, corresponding to the appropriate bit. This is used to select
bytes from the below lookup table.

X AND 7H Byte returned


0 10000000B
1 01000000B
2 00100000B
3 00010000B
4 00001000B
5 00000100B
6 00000010B
7 00000001B
To plot a pixel at coordinates (X, Y), we need to use logical operations with Find_Pixel.

1. Put X, Y into B, C and call FIND_PIXEL.

2. A= mask, HL = byte

3. Execute : A= A OR (HL)

4. Save back : (HL) <--- A

We used the mask and ORed it onto the video memory pointed by HL. Since the mask is the bit
needed, the appropriate bit is turned on. Calling OUTRAM would refresh the display.

Removing a pixel is similar


49 Memory Addressed Display

1. Put X, Y into B,C and call FIND_PIXEL.

2. A= mask, HL = byte

3. Execute: A <-- NOT A

4. Execute: A= A AND (HL)

5. Execute: (HL) <-- A

This works by ANDing whatever is at HL, with the complement of the mask. So a mask of 00010000,
evaluates to 11101111 which when ANDed will reset that appropriate bit.

These functions are packaged into the routines PutPixel and Remove Pixel. Other pixel routines are
similarly coded. A summary is provided later, and the full assembler source is in the appendix.

PIXELS TO PICTURES

Plotting pixels at arbitrary co-ordinates is very nice, but this is still inefficient to draw pictures as you
would need to draw it dot by dot. Therefore we must use another abstraction - sprites. A sprite is the equiva-
lent of a bitmap image, ie a bit by bit representation stored in ROM. For example the following assembler:

; Character 0x44 D

DB 8D ; Height of Sprite
DB 11111000B ; Hex F8h
DB 11001100B ; Hex CCH
DB 11000110B ; Hex C6h
DB 11000110B ; Hex C6h
DB 11000110B ; Hex C6h
DB 11001100B ; Hex CCh
DB 11111000B ; Hex F8h
DB 00000000B ; Hex 00h
This is an 8 x 8 sprite for the letter D where ones represent an LED on, and a zero represents off. It looks like
the figure below, when drawn to the screen.
50 Memory Addressed Display

Sprite gives us a nice way of storing and working with frequently used images. The sprite drawing rou-
tine SDR8, blits a sprite, 98-bits wide, arbitrary length to a (X, Y) coordinate. So we can say draw this particular
sprite to co-ordinate (2, 7) and SDR8, using FIND_PIXEL, works out where in VIDRAM to write to.

Assembler Example: To Put the above ‘D’ to co-ordinates (10,12)

LD B,10
LD C,12
LD HL,SPRITE <---(Pointer to sprite)
CALL SDR8
CALL OUTRAM
SPRITE: <--- Label
DB 8D ; Height of Sprite
DB 11111000B ;Data
DB 11001100B
DB 11000110B
DB 11000110B
DB 11000110B
DB 11001100B
DB 11111000B
DB 00000000B
The above code will draw the ‘D’ to coordinate (10, 12). By incorporating the above into a loop which
decrement B, clears the screen, waits , then repeats, the ‘D’ will be seen scrolling left across the display.

The simplest way in which a sprite routine would work is by copying the first byte to a location in
VIDRAM, then coping the second byte to the location + 4 (the next row), and so on. This is called aligned
drawing, because we have one byte from the sprite fit nicely into 1 byte in VIDRAM. This limits to the locations
on the x-axis where the sprite can be drawn. Either it starts at 0, 8, 16, or 24, but the y-axis can have any value.

To achieve non-aligned drawing ie when a byte from the sprite is split between two adjacent video
ram bytes, a modified routine is used. The routine needs to work out how much overlap there is and rotate the
byte accordingly. It must then blit the sprite, without destroying anything that was already there. SDR8 can do
all of this.

There is also another complication is that part of the sprite can be off-screen. There are 3 possible
situations. Considering any edge, either the sprite is fully on screen, fully off screen, or partly on and partly off.
As there are 4 edges there are 3*4 =7 possible scenarios. This routine must check for all of them and act ac-
cordingly. If it is fully on screen, then carry on as normal, if it is off screen, then don’t draw, and if it is partly on
and off, then clip. Clipping refers to the process of disregarding the right bits. The clipping version of SDR8 is
SDR8_CL

The way SDR8 works is very complex, so complex that in fact that the version used in this project is a
significantly modified version from a whole set of routines for memory mapped displays written by “JL and
Joa”. It was originally written for a 128x64 screen, so has to be significantly changed. Clipping had to be re-
written, as so did the checks. The full edited source is in the appendix.

Timing of the OUTRAM routine is critical to smooth transitions. If OUTRAM was called every time
VIDRAM was edited there would be screen flicker because of the way routines blit. Individual parts of each
51 Memory Addressed Display

large drawing operation would be seen. By timing OUTRAM right, when all the drawing operation for a par-
ticular scene are finished this flickering is avoided. This is technically called “double buffering” and it is process
of drawing all the little bits that make up a scene to a back buffer and then outputting it all in one go. Manual
control of the OUTRAM routine allows us to implement double buffering.

OTHER ROUTINES

There are many other routines available to the programmer to make their life easier and are summa-
rised below. Most of them call other routines thereby allowing significant code reuse.

For example Put_Num blits the binary number stored in D, E to coordinates B, C.

Put_Num does its job by calling many other routines. First it takes the binary number and by calling
BINTOBCD converts it into a string of binary coded decimals, which are then converted into an ASCII string,
deleting pre-leading zeros. This ASCII string is created in RAM. Put_Num then calls Put_Small which puts an
ASCII string at coordinates B, C. Put_Small takes the ASCII code, works out where in ROM the letter is stored,
and calls SDR8_CL. SDR8_CL calls Find_Pixel, working out where in the display it is, and draws it non-aligned
with clipping. All this occurs in a few microseconds.

The interrupt service routine is executed every time the interrupt pin goes low, about 100 times a
second. The interrupt routine first checks if the ‘pause’ button has been pressed, if it has then it saves the
screen and displays pause and counts upwards. When another button is pressed it returns. This gives a pause
function which allows freezing in the middle of the main routine.

The interrupt service routine also does the housekeeping of the sound system, making sure it is reset
and the right sound is playing

SOFTWARE SUMMARY

ROUTINE ROM TABLE

Routine Address
OUTRAM 400H
Find_Pixel 441H
Sdr8_Cl 048AH
Put_Pixel 046AH
Remove_Pixel 0472H
Change_Pixel 047BH
Test_Pixel 0483H
Clear_Vram 051CH
Put_Char 0529H
Put_Small 0565H
Rand 0634H
Binbcd 0646H
Put_Num 069CH
Wait 06B2H
Pause 06BcH
Sound 0726H
52 Memory Addressed Display

Sound Test 0759H


Menu 0044H
Logo 0120H
Game 0311H

RAM ADDRESS’

Address Routine
0800 - 0870 Video Buffer
0880 -08F0 Pause_Temp
0900 Keyram1
0901 Keyram2
0902 Clipflag
0903 Sound_0
0904 Sound_1
0905 Sound_2
0950 Puttext Temp Ram
0960 Randseed
0961 Bcd16
0966 Bcd16String

HELPER SUBROUTINE SUMMARY

Name: FindPixel
Function: Abstracts coordinates to memory
Input: BC = (X,Y)
Returns: HL= pointer to VIDRAM, A=MASK

Name: Put/Remove/Change/Test Pixel


Function: Draws /Un-sets/ Changes/ Tests pixel (X, Y)
Input: BC = (X, Y)
Returns: None

Name: OUTRAM
Function: Refreshes external frame buffer with internal buffer
Input: None
Returns: None

Name: SDR8_CL
Function: Draws a 8 x n sprite to arbitrary coordinates
Input: BC=(X, Y), HL= pointer to spite
53 Memory Addressed Display

Returns: None

Name: Put_Char
Function: Puts the a ASCII character at arbitrary coordinates
Input: BC = (X, Y), D = ASCII character
Returns: None

Name: Put_Small
Function: Puts a ASCII string limited by a 0 at arbitrary coordi-
nates
Input: BC = (X, Y), HL = pointer to string
Returns: None

Name: Put_Num
Function: Puts a 16-bit binary number at arbitrary coordinates
Input: DE = 16-bit number, BC = (X, Y)
Returns: None

Name: Random
Function: Returns a pseudo random number
Input: None
Returns: A = number

Name: Wait
Function: Wastes cycles for a chosen time
Input: C = multiplier
Returns: None, It returns after a wait

There entire source code can be found in the appendix. The above helper functions allow writing very
complex code. This project uses them to prove a menu interface with selectable choices for programs. The
program Scroller is also coded to allow user selected text to be scrolled across the screen.
54 Memory Addressed Display

DIARY

WEEK 1,2: THE Z80

The Z80 system was built subsystem by subsystem and separately tested. The clock was tested with a
frequency counter and an oscilloscope. The address and IO decoders were tested by entering a manual binary
code, and seeing with the logic probe that the right output was going low. The address and data buses were
testing using continuity meters as was every wire. A reset button was built for the Z80, and a RC network was
connected to it, to auto reset on power up

The ports were tested by writing a simple program, like output FF to port 1. This is where the prob-
lems started. The output and input ports would not function correctly. A small program which copied the input
to the output, only worked when a low was put in. When a high was put in, the output ports pulsed propor-
tionally to clock speed. After checking every wire and, replacing the Z80, the problem was found to be that the
input for the IO decode was going into /RD instead on /WR. This meant the output ports were being triggered
every time the input port was being triggered.

After that, all output ports and input ports were tested using the copycat code, with a LED segment
wired up - They all worked.

Once the Z80 was known to work the clock for it was replaced with a crystal oscillator. This was built,
but it would not clock the Z80. After looking at it with an oscilloscope, the waveform was found not to be
clean. A Schmitt trigger was wired to clean it up.

WEEK 2,3

The display driver was quite easy to construct and test. The resetting of the 4024 was checked by an
LED array, and a slow MDC. The MDC was adjusted with 2 potentiometers, so that the ghosting was minimal.
The shape of the MDC was adjusted, but the original was found to give best performance.

The RAMs were tested by writing known data into them, and seeing if they existed. The control bus was
checked by a continuity meter, and writing a test program to put the system into different modes, and check-
ing with a logic probe.

WEEK 2,3,4: THE PCB

Before the PCB was designed, the individual sub-circuits were testing on a spare bread-board. The
LM317 voltage regulator was tested this way, this allowed a trial and improvement to find a good resister
value to split the voltage. When the LED matrix arrived, it was found that they were wired the wrong way
around from their literature. This was not a problem, as the analogue switch has a W input that can be any
voltage. This was changed from 0V to 5V, the transistors were swapped, and inverting tristates were used.

The transistors were wired up to 1 display on a breadboard, but there was a large brightness problem.
This seemed to occur only when the LEDs where pulsed. The loss in brightness was way more than it should
have been. After testing with a volt meter, it was found the PNP transistors were dropping twice the voltage
needed. This was evidence to find out that the PNP transistors were in fact Darlington pairs therefore twice
the forward bias was being dropped (1.4V instead of 0.4V). Replacing these with non-Darlington’s solved the
55 Memory Addressed Display

problem. A base resistor value of 3R9 was selected, as this gave enough protection without sacrificing bright-
ness.

The PCB was designed using PCB Wizard software. It was a double sided beast that took over 20 hours
to design. Once the PCB was designed, it was printed to transparencies. The first side was exposed to UV, de-
veloped, and etched. The first side was then protected with gaffer tape, while the second side was exposed,
developed, and etched. Both sides lined up perfectly. All this was done by the multitalented Mr Evans.

Once the PCB was created, it needed to be drilled. This took quite a while, needing two drill bits as
they were worn down. Repair work was needed on the tracks that did not etch properly as well as some that
were touching. This was pretty trivial. The components were then soldered in, including 58 resistors and 58
transistors. Since each transistor has 3 legs and need to be soldered on both sides, this is tiresome. Add in all
the chips, also double sided, it can be seen why the PCB construction took so long. The SILL sockets were then
soldered in, on both sides, and then the displays were put in. They were tested by pulling lines high and low,
and seeing if the right LED came on. Some did not, and the problem was found to be dry joints which were
fixed. Throughout construction pin to pin connections were checked by a continuity meter.

Once the entire PCB was finished, three connectors were needed to connect the PCB to the bread-
board. The display was tested by using a test OUTRAM program with a pre-known frame. This showed that the
connectors were the wrong way round. Test programs were also written to see if the refreshes were correct.

WEEK ,3,4: OTHER SYSTEMS

The sound system was built and tested by playing different sounds. The speed of its clock was ad-
justed to make the most interesting noises. Software was written to test the sounds.

The pads were constructed on PCBs, and tested with logic probes. The subtle bouncing problems
were discovered later when there was working code. This led to the development of a software denouncing
solution.

The interrupt clock was first an equal mark space, by this made the interrupt trigger way too often. It
was then shaped using a reset signal of a clocked 4017, which worked better.
56 Memory Addressed Display

RESOURCES

TIME SPENT ON PROJECT:

Period Time (mins)


Lessons 4 * 8 * 35 1120
Free periods 4 * 6 * 35 840
Lunch times 4 * 7 * 70 1960
After school 3 * 7 * 60 1260
Total 5180 ~ 86 hours

Period Time (hours)


Home Time +/- 40
Software +/- 20
Using Program Loader and testing +/- 15
PCB construction +/- 20
Write up +/- 20
Thinking +/- 20
Total 135 hours

86 +135 =221 hours = 5.5 man weeks

MONEY SPENT ON PROJECT: (APPROX)

Component Price
Double sided PCB £15
25 displays £35
Chips £5
Sill sockets/connecters £3
Other £10
Switches £2
Total £70
57 Memory Addressed Display

EVALUATION

In general the project fitted the specification on all accounts. The display was a general memory
mapped one. When the system is reset an animation is shown, then a menu. The user can select from 3 pro-
grams, one resets the system, the other is a ‘Scroller’ program which allows the user to input a string which is
then scrolled across the display, from left to right, at random y values. There is also a sound test program with
plays different sounds when different buttons are pressed.

The system is reliable and works as according the specification.

o The project is built on a breadboard and PCB using the allowed components and equipment.

o The project was completed within 3 weeks, and in the feasibility of the equipment requirements.

o The required sound test and Scroller programs are coded, and work.

o There is an introductory screen and menu system.

o A Z80 microprocessor system clocked at 4MHz, with 4 output ports and 2 input ports was created.

o The Z80 has a ROM and RAM, both being 2K.

o There is memory and IO decoder circuitry.

o The interrupt port is pulsed with a spiked clock.

o The display driver is built as specified.

o It has 2 * 6116 RAMs wired as a 16*2k one connected to a display bus.

o It is clocked to 56, and reset, and under full control of output 2.

o The MDC was adjusted to give best performance (minimal ghosting, max brightness).

o The Display was built as specified, with a total of 840 dots driven through transistors.

o The column multiplexer and row tristates work as they should, after repair work.

o The voltage regulator circuit allows varying of brightness.

o A simple software controllable sound system is created and works.

o The input system, after bouncing problems works as it should.

The system has some minor problems but they were fixed, therefore the entire system fitted the specification
on all accounts.
58 Memory Addressed Display

ACKNOWLEDGEMENTS

GENERAL

Mr Evans, for help on soldering, PCB design, PCB construction, connector construction, transistor se-
lection etc. Mr Marvin, on Z80 construction and trouble shooting.

BOOKS

Brimicombe: Logic systems, transistor, sequential systems, counting systems .

TTL Data Book, Texas Instruments: 7493,74244,74374,74240,7411,7400

CMOS Cookbook, Don Lancaster: 4024,4067

RS monostable data reference: 555

INTERNET

The Giant IC Masturbator: Great site having data on virtual every chip ever made.

Z80 Operating Manual, Zilog.

Z80 Peripherals Manual, Zilog.

www.z80.info: Large amount of information on all things Z80.

www.ti86.acz.org: How to program a Z80 based graphics calculator, which was the inspiration for this project.

OTHER

Ti86 Graphics Calculator, Texas Instruments: Even though I do not own one, this project would not exist if it
were not for this calculator. It is based on a Z80, has a memory mapped LCD display and a lot of code is avail-
able for it.

SOFTWARE

SDR8: JL and Joa.

BINTOBCD16: Joe Pemberton.

http://icarus.ticalc.org/articles/z80_coding.html: Tutorials on Z80 assembly.

Barleywood: Z80 assembler and emulator, used for testing.


59 Memory Addressed Display

APPENDIX

HARDWARE

4067

16-to-1 line analogue multiplexer/demultiplexer. 7411


+-----+--+-----+ Triple 3-input AND gates.
Y |1 +--+ 24| VCC +---+--+---+ +---+---+---*---+
X7 |2 23| X8 1A |1 +--+ 14| VCC | A | B | C | Y | Y = ABC
X6 |3 22| X9 1B |2 13| 1C +===+===+===*===+
X5 |4 21| X10 2A |3 12| 1Y |0|X|X|0|
X4 |5 20| X11 2B |4 7411 11| 3C |1|0|X|0|
X3 |6 19| X12 2C |5 10| 3B |1|1|0|0|
X2 |7 4067 18| X13 2Y |6 9| 3A |1|1|1|1|
X1 |8 17| X14 GND |7 8| 3Y +---+---+---*---+
X0 |9 16| X15 +----------+
S0 |10 15| /EN
S1 |11 14| S2 7432
GND |12 13| S3 Quad 2-input OR gates.
+--------------+ +---+--+---+ +---+---*---+
4024 1A |1 +--+ 14| VCC |A|B|Y| Y = A+B
7-bit asynchronous binary counter with reset. 1B |2 13| 4B +===+===*===+
+---+--+---+ 1Y |3 12| 4A |0|0|0|
/CLK |1 +--+ 14| VCC 2A |4 7432 11| 4Y |0|1|1|
RST |2 13| 2B |5 10| 3B |1|0|1|
Q6 |3 12| Q0 2Y |6 9| 3A |1|1|1|
Q5 |4 4024 11| Q1 GND |7 8| 3Y +---+---*---+
Q4 |5 10| +----------+
Q3 |6 9| Q2
GND |7 8| 6116
+----------+ 2kx8 SRAM.
+-----+--+-----+
4017 A7 |1 +--+ 24| VCC
4-bit asynchronous decade counter with fully decoded outputs, reset and both active A6 |2 23| A8
high and active low clocks. A5 |3 22| A9
The two CLK inputs are ANDed together, so that either can be used as clock or clock A4 |4 21| /WE
enable. A3 |5 20| /OE
A2 |6 19| A10
+---+--+---+ A1 |7 5516 18| /CE
Q5 |1 +--+ 16| VCC A0 |8 17| D7
Q1 |2 15| RST D0 |9 16| D6
Q0 |3 14| CLK1 D1 |10 15| D5
Q2 |4 13| /CLK2 D2 |11 14| D4
Q6 |5 4017 12| RCO GND |12 13| D3
Q7 |6 11| Q9 +--------------+
Q3 |7 10| Q4
GND |8 9| Q8
+----------+

74240
Dual 4-bit 3-state inverting buffer/line driver.
+---+--+---+
/1OE |1 +--+ 20| VCC
1A1 |2 19| /2OE
/2Y4 |3 18| /1Y1
1A2 |4 17| 2A4
/2Y3 |5 74 16| /1Y2
1A3 |6 240 15| 2A3
/2Y2 |7 14| /1Y3
1A4 |8 13| 2A2
/2Y1 |9 12| /1Y4
GND |10 11| 2A1
+----------+

74244
Dual 4-bit 3-state noninverting buffer/line driver.
+---+--+---+
/1OE |1 +--+ 20| VCC
1A1 |2 19| /2OE
2Y4 |3 18| 1Y1
1A2 |4 17| 2A4
2Y3 |5 74 16| 1Y2
1A3 |6 244 15| 2A3
2Y2 |7 14| 1Y3
1A4 |8 13| 2A2
2Y1 |9 12| 1Y4
GND |10 11| 2A1
+----------+
60 Memory Addressed Display

LD B,56 ;SET COUNTER 28*2=56


SOFTWARE
Out_LOOP:
LD C,0 ;SET PORT POINTER TO 0
OUTRAM Equ 400H LD D,(HL) ;GET BYTE
Find_Pixel Equ 0441H OUT (C),D ;OUTPUT TO PORT 0
Sdr8_Cl Equ 048Ah INC HL ;INCREMENT POINTER
Put_Pixel Equ 046Ah INC C ;INCREMENT PORT COUNTER
Remove_Pixel Equ 0472H LD D,(HL) ;GET NEXT BYTE
Change_Pixel Equ 047Bh OUT (C),D ;OUTPUT TO PORT 1
Test_Pixel Equ 0483H
Clear_Vram Equ 051Ch ;PULSE /WR
Put_Char Equ 0529H LD A,10010100B ;MAKE /WR LOW
Put_Small Equ 0565H OUT (2),A ;OUTPUT
Rand Equ 0634H LD A,10110100B ;MAKE /WR HIGH
Binbcd Equ 0646H OUT (2),A ;OUTPUT
Put_Num Equ 069Ch
Wait Equ 06B2H ;PULSE CLOCK TO RAM
Pause Equ 06Bch LD A,11110100B ;MAKE CLOCK HIGH
OUT (2),A ;OUTPUT
Sound Equ 0726H LD A,10110100B ;MAKE CLOCK LOW
Sound Test Equ 0759H OUT (2),A ;OUTPUT

Menu Equ 0044H INC HL ;INCREMENT POINTER


Logo Equ 0120H
DJNZ Out_LOOP ;LOOP UNTIL ENTIRE RAM IS REFRESHED
Vidram Equ 0800H
Pause_Temp Equ 8080H LD A,10111101B ;RESET RAM COUNTER, AND DISABLE TRISTATES
Clipflag Equ 0902H OUT (2),A ;OUTPUT
Sound_0 Equ 0903H
Sound_1 Equ 0904H LD A,10100001B ;PULL ABOVE RESETS LOW, AND MAKE /RD LOW
Sound_2 Equ 0905H OUT (2),A ;OUTPUT

Puttext Temp Equ 0950H LD A,00100011B ;ENABLE MDC,and /en2


Randseed Equ 0960H OUT (2),A ;OUTPUT
Bcd16 Equ 0961H
Bcd16String Equ 0966H EX AF,AF'
EXX

EI ;RE-ANABLE INTERUPTS
;Routine to update external ram with interal vram buffer RET
;© Dharmesh Malam 2002
END
;PIN 0 = Trisate port 1 and 2, when high, ports are high impeadance, i.e. active low
;PIN 1 = Main Display Clock enable, active high, hgh for normal operation -------------------------------------------------------
;PIN 2 = Reset column/row select logic, active high ORG 000H
;PIN 3 = Reset ram counter, active high START:
;PIN 4 = /rd ,active low
;PIN 5 = /wr ,active low LD SP,0FFFH ;INITIALISE STACK
;PIN 6 =Manual clock of ram IM 1
;PIN 7 =/en2, low for normal operation XOR A
LD (0903H),A
;NORMAL MODE LD (0904H),A
;76543210 LD (0905H),A
;00100011 INC A
LD (0960H),A
;ROUTINE STOPS MDC EI
;THEN RESETS COLUMN,ROW LOGIC, disables screen CALL CLEAR_VRAM
;THEN RESET RAM COUNTER JP LOGO
;MAKES /RD HIGH
;LOAD DATA ON PORTS 1 AND 2
;ENABLES PORT TRISTATES --------------------------------------------------------
;PULSE /WR ORG CLEAR_VRAM
;PULSE CLOCK
;REPEAT UNTIL ALL RAM IS UPDATED CLEAR_VRAM:
;DISABLE PORT TRISTATES PUSH HL
;RESET LOGIC, AND RAM COUNTER XOR A ;ZERO A
;MAKE /RW LOW LD HL,VIDRAM
;START MDC LD B,112 ;ROWS/8 * COLUMNS
;RETURN CLEAR:
LD (HL),A
#include zinc.asm INC HL
DJNZ CLEAR ;CLEAR VIDRAM
ORG OUTRAM POP HL
RET
OUTRAM:
DI ;DISABLES INTERUPS, FOR SPEED ;IF SOUND_X IS ZERO, TURN OFF SOUND
EX AF,AF' ;IF SOUND_X IS NON-ZERO, THEN TURN ON SOUND FOR THAT MANY 100THS SEC
EXX ;
; 00100011
LD A,10110001B ;MAKE /RD HIGH, AND STOP MDC, /en2 -> high SOUND_0 EQU 0903H
OUT (2),A ;OUTPUT SOUND_1 EQU 0904H
SOUND_2 EQU 0905H
LD A,10111101B ;MAKE RESET ON COL/ROW LOGIC AND RAM COUNTER
HIGH snd:
OUT (2),A ;OUTPUT PUSH BC
LD B,0
LD A,10110100B ;KEEPS COL/ROW LOGIC HIGH, AND MAKES RAM
COUNTER LOW, AND ENABLES TRISTATES SND_0:
OUT (2),A ;OUTPUT LD A,(SOUND_0) ;GET SOUND VAR
CP 0 ;IS IT ZERO
LD HL,VIDRAM ;POINT TO VIDRAM JR Z,SND_1 ;IF SO END SOUND
61 Memory Addressed Display

DEC A ;OTHERWISE DEC


COUNTER ----------------------------------------------------------
LD (SOUND_0),A ;SAVE BACK
SET 0,B ;SET 0 ;Basix Pixel Operations
JR SND_1 ;© Dharmesh Malam 2002
;All destroy A needs FindPixel
SND_1: #include zinc.asm
LD A,(SOUND_1)
CP 0 Put_Pixel: ;Blit Pixel at B,C
JR Z,STOP_1 PUSH HL
DEC A CALL FindPixel
LD (SOUND_0),A OR (HL)
SET 0,B LD (HL),A
JR SND_2 POP HL
RET
SND_2:
LD A,(SOUND_2) Remove_Pixel: ;Remove Pixel at B,C
CP 0 PUSH HL
JR Z,OUT_SND CALL FindPixel
DEC A CPL
LD (SOUND_0),A AND (HL)
SET 0,B LD (HL),A
POP HL
OUT_SND: RET
LD A,B
OUT (3),A Change_Pixel: ; Change Pixel at B,C
POP BC PUSH HL
RET CALL FindPixel
XOR (HL)
-------------------------------------------------------------- LD (HL),A
POP HL
RET
; returns pseudo random 8 bit number in A. Only affects A.
; (r_seed) is the byte from which the number is generated and MUST be Test_Pixel: ; Tests Pixel at B,C
; initialised to a non zero value or this function will always return PUSH HL
; zero. Also r_seed must be in RAM, you can see why...... Call FindPixel
AND (HL) ; Zero flag set if no pixel
rand_8: POP HL
LD A,(r_seed) ; get seed RET
AND 184 ; mask non feedback bits
SCF ; set carry ----------------------------------------------------------
JP PO,no_clr ; skip clear if odd
CCF ; complement carry (clear ;Sprite Drawing Routine (SDR): 8 Bit Normal Version
it) ;by JL *original)
no_clr: ;
LD A,(r_seed) ; get seed back ;Inputs:
RLA ; rotate carry into byte ; b=x coordinate
LD (r_seed),A ; save back for next prn ; c=y coordinate
RET ; done ; hl=pointer to sprite data
;Outputs:
r_seed: ; af=destroyed
DB,1 ; prng seed byte (must not be zero) ; bc=destroyed
; de=destroyed
--------------------------------------------------------------- ; hl=pointer to byte after sprite
; no other registers are changed
;Find Pixel Routine for 3,4x6, (21,28x30 dots) ;If you want to save those registers that are destroyed, push/pop them!
;b=x c=y ;
;© Dharmesh Malam 2002 ;Sprite data should be stored as follows:
;ORIGIN IS TOP LEFT CORNER ;.db (# rows/bytes/height of sprite)
;.db (bitmap of sprite)
VIDRAM EQU 0FC00H ;
;Size=about 60 bytes (+pushes/pops)
ORG 0000H ;***CLOCKED AT MORE THAN 2000 8X8 SPRITES PER SECOND!!! THAT'S MORE
THAN 3X
Find_Pixel: ; FASTER THAN PUTSPRITE!!!*** (At the same size, or maybe even at a smaller
PUSH BC ;Save BC ; size!)
;
LD Hl,VIDRAM ;Start of Video Ram ;Notes:
LD A,C ;a=y TIMES Y BY HOW MANY BYTES PER ROW ;You can make this routine smaller by deleting the first 3 lines and
SLA A ;a=2y ; accounting in your program the fact the the origin (0,0) is the *bottom*
SLA A ;a=4y ; left corner (saves 4 bytes!).
LD L,A ;l=4y ;Also, if all your sprites are the same height, you can delete the next 2
LD A,B ;a=x ; lines (ld e,(hl)\inc hl); change the 3rd line after that (ld c,e) to
SRL A ;a=int(x/2) ; 'ld c,x', where x is the height of your sprites; and store all sprites
SRL A ;a=int(x/4) ; with only the sprite data, leaving off that first byte that defines the
SRL A ;a=int(x/8) ; height (saves 1 bytes + # of sprites!)
ADD A,L ;a=int(x/8) + 4y ;If you want the sprite to be drawn in the graphics memory instead of the
LD L,A ;l=int(x/8) + 4y, so Hl point to right byte ; video memory, simply replace the destination address before running the sprite
routine :
LD A,B ;a=x ;ld hl,VIDEO_MEM
AND 7 ;mask a,0000111,so which bit selected ;ld (DEST_ADDR),hl
LD BC,FP_Bits ;BC point to first bit mask
ADD A,C ;Simulated 16 bit addition, SDR8:
LD C,A ;..need even though 7 is max ld a,63 ;-->flips the x coordinate around for FIND_PIXEL
ADC A,B ;..as FP-bits is a 16 bit address sub c ; / may be deleted if accounted for in program
SUB C ;.. ld c,a ;/
LD B,A ;.., BC points to right mask ld e,(hl) ;e=number of rows in sprite
LD A,(BC) ;a=mask inc hl ;next byte (points to sprite now)
POP BC ;Restore BC push hl ;push pointer to sprite to stack
RET ;return to caller call FIND_PIXEL ;)
ld c,e ;c=number of rows in sprite
FP_Bits: DB 80H,40H,20H,10H,08H,04H,02H,01H ld de,(DEST_ADDR) ;define offset
62 Memory Addressed Display

add hl,de ;and add offset to get where to put sprite LD E,(HL) ;E=NUMBER OF ROWS IN SPRITE
INC HL ;NEXT BYTE (POINTS TO SPRITE NOW)
add a,a ;-> sets all bits to the right of set bit (for mask) XOR A ;ZERO A
dec a ;/ LD (CLIPFLAG),A ;CLEAR CLIPFLAG
ld e,a ;save mask into e
ld a,b ;a=x coor ; TOP CLIPPING DONE
and %00000111 ;find remainder of x/8
inc a ;get range between 1-8 CHECK_RIGHT:
ld b,a ;and save rotate counter LD A,B ;A=X COOR
BIT 7,B ;IS X NEGATIVE?
SDR8_NewRow: JR NZ,SDR8CL_CHECKLCLIP;IF SO THEN JUMP TO CHECK LEFT
ex (sp),hl ;hl(video location)<->(sp)(pointer to sprite) CP 30 ;CHECK IF X IS GREATER THAN OR EQUAL
ld a,(hl) ;a=byte in sprite TO 30
inc hl ;next byte JR NC,ENDSDR ;IF SO, THEN CARRY IS SET, AND JUMP
ex (sp),hl ;hl<->(sp) JR CHECK_BOT ;ELSE, DONE L/R CLIPPING (RIGHT
push bc ;save rotate counter and row counter CLIPPING IS "AUTOMATIC")

rlca ;rotate left once... SDR8CL_CHECKLCLIP: ;NOW CHECK LEFT CLIPPING


SDR8_PrepByte: CP -7 ;CHECK IF STARTS TOO FAR LEFT
rrca ;...then rotate right... JR C,ENDSDR ;IF SO, SPRITE WON'T SHOW
djnz SDR8_PrepByte ;...1 to 8 times ADD A,32 ;ADD 32 TO X COOR TO MAKE IT START ON RIGHT SIDE
AND WRAP
ld b,a ;save rotated sprite byte into b LD B,A ;SAVE INTO X COOR
and e ;mask away left bits LD (CLIPFLAG),A ;AND MAKE FLAG NON-ZERO
ld d,a ;save masked sprite byt into d
ld a,e ;a=sprite mask CHECK_BOT: ;CHECK FOR BOTTOM CLIPPING
cpl ;switch every bit BIT 7,C
and (hl) ;reset every bit sprite's going to write to JR NZ,CHECK_TOP ; IS Y NEGATIVE, THEN JUMP TO CHECK
or d ;and combine with masked sprite byte TOP
ld (hl),a ;put left half of sprite
inc hl ;next byte over LD A,C ;GET Y-COORD
CP 28 ;CHECK IF GREATER THAN 28
ld a,e ;a=sprite mask JR NC,ENDSDR ;Y IS GREATER THAN 28, SO END, AS NOT
cpl ;switch every byte VIEWABLE
and b ;mask off right bits
ld d,a ;save masked sprite byte into d LD A,28 ;NUMBER OF ROWS IN DISPLAY
ld a,e ;a=sprite mask (again) SUB E ;SUBTRACT ROWS IN SPRITE
and (hl) ;mask off bits where sprite's going to be put CP C ;COMPARE TO Y-COORD
or d ;set bits in sprite byte JR NC,SDR8CL_DONECLIP ;IF NO CARRY, THEN NO BOTTOM CLIPPING
ld (hl),a ;and put right half of sprite ;SO CLIP BOTTOM

ld bc,$10-1 ;bc=number of bytes in one row subtract one LD A,28 ;ROWS IN DISPLAY
add hl,bc ;add to point hl to next row SUB C ;SUBTRACT THE Y-COORD
pop bc ;restore rotate counter and row counter LD E,A ;USE ABOVE RESULT AS REDUCED ROW
dec c ;decrease row counter COUNTER
jr nz,SDR8_NewRow ;and repeat until whole sprite is drawn ;BOTTOM CLIPPING DONE
pop hl ;restore hl (which now points to next byte after sprite)
ret ;return JR SDR8CL_DONECLIP

----------------------------------------------------------------- CHECK_TOP:

;SPRITE DRAWING ROUTINE (SDR): 8 BIT CLIPPING VERSION ;Y IS NEG


;By Jl LD A,C ;A IS -1 OR LESS
;Rewritten by Dharmesh Malam ADD A,E ;SUBTRACT THE NUMBER OF ROWS IN
;INPUTS: SPRITE
; B=X COORDINATE JR NC,ENDSDR ;IF NO-CARRY, THEN NOT ON SCREEN
; C=Y COORDINATE
; HL=POINTER TO SPRITE DATA ; Y IS BETWEEN -1 AND -(LENGHT)+1
;OUTPUTS: PUSH BC ;SAVE X,Y COORDS
; AF=DESTROYED LD C,A ;C HAS NUMBER OF ROWS TO PUT
; BC=RESTORED SUB E ;MAKE NUMBER INVERSE
; DE=RESTORED NEG
; HL=RESTORED LD B,A ;B HAS COUNTER TO SHIFT HL BY
; NO OTHER REGISTERS ARE CHANGED LD E,C ;C HAS E
; SPRITE_SHIFT: ;SHIFT HL B TIMES TO CLIP IT
;SPRITE DATA SHOULD BE STORED AS FOLLOWS: INC HL
;DB (# ROWS/BYTES/HEIGHT OF SPRITE) DJNZ SPRITE_SHIFT
;DB (BITMAP OF SPRITE) POP BC ;RESTORE X,COORDS
; LD C,0 ;Y WILL ALWAYS BE O
;NOTES:
; SDR8CL_DONECLIP:
; IF X BETWEEN -1 AND -7, THEN SOME LEFT CLIPPING, PUSH HL ;PUSH POINTER TO SPRITE TO STACK
;......LESS THAN OR EQUAL TO -8, THEN RETURN CALL FIND_PIXEL ;)
;IF X BEWTWEEN 0 AND 22, THEN NO CLIPPING LD C,E ;C=NUMBER OF ROWS IN SPRITE
;IF X BETWEEN 23 AND 29, THEN RIGHT CLIPPING ADD A,A ;-> SETS ALL BITS TO THE RIGHT OF THE SET BIT (SPRITE
;IF X GREATER THAN 30, THEN RETURN MASK)
DEC A ;/
;IF Y LESS THAN OR EQUAL TO -(LENGHT), THEN RETURN T LD E,A ;SAVE SPRITE MASK INTO E
;IF Y BETWEEN -1 AND -(LENGHT)+1, THEN TOP CLIPPNG T LD A,B ;GET X COOR
;IF Y BEWTWENM 0 AND (27-LENGHT), THEN NO CLIPPING N AND 00000111B ;FIND REMAINDER OF X/8
;IF Y BETWEEN (27-LENGHT)+1 AND 27, THEN BOTTOM CLIPPING B INC A ;INCREASE TO GET RANGE OF 1-8
;IF Y GREATER THAN 28, THEN RETURN LD B,A ;B=ROTATE COUNTER
B
SDR8CL_NEWROW:
ORG SDR8_CL EX (SP),HL ;HL(VIDEO LOCATION)<->(SP)(POINTER TO SPRITE)
CLIPFLAG: DB,0 LD A,(HL) ;A=BYTE IN SPRITE
INC HL ;NEXT BYTE
SDR8_CL: EX (SP),HL ;HL<->(SP)
PUSH BC ;SAVE REGISTERS PUSH BC ;SAVE ROTATE COUNTER AND ROW COUNTER
PUSH DE
PUSH HL RLCA ;ROTATE LEFT ONCE...
SDR8CL_PREPBYTE:
63 Memory Addressed Display

RRCA ;...THEN ROTATE RIGHT... ;DESTROYS AF, BC, DE, HL, IX


DJNZ SDR8CL_PREPBYTE ;...B TIMES BINTOBCD16:
PUSH DE
LD B,A ;SAVE ROTATED SPRITE BYTE INTO B LD HL,BCD16
LD A,(CLIPFLAG) ;A=LEFT CLIPPING FLAG LD DE,BCD16+1
OR A ;CHECK IF NOT 0 LD BC,10
JR NZ,SDR8CL_SKIPLEFT ;IF LEFT CLIPPING, ONLY DISPLAY RIGHT HALF OF LD (HL),0
SPRITE LDIR
LD A,B ;ELSE, LOAD ROTATED SPRITE BYTE BACK POP DE
INTO A LD B,16
AND E ;MASK OFF LEFT BITS BCD16L: LD HL,BCD16
LD D,A ;(CHECK SDR8 TO SEE HOW THIS PUSH BC
WORKS...) LD B,5
LD A,E BCD16I: LD A,(HL)
CPL CP 5
AND (HL) JR C,BCD16A
OR D ADD A,3
LD (HL),A LD (HL),A
INC HL BCD16A: INC HL
DJNZ BCD16I
LD A,L ;A=LOWER BYTE OF VIDEO LOCATION TO DEC HL ;HL NOW POINTS TO THE
PUT SPRITE ONES
AND 00000011B ;MASK OFF UPPER NIBBLE LD B,5
JR Z,SDR8CL_NEXTROW ;IF ZERO, HL NOW POINTS TO A NEW ROW, SO RIGHT SLA E
CLIPPING RL D
JR SDR8CL_PUTRIGHT ;JUMP FOR NORMAL DRAWING BCD16B: RL (HL)
BIT 4,(HL)
SDR8CL_SKIPLEFT: JR Z,BCD16C
DEC HL ;DECREASE HL BY 3 TO POINT IT TO RES 4,(HL)
START OF ROW FOR CLIPPING SCF
DEC HL BCD16C: DEC HL
DEC HL DJNZ BCD16B
POP BC
SDR8CL_PUTRIGHT: DJNZ BCD16L
LD A,E ;A=SPRITE MASK INC HL
CPL ;SWITCH EVERY BYTE LD IX,BCD16STRING
AND B ;MASK OFF RIGHT BITS LD BC,(5*256)+0
LD D,A ;SAVE MASKED SPRITE BYTE INTO D BCD16D: LD A,(HL)
LD A,E ;A=SPRITE MASK (AGAIN) ADD A,30H
AND (HL) ;MASK OFF BITS WHERE SPRITE'S GOING TO BE PUT LD (IX+0),A
OR D ;SET BITS IN SPRITE BYTE CP 30H
LD (HL),A ;AND PUT RIGHT HALF OF SPRITE JR NZ,BCD16E
BIT 1,C
JR Z,BCD16F
SDR8CL_NEXTROW: BCD16E: INC IX
LD BC,4H-1 ;BC=NUMBER OF BYTES IN ONE ROW-1 SET 1,C
LD A,(CLIPFLAG) ;SEE IF CLIPFLAG IS ZERO BCD16F: INC HL
OR A DJNZ BCD16D
JR Z,LEFT_SKIP ;IF NOT, THEN ADD 7, AS CLIPPING RET
CHANGES VALUES
LD BC,7 BCD16: DB 0,0,0,0,0
BCD16STRING:
LEFT_SKIP: DB 0,0,0,0,0,0
ADD HL,BC ;ADD TO POINT HL TO NEXT ROW
POP BC ;RESTORE ROTATE COUNTER AND ROW
COUNTER ------------------------------------------------------------------------
DEC C ;DECREASE ROW COUNTER ;© Dharmesh Malam 2002
JR NZ,SDR8CL_NEWROW ;AND REPEAT ;PUT 16 BIT NUMBER DE, AT BC WITH SMALLFONT
POP HL ;RESTORE POINTER TO SPRITE (NOW
POINTS TO BYTE AFTER SPRITE) PUT_NUM
PUSH DE ;SAVE
ENDSDR: PUSH HL
POP HL ;RESTORE REGISTERS PUSH IX
POP DE PUSH BC
POP BC PUSH BC
RET ;RETURN
CALL BINTOBCD16
------------------------------------------------------------------------------ POP BC ;RESTORE X,Y
LD HL,BCD16STRING ;POINT TO STRING
; BINTOBCD CALL PUTSMALL ;DRAW
;
; THESE ROUTINES FORMAT A REGISTERS INTO THEIR ASCII STRING EQUIVALENTS, IE: POP BC ;RESTORE
; THE NUMBER 143 WOULD BE TURNED INTO POP IX
; .DB "143", 0 POP HL
; POP DE
; BINTOBCD16 DOES NOT FORMAT STRINGS WITH LEADING ZEROES, IE:
; THE NUMBER 353 WOULD BE TURNED INTO RET
; .DB "353",0
; NOT -------------------------------------------------------------
; .DB "00353",0 ;© Dharmesh Malam 2002
; Library of characte/text routines
; BINTOBCD16
; BY JOE PEMBERTON ; Values and conversion of bases and ASCII characters
;SIZE: 97 BYTES ;
; ;1 = value in decimal
;INPUT: ;2 = value in hexadecimal
;DE=NUMBER TO CONVERT ;3 = value in binary
; ;4 = value in two's complement
;RETURNS (BCD16) AS TEN THOUSANDS, THOUSANDS, HUNDREDS, TENS, ONES ;5 = ASCII charater if valid
;(BCD16STRING) CONTAINS THE FORMATTED BCD ASCII STRING
;B = 0 ;1 2 3 4 5
;DE = 0
64 Memory Addressed Display

; 32 20 00100000 32 SPACE ; 124 7C 01111100 124 |


; 33 21 00100001 33 ! ; 125 7D 01111101 125 }
; 34 22 00100010 34 " ; 126 7E 01111110 126 ~
; 35 23 00100011 35 # ; 127 7F 01111111 127 DELETE
; 36 24 00100100 36 $
; 37 25 00100101 37 % ;PUT_STRING/char takes the ascii value, subtracts 32, so the first character is 'space',
; 38 26 00100110 38 & times is by 8 and adds it to the FONT?_ROM address. This will find the right
; 39 27 00100111 39 ' character.
; 40 28 00101000 40 (
; 41 29 00101001 41 ) ;BC points to x,y point to put string/char
; 42 2A 00101010 42 * ;E has which font 1,2,3,4, being namco,coleco,speccy,and bbc
; 43 2B 00101011 43 + ;HL, points to the string in put_string
; 44 2C 00101100 44 , ;D, contains the character to display in put_char
; 45 2D 00101101 45 - ORG PUT_CHAR
; 46 2E 00101110 46 .
; 47 2F 00101111 47 /
; 48 30 00110000 48 0 PUT_CHAR: ;PUT THE CHARACTER IN D, WITH SMALL FONT, AT BC
; 49 31 00110001 49 1 PUSH HL ;SAVE REGISTERS
; 50 32 00110010 50 2 PUSH DE
; 51 33 00110011 51 3 PUSH BC
; 52 34 00110100 52 4 LD HL,SMALL
; 53 35 00110101 53 5
; 54 36 00110110 54 6 CHAR_START:
; 55 37 00110111 55 7 LD A,D ;LOAD A WITH ASCII CODE OF
; 56 38 00111000 56 8 CHARACTER
; 57 39 00111001 57 9 SUB 32 ;SUBTRACT 32, SO FIRST LETTER IS 00,
; 58 3A 00111010 58 : AS PER IN ROM
; 59 3B 00111011 59 ; LD E,A ;PUT E WITH ASCII CODE - 32
; 60 3C 00111100 60 < LD D,0 ;LOAD D WITH 0, SO DE IS THE
; 61 3D 00111101 61 = CHARACTER NEEDED
; 62 3E 00111110 62 >
; 63 3F 00111111 63 ? ADD HL,DE
; 64 40 01000000 64 @ ADD HL,DE
; 65 41 01000001 65 A ADD HL,DE ;SO HL = OFFSET + 3(ASCII - 32)
; 66 42 01000010 66 B ;NEED TO CREATE 8*6 SPRITE FROM
; 67 43 01000011 67 C CONDENSED DATA
; 68 44 01000100 68 D LD A,6D ;LENGTH OF SPRITE
; 69 45 01000101 69 E LD (0950H),A ;LOAD TO RAM
; 70 46 01000110 70 F LD IX,0951H
; 71 47 01000111 71 G
; 72 48 01001000 72 H LD B,3
; 73 49 01001001 73 I SPRITE_OUT:
; 74 4A 01001010 74 J LD D,(HL) ;GET FIRST BYTE
; 75 4B 01001011 75 K LD A,0F0H ;SPLIT IN TWO
; 76 4C 01001100 76 L AND D ;BY MASKING
; 77 4D 01001101 77 M LD (IX),A ;SAVE TO RAM
; 78 4E 01001110 78 N INC IX ;NEXT LOCATION IN RAM
; 79 4F 01001111 79 O LD A,0FH ;NEXT MASK
; 80 50 01010000 80 P AND D ;GETS SECOND HALF
; 81 51 01010001 81 Q RLCA ;ROTATE LEFT
; 82 52 01010010 82 R RLCA ;4 TIMES
; 83 53 01010011 83 S RLCA
; 84 54 01010100 84 T RLCA
; 85 55 01010101 85 U LD (IX),A ;SAVE NEXT HALF
; 86 56 01010110 86 V INC IX
; 87 57 01010111 87 W INC HL
; 88 58 01011000 88 X DJNZ SPRITE_OUT
; 89 59 01011001 89 Y
; 90 5A 01011010 90 Z LD HL,0950H ;POINTER TO SPRTE IN RAM
; 91 5B 01011011 91 [ POP BC ;RESTORE X,Y COORDS
; 92 5C 01011100 92 \ CALL SDR8_CL ;DRAW THE CHARACTER
; 93 5D 01011101 93 ]
; 94 5E 01011110 94 ^ POP DE ;RESTORE REGISTERS
; 95 5F 01011111 95 _ POP HL
; 96 60 01100000 96 `
; 97 61 01100001 97 a RET
; 98 62 01100010 98 b
; 99 63 01100011 99 c
; 100 64 01100100 100 d PUT_SMALL: ;PUT AT BC, (X,Y), STRING POINTED TO BY HL, WITH SMALL FONT,END
; 101 65 01100101 101 e AT 0
; 102 66 01100110 102 f ;BEFORE: HL POINTS TO STRING, BC = XY
; 103 67 01100111 103 g ;AFTER: HL POINTS TO END OF STRING, ,
; 104 68 01101000 104 h BC = (X+4CHARS),Y,
; 105 69 01101001 105 i ; A=0, D=LAST BYTE
; 106 6A 01101010 106 j
; 107 6B 01101011 107 k LD A,(HL) ;FETCH BYTE
; 108 6C 01101100 108 l CP 0 ;IS IT ZERO
; 109 6D 01101101 109 m RET Z ;IF SO, THEN RETURN TO CALLER
; 110 6E 01101110 110 n LD D,A ;PUT CHARACTER INTO D FOR
; 111 6F 01101111 111 o PUT_CHAR
; 112 70 01110000 112 p CALL PUT_CHAR
; 113 71 01110001 113 q LD A,B ;GET X-COORD
; 114 72 01110010 114 r ADD A,4 ;SHIFT X-COORD BY 5, AS SMALL FONT
; 115 73 01110011 115 s LD B,A ;SAVE
; 116 74 01110100 116 t INC HL ;NEXT BYTE
; 117 75 01110101 117 u JR PUT_SMALL ;JUMP TO TOP,HENCE REPEAT UNTILL ALL CHAR'S ARE
; 118 76 01110110 118 v DONE
; 119 77 01110111 119 w
; 120 78 01111000 120 x -----------------------------------------------------------------------------
; 121 79 01111001 121 y ;© Dharmesh Malam 2003
; 122 7A 01111010 122 z ORG Pause
; 123 7B 01111011 123 { Pause:
65 Memory Addressed Display

IN A,(0) ;GET KEYS OF PAD 1 DB 01000100B


BIT 0,A ;SEE IF START WAS PRESSED DB 01000000B
RET Z ;RETURN IF IT WASN'T DB 01000000B
LD C,2
CALL WAIT ; Character 0x22 "
IN A,(0)
RET Z DB 10101010B
DB 10000000B
PUSH HL ;SAVE REGSTERS DB 00000000B
PUSH DE
PUSH BC ; Character 0x23 #

LD HL,VIDRAM ;SAVE SCREEN, HL POINTS TO CURRENT SCREEN DB 10101110B


LD DE,PAUSE_TEMP ;TEMP SCRENN DB 10101110B
LD BC,112 ;SIZE OF SCREEN DB 10100000B
LDIR ;SAVE DATA

CALL CLEAR_VRAM ;CLEAR SCREEN ; Character 0x24 $

LD HL,PAUSE_TEXT ;"PAUSE" DB 01001110B


LD B,6 ;OFF CENTRE DB 01001110B
LD C,8 DB 01000000B
CALL PUT_SMALL ;PUT TEXT
LD DE,0 ;ZERO COUNTER ; Character 0x25 %
TEXT:
LD B,6 ;COORS DB 10100010B
LD C,16 DB 01001000B
CALL PUT_NUM DB 00100000B
CALL OUTRAM
; Character 0x26 &
LD B,100
KEY_LOOP: DB 00001000B
IN A,(0) DB 10000000B
BIT 0,A DB 10100000B
JR NZ,UNPAUSE
LD C,2 ; Character 0x27 '
CALL WAIT ;WAIT FOR A FEW MS
DJNZ KEY_LOOP ;CHECK PAD 100 TIME, THEN INC DB 10001000B
COUNTER DB 00000000B
INC DE DB 00000000B
JR TEXT
; Character 0x28 (
UNPAUSE:
LD C,2 DB 01001000B
CALL WAIT DB 10001000B
IN A,(0) DB 01000000B
BIT 0,A
JR Z,KEY_LOOP ; Character 0x29 )

LD HL,PAUSE_TEMP ;OPPOSITE TO ABOVE DB 01000010B


LD DE,VIDRAM ;RESTORE DATA DB 00100010B
LD BC,112 DB 01000000B
LDIR
CALL OUTRAM ; Character 0x2A *

POP BC ;RESTORE REGISTERS DB 10100100B


POP DE DB 11100100B
POP HL DB 10100000B

RET ;THEN RETURN ; Character 0x2B +

PAUSE_TEXT: DB 00000100B
DB "PAUSE",0 DB 11100100B
DB 00000000B
---------------------------------------------
;© Dharmesh Malam 2003 ; Character 0x2C ,

WAIT: ;CALL WITH C AS MULTIPLIER DB 00000000B


PUSH BC ;SAVE DB 00000100B
WAI2 DB 10000000B
LD B,255
WAI: ;INNER LOOP ; Character 0x2D -
DJNZ WAI
DEC C DB 00000000B
JR NZ,WAI2 ;OUTER LOOP DB 11100000B
POP BC DB 00000000B
RET
; Character 0x2E .

;© Dharmesh Malam 2003; DB 00000000B


;EACH FONT IS 4x6, stored condensed DB 00000000B
;------------------------------------ DB 10000000B

ORG FONT1_ROM ; Character 0x2F /


; Character 0x20 (Space)
DB 00100100B
DB 00000000B DB 01001000B
DB 00000000B DB 00000000B
DB 00000000B
; Character 0x30 0
; Character 0x21 !
DB 01001010B
66 Memory Addressed Display

DB 11101010B
DB 01000000B ; Character 0x40 @

; Character 0x31 1 DB 11001000B


DB 11001000B
DB 01001100B DB 11000000B
DB 01000100B
DB 11100000B ; Character 0x41 A

; Character 0x32 2 DB 01001010B


DB 11101010B
DB 01001010B DB 10100000B
DB 00100100B
DB 11100000B ; Character 0x42 B

; Character 0x33 3 DB 11001010B


DB 11001010B
DB 11100010B DB 11000000B
DB 01000010B
DB 11000000B ; Character 0x43 C

; Character 0x34 4 DB 01101000B


DB 10001000B
DB 10101010B DB 01100000B
DB 11100010B
DB 00100000B ; Character 0x44 D

; Character 0x35 5 DB 11001010B


DB 10101010B
DB 11101000B DB 11000000B
DB 11000010B
DB 11000000B ; Character 0x45 E

; Character 0x36 6 DB 11101000B


DB 11001000B
DB 01001000B DB 11100000B
DB 11001010B
DB 01000000B ; Character 0x46 F

; Character 0x37 7 DB 11101000B


DB 11001000B
DB 11100010B DB 10000000B
DB 01001000B
DB 10000000B ; Character 0x47 G

; Character 0x38 8 DB 01101000B


DB 10101010B
DB 01001010B DB 01100000B
DB 01001010B
DB 01000000B ; Character 0x48 H

; Character 0x39 9 DB 10101010B


DB 11101010B
DB 01001010B DB 10100000B
DB 01101010B
DB 01000000B ; Character 0x49 I

; Character 0x3A : DB 11100100B


DB 01000100B
DB 00001000B DB 11100000B
DB 00000000B
DB 10000000B ; Character 0x4A J

; Character 0x3B ; DB 11100010B


DB 00101010B
DB 00001100B DB 01100000B
DB 00000100B
DB 10000000B ; Character 0x4B K

; Character 0x3C < DB 10101010B


DB 11001010B
DB 00100100B DB 10100000B
DB 10000100B
DB 00100000B ; Character 0x4C L

; Character 0x3D = DB 10001000B


DB 10001000B
DB 00000000B DB 11100000B
DB 11100000B
DB 11100000B ; Character 0x4D M

; Character 0x3E > DB 10101110B


DB 10101010B
DB 10000100B DB 10100000B
DB 00100100B
DB 10000000B ; Character 0x4E N

; Character 0x3F ? DB 00001010B


DB 11101010B
DB 01001010B DB 10100000B
DB 00100100B
DB 01000000B ; Character 0x4F O
67 Memory Addressed Display

DB 00000000B
DB 01001010B DB 00000000B
DB 10101010B
DB 01000000B ; Character 0x5F (underscore)

; Character 0x50 P DB 00000000B


DB 00000000B
DB 11001010B DB 11110000B
DB 11001000B
DB 10000000B
;© Dharmesh Malam 2003
; Character 0x51 Q ;Menu routine
ORG 0044H
DB 01001010B
DB 10100100B MENU:
DB 01100000B CALL CLEAR_VRAM
LD B,3
; Character 0x52 R LD C,1
LD HL,TITLE
DB 11001010B CALL PUT_SMALL
DB 11001010B LD B,4*8
DB 10100000B LD HL,VIDRAM
INV:
; Character 0x53 S LD A,(HL)
CPL
DB 01101000B LD (HL),A
DB 01000010B INC HL
DB 11000000B DJNZ INV

; Character 0x54 T LD B,1


LD C,8
DB 11100100B LD HL,ENT_1
DB 01000100B CALL PUT_SMALL
DB 01000000B INC HL
LD B,1
; Character 0x55 U LD C,14
CALL PUT_SMALL
DB 10101010B INC HL
DB 10101010B LD B,1
DB 01000000B LD C,20
CALL PUT_SMALL
; Character 0x56 V
LD C,8
DB 10101010B CALL INVERT_CUR
DB 10101010B CALL OUTRAM
DB 11000000B
MENUL:
; Character 0x57 W
IN A,(0)
DB 10101010B BIT 7D,A ; DID THEY PRESS UP?
DB 10101110B JR NZ,MENUUP ; MOVE
DB 10100000B MENU BAR UP
BIT 6D,A ; OR WAS IT DOWN?
; Character 0x58 X JR NZ,MENUDOWN ; THEN MOVE THE BAR
DOWN
DB 10101010B BIT 2D,A ; DID THEY PRESS X
DB 01001010B JR NZ,MENUSELECT ; JUMP TO THAT
DB 10100000B SELECTION
JR MENUL ; THEY'RE JUST SITTING
; Character 0x59 Y THERE, LOOP AGAIN

DB 10101010B
DB 01000100B INVERT_CUR
DB 01000000B PUSH BC
LD HL,VIDRAM
; Character 0x5A Z LD B,0
SLA C
DB 11100010B SLA C
DB 01001000B ADD HL,BC
DB 11100000B LD B,4*6

; Character 0x5B [ INVERT:


LD A,(HL)
DB 11101000B CPL
DB 10001000B LD (HL),A
DB 11100000B INC HL
DJNZ INVERT
; Character 0x5C \ POP BC
RET
DB 00001000B
DB 01000100B
DB 00100000B MENUUP:
IN A,(0)
; Character 0x5D ] BIT 7,A
JR Z,MENUL
DB 11100010B CALL INVERT_CUR ; INVERT CURRENT
DB 00100010B SELECTION BACK TO NORMAL
DB 11100000B LD A,C
SUB 6D
; Character 0x5E ^ LD C,A ; MOVE UP
CP 2D
DB 01001010B JR NZ,MENUBAR ; IF IT'S
68 Memory Addressed Display

ZERO, WE'RE AT THE TOP ;#include zinc.asm


LD C,20 ; SO MOVE TO THE
BOTTOM ORG 021AH
JR MENUBAR ; HANDLE MENU BAR SCROLLER:

MENUDOWN: LD B,32
IN A,(0) LD HL,TEMP_STRING
BIT 6,A ZERO_TEMPS:
JR Z,MENUL XOR A
LD (HL),A
CALL INVERT_CUR ; SAME AS UP, GO BACK INC HL
TO NORMAL TEXT DJNZ ZERO_TEMPS
LD A,C ; GET LD E,A
CURRENT ENTRY FOR CHECK
CP 20 ; AT THE FROM_DISP:
BOTTOM? CALL CLEAR_VRAM
JR Z,MENUDOWNT ; THEN MOVE TO THE
TOP LD BC,0000 ;RESET COORDS
ADD A,6D ; NEXT LINE LD HL,ENTER1 ;POINT TO 'ENTER' TEXT
LD C,A ; SAVE CALL PUT_SMALL ;DRAW TEXT
JR MENUBAR ; HANDLE MENU BAR LD BC,7 ;INC Y COORD
LD HL,ENTER2 ;POINT TO 'TEXT'
MENUDOWNT: CALL PUT_SMALL ;DRAW
LD C,8D ; MOVE TO THE TOP
LD D,32 ;LOAD THAT CHARACTER
MENUBAR: INTO D
CALL INVERT_CUR ; INVERT THE NEW NORMAL:
SELECTION LD B,22 ;PUT CHAR IN BOT RIGHT
CALL OUTRAM LD C,22
PUSH BC LD HL,TEMP_STRING
LD C,00AAH CALL PUT_SMALL
CALL WAIT CALL OUTRAM
POP BC
JR MENUL ; NOW IT'S TIME TO LOOP
INPUT_WAIT: ;LOOP TO EDIT TEXT
PUSH BC
MENUSELECT: LD C,00FFH
CALL WAIT
PUSH BC POP BC
LD C,00AAH
CALL WAIT INPUT_WAT
POP BC IN A,(0)

LD A,B BIT 7,A ;ZERO FLAG SET, IF NOT


CP 8 PRESSED
JR NZ CP2 JR NZ,UP ;THEREFORE ZERO FLAG NOT SET, IF
LD HL,JM_1 PRESSED
JR LOAD
BIT 6,A ;DOWN
CP2: JR NZ,DOWN
CP 14
JR NZ CP3 BIT 1,A ;BUTTON Z
LD HL,JM_2 JR NZ,ENTER
JR LOAD
BIT 3,A ;BUTTON X
CP3: JR NZ,DELETE
LD HL,JM_3
BIT 2,A ;START
LOAD: JR NZ,DISP
LD A,(HL) ; GET LOWER BYTE OF
POINTER JR INPUT_WAT
INC HL ; NEXT
BYTE UP:
LD H,(HL) ; GET UPPER BYTE OF LD A,96
POINTER INC D
LD L,A ; CP D
COMPLETE POINTER WITH LOWER BYTE JR NZ,HERE1
JP (HL) ; JUMP TO THE ADDRESS LD D,32
FROM THE TABLE--HL, NOT (HL) HERE1:
PUSH BC
TITLE: LD B,25
DB "*SELECT*" LD C,15
ENT_1: CALL PUT_CHAR
"GAME",0 POP BC
"SOUND",0 CALL OUTRAM
"SCROLER",0 JR INPUT_WAIT

JM_1: DOWN:
DB 0 LD A,31
DB 0 DEC D
JM_2: CP D
DB 0 JR NZ, HERE1
DB 0 LD D,95
JM_3: JR HERE1
DB 0
DB 0 ENTER:
LD A,32 ;MAX NUMBER OF CHARS
---------------------------------------------------------------- CP E
;© Dharmesh Malam 2003 JR Z,INPUT_WAIT ;JUMP IF AT THIS NUM
;Scrolls user inputted text across the screen
;at random y values LD (HL),D ;SAVE CHARACTER
;© Dharmesh Malam 2002 INC E
69 Memory Addressed Display

LD A,B END
SUB 4
LD B,A -----------------------------------------------------------------

PUSH BC ;© Dharmesh Malam 2003


LD HL,TEMP_STRING ORG 120H
CALL PUT_SMALL ;DRAW STRING
POP BC Logo: ;Does intro screen
LD B,0
CALL OUTRAM LD C,4
JR INPUT_WAIT LD HL,TEXT1 ;DARMESH
CALL PUT_SMALL
DELETE: LD B,0
XOR A LD C,12
CP E INC HL
JR Z,INPUT_WAIT CALL PUT_SMALL ;MALAM
DEC HL CALL OUTRAM
LD (HL),A ;DELETE CHAR LD C,00FFH
DEC E CALL WAIT

PUSH DE LD B,0
LD D," " LD C,20
CALL PUT_CHAR ;CLEAR BIT ON LEFT INC HL ;PRESENTS
CALL PUT_SMALL
LD A,B CALL OUTRAM
ADD A,4 LD C,00FFH
LD B,A LD B,4
PUSH BC ;SAVE X,Y WAIT_L:
LD HL,TEMP_STRING CALL WAIT
CALL PUT_SMALL DJNZ WAIT_L
POP BC
POP DE CALL CLEAR_VRAM
CALL OUTRAM LD B,0
JR INPUT_WAIT LD C,4
INC HL
DISP: ;WE HAVE A STRING TO CALL PUT_SMALL ;MEMORY
DISPLAY
CALL CLEAR_VRAM LD B,0
LD C,0 ;Y, IE TOP LINE LD C,10
INC HL
LOOP_INIT: CALL PUT_SMALL ;ADRESED
LD D,E ;NUMBER OF CHARS
LD A,30 ;ONE DISPLAY LD B,0
SLA D ;X2 LD C,19
SLA D ;X4 INC HL
ADD A,D ;ADD TOGETHER CALL PUT_SMALL ;DISPLAY
LD D,A ;THIS IS THE COUNTER CALL OUTRAM

LD C,00FFH
LD B,30 ;X, JUST OFF SCREEN LD B,4
WAIT_LL:
DISP_LOOP: CALL WAIT
LD HL,TEMP_STRING ;POINTER TO STRING DJNZ WAIT_LL
PUSH BC
PUSH DE
CALL PUT_SMALL ;DRAW WITH CLIPPING LD HL,VIDRAM
AT BC LD B,112
POP DE INVERT:
LD A,(HL)
CALL OUTRAM ;OUTPUT CPL
CALL CLEAR_VRAM ;CLEAR INTERNAL VRAM LD (HL),A
CALL OUTRAM
LD C,00AAH INC HL
CALL WAIT ;WAIT 1 TENTH LD C,10
POP BC CALL WAIT
DJNZ INVERT
IN A,(0)
BIT 1,A
JR NZ,FROM_DISP CALL CLEAR_VRAM
BIT 2,A LD D,18
JR NZ,MENU
LD B,0
DEC B LD C,0
DEC D LD HL,MAD
JR NZ,DISP_LOOP ;LOOP 30+4(NUM_CHAR) SLIDE:
CALL PUT_SMALL
LD A,R CALL OUTRAM
AND 00011111B PUSH BC
SUB 2 ;GET RANDOM NUMBER LD C,0AAH
BETWEEN -2 AND 30 CALL WAIT
LD C,A POP BC
JR LOOP_INIT ;LOOP INC B
INC C
DEC D
ENTER1: DB,"ENTER",0 JR NZ,SLIDE
ENTER2: DB,"TEXT:",0
LD B,3
ORG 096AH LD C,19
TEMP_STRING: DB,0,0,0,0,0,0,0,0 LD HL,FACE
DB,0,0,0,0,0,0,0,0 CALL SDR8_CL
DB,0,0,0,0,0,0,0,0,0 CALL OUTRAM
70 Memory Addressed Display

LD C,00FFH
LD B,2
WAIT_LLL:
CALL WAIT
DJNZ WAIT_LLL

LD B,112
SHIFT:
PUSH BC
LD HL,0870H-4
LD DE,0870H
LD BC,112
LDDR
CALL OUTRAM

LD C,90H
CALL WAIT
POP BC
DJNZ SHIFT ;SHIFT DOWN THE DIPLAY

LD C,00FFH
CALL WAIT
JP 0044H

TEXT1:
DB "DARMESH",0
DB "MALAM",0
DB "PRESENTS",0
DB "MEMORY",0
DB "ADRESED",0
DB "DISPLAY",0
MAD:
DB "MAD",0
FACE:
DB 8
DB 00111100B
DB 01000010B
DB 10100101B
DB 10000001B
DB 10100101B
DB 10011001B
DB 01000010B
DB 00111100B

Das könnte Ihnen auch gefallen