; Test program for Z180 CPU (C)Eugene Po - efu@mail.ru (http://orion.efu.name)
; Test RAM	- OK
; Test VGA
; Test PS/2
; Test SD card
; Test CMOS - OK
; Test Sound
; TEST LPT	- OK
; Step-7

CNTLA0	equ	00h		; ASCI Control Register A 0
CNTLB0	equ	02h		; ASCI Control Register B 0
CNTR	equ	0Ah		; CSI/O Control/Status Register
TRDR	equ	0BH		; CSI/O Transmit/Receive Data Register
TCR		equ	10H		; Timer Control Register
AECR0	equ	12h		; ASCI0 Extension Control Register
CCR		equ	1Fh		; CPU Control Register
DCNTL	equ	32h		; DMA/WAIT Control Register
;RCR	equ	36h		; Refresh Control Register
CBR		equ	38h		; MMU Common Base Register
BBR		equ	39h		; MMU Bank Base Register 
CBAR	equ	3Ah		; MMU Common/Bank Area Register
OMCR	equ	3Eh		; Operation Mode Control Register

; CPU Timing IOC = 0
; порты внешних устройств =====================================================
;SNDADR	equ	01000110b	; порт 44h, в ZX 65533
SNDADR	equ	01000000b	; порт 44h, в ZX 65533
SNDDAT	equ	01001111b	; порт 46h, в ZX 49149
;SNDDAT	equ	01000100b	; порт 46h, в ZX 49149

SDSEL	equ	58h			; выбор SD карты битом 2
SDUNSEL	equ	5Ch			; сброс SD карты битом 2

PS2DATA	EQU	60h			; порт 60h данных PS/2 контроллера
PS2CNTR	EQU	64h			; порт 64h управлениЯ PS/2 контроллера

CMOSADR	equ	70h			; порт 70h адреса часов
CMOSDAT	equ	71h			; порт 71h данных часов

PIODRA	equ	01111000b	; порт 78h PIO A Data register
PIODRB	equ	01111001b	; порт 79h PIO B Data register
PIOCRA	equ	01111010b	; порт 7Ah PIO A Control register
PIOCRB	equ	01111011b	; порт 7Bh PIO B Control register

VIDEO_RAM	equ 08000h	; начало видеопамяти
;==============================================================================
  org (0000h)
START:
  di				; откл. прерывания
  xor a				; обнулить аккумулятор
  out0 (36h),a		; откл. регенерацию памяти
  in0	a,(OMCR)
  res	5,a
  out0	(OMCR),a	; IO в режим Zilog
;  out0 (TCR),a		; откл. таймер, A18 - адрес
;  ld a,00110000b
;  out0 (DCNTL),a	; доп. такты ожидания
;  ld a,00010111b
;  out0 (CCR),a		; замедлить 33%
;=============================================================================
; распределение памяти Bank Area = 8000H, Common Area 1 = C000h
;=============================================================================  
  ld a,0C8H		; распределение Common Area-1 - 0C000h, Bank Area - 08000h
  out0 (CBAR),a
;  ld a,0A0H		; VGA графическую видеопамять от 0A0000h отражаем на Bank Area
;  ld a,0B8H		; VGA текстовую видеопамять от 0B8000h отражаем на Bank Area
  ld a,80H		; RAM от 80000h отражаем на Bank Area
  out0 (BBR),a
  ld a,10H		; RAM от 10000H отражаем на Common Area-1
  out0 (CBR),a
;=============================================================================
; настройка Serial Port 0
;=============================================================================
;  in0 a,(AECR0)
;  set 4,a
;  out0 (AECR0),a	; установка внешнего тактирования ASCI0 18,432 мГц
;  set 7,a		; установить рабочую частоту PHI = 18,432 мГц
;  out0 (CCR),a		; CPU Control Register
  ld a,01110100b	; прием и передача вкл. RTS=1,8,N,1
  out0 (CNTLA0),a	; Init CNTLA0 (COM1)
;  ld a,10111000b	; PS=30, DR=64, SS=1, 9600BPS для PHI=18,432 мГц или 4800 длЯ PHI/2
  ld a,10110000b	; PS=30, DR=16, SS=1, 9600BPS для PHI=18,432/4/2 мГц = 2.304 МГц
;  ld a,10111111b	; DR=64, SS=111, 28800BPS для внешнего генератора 1,8432 мГц
  out0 (CNTLB0),a	; Init CNTLB0 (COM1)
;==============================================================================
; Test RAM0
;==============================================================================
TEST_RAM0:
  ld	hl,0C000h	; адрес ОЗУ
  ld	a,(hl)		; читаем байт
  cpl				; инвертируем
  ld	(hl),a		; записываем назад (точно не мусор)
  ld	a,(hl)		; читаем ущё раз
  cp	(hl)		; сравниваем
  jr	z,RAM0_OK	; если равны, то сообщение OK, иначе ERR
  ld	hl,RAM0_ERR_String	; вывод строки  "RAM0 Err!"
out_str1:
  ld	a,(hl)
  cp	0		; пока не встретится символ "00"
  jr	z,TEST_RAM_VGA
  ld	c,a
test_sym1:
  in0	a,(04h)		; читать статус порта COM1 (STAT0)
  rra
  rra			; проверяем бит 1
  jr	nc,test_sym1	; если буфер не пустой - байт не передан (флаг C=0), опять проверить
  out0	(06h),c		; отправить в COM1
  inc	hl		; следующий символ
  jr	out_str1
; Попытка использовать вместо RAM0 - RAM VGA потом будет
TEST_RAM_VGA:
  ld hl,RAMVGA_ERR_String
  jp STOP
;==============================================================================
RAM0_OK:
  ld	sp,0D000h			; установить стек
  ld	hl,R_String			; вывод строки-разделитель
  call	out_string
  ld	hl,WelcomeString	; вывод строки приветствиЯ
  call	out_string
;  ld	b,7
;  call	beep				; писк
  ld	hl,RAM0_OK_String	; вывод строки "RAM0 OK"
  call	out_string
;==============================================================================
; Test RAM1
;==============================================================================
TEST_RAM1:
  ld	hl,08000h		; адрес ОЗУ
  ld	a,(hl)			; читаем байт
  cpl					; инвертируем
  ld	(hl),a			; записываем назад (точно не мусор)
  ld	a,(hl)			; читаем ещё раз
  cp	(hl)			; сравниваем
  jr	z,RAM1_OK		; если равны, то сообщение OK, иначе ERR
  ld	hl,RAM1_ERR_String	; вывод строки "RAM1 Err!"
  call	out_string
;  ld	b,5
;  call	beep
  jr	INIT_HW
RAM1_OK:
;  ld	b,7
;  call	beep			; писк
  ld	hl,RAM1_OK_String	; вывод строки "RAM1 OK"
  call	out_string
;=============================================================================
; Test VGA RAM
;=============================================================================
TEST_RAM_VGA1:

;=============================================================================
INIT_HW:
	call	INIT_CMOS	; проверка и запуск часов
	call	beep5
	call	INIT_PS2	; проверка PS/2
	call	beep1
;	call	INIT_VGA	; инициализация VGA
	call	beep2
;	call	INIT_CSIO	; проверка SPI SD Card
	call	beep4
;	call	INIT_SND	; проверка звукового чипа
	call	beep2
	call	INIT_PIO	; проверка параллельного интерфейса
	call	beep1
;==============================================================================
TEST:
  call	in_sym
;  cp	0FFh
;  call	z,KEYB_IN
  cp	'c'
  call	z,TEST_CMOS
  cp	'f'
  call	z,TEST_CSIO
  cp	'h'
  jr	z,IOC_HITACHI
  cp	'k'
  call	z,TEST_PS2
  cp	'l'
  call	z,KEYB_LED_ON
  cp	'm'
  call	z,TEST_MEM
  cp	'p'
  call	z,TEST_PIO
  cp	'r'
  jp	z,START
  cp	's'
  call	z,TEST_SND
  cp	't'
  call	z,SET_CMOS
  cp	'o'
  call	z,KEYB_LED_OFF
  cp	'v'
  call	z,TEST_VGA
  cp	'z'
  jr	z,IOC_ZILOG
  
  cp	'1'
  call	z,INIT_VGA
  cp	'2'
  call	z,INIT_PS2
  cp	'3'
  call	z,INIT_CSIO
  cp	'4'
  call	z,INIT_CMOS
  cp	'5'
  call	z,INIT_SND
  cp	'6'
  call	z,INIT_PIO
  cp	'7'
  call	z,KEYB_IN
  cp	0FFh
  jr	z,TEST
  call	out_hex		; вывести на экран
  ld	hl,SYM_CR_LF
  call	out_string	; конец строки
;  ld	a,'_'
;  call	out_sym		; вывести разделитель
  
  jr TEST
;==============================================================================
IOC_HITACHI:
  in0	a,(OMCR)
  set	5,a
  out0	(OMCR),a
  ld	b,4
  call	beep
  jp	TEST
IOC_ZILOG:
  in0	a,(OMCR)
  res	5,a
  out0	(OMCR),a
  ld	b,8
  call	beep
  jp	TEST
WaitFF:
  ld a,0F0h
  out0 (DCNTL),a	; доп. такты ожидания
  jp TEST
Wait00:
  ld a,00h
  out0 (DCNTL),a	; доп. такты ожидания
  jp TEST
;==============================================================================
ReadDataKeyb:
  ld bc,PS2CNTR		; номер порта команд  в bc
  in a,(c)		; читаем байт состояния
  rra			; проверЯем готовность приЮма
  jp nc,ReadDataKeyb	; если не готов (бит 0 = 0)- читаем ещЮ
  ld bc,PS2DATA		; номер порта данных в bc
  in a,(c)		; получить в A
  ld hl,SCAN_CODE_SET1	; адрес таблицы
  add a,l
  ld l,a
  ld a,(hl)		; символ из таблицы
  call out_sym		; отправить в терминал
  jp ReadDataKeyb
;==============================================================================
STOP:
  set 7,a			; установка бита 7
  out0 (36h),a		; вкл. регенерацию памяти , т.е. пищалку
  ld hl,StopString	; СТОП!!!
out_str2:
  ld	a,(hl)
  cp	0			; пока не встретитсЯ символ "00H"
  jr	z,SYSTEM_STOP
  ld	c,a
test_sym2:
  in0	a,(04h)		; читать статус порта COM1 (STAT0)
  rra
  rra				; проверяем бит 1
  jr	nc,test_sym2	; если буфер не пустой - байт не передан (флаг C=0), опять проверить
  out0	(06h),c			; отправить в COM1
  inc	hl
  jp	out_str2
SYSTEM_STOP:
  halt			; СТОП!!!
;==============================================================================
; подпрограммы
;==============================================================================
; ввод символа с клавиатуры из терминала в A
;==============================================================================
in_sym:
  in0	a,(04h)		; читать статус порта COM1 (STAT0)
  rla				; проверяем бит 7
  jr	nc,NO_IN	; если ничего не пришло (флаг C=0), вернуть в A 0FFh
  in0	a,(08h)		; принять из COM1
  ret
NO_IN:
  ld	a,0FFh
  ret
;==============================================================================
; Test VGA - прочитать память VGA и показать в терминале
;==============================================================================
TEST_VGA:
  ld	b,63		; байт показать
  ld	hl,VIDEO_RAM	; начало видеопамяти
test_vga1:
  ld	a,(hl)		; прочитать байт
  call	out_hex		; вывести на экран
  ld	a,'_'
  call	out_sym		; вывести разделитель
  inc	hl
  djnz	test_vga1
  ret
;=============================================================================
; инициализация VGA
;==============================================================================
INIT_VGA:
  ld	a,0B8H		; VGA текстовую видеопамять от 0B8000h отражаем на Bank Area
  out0	(BBR),a
  ld a,1		; разрешить доступ к видеопамяти и портам ввода/вывода видеоадаптера 
  ld bc,3C3h
  out (c),a
  
  ld	hl,08000h		; адрес ОЗУ
  ld	a,(hl)			; читаем байт
  cpl				; инвертируем
  ld	(hl),a			; записываем назад (точно не мусор)
  ld	a,(hl)			; читаем ущё раз
  cp	(hl)			; сравниваем
  jr	z,RAM_VGA_OK		; если равны, то сообщение OK, иначе ERR
  ld	hl,RAM_VGA_ERR_String	; вывод строки "RAM VGA Error"
  call	out_string
  jr	INIT_VGA_1
RAM_VGA_OK:
  ld	hl,RAM_VGA_OK_String	; вывод строки "RAM VGA OK"
  call	out_string
INIT_VGA_1:  
  ld a,23h		; 
  ld bc,3C2h		; регистр определения различных режимов работы MOR
  out (c),a		;
  ld bc,3CCh		; читаем то, что записали из порта VGA MOR
  in a,(c)
  cp 23h
  jp z,VGA_OK		; продолжить инициализацию, если VGA найден.
  ld hl,VGA_ERR_String	; вывод строки ERR
  call out_string
;  ret
VGA_OK:
  ld bc,3DAh		; Читаем из 3DA
  in a,(c)

  call beep		; писк
  ld hl,VGA_OK_String	; вывод строки OK
  call out_string
  
  ld hl,REGS_DATA	; таблица данных регистров
  ld a,(hl)		; содержимое из таблицы
  ld bc,3C2h		; Регистр определения различных режимов работы
  out (c),a
  inc hl
  ld a,(hl)		; содержимое из таблицы
  ld bc,3DAh		; Регистр управления дополнительным устройством
  out (c),a
  inc hl
;=============================================================================
; Регистры синхронизатора SEC 5 шт.
;=============================================================================
  xor a
VGA_SEC:
  ld bc,3C4h
  out (c),a		; индекс из A
  ld d,(hl)		; значение из таблицы
  ld bc,3C5h
  out (c),d		; данные из D
  inc hl  		; следующая ячейка
  cp 5
  inc a			; следующий номер регистра
  jp c,VGA_SEC		; пока не загрузится 5 ячеек
;=============================================================================
; Регистры контроллера CRTC 25 шт. - 18H
;=============================================================================
  xor a
VGA_CRT:  
  ld bc,3D4h
  out (c),a
  ld d,(hl)		; значение из таблицы
  ld bc,3D5h
  out (c),d
  inc hl  		; следующая ячейка
  cp 18h
  inc a			; следующий номер регистра
  jp c,VGA_CRT		; пока не загрузится 25 ячеек
;=============================================================================
; Регистры графического контроллера GC 9 шт.
;=============================================================================
  xor a
VGA_GC:
  ld bc,3CEh
  out (c),a
  ld d,(hl)		; значение из таблицы
  ld bc,3CFh
  out (c),d
  inc hl  		; следующая ячейка
  cp 9
  inc a			; следующий номер регистра
  jp c,VGA_GC		; пока не загрузится 9 ячеек
;=============================================================================
; Регистры графического контроллера AC 21 шт.
;=============================================================================
  xor a
VGA_AC:
;  ld bc,3BAh
;  in d,(c)		; переключить регистр в исходное состояние для монохромного режима
  ld bc,3DAh
  in d,(c)		; переключить регистр в исходное состояние для цветного режима
  ld bc,3C0h
  out (c),a
  ld d,(hl)		; значение из таблицы
  ld bc,3C1h	; Было 3C0h !!!!!!!!!!!!!!!!!!!!!!!!
  out (c),d
  inc hl  		; следующая ячейка
  cp 21
  inc a			; следующий номер регистра
  jp c,VGA_AC		; пока не загрузится 21 ячеек
;=============================================================================
; Загрузка шрифтов в 2 плоскость видеопамяти
;=============================================================================
  ld bc,03c4h	; Регистр разрешения записи цветового слоя (Color Plane Write Enable - CPWE) (индекс 2)
  ld a,2
  out (c),a
  ld bc,03c5h
  ld a,0100b	; Если бит D2 равен единице, то можно записывать данные в второй цветовой слой.
  out (c),a
;  ld hl,FONT
  ld de,VIDEO_RAM
  ld bc,4095
  ldir		; копируем шрифт
  ld bc,03c4h	; Регистр разрешения записи цветового слоя (Color Plane Write Enable - CPWE) (индекс 2)
  ld a,2
  out (c),a
  ld bc,03c5h
  ld a,1	; можно записывать данные только в нулевой цветовой слой
  out (c),a
;=============================================================================
; Выводим сообщение в память VGA
;=============================================================================
  ld hl,Welcome_string
  ld de,VIDEO_RAM
Print_String:
  ld a,(hl)
  ld (de),a
  cp 0dh
  inc hl
  inc de
  inc de
  jp c,Print_String
  call beep		; писк
  ld hl,VGA_INIT_String	; вывод строки INIT
  call out_string
  ret
;==============================================================================
; тест PS/2 контроллера
;==============================================================================
TEST_PS2:
;  call	KEYB_IN
;  call	out_hex
;  ld	a,'.'
;  call	out_sym
  in	a,PS2CNTR		; читаем байт состояния
  rra
  rra				; проверяем готовность приёма
  ret	c			; если не готов (бит 1 = 1) возврат
  ld	a,0C0h
  out	PS2CNTR,a
  in	a,PS2DATA		; чтение входного порта
  call	out_hex
  ld	a,'.'
  call	out_sym
  ld	a,0D0h
  out	PS2CNTR,a
  in	a,PS2DATA		; чтение выходного порта
  call	out_hex
  ld	hl,SYM_CR_LF
  call	out_string		; перенос строки
  ret
;==============================================================================
; инициализация PS/2 контроллера
;==============================================================================
INIT_PS2:
  in	a,PS2CNTR			; читаем байт состояния
  rra
  rra						; проверяем готовность приёма
  jr	c,KEYB_NOT_READY	; если не готов (бит 1 = 1)
  
  ld 	a,0AAH
  out	PS2CNTR,a		; самотестирование контроллера
  ld 	d,0FFh			; проверять ff раз
KEYB_TEST:
  dec 	d
  ld 	a,d
  jr 	z,KEYB_NOT_READY
  in 	a,PS2CNTR		; читаем байт состояния
  rra
  rra					; проверяем готовность чтения
  jr 	c,KEYB_TEST		; если не готов (бит 1 = 1)- читаем ещё
  in	a,PS2DATA		; получить ответ самотестирования
  cp	055H
  jr	nz,KEYB_ERROR
  ld	hl,KeybOkString
  call	out_string		; Test OK - внутренний тест прошел
  call	beep2
  ret
  
KEYB_ERROR:
  cp 0FDH
  ld hl,KeybErrorString
  call z,out_string		; Diag. Failure - ошибка внутреннего теста.
  call beep2
  ret
  
KEYB_NOT_READY:
  ld hl,KeybNRstring	; контроллер не готов
  call out_string
  call beep5
  ret
;==============================================================================
; Запрос кода нажатой клавиши PS/2
;==============================================================================
KEYB_IN:
	in	a,PS2CNTR	; читаем байт состояния
;	rra
	rra				; проверяем готовность чтения
	jp	nc,KEYB_IN
	in	a,PS2DATA
	ld	b,a
KEYB_IN_1:	
	in	a,PS2CNTR
;	rra
	rra
	rra
	jp	c,KEYB_IN_1
	ld	a,0ADh			; команда AD
	out	PS2CNTR,a
KEYB_IN_2:
	in	a,PS2CNTR
;	rra
	rra
	rra
	jp	c,KEYB_IN_2
	ld	a,0AEh			; команда AE
	out	PS2CNTR,a
	ld	a,b
	ret
;==============================================================================
; Включить светодиоды на клавиатуре PS/2
;==============================================================================
KEYB_LED_ON:
	in		a,PS2CNTR		; читаем байт состояния
	rra
	rra						; проверяем готовность записи
	jp		c,KEYB_LED_ON
	ld		a,0EDh
	out		PS2DATA,a		; команда управления индикаторами
KEYB_LED_ON_1:
	in		a,PS2CNTR		; читаем байт состояния
;	rra
	rra
	jp		nc,KEYB_LED_ON_1
	in		a,PS2DATA
	cp		0FAh
	jp		nz,KEYB_LED_ON_ERR
	ld		a,07h
	out		PS2DATA,a		; включить все индикаторы
KEYB_LED_ON_2:
	in		a,PS2CNTR		; читаем байт состояния
;	rra
	rra						; проверяем готовность чтения
	jp		nc,KEYB_LED_ON_2
	in		a,PS2DATA
	cp		0FAh
	jp		nz,KEYB_LED_ON_ERR
	call	beep1
	ret
KEYB_LED_ON_ERR:
	ld		hl,KeybLedOnErrString
	call	out_string		; сообщение об ошибке
	call	beep5
	ret
;==============================================================================
; Выключить светодиоды на клавиатуре PS/2
;==============================================================================
KEYB_LED_OFF:
	in		a,PS2CNTR		; читаем байт состояния
	rra
	rra						; проверяем готовность записи
	jp		c,KEYB_LED_ON
	ld		a,0EDh
	out		PS2DATA,a		; команда управления индикаторами
KEYB_LED_OFF_1:
	in		a,PS2CNTR		; читаем байт состояния
;	rra
	rra
	jp		nc,KEYB_LED_OFF_1
	in		a,PS2DATA
	cp		0FAh
	jp		nz,KEYB_LED_OFF_ERR
	ld		a,00h
	out		PS2DATA,a		; выключить все индикаторы
KEYB_LED_OFF_2:
	in		a,PS2CNTR		; читаем байт состояния
;	rra
	rra						; проверяем готовность чтения
	jp		nc,KEYB_LED_OFF_2
	in		a,PS2DATA
	cp		0FAh
	jp		nz,KEYB_LED_OFF_ERR
	call	beep1
	ret
KEYB_LED_OFF_ERR:
	ld		hl,KeybLedOnErrString
	call	out_string		; сообщение об ошибке
	call	beep5
	ret
;==============================================================================
; пищалка, частота в регистре B
;==============================================================================
beep5:
  ld	b,00100111b
  jp	beep
beep1:
  ld	b,00100110b
  jp	beep
beep2:
  ld	b,00100101b
  jp	beep
beep4:
  ld	b,00100100b
beep:
  ld	a,0Ah
  out	(CMOSADR),a
  ld	a,b
  out	(CMOSDAT),a		; установка частоты на выходе SQW
  ld	a,0Bh
  out	(CMOSADR),a
  in	a,(CMOSDAT)
  set	3,a				; уст бита 3 вкл. выхода
  ld	b,a				; сохраним A
  ld	a,0Bh
  out	(CMOSADR),a
  ld	a,b				; восстановим A
  out	(CMOSDAT),a		; включить звук
  
 
  ld	b,10h			; столько раз задержаться
beep_wait:
  push	bc
  ld	b,0FFh			; по столько
beep_wait1:
  nop  
  nop
  nop
  nop
  nop
  nop
  djnz	beep_wait1
  pop	bc
  djnz	beep_wait

  ld	a,0Ah
  out	(CMOSADR),a
  ld	a,00100000b
  out	(CMOSDAT),a		; отключить звук - частота=0Гц

  ret
;==============================================================================
; вывод байта из A в HEX виде
;==============================================================================
out_hex:
  PUSH	AF
  RRCA
  RRCA
  RRCA
  RRCA
  CALL	NIBBLE
  POP	AF
NIBBLE:
  AND	0FH			; обнулим старшие 4 бита
  add	a,30h		; прибавим 30h
  CP	3Ah			; не больше кода символа "9"?
  jr	c,out_hex_1
  add	a,7			; прибавим 7 до символов A-F
out_hex_1:
  call	out_sym		; вывод на экран
  ret
;==============================================================================
; вывод строки по HL в порт до 0
;==============================================================================
out_string:  
  ld	a,(hl)
  cp	0			; пока не встретитсЯ символ "00H"
  ret	z
  call	out_sym
  inc	hl
  jp	out_string
;==============================================================================
; вывод символа из A в порт
;==============================================================================
out_sym:
  ld	c,a
test_sym:
  in0	a,(04h)		; читать статус порта COM1 (STAT0)
  rra
  rra			; проверяем бит 1
  jr	nc,test_sym	; если буфер не пустой - байт не передан (флаг C=0), опять проверить
  out0	(06h),c		; отправить в COM1
  ret
;=============================================================================
; инициализация CMOS
;=============================================================================
INIT_CMOS:
  ld	a,0Dh		; регистр D
  out	(CMOSADR),a
  in	a,(CMOSDAT)
  rla
  jr	c,CMOS_OK
CMOS_ERROR:			; Батарея неисправна
  ld	hl,CMOS_ERR_String
  call	out_string
  ret
CMOS_OK:			; Батарея исправна
  ld	a,0Ah
  out	(CMOSADR),a
  ld	a,00100000b
  out	(CMOSDAT),a	; откл. звук
  ld	a,0Bh
  out	(CMOSADR),a
  ld	a,00001010b	; 
  out	(CMOSDAT),a	; запуск часов
  ld	hl,CMOS_OK_String
  call	out_string
;  ld	b,4
;  call	beep
  ret
;=============================================================================
; проверка CMOS
;=============================================================================
TEST_CMOS:
  ld a,0Ah
  out (CMOSADR),a
  in a,(CMOSDAT)
  rla
  jr	c,TEST_CMOS	; ждать готовность чтения
  ld a,4h			; запросить часы
  out (CMOSADR),a
  in a,(CMOSDAT)
  call out_hex		; вывести в терминал
  ld a,':'
  call out_sym		; вывести разделитель
  ld a,2h			; запросить минуты
  out (CMOSADR),a
  in a,(CMOSDAT)
  call out_hex		; вывести в терминал
  ld a,':'
  call out_sym		; вывести разделитель
  ld a,0h			; запросить секунды
  out (CMOSADR),a
  in a,(CMOSDAT)
  call out_hex		; вывести в терминал
  ld hl,SYM_CR_LF
  call out_string	; конец строки

  ret

  ld d,0eh		; прочитать содержимое ячеек памяти от 0E до 7F
Read_CMOS:
  ld a,d
  out (CMOSADR),a
  in a,(CMOSDAT)
  call out_hex		; вывести в терминал
  ld a,' '
  call out_sym		; вывести разделитель
  inc d
  ld a,d
  cp 80h
  ret z
  jr Read_CMOS
;=============================================================================
; установка времени CMOS
;=============================================================================
SET_CMOS:
  ld	a,0Ah
  out	(CMOSADR),a
  ld	a,00100110b
  out	(CMOSDAT),a		; установка 1024 гц на выходе SQW
  ld	a,0Bh
  out	(CMOSADR),a
  ld	a,11111010b
  out	(CMOSDAT),a		; разрешить установку времени
  ld	a,4
  out	(CMOSADR),a
  ld	a,1
  out	(CMOSDAT),a		; часы
  ld	a,2
  out	(CMOSADR),a
  ld	a,1
  out	(CMOSDAT),a		; минуты
  ld	a,0
  out	(CMOSADR),a
  ld	a,1
  out	(CMOSDAT),a		; секунды
  
  ld	hl,TIME_SET_String	; вывод строки "Time Setting"
  call	out_string

  ld	a,0Bh
  out	(CMOSADR),a
  ld	a,01111010b
  out	(CMOSDAT),a		; запустить часы

  ld	a,0FFh
  ret
;=============================================================================
; проверка RAM блоками по 64 КБ
;=============================================================================
TEST_MEM:
  ld	hl,SYM_CR_LF		; курсор в начало новой строки
  call	out_string
  in0	a,(BBR)	
  ld	b,a			; сохраним BBR
  ld	a,10H

TEST_MEM1:
  out0 (BBR),a
  push	af
  call out_hex
  ld	hl,08000h		; адрес ОЗУ
  ld	a,(hl)			; читаем байт
  cpl				; инвертируем
  ld	(hl),a			; записываем назад (точно не мусор)
  ld	a,(hl)			; читаем ущё раз
  cp	(hl)			; сравниваем
  jr	z,MEM_OK		; если равны, то сообщение OK, иначе ERR

  ld	hl,RAM_ERR_String	; вывод строки "RAM Error"
  call	out_string
  pop	af
  add	a,10H
  out0 (BBR),b			; восстановим BBR
  ret	c
  jp	TEST_MEM1
MEM_OK:
  ld	hl,RAM_OK_String	; вывод строки "RAM OK"
  call	out_string
  pop	af
  add	a,10H
  out0 (BBR),b			; восстановим BBR
  ret	c
  jp	TEST_MEM1
;=============================================================================
; проверка LPT
;=============================================================================
TEST_PIO:
  ld	b,25h
  call	beep
  
  ld	hl,WelcomeString
out_string_prn:  
  ld	a,(hl)
  cp	0			; пока не встретится символ "00"
  ret	z
  call	out_sym_prn
  inc	hl
  jp	out_string_prn
;==============================================================================
; вывод символа из A на принтер
;==============================================================================
out_sym_prn:
;  ld	c,a
test_sym_prn:
;  in	a,(PIOCRA)	; читать состояние PIO-A port
;  in0	a,(04h)		; читать статус порта COM1 (STAT0)
;  rra
;  rra			; проверяем бит 1
;  jr	nc,test_sym_prn	; если буфер не пустой - байт не передан (флаг C=0), опять проверить
  out	(PIODRA),a	; отправить на принтер
  ret
;=============================================================================
; инициализация PIO - параллельного интерфейса - РАБОТАЕТ!!!
;=============================================================================
INIT_PIO:
  ld	a,0fh		; Output mode 0
  out	(PIOCRA),a
  out	(PIOCRB),a
  ld	a,07h		; отключить прерывания
  out	(PIOCRA),a
  out	(PIOCRB),a
  ld	a,03h		; отключить прерывания
  out	(PIOCRA),a
  out	(PIOCRB),a
  in	a,(PIODRA)	; читаем данные
  cpl			; инвертируем
  ld	b,a
  out	(PIODRA),a	; записываем
  in	a,(PIODRA)	; читаем данные
  cp	b
  jr	z,PIO_OK
  ld	hl,PIO_ErrString
  call	out_string
  call	beep
  call	beep
  ret
PIO_OK:  
  ld	hl,PIO_OKString
  call	out_string
  call	beep
  ret
;=============================================================================
; инициализация звукового чипа Yamaha
; на выходе: Z сброшен - сопроцессор присутствует. В противном случае - нет.
;=============================================================================
INIT_SND:
  XOR   A          	; A=0
  OUT   (SNDADR),A    ; выбор регистра 0
  OUT   (SNDDAT),A    ; вывод 0 в выбранный регистр
  IN    A,(SNDADR)	; ввод значения из выбранного регистра
  or	a
  jr	nz,SND_ERR
  ld	hl,SoundOKString	; контроллер обнаружен
  call	out_string
  call	beep
  ret
SND_ERR:
  ld	hl,SoundErrString	; контроллер не готов
  call	out_string
  call	beep
  call	beep
  call	beep
  RET
;=============================================================================
; проверка звукового чипа Yamaha - выдать звук
; https://zxpress.ru/book_articles.php?id=667
;=============================================================================
TEST_SND:
  ld	b,7
  call	beep

	LD A,3        	;в порт 65533 загружается номер 3-го регистра
	OUT (SNDADR),A  ;(грубая установка тона в канале В)
	LD A,5        	;(высота тона 5)
	OUT (SNDDAT),A     ;

	LD A,7        ;
	OUT (SNDADR),A	;значение регистра 7
	LD A,%11111101	;(включается канал В,без шумовых эффектов
	OUT (SNDDAT),A     ;
	
	LD A,9        	;(амплитуда канала В)
	OUT (SNDADR),A  ;прогрвммирование регистра 9
	LD A,16       	;(т.к. амплитуда равна 16,то включается гене-
	OUT (SNDDAT),A  ;ратор огибающей
	
	LD A,12       	;(грубое управление периодом огибающей)
	OUT (SNDADR),A  ;программирование регистра 12
	LD A,255      	;величена периода огибающей
	OUT (SNDDAT),A     ;
	
	LD A,13       	;программирование типа огибающей
	OUT (SNDADR),A     ;
	LD A,%11111110;
	OUT (SNDDAT),A     ;
	
	ld	hl,SoundTestString	; конец теста
	call	out_string
	ret
;==============================================================================
; инициализация Serial Port CSI/O - SD карта
;==============================================================================
INIT_CSIO:
  xor	a
  out	(SDSEL),a		; выбрать SD card
  ld	a,00001000b		; делитель SS=20
  out0	(CNTR),a		; разрешить прием и передачу CSI/O на скорости 18,432/4/2/20 = 115,2 КГц
;  ld	a,0		
  ld	hl,CMD0_data		; отправить команду CMD0 - сброс устройства
  call	out_csio
  call	beep			; задержка
  call	in_csio			; получить ответ
  jr	z,CSIO_OK
  ld	hl,CSIO_Err_String	; SD карта не обнаружена!!!
  call	out_string
  call	beep
  call	beep
  ret
CSIO_OK:			; SD карта обнаружена
;  ld	a,8	
  ld	hl,CMD8_data		; отправить команду CMD8
  call	out_csio
  call	beep			; задержка
  call	in_csio
  call	out_hex

  ld	hl,CSIO_OK_String	; SD карта готова
  call	out_string
  ret
;==============================================================================
in_csio:		; принять из SD карты
  in0	a,(CNTR)
  set	5,a
  res	4,a
  out0	(CNTR),a	; разрешить прием CSI/O и отключить передачу
  in0	a,(TRDR)	; прочитать SD
  ret
;==============================================================================
out_csio:		; отравляется 6 байт и CRC на SD карту с адреса в hl
  ld	b,5
  in0	a,(CNTR)
  set	4,a
  out0	(CNTR),a	; разрешить передачу CSI/O
out_scio1:
  ld	a,(hl)
  out0	(TRDR),a	; отправить
  inc	hl
  djnz	out_scio1
  ret
;==============================================================================
CMD0_data:
  .db 40h, 00, 00, 00, 00, 95h	; 48 бит, контрольная сумма 0x95
CMD8_data:
  .db 48h, 00, 00, 00, 00, 95h
;==============================================================================
; проверка асинхронного последовательного канала
; стр. 149 datasheet
;==============================================================================
TEST_CSIO:
  xor	a
  out	(SDSEL),a		; выбрать SD card

;  call	beep		; задержка
;  in0	a,(CNTR)
;  call	out_hex		; показать байт состояния

  ld	hl,SYM_CR_LF
  call	out_string	; конец строки
  call	beep

  in0	a,(CNTR)
  set	4,a
  out0	(CNTR),a	; разрешить передачу CSI/O
  xor	a
  out0	(TRDR),a	; отправить 0
  call	beep		; задержка
  in0	a,(CNTR)
  set	5,a
  out0	(CNTR),a	; разрешить прием CSI/O
  in0	a,(TRDR)	; прочитать
  call	out_hex		; показать прочитанный байт
  ld	hl,SYM_CR_LF
  call	out_string	; конец строки
  ld	a,0FFh
  out	(SDSEL),a	; отключить SD card
  ret

;SCAN_CODE_SET2:
; .db 0,0,0,0,0,0,0,0,0,0,0,0,0,126,0,0,0,0,0,0,'Q','1',0,0,0,'Z','S','A','W','2',0,0,'C','X','D','E','4','3',0,0,' ','V"
; .db "F','T','R','5',0,0,'N','B','H','G','Y','6',0,'J',0,'M',0,'U','7','8',0,0,44,'K','I','O','0','9',0,0,'.','/','L',59,'P','-',0,0,0
; .db 39,0,'[','=',0,0,0,0,0,']',0,92,0,0,0,0,0,0,0,0,0,0,0,'1',0,'4','7',0,0,0,'0','.','2','5','6','8',0,0,'0','+','3','-','*','9',0,0,0,0,0,0
;=============================================================================
REGS_DATA:
; MISC
; .db    67h, 00h
.db    10100111b, 00h	; 400 x 720
; SEQ
.db    03h, 00h, 03h, 00h, 02h
; CRTC
.db    5Fh, 4Fh, 50h, 82h, 55h, 81h, 0BFh, 01Fh
.db    00h, 4Fh, 0Dh, 0Eh, 00h, 00h, 00h, 50h
.db    9Ch, 0Eh, 8Fh, 28h, 1Fh, 96h, 0B9h, 0A3h
.db    0FFh
; GC
.db    00h, 00h, 00h, 00h, 00h, 10h, 0Eh, 00h
.db    0FFh
; AC
.db    00h, 01h, 02h, 03h, 04h, 05h, 14h, 07h
.db    38h, 39h, 3Ah, 3Bh, 3Ch, 3Dh, 3Eh, 3Fh
.db    0Ch, 00h, 0Fh, 08h, 00h
;=============================================================================
#include	"messages.asm"
; #include	"fontvga.asm"

end
