;	Disassembled by:
;		DASMx object code disassembler
;		(c) Copyright 1996-2003   Conquest Consultants
;		Version 1.40 (Oct 18 2003)
;	File:		klm8048.bin
;	Size:		1024 bytes
;	Checksum:	DFAD
;	CRC-32:		130FB945
;	Date:		Sun Mar 23 16:02:25 2014
;	CPU:		Intel 8048 (MCS-48 family)

; tasm -48 -g3 klm8048.asm myklm8048.bin
; g0 is Intel Hex
; g3 selects binary

; Assembly source code for Korg PolySix D8048C Patch MCU
; Looks like one pass through all of the switches and pots takes 8.7 mSec (115 Hz)
; You can see this rate on pin 32 of the 8048
; This file is valid input for TASM32 and will produce a binary that 
; matches the original code.

; Note: Comments are mine, based on how I think the code works.
; 	There could easily be mistakes.

;8048 only has RAM from 0-3F

rb0r0		.equ	00h	;first set of registers
rb0r1		.equ	01h	;occupy RAM addresses 0-7
rb0r2		.equ	02h
rb0r3		.equ	03h
rb0r4		.equ	04h
rb0r5		.equ	05h
rb0r6		.equ	06h
rb0r7		.equ	07h

what1		.equ	08h
what2		.equ	09h
what3		.equ	0Ah
what4		.equ	0Bh
				;0C-13 get cleared when we rd or wr a patch to RAM
				;that would put pots in edit mode
what5		.equ	0Ch
what6		.equ	0Dh

limhit0to7	.equ	0Eh	;pot limit has been reached in this channel since prog ld
limhit8toD	.equ	0Fh	;same as above, but for ADC channels 8 to D

absmde0to7	.equ	10h	;set if pot is in absolute mode, channel 0-7
absmde8toD	.equ	11h	;set if pot is in absolute mode, channel 8-D

D0D1swchgmsk	.equ	12h	;1's mean switch has changed since program load
				;so we update program based on switch value
D2D3swchgmsk	.equ	13h	;1's mean switch has changed since program load
				;same as pots in absolute mode

progLEDst	.equ	14h	;current state of Program LED's 8-1?
bankLEDst	.equ	15h	;current state of WrEn Write Bank LED's?

prgswst		.equ	16h	;program sw states
bnkswst		.equ	17h	;bank, man, write, wr enab sw states

				;second set of regs occupy RAM addr 24-31:
rb1r0		.equ	18h	
rb1r1		.equ	19h
rb1r2		.equ	1Ah
rb1r3		.equ	1Bh
rb1r4		.equ	1Ch
rb1r5		.equ	1Dh
rb1r6		.equ	1Eh	;pointer to current patch in external RAM page
rb1r7		.equ	1Fh	;used to flash Write LED

currpatch0	.equ	020h	;current patch data storage
currpatch1	.equ	021h	;same order as 30-3F
currpatch2	.equ	022h
currpatch3	.equ	023h
currpatch4	.equ	024h
currpatch5	.equ	025h
currpatch6	.equ	026h
currpatch7	.equ	027h
currpatch8	.equ	028h
currpatch9	.equ	029h
currpatchA	.equ	02Ah
currpatchB	.equ	02Bh
currpatchC	.equ	02Ch
currpatchD	.equ	02Dh
currpatchE	.equ	02Eh
currpatchF	.equ	02Fh

EffSpIntval	.equ	030h	;current ADC results for the pots
VCFcutval	.equ	031h
EGintval	.equ	032h
Resval		.equ	033h
Attval		.equ	034h
Decval		.equ	035h
Sustval		.equ	036h
Relval		.equ	037h
KBtrkval	.equ	038h
PWPWMval	.equ	039h
PWMSpval	.equ	03Ah
MGfreqval	.equ	03Bh
MGdelval	.equ	03Ch
MGlevval	.equ	03Dh
Swstates1	.equ	03Eh	;current VCO octave, Waveform, Sub Osc and Mod switch states
Swstate2	.equ	03Fh	;current EG mode, Chorus Sel, VCA atten switch states

	.org	00000h

L0000:
	anl	p1,#01FH	;shut off P25,26,27 strobes
	clr	a
L0003:
	call	L02D6		;turn off all Program LED's
	call	L02DC		;turn off Bank, Man, and Wr LED's
	mov	psw,a
L0008:
	in	a,p1
	jb4	L000D		;Test switch? (bit4 = 0)
	jmp	L03B9		;if so, jump


