Sharp logo
8253 sound functions 
( Additional information / details; Part II )  
Tables of frequencies stored in the monitor 1Z-013A

The monitor program 1Z-013A uses 2 tables to compute the output frequencies of the valid notes. The first table at location $026C called MTBL is used for the notes C, D, E, F, G, A, and B, and for a rest R. The second table at location $0284 called M#TBL is used for the seminotes #C, #D, #E ( ! ), #F, #G, #A, and #B ( ! ), and for a rest R if #R was coded.

Each of the 8 table entries contains 1 ASCII character for the name of the note ( e.g. C, D, E, etc. ) and at least an ASCII-character "R" for a rest. Each ASCII character is followed by a 2 byte hexadecimal value used to compute the load value for the counter's register. If the upper octave is coded without any tempo specification ( e.g. "+A" ) then the value ( i.e. $04EC or 1260 dec. ) is used without any computation. The last entry is for a rest and contains $0000.

The values in both tables of the monitor 1Z-013A are specified for the upper octave and the values for the other octaves are simply computed by a multiplication by 2 for the medium octave and by a multiplication by 4 for the lower octave.

Note The seminote #E isn't a valid musical note but the MZ plays the note F instead of #E! The frequency of the lower octave -#B results to that of the medium octave C and the medium octave #B results to that of the upper octave +C. They have the same output frequency but the upper octave +#B has the output frequency of note C of the octave that follows the upper octave.

To this, see the following table of the frequencies generated by the 8253 if the input frequency SOIN of your MZ-700 is 1.1088MHz exactly otherwise other frequencies will be outputted. If exact frequencies were needed try to measure the exact input frequency SOIN of your MZ by a frequency counter. Then try to tune your MZ to 1.1088MHZ or calculate the resulting frequencies for each note by:
YourSOINfrequency divided by the table's counter register value of MTBL or M#TBL results to the frequency value of the note for the upper octave.

For the medium octave multiply the table value by 2 and for the lower octave multiply the table value by 4 and next compute the frequencies again.

For example, if your MZ-frequency SOIN is 1.107MHz and you want to know the output frequency of the note +#B ( table value of note +#B is $0423 that's 1059 decimal ):

1.107MHz / 1059 = 1045.3Hz ( instead of 1046.5Hz, deviation is -1.2Hz ).

note
counter register value from table MTBL/M#TBL
octave multiplier
output frequency by 8253
( Hz )
nominal output frequency
( Hz )
-C
$0846 (2118)
4
130.9
130.81
-#C
$07CF (1999)
4
138.7
138.59
-D
$075F (1887)
4
146.9
146.83
-#D
$06F5 (1781)
4
155.6
155.56
-E
$0691 (1681)
4
164.9
164.81
-#E
$0633 (1587)
4
174.7
174.61
-F
$0633 (1587)
4
174.7
174.61
-#F
$05DA (1489)
4
185.0
184.997
-G
$0586 (1414)
4
196.0
195.998
-#G
$0537 (1335)
4
207.6
207.65
-A
$04EC (1260)
4
220.0
220.00
-#A
$04A5 (1189)
4
233.1
233.08
-B
$0464 (1124)
4
246.6
246.94
-#B
$0423 (1059)
4
261.8
261.63
-R
$0000
-
-
-
-#R
$0000
-
-
-
C
$0846 (2118)
2
261.8
261.63
#C
$07CF (1999)
2
277.4
277.18
D
$075F (1887)
2
293.8
293.66
#D
$06F5 (1781)
2
311.3
311.13
E
$0691 (1681)
2
329.8
329.63
#E
$0633 (1587)
2
349.3
349.23
F
$0633 (1587)
2
349.3
349.23
#F
$05DA (1489)
2
370.1
369.99
G
$0586 (1414)
2
392.1
391.995
#G
$0537 (1335)
2
415.3
415.30
A
$04EC (1260)
2
440.0
440.00
#A
$04A5 (1189)
2
466.3
466.16
B
$0464 (1124)
2
493.2
493.88
#B
$0423 (1059)
2
523.5
523.25
R
$0000
-
-
-
#R
$0000
-
-
-
+C
$0846 (2118)
1
523.5
523.25
+#C
$07CF (1999)
1
554.7
554.37
+D
$075F (1887)
1
587.6
587.33
+#D
$06F5 (1781)
1
622.6
622.25
+E
$0691 (1681)
1
659.6
659.26
+#E
$0633 (1587)
1
698.7
698.46
+F
$0633 (1587)
1
698.7
698.46
+#F
$05DA (1489)
1
740.2
739.99
+G
$0586 (1414)
1
784.2
783.99
+#G
$0537 (1335)
1
830.6
830.61
+A
$04EC (1260)
1
880.0
880.00
+#A
$04A5 (1189)
1
932.5
932.33
+B
$0464 (1124)
1
986.5
987.77
+#B
$0423 (1059)
1
1,047.0
1,046.50
+R
$0000
-
-
-
+#R
$0000
-
-
-
Other frequencies of musical notes

