8253 functions in the MZ-700
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.
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.
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'.
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
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
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.
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:
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:
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:
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:
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.