MZ-700 – 8253 functions 1

8253 functions in the MZ-700

General functions

The 8253 is used by the MZ-700 for the sound generation and to get an internal clock. The 8253 contains 3 counters, #0, #1, #2. Counter #0 is used for the sound generation and the other counters #1 and #2 are used to install the clock.

Counter #0 operates as a square wave generator for the sound generation in mode 3 and divides the input signal of 1.1088 MHz by the value given at the setup information for the 8253. The output of counter #0 is the input for an audio amplifier. A loudspeaker is connected to this amplifier.

Counter #1 operates as a rate generator in mode 2 and counter #2 operates in mode 0 and generates an interrupt signal labeled INT by a hardware logic used to interrupt the Z80. The interrupt is used to toggle AM and PM of the clock and to reset the output line OUT2 for the next interrupt at 12 o’ clock. For further details, go to the section describing the interrupt.

The time interrupt can be suppressed (masked) by the software using the signal INTMSK. An external hardware can interrupt the CPU too by using the line EXINT of the external bus, but cannot be suppressed by the software. For further details, go to the section describing the masking by the software.

8253 functions in the MZ-700

Counter #1 reduces the input signal of 15.611 kHz to an 1 Hz pulse (one second). The output of this counter is the input to counter #2. Counter #2 reduces this 1 Hz signal to a signal that can invoke the interrupt routine at 12 o’ clock to toggle the AM/PM value located at $119B by a control logic.

The OUT line remains at a logical 1 state until the counter is reloaded or until a control word is written to the 8253 for the counter #2 (for this refer to the description of the mode 0). The interrupt routine reinitiates the counter to 43,200 seconds (12 hours) and by this the output line will be reset.

The following table is an overview of all 8253 ports:

address
scope circuit function IC#
$E004
C0: Sound, mode 3 (square wave generator) 8253
Programmable
Interval
Timer
( PIT )
AG
$E005
C1: Clock, mode 2 (rate generator)
$E006
C2: Clock, mode 0 (interrupt on terminal count)
$E007
PT control word
$E008
tempo
joysticks
HBLNK
LS367 buffer 4C
LS74 C0 control 7E
556 timer 32 Hz BJ
LS02 control 6F
LS32 control 6C

Not all of the 8253’s counters will be set up by the MZ-700 initially. During startup only the sound generator is set up and turned off by some monitor instructions. Please take a note of the description of the sound initiation routine. The counters #1 and #2 will be setup by the initiation routines for the clock.

The internal clock

The internal clock must be set by the user to invoke the clock. The internal clock will not be initiated by the monitor during its startup. This can be done by calling the monitor’s time set subroutine $0033.

The register DE must be established for this before calling $0033 and must contain the time in seconds represented by a binary value. The accumulator register must contain the AM/PM value, defined as $00 for AM and $01 for PM.

For example, to set the time to 05:32:12 PM you have to compute this time in seconds. First set the accumulator to the PM value of $01. Compute the hours: 5 x 60 minutes x 60 seconds result into 18,000 seconds. Now you have to compute the minutes. There are 32 minutes x 60 seconds per minute result into 1,920 seconds. Add the remaining 12 seconds and the other two values: 18,000 + 1,920 +12 = 19,932 seconds. At last compute this decimal value into a hex value ($4DDC) and load DE with this value:

B000 3E01	LD	A,$01	 ;PM value to the accu
B002 11DC4D	LD	DE,$4DDC ;time value to DE (05:32:12)
B005 CD3300	CALL	$0033	 ;invoke time set subroutine

The clock’s counters #1 and #2 will be set up by the monitor’s subroutine $0033. Here is a copy of the relevant instructions of this subroutine:

0033 C30803	JP	$0308

0308......
031D 2107E0	LD	HL,CONTF ;address to control word port $E007
0320 3674	LD	(HL),$74 ;control word into port $E007
0322 36B0	LD	(HL),$B0 ;next control word into port $E007
0323 2B		DEC	HL	 ;address to port $E006 
0325 73		LD	(HL),E	 ;load time value, least significant first
0326 72		LD	(HL),D	 ;most significant byte last into port $E006