The following table shows the frequencies of other notes within more lower and more upper octaves to enable you to program your own compositions with other, expanded notes ( all frequencies in Hz; middle A has 440Hz; values in paranthesis are the counter register values which are to load into the port $E004 for the associated note frequency ):

C
#C (Db)
D
#D (Eb)
E
F
#F (Gb)
G
#G (Ab)
A
#A (Bb)
B
16.35
(-)
17.32
($FA12)
18.35
($EC09)
19.45
($DEB0)
20.60
($D241)
21.83
($C668)
23.12
($BB56)
24.50
($B0C9)
25.96
($A6D8)
27.50
($9D80)
29.13
($94B0)
30.87
($8C4E)
32.70
($8474)
34.65
($7D00)
36.71
($75FC)
38.89
($6F5F)
41.20
($6921)
43.65
($633A)
46.25
($5DA6)
49.00
($5865)
51.91
($5370)
55.00
($4EC0)
58.27
($4A55)
61.74
($4627)
65.41
($4238)
69.30
($3E80)
73.42
($3AFE)
77.78
($37B0)
82.40
($3490)
87.31
($319C)
92.50
($2ED3)
98.00
($2C32)
103.83
($29B7)
110.00
($2760)
116.54
($252A)
123.47
($2314)
130.81
($211C)
138.59
($1F41)
146.83
($1D80)
155.56
($1BD8)
164.81
($1A48)
174.61
($18CE)
185.00
($176A)
196.00
($1619)
207.65
($14DC)
220.00
($13B0)
233.08
($1295)
246.94
($118B)
261.63
($108E)
277.18
($0FA0)
293.66
($0EC0)
311.13
($0DEC)
329.63
($0D24)
349.23
($0C67)
369.99
($0BB5)
392.00
($0B0D)
415.30
($0A6E)
440.00
($09D8)
466.16
($094B)
493.88
($08C5)
523.25
($0847)
554.37
($07D0)
587.33
($0760)
622.25
($06F6)
659.26
($0692)
698.46
($0633)
739.99
($05DA)
783.99
($0586)
830.61
($0537)
880.00
($04EC)
932.33
($04A5)
987.77
($0463)
1046.50
($0424)
1108.73
($03E8)
1174.66
($03B0)
1244.51
($037B)
1318.51
($0349)
1396.91
($031A)
1479.98
($02ED)
1567.98
($02C3)
1661.22
($029B)
1760.00
($0276)
1864.66
($0253)
1975.53
($0231)
2093.00
($0212)
2217.46
($01F4)
2349.32
($01D8)
2489.02
($01BD)
2637.02
($1A4)
2793.83
($018D)
2959.96
($0177)
3135.96
($0162)
3322.44
($014E)
3520.00
($013B)
3729.31
($0129)
3951.07
($0119)
4186.01
($0109)
4434.92
($00FA)
4698.64
($00EC)
4978.03
($00DF)
5274.04
($00D2)
5587.65
($00C6)
5919.91
($00BB)
6271.93
($00B1)
6644.88
($00A7)
7040.00
($009E)
7458.62
($0095)
7902.13
($008C)
8372.02
($0084)
8869.84
($007D)
9397.28
($0076)
9956.06
($006F)
10548.08
($0069)
11175.30
($0063)
11839.82
($005E)
12543.85
($0058)
-
-
-
-