L000D:				;Normal start-up code:
	sel	rb1		;select second reg bank
	mov	r1,#014H
	mov	a,#001H
	mov	@r1,a		;init addr 0x14 to 1 (enable Program 1 LED)
	inc	r1
	mov	@r1,a		;init addr 0x15 to 1 (enable Bank A LED)
	inc	r1
	clr	a		;init addr 0x16 to 0
	mov	@r1,a
	inc	r1
	mov	@r1,a		;init addr 0x17 to 0
	mov	r3,#040H
	mov	r6,a		;clear rb1,r6 (sel patch 0)
	clr	f0		;select low page of external SRAM
	jmp	L01C8

L0020:
	mov	a,#00DH
	mov	r7,a		;load rb0 r7 with 0x0D
	inc	a
	mov	r5,a		;rb0 r5 holds 0x0E (loop ctr)
	mov	r6,#000H	;in this loop, r6 counts 0-D
				;r7 counts              0D,0-C

L0027:				;we must be in rb0 at this pt
				;from here to P16 going high is 312 uSec 
				;(it's the DAC SAR time)
	call	L021A		;perform ADC conv, r6 is chan, rlst in r4, acc

	mov	a,#0FDH
	mov	t,a
	strt	t		;start timer (incs every 80 uSec)

	mov	a,r7
	outl	p2,a		;select front panel analog mux channel
				;and analog demux channel too

	add	a,#020H		;add 0x20 to r7 value
	mov	r0,a		;save sum in r0
	mov	a,@r0		;read program value at this address
	outl	bus,a		;and send it out on data bus
	orl	p1,#040H	;raise P16/enable one of the 4051's
				;channel we are sending out is different
				;from channel we just converted, but we
				;send out the correct patch data for it
				;from here to where P16 drops is 240 uSec

	mov	a,#020H
	add	a,r6		;add 0x20 to r6 value
	mov	r0,a		;save sum in rb0 r0
	mov	r1,#010H	;put 0x10 in rb0 r1
	mov	a,#0F8H
	add	a,r6		
	jc	L0044		;test for r6 > 7
	mov	a,r6		;if it was > 7, use  r6-8 value in acc
	jmp	L0045		;otherwise, use r6 value before subtraction
				;we don't change r6 here
L0044:
	inc	r1		;if r6>7 bump rb0 r1 to 0x11
L0045:
	add	a,#0EFH
	movp3	a,@a		;get bit mask for r6 value (0-7)
	mov	r3,a		;into r3

	mov	a,r1		;get rb0 r1 into acc (either 0x10 or 0x11)
	sel	rb1
	add	a,#0FCH		;-4
	mov	r1,a		;point rb1 r1 to 0x0C or 0x0D
	sel	rb0
	mov	a,r3		;get bitmask for r6 value
	anl	a,@r1		;test this bit in 0x10 or 0x11 address
	jnz	L00A5		;if it's set, jump to absolute mode end code
	dec	r1
	dec	r1		;point to either 0x0E or 0x0F
	mov	a,@r1
	anl	a,r3		;check bitmask bit at this address
	jz	L006A		;jump if it's 0
	mov	a,#0FEH		;check conversion result for min value
	add	a,r4
	jnc	L0073		;if no cy, then r4 is 0 or 1
	mov	a,#002H
	add	a,r4		;if cy then r4 is 0xFE or 0xFF
	jc	L0073		;jump if pot is close to a limit
	inc	r1		
	inc	r1		;point to either 0x10 or 0x11
	mov	a,@r1
	orl	a,r3		;set bitmask bit at this address
	mov	@r1,a		;probably this switches pot to absolute mode
	jmp	L00A5		;and jump to absolute mode end code

L006A:				;jump here if pot has not reached limit yet
	mov	a,r4
	jz	L0070
	cpl	a
	jnz	L0073
L0070:				;we come here if r4 value is 0 or 0xFF
	mov	a,@r1
	orl	a,r3		;set bit to indicate limit has been reached
	mov	@r1,a		;in 0x0E or 0x0F
L0073:
	mov	a,#030H		
	add	a,r6
	mov	r1,a
	mov	a,@r1		;get previous conversion value for this pot
	cpl	a
	inc	a		;negate it
	add	a,r4		;so acc = new conversion - previous value
	mov	r2,a		;save this in r2
	mov	a,r3		;get bit mask
	sel	rb1
	anl	a,@r1		;check bitmask bit in 0x0C or 0x0D
	sel	rb0
	jnz	L0092		;jump if it's set
	mov	a,r2
	jb7	L0087		;if difference is negative
	jmp	L0089

L0087:
	cpl	a		;negate it
	inc	a
L0089:
	add	a,#0FDH		;see if difference > 2 (pot has moved)
	jnc	L00A7		;jump if not
	mov	a,r3		;otherwise, get bit mask
	sel	rb1
	orl	a,@r1		;set bitmask bit in 0x0C or 0x0D
	mov	@r1,a
	sel	rb0
L0092:				;we may have jumped here
	mov	a,r2		;get difference
	jb7	L009C		;jump if it's negative
	add	a,@r0		;add positive difference to patch value for this channel
	jnc	L00A0		;if no overflow, jump
	clr	a		;if overflow, 
	cpl	a		;load a with 0xFF
	jmp	L00A0

L009C:
	add	a,@r0		;difference is negative, add it to patch value for this channel
	jc	L00A0		;if sum is negative
	clr	a		;set value to 0
L00A0:
	mov	@r0,a		;update patch value for this channel
	mov	a,r4
	mov	@r1,a		;and update current value for this pot		
	jmp	L00A7

L00A5:				;this pot is in absolute mode 
	mov	a,r4		;simply write conversion result 
	mov	@r0,a		;to patch location for this channel
L00A7:
	jtf	L00AB		;wait for timer flag to be set (240 uSec from start t?)
	jmp	L00A7		;if it's not, we loop

L00AB:
	stop	tcnt
	mov	a,r6		;save r6 in r7
	mov	r7,a
	inc	r6		;then bump r6
	anl	p1,#0BFH	;drop P16/inhibit both 4051's
	djnz	r5,L0027	;and loop


				;code for switches that are stored with programs:
	mov	r0,#02EH	
	mov	r1,#012H
	mov	r5,#000H
	sel	rb1
	mov	r0,#03EH	;low prog sw state byte
	mov	r2,#0FEH
	mov	r3,#010H
	sel	rb0
	mov	r6,#002H
L00C3:				
	call	L0230		;read switch row sel by r2 0 bit and bit to left of it
	mov	r4,a		;first row returned in low four bits
	sel	rb1
	xrl	a,@r0		;see if switch pos has changed
	sel	rb0
	mov	r2,a		;save xor result
	mov	a,#0C9H
	add	a,r0
	movp3	a,@a		;read from  0x3F7 table in ROM page 3
	mov	r7,a		;this is a loop ctr (first value is 0x04)
L00CF:
	mov	a,r5
	add	a,#0F9H
	movp3	a,@a		;read from  0x3F9 table in ROM page 3
	mov	r3,a		;first value is 0x03
	anl	a,@r1		;use it as a mask against @r1
	jnz	L00DE
	mov	a,r2
	anl	a,r3		;AND xor result with mask
	jz	L00E5		;jump if switch pos matches prog sw state byte bits
	mov	a,@r1
	orl	a,r3		;otherwise, set mask bits in @r1 
	mov	@r1,a
L00DE:
	mov	a,r3
	cpl	a		;invert mask from table
	anl	a,@r0		;clear bits in sw state byte, leave other switch bits in place
	xch	a,r3
	anl	a,r4		;AND mask with switch bits we read
	orl	a,r3		;OR in other sw state byte bits		
	mov	@r0,a		;and put it back in RAM
L00E5:
	inc	r5
	djnz	r7,L00CF

	mov	a,@r0		;send out updated sw state byte to hw
	outl	bus,a
	inc	r0
	inc	r1
	sel	rb1

	in	a,p2		;send P24 or P25 stb high
	orl	a,r3		
	outl	p2,a

	inc	r0

	mov	a,r3
	rl	a		;rotate stb select from P24 to P25
	mov	r3,a

	sel	rb0
	anl	p2,#00FH	;shut off P24 or P25 stb
	djnz	r6,L00C3	;loop

	jni	L00FD		;interrupt hooks to tape enable switch (0 = tape enabled)
	jmp	L00FF
L00FD:
	jmp	L031E		;tape is enabled

				
L00FF:				;from L0020 to here is 8.37 mSec)			
	orl	p1,#020H	;bring P15 test pt signal high (here to end of loop is 343 uSec)
	mov	r1,#016H
				;read program number switches
	call	L0230		;read switch row sel by r2 0 bit and bit to left of it
				;first row returned in low 4 bits, 1 means sw pressed
	xch	a,@r1		;update address 0x16 with current sw status		
	cpl	a		;any switches that were pressed before will now be 0's
	anl	a,@r1		;so this gives us only the switches that were just pressed		
	jnz	L010C
	jmp	L012E