The first instruction loads the address of the control word port $E007 into the register HL. Next a control word is written into the port. Please refer to control word definitions of the 8253. The binary value of this control word is ‘01110100’.
Bits D7=0 and D6=1 select counter #1.
Bits D5=1 and D4=1 define the read/load mode for the counter register. In this case the least significant byte is to read/load first and then the most significant byte.
Bits D3=0, D2=1, and D1=0 determine the basic mode of operation, in this case it is the mode 2 (rate generator).
Bit D0=0 determines that the count will be in binary.

Counter #1 will operate now as a rate generator in mode 2 and the count will be in binary. The counter is to be load/read with the least significant byte first and then the most significant byte.

The binary value of the next control word written into the control word port $E007 by the instruction at the location $0322 is 10110000 binary.
Bits D7=1 and D6=0 select counter #2.
Bits D5=1 and D4=1 will load/read the least significant byte first and next the most significant byte.
Bits D3=0, D2=0, and D1=0 set the operation mode 0 (interrupt on terminal count).
Bit D0=0 determines that the count will be in binary.

Counter #2 will operate now in mode 0 binary counting down and is to load/read with the least significant byte first and then the most significant byte.

The instructions from location $0323 to $0326 load counter #2 with the correct value of the time to be set into its port $E006. This value is given by the caller of the subroutine $0033.

The input frequency of counter #1 is 15.611 KHz. To get an output pulse at each second the counter must be loaded with a count value of 15,611 decimal or $3CFB hexadecimal. Please refer to the formula and the description of mode 2. This is done by the monitor’s subroutine at the location $033E:

033E 36FB	LD	(HL),$FB ;(HL=$E005)load least significant byte first
0340 363C	LD	(HL),$3C ;load most significant byte last

You can read the time by the monitor’s subroutine $003B. On return you get back the AM/PM value in the accumulator register. Again, $00 means AM, while $01 means PM. You get back the time read from the 8253’s counter #2 in the register DE. The time value returned is in seconds and you have to compute it into hours/minutes/seconds.

Using the S-BASIC you can use the time set and time read function by TI$. The format of TI$’s data is hhmmss.

Once the clock is setup it works until it will be stopped by own software or by a reset. The clock will interrupt the CPU at 12 o’ clock AM and PM. The AM/PM value located at $119B must be toggled by the interrupt routine of the monitor and some other functions must be performed. To this, please read the following section.


The time interrupt

The Z80 CPU is set by the monitor during startup into the interrupt mode 1 (see location $004D of the monitor program). This means, if an interrupt at the INT pin of the Z80 CPU occurs, the Z80 pushes the current instruction pointer to the stack and then executes the monitor’s instruction located at $0038.

The monitor ROM contains at the location $0038 a jump command to the location $1038 – outside of the ROM. At this location is a 2nd jump command: $C38D03. This jump command was stored by the monitor during its startup (see the location $0085 of the monitor program) and the jump command points to the monitor’s interrupt routine at location $038D.

You can change the instruction at location $1038 for your own interrupt routines. Note, the value will be changed by the monitor every time a reset/power on was done.

The interrupt routine will be invoked by the counter #2 if the timer value is zero. This will occur at 12 o’ clock AM and PM and if the interrupt is not masked. I’ll describe the masking of this interrupt by the software later in this section.

If the timer has counted down to 0 its line labeled OUT2 goes high and sets the interrupt pin INT of the Z80 CPU by a control logic. The description of this control logic follows later in this section. The output will stay a logical 1 until the counter is reloaded with a new value or the same value. Therefore, the interrupt routine must reload the counter #2 that operates in mode 0 to reset the output line of the counter. Please refer to the description of this attributes of the mode 0.

The AM/PM value used by the monitor’s time read subroutine at the location $003B will be toggled first by the monitor’s interrupt routine. Please see, what the monitor’s interrupt routine does:

0391 219B11	LD	HL,AMPM ;address to the AMPM value at $119B
0394 7E		LD	A,(HL)	;load the current value
0395 EE01	XOR	$01	;toggle the value by exclusive OR bit 0
0397 77		LD	(HL),A	;store the new, toggled value

Next the counter #2 will be reloaded:

0398 2107E0	LD	HL,CONTF  ;address to control word port $E007
039B 3680	LD	(HL),80	  ;determine counter to be read
039D 2B		DEC	HL	  ;address to port $E006
039E E5		PUSH	HL	  ;save contents of HL ($E006)
039F 5E		LD	E,(HL)	  ;read least significant byte first
03A0 56		LD	D,(HL)	  ;then most significant byte
03A1 21C0A8	LD	HL,$A8C0  ;12 hours = 43,200 seconds
03A4 19		ADD	HL,DE	  ;consider current counter value in DE
03A5 2B		DEC	HL	  ;and consider 2 seconds around zero
03A6 2B		DEC	HL	  ;
03A7 EB		EX	DE,HL	  ;exchange contents DE-HL
03A8 E1		POP	HL	  ;HL contents now $E006
03A9 73		LD	(HL),E	  ;load value into the port, first least...
03AA 72		LD	(HL),D	  ;then most significant byte

Now the counter is ready and can interrupt the CPU again.


Masking the time interrupt and the external hardware interrupt

The time interrupt can be suppressed (masked) by the software using the signal INTMSK. INTMSK is the name of the physical line connected to PC2 of the port $E002 of the 8255. No interrupt by the output line OUT2 of the timer counter #2 can be invoked if PC2 is set to 0 by any software.

INTMSK can suppress the interrupt by OUT2

An external interrupt can occur if an external hardware is used and if it resets the line EXINT of the external bus, but this cannot be suppressed by the software using INTMSK. To this, see the complete hardware logic to interrupt the Z80 CPU:

Interrupt control logic of the MZ-700

I’ll try to explain the control logic step by step now.

The IC (Integrated Circuit) on the left side of the diagram is labeled IC CH and its function is a NAND (Not AND). The NAND has two input lines labeled INTMSK, OUT2 and one output line labeled INTI. The logic of the NAND is as follows:

NAND inputs
NAND output
INTMSK
OUT2
INTI
0
0
1
0
1
1
1
0
1
1
1
0

Please take note, INTI is low (=0) if the counter counted down to 0 (OUT2 = 1) and is not masked by INTMSK (INTMSK = 1). Download the datasheet of the 74LS00 for further details ( PDF, 121 kb ).

The IC (Integrated Circuit) on the right side of the diagram above is labeled IC 7D and its function is an AND. The AND has two input lines labeled INTI, EXINT and one output line labeled INT. The logic of the AND is as follows:

AND inputs
AND output
INTI EXINT
INT
0
0
0
0
1
0
1
0
0
1
1
1

If INTI is low an interrupt will occur by setting INT to low. An interrupt will also occur even if INTI is not low, but if EXINT is low. This means, that the external interrupt by an external hardware will interrupt the CPU too by resetting EXINT. Download the datasheet of the 74LS08 for further details ( PDF, 125 kb ).

Now I’ll recapitulate the function of all the logic by a table. Please take a note of all possible occurrences summarized by the following table:

OUT2 of timer counter #2 (OUT2 = 1 if counter = 0) INTMSK (bit PC2 of port $E002)
(interrupt masked/suppressed if 0)
external interrupt EXINT
(true if 0)
Interrupt?
(yes, if INT is low)
0
0
1
no
0
1
1
no
1
0
1
no
1
1
1
yes
0
0
0
yes
0
1
0
yes
1
0
0
yes
1
1
0
yes
The logical formula to this is: INT = EXINT OR (INTMSK AND OUT2)

At the first 4 events an interrupt occurs only if the interrupt is not masked by INTMSK (INTMSK = 1) and if the counter has counted down to 0. Remember, the output line of the counter #2 goes to a logical 1 if the counter’s value is 0.

At the 3rd event the counter has reached 0, but no interrupt occurs because the interrupt is masked by INTMSK = 0.

At the 4th event the counter has counted down to 0 and the interrupt is not masked by INTMSK, so an interrupt will occur.

At the last 4 events an interrupt occurs because the external hardware has reset the external interrupt line EXINT. The hardware interrupt cannot be masked by INTMSK. The hardware interrupt will not be influenced by the counter or the mask.

Summary of contents

The CPU can be interrupted by the external hardware using EXINT of the external bus (pin 48) or by the timer counter #2 of the clock. The interrupt by counter #2 can be suppressed by resetting bit PC2 of the port $E002, but the external hardware interrupt cannot be suppressed by this.

If an interrupt occurs the instruction outside of the ROM at location $1038 is executed and can be modified for own purposes. Normally the monitor’s subroutine at location $038D is executed to toggle the AM/PM value and to re-establish the counter #2 for further interrupts.

A detailed description/explanation of the sound generation routines follows here.