The inaccuracy/deviation of the real output frequency played by the 8253 grows with its nominal frequency value shown in the table.

For example the nominal frequency of the last entry for note G is 12,543.85Hz:

I calculated a counter register value of $0058 or 88 decimal. The real output frequency will be:

1.1088MHz / 88 = 12,600.00Hz ( deviation is +56.15Hz = +0.45 % ).

The same calculation but for the first entry, that is the lowest note #C having a frequency of 17.32Hz and a counter register value of $FA12 or 64,018 decimal:

1.1088MHz / 64,018 = 17.32Hz ( deviation is ±0 % ).

You must not include the values in a table of your program. You can compute the frequencies as shown in the following program written in BASIC but the first 13 values ( <16.9Hz, i.e. FREQ(0) to FREQ(12) ) can't be outputted by the 8253. The minimum output frequency is 16.9Hz with an input frequency of 1.1088MHz and these first 13 notes have lower frequency values. The resulting values in FREQ(I) base on A=440, the middle A that has a frequency of 440Hz.

10 DIM FREQ(127): REM insert table for 128 notes
20 A=440: REM middle A has 440Hz
30 FOR I=0 to 127: REM loop 128 times
40 FREQ(I)=(440/32)*(2exponential function((I-9)/12)):REM calculate frequency
50 NEXT I: REM next if not all
Description of 8253 related subroutines
The monitor subroutine BELL ( loc. $003E )

BELL invokes the subroutine ?BEL by a jump command: JP ?BEL at location $003E. ?BEL is located at $0577. Here is a copy of this subroutine:

003E C37705 BELL:  JP   ?BEL	 ;invoke ?BEL

0577 D5     ?BEL:  PUSH DE	 ;save DE
0578 115203        LD   DE,?BELD ;address to bell data
057B F7            RST  6	 ;invoke MELDY
057C D1            POP  DE	 ;restore DE
057D C9            RET		 ;goback to caller

0352 D7     ?BELD: DB	0D7H	 ; "+" upper octave
0353 4130          DB	"A0"	 ; note "A" 1/32
0355 0D            DB	0DH	 ; end of data char.

Everytime ?BEL is called a short tone, the 1/32 note "A" having 880Hz, comes over the loudspeaker. To this the subroutine MELDY at location $0030 is called by RST 6 at location $057B. Before invoking MELDY the bell data address to a simple note +A0 is stored into the register DE. This address in register DE is used by MELDY to play the note.

If you enter the monitor command B then ?BEL is called everytime a key is pressed. The status of the beep function will be inverted by the next command B. To this see what the monitor does in detail:

00CD FE42	   CP	'B'	 ;BELL command?
00CF 2826	   JZ	Z,SG	 ;yes, goto SG ($00F7)

00F7 3A9D11 SG:	   LD	A,(SWRK) ;get bell status bit 0
00FA 1F		   RRA		 ;shift bit 0 into carry flag
00FB 3F		   CCF		 ;complement carry flag
00FC 17		   RLA		 ;shift carry flag into bit 0
00FD 18A5	   JR	SS+2	 ;goto ss + 2 bytes ($00A4)

00A4 329D11	   LD	(SWRK),A ;store inverted status

If the B command was entered into the input line area of the monitor ( loc. $11A3 ) then the subroutine SG will be invoked by the jump command at location $00CF.

First the bell status SWRK at location $119D is loaded into the accumulator register A and then A is rotated right whereby bit 0 will be stored into the carry flag. The carry flag will be inverted by the command CCF at location $00FB and then the accumulator register is rotated left whereby the ( inverted ) carry flag is inserted into bit 0.

