;********************************************************
;* MIDI8031, Mini-OS fuer EPROM, (C) JP 1992			*
;* Juergen Piscol, Rastatterstr. 144, 7500 Karlsruhe 51 *
;********************************************************

	.registers reg51.inc		; 8051 SF-Register

	.text_org $0				; EPROM-Bereich

; ----- Interruptbereich -----

reset:	ljmp start
int0:	ljmp $8003
		.ds.b 5
timer0:	ljmp $800b
		.ds.b 5
int1:	ljmp $8013
		.ds.b 5
timer1:	ljmp $801b
		.ds.b 5
serial:	jnb PSW.5,?ose		; F0=0: MIDI abfangen		 
		ljmp $8023			; F1=1: USER-MIDI
?ose:	ajmp midio

; ----- EPROM-Info -----

	.dc.b "+++++++++++++++++++++++++++++++++++++++"
	.dc.b " MIDI8031 / 12MHz / (C) JP 1992 / V2.0 "
	.dc.b "+++++++++++++++++++++++++++++++++++++++"

; ----- Initialisierung der Hardware -----

start:
	mov SP,#$2F				; SP oberhalb Bitbereich
	mov	TMOD,#%00100000		; Timer 1 Baudrate, Timer 2 aus
	mov	TCON,#%01000000		; Timer 1 laeuft...
	mov	TH1,#$FF			; Timer 1 Reload fuer Baudrate 31250
	mov	SCON,#%01111100		; Ini. Schnittstelle
	mov	IP,#%00010000		; Nur Ser. Int. Hohe Prioritaet

	mov R1,#20
?s1: cpl P3.5				; LED Flackern- Reset
	mov A,#30				; ca. 0.6 sec warten
	acall wait_ams			; A ms warten...
	djnz R1,?s1

	clr SCON.1				; RI=0 Nix Interrupt!
	clr SCON.0				; TI=0 dto.
	mov	IE,#%10010000		; Nur Ser. Interrupt zulassen

; ----- Hauptwarteschleife -----

main:
	mov R1,#200				; R1: Zeitkonstante
?ma1: mov A,R1
	acall wait_ams			; warten
	cpl P3.5				; LED toggeln
	sjmp ?ma1				; u. das gleiche nochmal

; ----- wait ams: Wartet Anz. msec (ca.) in A, Reg.: A,R0 -----

wait_ams:
	mov R0,#248				; so in etwa 1 ms.
?w1:
	nop
	nop
	djnz R0,?w1
	djnz ACC,wait_ams
	ret

; ----- cha_out: Zeichen in A ueber MIDI ausg., Reg.: A -----
cha_out:
	mov C,SCON.1			; TI merken
	clr SCON.1				; und loeschen

	mov SBUF,A				; Zeichen absetzen
	jnb SCON.1,!			; TI=1 abwarten

	mov SCON.1,C			; und alter Zustand
	ret

; ----- cha_in: Zeichen von MIDI abholen nach A., Reg.: A -----

cha_in:
	jnb SCON.0,!			; RI=1 abwarten
	clr SCON.0				; quittieren
	mov A,SBUF
	ret

; ----- xbkl_out: XRAM-Block @DPTR, Laenge R0 absenden, Reg.: DPTR,R0
xblk_out:
	movx A,@DPTR			; Byte holen
	acall cha_out			; Byte ausgeben
	inc DPTR				; Speicher weiter...
	djnz R0,xblk_out		; bis fertig!
	ret

; ----- xbkl_in: XRAM-Block @DPTR, Laenge R0 einlesen, Reg.: DPTR,R0

xblk_in:
	acall cha_in			; Byte holen
	movx @DPTR,A			; Byte poken
	inc DPTR				; Speicher weiter...
	djnz R0,xblk_in			; bis fertig!
	ret

; ----- rbkl_out: RAM-Block @R1, Laenge R0 absenden, Reg.: R1,R0

rblk_out:
	mov A,@R1				; Byte holen
	acall cha_out			; Byte ausgeben
	inc R1					; Speicher weiter...
	djnz R0,rblk_out		; bis fertig!
	ret

; ----- rbkl_in: RAM-Block @R1, Laenge R0 einlesen, Reg.: R1,R0
rblk_in:
	acall cha_in			; Byte holen
	mov @R1,A				; Byte poken
	inc R1					; Speicher weiter...
	djnz R0,rblk_in			; bis fertig!
	ret

; ----- Midi-Interrupt -----