L010C:
	mov	r2,#0FFH
L010E:
	inc	r2
	rrc	a		;get bit pos of rightmost one bit (0-7)
	jnc	L010E

	dec	r1		;point to address 0x15
	mov	a,#0EFH
	anl	a,@r1		;clear bit 4
	mov	@r1,a		;and update it
	mov	r3,a		;save a copy in r3

	dec	r1		;point to address 0x14		
	mov	a,#0EFH
	add	a,r2
	movp3	a,@a		;get bit mask for r2 value (0-7) into acc

	mov	@r1,a		;put bit mask for program into addr 0x14 (turn on the correct LED)

	mov	a,r2		;get program # - 1 (0-7) value
	swap	a		;multiply it by 16
	sel	rb1
	xch	a,r6		;put it in rb1 r6
	anl	a,#080H		;get D7 of old rb1 r6 value
	orl	a,r6		
	mov	r6,a		;and put it back into rb1 r6
	sel	rb0
	mov	a,#020H
	anl	a,r3		;check bit 5 of r3 (addr 15 value from before, so Write LED bit)
	jnz	L01AF		;if set, save patch in external SRAM, using rb1 r6 as dest
	jmp	L01C7		;otherwise, read patch from external RAM using rb1 r6 as srce addr



L012E:				;we jump here if no program switches are newly pressed
	inc	r1		;point to 0x17
				;now read Bank, Manual, Write, and Write Enable Switches
	call	L0230		;read switch row sel by r2 0 bit and bit to left of it
	xch	a,@r1		;update address 0x17 with current sw status
	cpl	a		;any switches that were pressed before will now be 0's
	anl	a,@r1		;so this gives us only the switches that were just pressed
	mov	r4,a		;save result
	mov	a,#040H
	anl	a,@r1		;get D6 of new switch state (Write enable)
	orl	a,r4		;OR it into change result 		
	mov	r4,a		;and save that in r4
	dec	r1
	dec	r1		;r1 points to 0x15 now
	anl	a,#00FH		;check for bank switches newly pressed
	jz	L016F		;jump if none newly pressed

	mov	r2,#0FFH	;bank switch was just pressed:
L0142:
	inc	r2
	rrc	a
	jnc	L0142		;get bit pos of rightmost 1 bit in bank switch positions

	mov	a,#0EFH
	add	a,r2
	movp3	a,@a		;get bit mask for r2 value (0-7) into acc

	xch	a,@r1		;update addr 0x15 with curr bank bit mask 
	anl	a,#0F0H		;clear out any previous bank mask bits
	orl	a,@r1		;OR in new bank bit mask
	mov	@r1,a		;and update addr 0x15 value (turn on correct Bank LED)
	mov	r3,a		;save it in r3 also

	mov	a,r2		;get bank sw bit pos (0-3)
	cpl	a		;invert bits
	clr	f0		;select low page of external SRAM
	jb1	L0156		;if bank was 0 or 1, bit 1 is now set
				;so we leave f0 flag cleared
	cpl	f0		;if it was 2 or 3, set flag to 
				;select high page of external SRAM
				;(checked when we read or write to external SRAM)
L0156:
	sel	rb1
	jb0	L015E		;if bank was 0 or 2, bit is is now set
	mov	a,#080H		;new bank is 1 or 3, so set rb1 r6 bit 7
	orl	a,r6
	jmp	L0161

L015E:				;new bank is 0 or 2, so clear rb1 r6 bit 7
	mov	a,#070H
	anl	a,r6
L0161:
	mov	r6,a		;update rb1 r6 (ptr to current program in SRAM page)
	sel	rb0
	mov	a,#020H
	anl	a,r3		;check write LED bit in 0x15 addr (also in r3)
	jnz	L018D
	mov	a,#010H
	anl	a,r3		;check manual LED bit in 0x15 addr (also in r3)
	jnz	L0186
	jmp	L01C7		;read patch from external RAM using rb1 r6 as srce addr