At least the contents of register A is stored back into the bell status SWRK at location $119D.

The subroutine GETL is active while your monitor 1Z-013A awaits any input / key and the cursor is active. The subroutine GETL is at location $0003 and invokes the subroutine ?GETL at location $07E6 by a simple jump command. ?GETL interprets the bell status and invokes the bell subroutine if necessary ( see the monitor program at loc. $07EF ):

0003 C3E607 GETL:  JP   ?GETL

07E6        ?GETL: .........

07EF 3A9D11 	   LD   A,(SWRK) ;get bell satus
07F2 0F	    	   RRCA	         ;rotate bit 0 into carry flag
07F3 DA7705 	   CALL NC,?BEL  ;invoke ?BEL if carry flag not set
The monitor subroutine XTEMP

XTEMP can be called by CALL $0041 to set the tempo of a melody is to be played.

XTEMP jumps to ?TEMP at location $02E5 and sets the variable TEMPW. TEMPW is used by ONPU to set the correct value of the counter register.

The accu is to establish with the tempo before invoking XTEMP. The valid range is from $01 ( slow ) to $07 ( fast ). ?TEMP changes from $01 ( fast ) to $07 ( slow ), contrary to the input value stored by the caller into the accu before calling XTEMP:

02E5 F5     ?TEMP: PUSH AF	  ;save AF on stack
02E6 C5		   PUSH BC	  ;save BC on stack
02E7 E60F	   AND  0FH	  ;turn off bits 7 - 4
02E9 47		   LD   B,A	  ;tempo value to reg. B
02EA 3E08	   LD   A,8	  ;compute $01 - $07
02EC 90		   SUB  B	  ;to $07 - $01
02ED 329E11	   LD   (TEMPW),A ;set TEMPW used by ONPU subroutine
02F0 C1		   POP  BC	  ;restore callers register BC
02F1 F1		   POP  AF	  ;restore callers register BC
02F2 C9		   RET		  ;goback to caller
The monitor subroutines MSTA and MSTP

These routines start / stop the counter #0.

MSTA at location $0044 invokes MLDST at location $02AB.

MSTP at location $0047 invokes MLDSP at location $02BE.

MSTP/MLDSP needs no further input but MSTA / MLDST uses RATIO at location $11A1 / 11A2 to set the correct counter register value for the note to be played.

This is a copy of these routines:

0044 C3AB02 MSTA:   JP   MLDST	    ;start output (input is RATIO)
0047 C3BE02 MSTP:   JP	 MLDSP	    ;stop output

02AB 2AA111 MLDST:  LD	 HL,(RATIO) ;get RATIO
02AE 7C		    LD	 A,H	    ;get most significant byte
02AF B7		    OR	 A	    ;sets zero flag if A=0
02B0 280C	    JR	 Z,MLDSP    ;RATIO <= $00FF not allowed ( why not? )
02B2 D5		    PUSH DE	    ;save callers register DE
02B3 EB		    EX	 DE,HL	    ;RATIO to DE
02B4 2104E0	    LD	 HL,CONT0   ;address to port $E004
02B7 73		    LD	 (HL),E	    ;load least significant byte (LSB)
02B8 72		    LD	 (HL),D	    ;then MSB into port $E004
02B9 3E01	    LD	 A,1	    ;prepare to turn counter on
02BB D1		    POP	 DE	    ;restore register
02BC 1806	    JR	 MLDS1	    ;jump to MLDS1