?m0:
	mov A,#109				; //109// Single-Step
	acall cha_out			; 109 ausgeben, aber
	mov A,#104				; 104 merken
	sjmp ?mm1				; ausgeben und weiter...
midio:

	push PSW				; Flags sichern
	push ACC				; Register sichern!
	mov A,R0
	push ACC
	mov A,R1
	push ACC
	push DPL
	push DPH
	jb SCON.1,?m0			; evtl. TI: Single-Step

mid_com:					; Kommando holen
	acall cha_in			; Zeichen holen
	acall cha_out			; Quittieren...
?mm1:

	cjne A,#100,?m1			; //100//: XRAM Block senden?
	acall cha_in
	mov DPL,A				; Source_Low
	acall cha_in
	mov DPH,A				; Source_High
	acall cha_in
	mov R0,A				; Laenge
	acall xblk_out
	sjmp mid_com

?m1:
	cjne A,#101,?m2			; //101//: XRAM Block empfangen?
	acall cha_in
	mov DPL,A				; Destin_Low
	acall cha_in
	mov DPH,A				; Destin_High
	acall cha_in
	mov R0,A				; Laenge
	acall xblk_in
	sjmp mid_com

?m2:
	cjne A,#102,?m3			; //102//: Block senden?
	acall cha_in
	mov R1,A				; Source
	acall cha_in
	mov R0,A				; Laenge
	acall rblk_out
	sjmp mid_com

?m3:
	cjne A,#103,?m4			; //103//: Block empfangen?
	acall cha_in
	mov R1,A				; Destin.
	acall cha_in
	mov R0,A				; Laenge
	acall rblk_in
	sjmp mid_com

?m4:
	cjne A,#104,?m5			; //104//: PC ausg. u. warten (BREAK in ...)
	mov A,SP				; A aus SP holen
	add A,#-6				; 6 Bytes weniger (DPL/H R1 R0 ACC PSW)
	mov R0,A				; R0=SP-7
	mov A,@R0
	acall cha_out			; PC_High ausg.
	dec R0
	mov A,@R0
	acall cha_out			; PC_Low ausg.
	sjmp mid_com			; weiter warten...

?m5:
	cjne A,#105,?m6			; //105//: PC setzen (GO ...)

	mov A,SP				; A aus SP holen
	add A,#-6				; 6 Bytes weniger (DPL/H R1 R0 ACC PSW)
	mov R0,A				; R0=SP-7

	acall cha_in			; High-Byte PC
	mov @R0,A
	dec R0
	acall cha_in			; Low-Byte PC
	mov @R0,A
	sjmp ?mx				; EXIT, Schleife verlassen!

?m6:
	cjne A,#106,?m7			; //106//: Interrupts abschalten (INIT)
	mov	IE,#%10010000		; Nur Ser. Interrupt zulassen
	mov	IP,#%00010000		; Nur Ser. Int. Hohe Prioritaet
	sjmp mid_com			; weiter warten...

?m7:
	cjne A,#107,?m8			; //107// Single Step ON
	setb SCON.1				; TI = ON
	sjmp mid_com

?m8:
	cjne A,#108,?m10		; //108// Single Step OFF
	clr SCON.1				; TI = OFF
	sjmp mid_com

?m10:
	cjne A,#110,?mx			; //110//: wichtige Register lesen
	mov R0,SP				; R0 aus SP
	mov A,@R0
	acall cha_out			; DPL
	dec R0
	mov A,@R0
	acall cha_out			; DPH
	dec R0
	mov A,R7
	acall cha_out			; R7
	mov A,R6
	acall cha_out			; R6
	mov A,R5
	acall cha_out			; R5
	mov A,R4
	acall cha_out			; R4
	mov A,R3
	acall cha_out			; R3
	mov A,R2
	acall cha_out			; R2
	mov A,@R0
	acall cha_out			; R1
	dec R0
	mov A,@R0
	acall cha_out			; R0
	dec R0
	mov A,@R0
	acall cha_out			; ACC
	dec R0
	mov A,@R0
	acall cha_out			; PSW
	mov A,SP
	add A,#-6				
	acall cha_out			; SP (excl. Debugger, 6 zuwenig!)
	mov A,B
	acall cha_out			; B
	ajmp mid_com			; weiter warten...

?mx:						; Andere Daten: Schleife verlassen
	pop DPH
	pop DPL
	pop ACC
	mov R1,A
	pop ACC
	mov R0,A
	pop ACC
	pop PSW
	reti					; Fertig!