L016F:				;we jump here if no new bank has been selected
	mov	a,#010H		;r4 has newly pressed switches as 1's
	anl	a,r4		;check for Manual switch pressed
	jz	L0186		;skip if not

	mov	a,@r1		;manual switch was pressed, read addr 0x15
	orl	a,#010H		;set D4 bit (turn on Manual LED?)
	anl	a,#0DFH		;and clear D5 bit (make sure Write LED is off)
	mov	@r1,a		;update addr 0x15

	dec	r1		;point to addr 0x14
	clr	a
	mov	@r1,a		;clear it (Turn off all program LED's)

	cpl	a
	mov	r0,#004H
L0180:
	dec	r1		;and set addr 0x13, 0x12, 0x11, 0x10 to 0xFF's
	mov	@r1,a		;this puts all pots and switches in absolute mode
	djnz	r0,L0180	;so we are updating the program directly with their
	jmp	L0204		;values,  (we always send the program to the hw)

L0186:
	mov	r1,#015H	;we come here if manual sw not newly pressed
	mov	a,#020H		;check Write LED state?
	anl	a,@r1
	jz	L0198
L018D:				;we come here if Write LED is on
	mov	a,r4
	anl	a,#040H
	jz	L01A9
	sel	rb1
	mov	a,#005H		;bump rb1 r7, used to flash Write LED
	add	a,r7
	jmp	L01A6

L0198:
	mov	a,r4
	cpl	a
	anl	a,#060H
	jz	L01A0		;if both write and write enable "pressed" bits are set, jump
	jmp	L0204		;(write enable "pressed" bit is set whenever Write Enable LED is on)

L01A0:
	mov	a,@r1
	orl	a,#020H		;turn on Write LED
	mov	@r1,a
	sel	rb1
	clr	a		;clear acc
L01A6:
	mov	r7,a		;move acc into rb1 r7, if we jumped here after L018D
	jmp	L0204		;then we are adding 5 to r7

L01A9:
	mov	a,@r1		;clear bit D5 at @r1 address, jump to L0204
	anl	a,#0DFH
	mov	@r1,a
	jmp	L0204



L01AF:				;copies 16 bytes from address 0x020 into ext SRAM
	sel	rb1		;dest address is rb1 r6
	mov	r0,#020H	;start of current patch storage in 8048 RAM
	mov	a,r6		;external RAM storage location ptr
	mov	r1,a
	clr	a
	jf0	L01B9		;flag0 selects low or high page of SRAM
	jmp	L01BB

L01B9:
	orl	a,#002H
L01BB:
	outl	p2,a
	mov	r5,#010H	;copy 16 bytes into external SRAM (one program)
L01BE:
	mov	a,@r0
	call	L0258		;write acc to  external SRAM byte pointed to by r1
	inc	r0
	djnz	r5,L01BE
	sel	rb0
	jmp	L01DE



L01C7:				;copies 16 bytes from ext SRAM into address 0x20
	sel	rb1		;src addr is rb1 r6
L01C8:
	mov	r0,#020H	;current patch location in 8048 RAM?
	mov	a,r6		;external RAM storage location ptr
	mov	r1,a
	mov	a,#001H
	jf0	L01D2		;flag0 selects low or high page of SRAM
	jmp	L01D4

L01D2:
	orl	a,#002H
L01D4:
	outl	p2,a
	mov	r5,#010H	;copy 16 bytes into 8048 RAM (one program)
L01D7:
	call	L0245		;read external SRAM byte pointed to by r1 into acc
	mov	@r0,a
	inc	r0
	djnz	r5,L01D7
	sel	rb0
L01DE:
	mov	r1,#00CH	;clear eight bytes starting at addr 0x0C
	clr	a
	mov	r2,#008H
L01E3:
	mov	@r1,a
	inc	r1
	djnz	r2,L01E3

	mov	r6,#000H
	mov	r0,#030H	;starting address for conversion results
	mov	r5,#00EH	;14 front panel pots to convert
L01ED:
	call	L021A		;perform ADC conv, r6 is chan, rlst in r4, acc
	mov	@r0,a
	inc	r0
	inc	r6
	djnz	r5,L01ED	;do all 14 conversions and save results

	mov	r0,#03EH
	sel	rb1
	mov	r2,#0FEH
	call	L0230		;read VCO octave, Waveform, Sub Osc and Mod switch states (D0,D1)
	mov	@r0,a		;and save with pot values
	inc	r0
	call	L0230		;read EG mode, Chorus Sel, VCA atten switch states (D2,D3)
	mov	@r0,a		;and save with pot values
	mov	r1,#015H
	jmp	L01A9		;clear bit D5 at @r1 address (Turn off Write LED), jump to L0204


L0204:
	sel	rb1
	mov	r0,#014H
	mov	a,@r0		;send value at address 14 to Program LED's
	call	L02D6		;write acc contents to Program LED's, 1=on
	inc	r0		;r0 = 0x15
	mov	a,r7		;if rb1 r7 bits 7 and 6 are both 1
	rr	a			
	anl	a,r7		;then bit 6 will be 1 here
	rr	a		;and will be bit 5 here
	anl	a,#020H		;AND with 0x20 (only leave D5)
	cpl	a		;invert, if D5 was set it will be off now
	anl	a,@r0		;AND result with Bank, Man, and write LED state in RAM
	call	L02DC		;write acc to Bank (0-3), Man(4) and Write(5) LED's
	sel	rb0
	anl	p1,#0DFH	;drop P15 test point signal (This shows how long each pass takes)
	jmp	L0020		;jump back to start of main loop



L021A:				;successive approx ADC routine
	mov	a,r6		;channel to convert
	anl	a,#00FH		;keep stbs off
	outl	p2,a
	mov	r3,#080H	;starting DAC value
	clr	a
	mov	r4,a		;conversion result
	mov	r2,#008H	;number of bits
L0224:
	add	a,r3		;add in bit we are testing
	outl	bus,a		;send current result to DAC
	xch	a,r3
	rr	a		;rotate test bit to right
	xch	a,r3
	jnt0	L022C		;if that bit makes DAC > pot, don't add it in
				;t0=0 means DAC > pot
	mov	r4,a		;otherwise, update result to include that bit
L022C:
	mov	a,r4		;get result into acc
	djnz	r2,L0224	;iterate over 8 bits
	ret



L0230:				;reads two 4-bit switch state values from hw
	sel	rb1		;and combines them into a byte
	mov	a,r2		;value in rb1 r2 determines which switches we read
	outl	bus,a		;only one bit is low at a time, and goes out on D0-D7
	rl	a
	mov	r2,a
	in	a,p1
	orl	a,#0F0H
	mov	r5,a
	mov	a,r2
	outl	bus,a
	rl	a
	mov	r2,a
	in	a,p1
	swap	a
	orl	a,#00FH
	anl	a,r5
	cpl	a		;invert switch levels to make them active high
	sel	rb0
	ret


L0245:				;reads byte pointed to by r1 from external 4-bit SRAM
				;which is used as two banks of 256 bytes
				;P21 selects bank0 or bank 1 of SRAM
				;byte is returned in acc
	orl	p1,#080H	;enable external RAM chip select
	anl	p2,#0FEH	;clear A0, select low nibble
	movx	a,@r1		;read low nibble 
	anl	a,#00FH		;low 4 bits only
	mov	r2,a		;save it
	orl	p2,#001H	;set A0, select high nibble
	movx	a,@r1		;read high nibble
	anl	p1,#07FH	;disable external RAM chip select
	swap	a		;put nibble in high bits
	anl	a,#0F0H		;clear out low bits
	orl	a,r2		;OR in low nibble
	inc	r1		;inc ptr?
	ret


L0258:				;writes byte in acc to external SRAM
				;which is used as two banks of 256 bytes
				;P21 selects bank0 or bank 1 of SRAM
	orl	p1,#080H	;enable external RAM chip select
	anl	p2,#0FEH	;clear A0, select low nibble	
	movx	@r1,a		;write low nibble
	swap	a		;swap nibbles
	orl	p2,#001H	;set A0, select high nibble
	movx	@r1,a		;write high nibble
	anl	p1,#07FH	;disable external RAM chip select
	inc	r1		;inc ptr?
	ret


;; **************** Start of tape Load/Store/Verify routines *****************************


L0265:				;receive a byte from tape
	call	L0274
	jc	L0265
	mov	r7,#008H	;bit count
L026B:
	call	L0274		;get one bit
	xch	a,r3
	rrc	a		;rotate it into r3, lsbit is first
	xch	a,r3
	djnz	r7,L026B
	mov	a,r3		;put byte in acc
	ret



L0274:				;get one bit from tape input
	clr	c
	mov	r2,#000H	;set loop limit?
	jf1	L027F
L0279:
	jt1	L0287		;t1 is tape input comparator signal
	djnz	r2,L0279
	jmp	L0283

L027F:
	jnt1	L0287		;t1 is tape input comparator signal
	djnz	r2,L027F
L0283:
	mov	r5,#001H
	mov	r6,#001H
L0287:
	cpl	f1
	jtf	L028B		;jump if timer has overflowed
	cpl	c
L028B:
	mov	a,#0FAH
	mov	t,a
	call	L02E2
	ret			;end of get one tape bit 



L0291:				;sends byte in acc to tape
	mov	r3,a
	clr	c
	call	L02A5		;send 0 bit (cy)
	mov	r7,#008H	;bit counter
L0297:
	mov	a,r3
	rrc	a
	mov	r3,a
	call	L02A5		;send 8 bits, lsb first
	djnz	r7,L0297
	clr	c
	cpl	c		;set cy
	call	L02A5		;send 1 bit
	call	L02A5		;send 1 bit
	ret

L02A5:
	call	L02F0		;check for cancel sw or tape no longer enabled
	in	a,p2
	jb2	L02AE		
	orl	a,#00CH
	jmp	L02B0

L02AE:
	anl	a,#003H
L02B0:
	mov	r2,a
	mov	a,#0FCH
	jc	L02BA
	rlc	a
	xch	a,r2
	xrl	a,#008H
	xch	a,r2
L02BA:
	jtf	L02BE
	jmp	L02BA

L02BE:
	mov	t,a
	mov	a,r2
	outl	p2,a
	ret

L02C2:
	call	L0265		;receive a byte from tape
	xrl	a,#050H		;check for first header byte
	jnz	L02C2		;restart if no match
	call	L0265		;receive a byte from tape
	xrl	a,#036H		;check for second header byte
	jnz	L02C2		;restart if no match
	ret			;return if we got header

L02CF:
	mov	r0,#000H
	mov	r5,#002H
	anl	p2,#0FDH	;clear P21 output
	ret

L02D6:				;write acc contents to Program LED's
	outl	bus,a		;1 turns on LED
	orl	p2,#040H	;P26 is stb for Program LED's 1-8
	anl	p2,#0BFH
	ret

L02DC:				;write acc contents to Bank LED's, Man and Wr
	outl	bus,a		;0=on, D0-3 are Bank, D4 is manual, D5 is Write		 
	orl	p2,#080H	;P27 is stb for Bank LED's, Man, Wr
	anl	p2,#07FH
	ret

L02E2:
	jf0	L02E6
	jmp	L02F0

L02E6:
	mov	a,#07FH
	outl	bus,a		;send D7 low
	in	a,p1		;read a row of matrix switches
	jb2	L02EE		;check Write Enable switch		
	jmp	L02F0		
L02EE:
	jmp	L031E		;if write enable sw open

L02F0:
	jni	L02F4		;interrupt hooks to tape enable switch (0 = tape enabled)
	jmp	L0000		;if input is 0, jni will jump


L02F4:				;read tape switches/check for cancel
	mov	a,#0BFH		
	outl	bus,a		;send D6 low
	in	a,p1		;read tape-related matrix switches
	jb3	L02FC		;check Error/Cancel switch
	jmp	L031E		;jump to start of tape code if it's pressed
L02FC:				;otherwise ret
	ret


L02FD:
	call	L02DC		;write acc to Bank (0-3), Man(4) and Write(5) LED's
	clr	a
	mov	r4,a		;turn off all program LED's
	call	L02D6		;write acc contents to Program LED's, 1=on
	strt	t
	ret


L0305:				;this code fills program LEDs to indicate
	mov	a,#0C0H		;tape operation progress
	orl	a,r1
	cpl	a
	jnz	L0312		;only update LED's if r1[5:0] == 0x3F (once every 64 bytes)
	mov	a,r4
	clr	c
	cpl	c		;set cy flag
	rlc	a		;rotate it left into acc
	mov	r4,a		;r4 holds LED's state
	call	L02D6		;write acc contents to Program LED's, 1=on
L0312:
	ret


L0313:
	clr	c
	cpl	c		;set cy flag
	mov	r7,#000H
L0317:
	call	L02A5
	djnz	r7,L0317
	djnz	r6,L0317
	ret


L031E:				;we come here if tape is enabled
	clr	a		;turn off all 12 KLM-367 LED's
	call	L02D6		;write acc contents to Program LED's, 1=on
	call	L02DC		;write acc to Bank (0-3), Man(4) and Write(5) LED's
	mov	psw,a
L0324:
	clr	f0		;select low page of external SRAM
	stop	tcnt		;stop the timer
	call	L02F0		;restart if tape no longer enabled, otherwise read tape switches
	cpl	a		;which are active low
	jb0	L0331		;"To Tape" pressed, so do tape send operation
	jb2	L038C		;"Verify" pressed
	jb1	L0361		;"From Tape" pressed, so do tape receive
	jmp	L0324		;no tape switches pressed yet, so wait for one


L0331:				;tape send operation
	mov	a,#001H
	call	L02FD		;turn on Bank A/To Tape LED, turn off all program LED's, zero r4
	mov	r6,#028H
	call	L0313
	mov	a,#050H
	call	L0291		;send 0x50 byte to tape
	mov	a,#036H
	call	L0291		;send 0x36 byte to tape
	call	L02CF		;set r5 to 2, clear P21
	jmp	L0347
L0345:
	orl	p2,#002H	;for second pass we set top address bit (P21)
L0347:
	mov	r6,#000H
	mov	r1,#000H
L034B:
	call	L0245		;read external SRAM byte pointed to by r1 into acc
	xch	a,r0
	add	a,r0
	xch	a,r0		;r0 = r0 + acc (checksum?) 
	call	L0291		;transmit acc byte to tape
	call	L0305		;show tape operation progress on LEDs, only incs LEDs when r1=0x3F
	djnz	r6,L034B
	djnz	r5,L0345

	mov	a,r0
	call	L0291		;send checksum at the end
	mov	r6,#006H
	call	L0313
	jmp	L031E		;stay in tape code



L0361:				;should be tape receive code
	cpl	f0
	call	L02E2
	mov	a,#002H
	call	L02FD		;turn off "From Tape, turn off all program LED's, zero r4
	call	L02C2		;wait for two-byte header

	mov	a,#032H		;turn on "From Tape", Manual and Write LED's	
	call	L02DC		;write acc to Bank (0-3), Man(4) and Write(5) LED's

	call	L02CF		;set r5 to 2, clear P21
	jmp	L0374

L0372:
	orl	p2,#002H	;write to second page on second pass
L0374:
	mov	r6,#000H
	mov	r1,#000H
L0378:
	call	L0265		;receive a byte from tape
	xch	a,r0
	add	a,r0		;add it to checksum
	xch	a,r0
	call	L0258		;write acc to external SRAM byte pointed to by r1
	call	L0305		;show tape operation progress on LEDs, only incs LEDs when r1=0x3F
	djnz	r6,L0378
	djnz	r5,L0372	;write two pages of 256 bytes each
L0385:
	call	L0265		;receive checksum byte from tape
	xrl	a,r0		;compare to computed checksum
	jnz	L03B3		;err if not equal
	jmp	L031E		;stay in tape code



L038C:				;Tape verify code
	mov	a,#004H
	call	L02FD		;turn on "Verify" LED, turn off program LED's, zero r4
	call	L02C2		;wait for two-byte header

	mov	a,#014H		;turn on "Manual" and "Verify" LED's
	call	L02DC		;write acc to Bank (0-3), Man(4) and Write(5) LED's

	call	L02CF		;set r5 to 2, clear P21
	jmp	L039C

L039A:
	orl	p2,#002H	;read second page on second pass
L039C:
	mov	r6,#000H
	mov	r1,#000H
L03A0:
	call	L0265		;receive a byte from tape
	xch	a,r0
	add	a,r0		;add it to checksum
	xch	a,r0
	mov	r3,a		;and save in r3
	call	L0245		;read external SRAM byte pointed to by r1 into acc
	xrl	a,r3		;compare to rec'd byte
	jnz	L03B3		;err if not equal
	call	L0305		;show tape operation progress on LEDs, only incs LEDs when r1=0x3F
	djnz	r6,L03A0
	djnz	r5,L039A	;read two pages of 256 bytes each
	jmp	L0385

L03B3:				;Verify Failed
	mov	a,#008H		;turn on "Error/Cancel" LED
	call	L02DC		;write acc to Bank (0-3), Man(4) and Write(5) LED's
	jmp	L0324		;back to tape code



;; **************** End of tape Load/Store/Verify routines *****************************



L03B9:				;DAC Calibration code:
	mov	r0,#00CH	
L03BB:
	mov	r1,#00CH
	mov	r6,#000H	;select chan 0 (Eff Spd/Int=0, or -5V)
	call	L021A		;perform ADC conv, r6 is chan, rlst in r4, acc
	call	L03D9		;conversion result around 0
	inc	r1
	inc	r6		;select chan 1 (Filt Cutoff=10, or +5V)
	call	L021A		;perform ADC conv, r6 is chan, rlst in r4, acc
	cpl	a		;conversion result around 0xFF, so invert it
	call	L03D9

	mov	r2,#004H
L03CC:
	xch	a,@r1
	rlc	a		;rotate @r1 left one bit through cy
	xch	a,@r1
	xch	a,@r0
	rrc	a		;rotate @r0 right one bit, shifting in msbit of @r1
	xch	a,@r0
	djnz	r2,L03CC	
				;seems like they wanted D4 set to get 10000001 after rotating
	mov	a,@r0
	call	L02D6		;send acc to Program 1-8 LEDs, 1=on
	jmp	L03BB		;and loop

L03D9:
	jnz	L03DE
	mov	@r1,#010H	;if conversion result = 0, set D4
	ret
L03DE:
	add	a,#0FEH
	jc	L03E5
	mov	@r1,#020H	;if conversion result < 2, set D5
	ret
L03E5:
	add	a,#0FEH		;if conversion result was < 4, set D6
	jc	L03EC
	mov	@r1,#040H
	ret
L03EC:				;if conversion result was >= 4, set D7
	mov	@r1,#080H
	ret			;end of DAC calibration code


L03EF:	.db	001h		;bitmask table
	.db	002h
	.db	004h
	.db	008h
	.db	010h
	.db	020h
	.db	040h
	.db	080h

L03F7:	.db	004h		;these end up being loop ctrs to read the values
	.db	003h		;in the next table, which are bit masks for some switches
			
				;combine these four values and you get all of the bits
				;in a byte.   These are masks for the switch/contr reg hw.
L03F9:	.db	003h		;octave switch
	.db	00Ch		;waveform select		
	.db	030h		;sub harmonic
	.db	0C0H		;modulation destination select

	.db	001H		;EG Mode
	.db	00Eh		;Chorus/Phaser
	.db	0F0h		;VCA Attenuation

	.end