02BE 3E36   MLDSP:  LD	 A,36H	    ;control word of $36
02C0 3207E0	    LD	 (CONTF),A  ;into port $E007 (counter #0)
02C3 AF		    XOR	 A	    ;prepare to turn counter off 
02C4 3208E0 MLDS1:  LD	 (SUNDG),A  ;turn counter on/off
02C7 C9		    RET		    ;return to caller

RATIO may not be lower than $0100 ( see $02AB to $02B0 ). If so, the current output will be stopped if present or no output will come over the loudspeaker.

But if RATIO is >= $00FF then it will be loaded into the counter register $E004 of counter #0 ( $02B4 to $02B8 ).

Next the counter will be started by setting bit D0 of port $E008 ( $02B9 and $02C4 ). This means, first, the GATE0 initiates counting on the rising edge ( GATE 0 goes high ) with the loaded value RATIO into the counter register and next counting will be enabled at the end of the rising edge ( GATE0 is high ). These steps will occur on the next pulse at CLK0 by the signal SOIN.

To stop an output the control word of $36 is written to the counter #0 ( $02BE and $02C0 ) and the GATE0 is set to low ( $02C3 and $02C4 ).

The monitor subroutine RYTHM

This routine is used by the routine MELDY / ?MLDY which plays a melody. RYTHM is used to control the tempo a melody is to be played and to control the time periods for a note / rest.

To this the appropriate numbers of cycles of the generator of 32Hz pulses ( tempo controller part3 in the schematic diagram ) were counted given by the register B on entry to RYTHM. See the following copy of tis monitor subroutine.

First the SHIFT / BREAK keys were checked to break the current play of a melody if the user entered these keys ( $02C8 to $02D4 ):

02C8 2100E0 RYTHM:  LD	 HL,KEYPA  ; address to port $E000 keyboard input
02CB 36F8           LD   (HL),0F8H ; select column of SHIFT and BREAK keys
02CD 23             INC  HL	   ; address to port $E001 keyboard output
02CE 7E             LD   A,(HL)	   ; read keyboard row
02CF E681           AND  81H	   ; bit 7=BREAK, bit 1=SHIFT
02D1 2002           JR   NZ,L02D5  ; goto L02D5 if not break condition
02D3 37             SCF		   ; Break condition, carryflag will show
02D4 C9             RET		   ; break condition, goback to caller

02D5 3A08E0 L02D5:  LD   A,(TEMP)  ; get cycle of generator 32Hz from
02D8 0F             RRCA	   ; bit 0 of port $E008 (signal TEMPO OUT)
02D9 38FA           JR   C,L02D5   ; wait on low 
02DB 3A08E0 L02DB:  LD   A,(TEMP)  ; get TEMPO OUT again
02DE 0F             RRCA	   ;
02DF 30FA           JR   NC,L02DB  ; wait on high
02E1 10F2           DJNZ L02D5	   ; wait for all defined cycles by B-reg.
02E3 AF             XOR  A	   ; indicate no break by carry flag.
				   ; all defined cycles awaited. 
02E4 C9             RET		   ; returning to caller

The number of cycles contained in the register B will be counted by $02E1.

The instruction set between $02D5 and $02E1 will be executed until the number of cycles given by the register B is reached.

First the routine waits for the end of the low part of the square wave ( $02D5 to $02D9 ) then for the end of the high part ( $02DB to $02DF ). If both the low part and the high part were detected, a full cycle is occured in bit 0 of port $E008 and the instruction at location $02E1 will be executed. This is a DJNZ instruction that counts down the contents of the register B until the contents is 0.

If the register contents is not 0 then a branch to L02D5 occurs too.

If the contents is 0 then the next instruction just behind the DJNZ instruction at location $02E3 will be executed.

The carry flag will be reset by XOR A to indicate that no break condition occured.

In work

A description of the monitor subroutines ( ONPU, MLDY / ?MLDY ) and related work area variables $119E to $11A2 and a description of the tables stored in the monitor is in progress.

A description of the following hardware is in progress too: tempo controllers 1 - 3 for start / stop output by writing bit D0 of port $E008 ( IC #6F and #7E ) to GATE0, tempo control / intervals ( reading bit D0 from the buffer IC #4C and the timer 32Hz
IC #BJ ), generating signal SOIN from signal LOAD by the monoflop IC #BH with Schmitt Trigger, and clear to get a good pulse.

curves of LOAD and SOIN signal


Go to the top of this page Home

last updated August 5, 2002
sharpmz@sharpmz.org