; code: language=z80-asm tabSize=8 ; SIMULATE_ERROR = $80 ; SIMULATE_ERROR = $3C .include "inc/z80.mac" .include "inc/spt.mac" ; Notes on global register allocation: ; ; This ROM doesn't work like typical Z80 code, which assumes the presence of a stack. ; There may in fact be no working memory in the machine for holding the stack. ; ; An overall goal for this version of the code is to run in the absence of any working ; ram at all. There is no stack and no RAM variables. The only storage of variables ; is in registers, so the registers must be carefully preserved. ; ; Without a stack, that means either saving them to other registers and restoring before ; jumping to other code (remembering there can be no CALLs when there is no stack) ; or avoiding their use altogether. These are extremely confining restrictions. ; ; Assembly purists will shudder at the extensive use of macros, but for sanity it ; cannot be avoided. ; ; Globally, the contents of these registers must be preserved ; e = bit errors in the region of memory currently being tested ; ix = current location in VRAM for printing messages ; iy = current table entry for test parameters ; VBASE equ 03000h VSIZE equ 0ffeh VLINE equ 80 .org 0000h ; z80 boot code starts at location 0 reset: di ; mask INT im 1 diagnostics: xor a out (0c0h),a ;0046 clear io, floppy control out (0c4h),a ;0048 clear io,Program map A base out (0c5h),a ;004a clear io,Program map B base out (0c6h),a ;004c clear io,DMA map A base out (0c7h),a ;004e clear io,DMA map B base out (0d4h),a ;0050 clear io,Hi-res color out (0d8h),a ;0052 clear io,Hi-res start ld hl,set_regs_start jp set_monroe_regs init_continue: jp setupclearscreen screen_clear_continue: ld a,080h ; out (0d4h),a ; Setup Screen ld a,005h ; out (0a3h),a ; DART B command ld a,068h ; out (0a3h),a ; DART B command ld a,0f0h ; ????? out (0c8h),a ; Map and system control ;select screen memory ld a,004h ; Select display memory out (0c8h),a ; Output to screen Map and system control test_vram: SPTHREAD_BEGIN ; set up to begin running threaded code SPT_SKIP_NMIVEC dw spt_playmusic, tones_welcome dw spt_select_test, tp_vram dw memtestmarch ; test the VRAM dw spt_check_7bit_vram ; dw spt_sim_error, $40 dw spt_jp_nc, .vram_ok ; we have bad vram dw spt_prepare_display dw spt_chartest .vram_bad_loop: ;dw spt_play_testresult ; play the tones for bit errorssetupcrt ;dw spt_pause, $0000 dw spt_jp,.vram_bad_loop .vram_7bit: dw spt_con_print, msg_ok7bit ; dw spt_play_testresult ; play the tones for bit errors ;dw spt_jp,.vram_goodtones .vram_ok: dw spt_prepare_display MAC_SPT_CON_GOTO 2,0 dw spt_announcetest2 ; print results of VRAM tst ; dw print_biterrs dw spt_jp_e_7bit_vram, .vram_7bit dw spt_con_print, msg_ok8bit .vram_goodtones: ;dw spt_playmusic, tones_vramgood ; play the VRAM good tones .vram_continue: MAC_SPT_CON_GOTO 1,0 dw spt_check_size dw spt_jp_256_fail, .skip256 dw spt_con_print, msg_256k dw spt_select_test, tp_16k_256 ; load the first test dw spt_jp, .start .skip256: dw spt_con_print, msg_128k dw spt_select_test, tp_16k ; load the first test dw spt_jp, .start .start: dw spt_con_goto MAC_SPT_CON_OFFSET 3,0 .loop: dw spt_announcetest ; announce what test we are about to run dw memtestmarch2 ; test the current bank dw spt_jp_nc, .ok dw spt_con_print, msg_biterrs ; we have errors: print the bit string dw print_biterrs ;dw spt_play_testresult ; play the tones for bit errors dw spt_jp, .cont .ok: dw spt_con_print, msg_testok ; bank is good: print the OK message ;dw spt_play_testresult ; play the tones .cont: dw spt_tp_next, .start dw spt_jp, .loop ;; ------------------------------------------------------------------------------------------------- ;; end of main program. spt_prepare_display: SPTHREAD_ENTER dw con_clear dw spt_con_print, msg_banner ; print the banner dw spt_print_charset dw spt_exit spt_check_size: ; Check if 256k memory or 128k ld hl,0c000h ; Point to test address ld a,0a0h ; Memory bank ld b,$FF ; B = FF out (0c5h),a ; ld (hl),b ; inc a ; A = A1 out (0c5h),a ; ld (hl),b ; dec a ; A = A0 add b ; B = 00 out (0c5h),a ; Select memory bank 9 ld (hl),b ; dec b ; B = FF inc a ; A = A1 out (0c5h),a ; Select memory bank 1 ld (hl),b ; dec a ; A = A0 out (0c5h),a ; Select memory bank 9 ld b,(hl) ; If 256kb B should be 0 ret spt_check_vram_contents: pop bc ld a,b ld d,c ; confirm that all of VRAM contains the value in register A check_vram_contents: ld hl,VBASE ld bc,VSIZE .fillloop: ld (HL),a cpi jp pe,.fillloop ld hl,VBASE ld bc,VSIZE ld a,d .readloop: cpi jr nz,.bad jp pe,.readloop or a ; clear carry flag ret .bad: scf ret spt_check_7bit_vram: ret nc ; if carry flag is not set, do nothing ld a,01000000b cp e jr z,.scantests scf ; something other than bit 6 is bad, so this is not 7bit VRAM ret .scantests: SPTHREAD_ENTER dw spt_check_vram_contents, $0040 dw spt_jp_c, .exit dw spt_check_vram_contents, $FFBF dw spt_jp_c, .exit dw spt_check_vram_contents, $AAAA dw spt_jp_c, .exit dw spt_check_vram_contents, $5555 dw spt_jp_c, .exit .exit: dw spt_exit ; if carry flag is set, this is not good 7-bit VRAM spt_sim_error: pop de scf ret ; test if the error is $FF (all bits bad) spt_jp_256_fail: pop hl ; get the address for jumping if match inc b ret nz ; return without jump if there is NOT a match ld sp,hl ; else jump to the requested location ret ; test if the e register matches 7-bit vram and jump to spt address if match spt_jp_e_7bit_vram: pop hl ; get the address for jumping if match ld a,01000000b ; ignore bit 6 cp e ; see if there are other errors ret nz ; return without jump if there is NOT a match ld sp,hl ; else jump to the requested location ret ; test if the e register matches 7-bit vram and jump to spt address if match spt_jp_e_zero: pop hl ; get the address for jumping if match ld a,0 ; test clean cp e ; see if there are other errors ret nz ; return without jump if there is NOT a match ld sp,hl ; else jump to the requested location ret ; load the label string address from the current test parameter table entry into hl spt_ld_hl_tp_label: ld l,(iy+4) ld h,(iy+5) ret ; load the label string address from the current test parameter table entry into hl spt_ld_hl_tp_tones: ld l,(iy+6) ld h,(iy+7) ret spt_ld_new_line: ld a,(iy+9) ld ixh,a ld a,(iy+8) ld ixl,a ret ; move to the next test parameter table entry spt_tp_next: pop hl ; get the address to jump to if we are starting over ld bc,tp_size ; find the next entry add iy,bc ld a,(iy+0) ; is the length zero? add a,(iy+1) ret nz ; no, use it ld c,(iy+2) ; yes, get the address of the first entry ld b,(iy+3) ld iy,0 add iy,bc ; sub a ; clear zero flag when restarting ld sp,hl ; jump to the next location ret spt_announcetest: ; pop hl ; get the message to be printed SPTHREAD_ENTER dw spt_ld_new_line ;dw con_NL dw spt_ld_hl_tp_label dw con_print ; picks up message from hl dw spt_con_print, msg_testing dw spt_con_index, -18 dw spt_exit spt_announcetest2: ; pop hl ; get the message to be printed SPTHREAD_ENTER dw spt_ld_hl_tp_label dw con_print ; picks up message from hl dw spt_con_print, msg_testing dw spt_con_index, -18 dw spt_exit spt_play_testresult: SPTHREAD_SAVE ; save the stack pointer SPTHREAD_BEGIN dw spt_ld_hl_tp_tones ; play the ID tune for current bank ;dw playmusic dw spt_pause, $2000 SPTHREAD_END ld a,$FF cp e jr z,.allbad ; if all bits bad, play shorter tune cpl cp e jr z,.allgood ; if all bits good, play shorter tune ld d,8 ; play bit tune for each bit, high to low .showbit: rlc e jr nc,.zero ld hl,tones_bitbad jr .msbe_cont .zero: ld hl,tones_bitgood .msbe_cont: SPTHREAD_BEGIN ;dw playmusic dw spt_pause, $2000 SPTHREAD_END ; pause $4000 dec d jr nz,.showbit jr .done .allbad: SPTHREAD_BEGIN ;dw spt_playmusic, tones_bytebad dw spt_pause, $8000 SPTHREAD_END jr .done .allgood: SPTHREAD_BEGIN ;dw spt_playmusic, tones_bytegood dw spt_pause, $8000 SPTHREAD_END .done: SPTHREAD_RESTORE ; restore the stack pointer ret spt_pause: pop bc ; pause by an amount specified in BC pause_bc: .loop: dec bc ld a,b or c jr nz,.loop ret print_biterrs: ld a,004h ; Select display memory out (0c8h),a ; Output to screen Map and system control ld a,'7' ld b,8 .showbit: rlc e jr nc,.zero ld (ix+1),a jr .cont .zero: ld (ix+1),'.' .cont: inc ix inc ix dec a djnz .showbit xor a ;054b Reset map out (0c8h),a ;054c Reset to memory Map and system control ret spt_ld_bc: pop bc ret spt_print_charset: ld a,ixh ld h,a ld a,ixl ld l,a ld a,0 SPTHREAD_ENTER MAC_SPT_CON_GOTO 15,24 dw spt_con_print, msg_charset ; show a copy of the character set MAC_SPT_CON_GOTO 16,0 dw spt_ld_bc, $100 dw do_charset_ix dw spt_exit spt_chartest: ld ix,VBASE ld bc,VSIZE do_charset_ix: ld a,004h ; Select display memory out (0c8h),a ; Output to screen Map and system control ld a,32 .charloop: ld (ix+1),a ; copy A to byte pointed by HL inc a ; increments A inc ix inc ix cpi ; increments HL, decrements BC (and does a CP) jp pe, .charloop xor a ;054b Reset map out (0c8h),a ;054c Reset to memory Map and system control ret screenclearloop: otir ;0560 out B bytes from (HL) to (C) set_monroe_regs: ld c,(hl) ; get register inc hl ; bump ld b,(hl) ;get count inc hl ; bump ld a,b ; and a ; jr nz,screenclearloop ;0568 if count not 0 loop $-8 jp init_continue setupclearscreen: ;entry during initiation w xor a ; start A=0 ld bc,00eb9h ; C=B9 B=14 ld hl,set_up_crt ; setupclearloop: out (0b8h),a ;CRT register select inc a ; A++ outi ; C)=(HL++) and B-- jr nz,setupclearloop ; loop until B==0 (14 bytes to write) $-5 jp screen_clear_continue label_vram: dbz " 4K VRAM 3000-3FFE " label_dram16k1: dbz "16K DRAM 0 C000-FFFF " label_dram16k2: dbz "16K DRAM 1 " label_dram16k3: dbz "16K DRAM 2 " label_dram16k4: dbz "16K DRAM 3 " label_dram16k5: dbz "16K DRAM 4 " label_dram16k6: dbz "16K DRAM 5 " label_dram16k7: dbz "16K DRAM 6 " label_dram16k8: dbz "16K DRAM 7 " label_dram64k1: dbz " 0K DRAM 0 C000-FFFF " label_dram64k2: dbz "16K DRAM 0 " label_dram64k3: dbz "32K DRAM 0 " label_dram64k4: dbz "48K DRAM 0 " label_dram64k5: dbz " 0K DRAM 1 " label_dram64k6: dbz "16K DRAM 1 " label_dram64k7: dbz "32K DRAM 1 " label_dram64k8: dbz "48K DRAM 1 " label_dram64k9: dbz " 0K DRAM 2 " label_dram64k10: dbz "16K DRAM 2 " label_dram64k11: dbz "32K DRAM 2 " label_dram64k12: dbz "48K DRAM 2 " label_dram64k13: dbz " 0K DRAM 3 " label_dram64k14: dbz "16K DRAM 3 " label_dram64k15: dbz "32K DRAM 3 " label_dram64k16: dbz "48K DRAM 3 " msg_banner: dbz "Monroe OC8820 TEST ROM -- FRANK IZ8DWF / DAVE KI3V / ADRIAN BLACK" msg_charset: dbz "-CHARACTER SET-" ; msg_testing: db " ", " "+$80, "t"+$80, "e"+$80, "s"+$80, "t"+$80, " "+$80, " ", 0 msg_testing: dbz "..TEST.. " msg_128k: dbz "128K machine" msg_256k: dbz "256K machine" msg_testok: dbz "---OK--- " msg_biterrs: dbz "BIT ERRS " msg_ok7bit: dbz "OK! (7-BIT MODEL 1)" msg_ok8bit: dbz "OK! (8-BIT)" ; test parameter table. 2-byte entries: ; 1. size of test in bytes ; 2. starting address ; 3. address of string for announcing test ; 4. address of tones for identifying the test audibly tp_size equ 10 memtest_ld_bc_size .macro ld c,(iy+0) ld b,(iy+1) .endm memtest_ld_hl_base .macro ld l,(iy+2) ld h,(iy+3) .endm memtest_loadregs .macro memtest_ld_bc_size memtest_ld_hl_base .endm spt_ld_iya6 .macro ld a,(iy+6) .endm spt_ld_iya7 .macro ld a,(iy+7) .endm tp_vram: dw VSIZE, VBASE, label_vram, tones_vram tp_16k: dw $4000, $C000, label_dram16k1, $a100,$31e0 dw $4000, $C000, label_dram16k2, $c100,$3280 dw $4000, $C000, label_dram16k3, $e100,$3320 dw $4000, $C000, label_dram16k4, $0000,$33c0 dw $4000, $C000, label_dram16k5, $2000,$3460 dw $4000, $C000, label_dram16k6, $4000,$3500 dw $4000, $C000, label_dram16k7, $6000,$35a0 dw $4000, $C000, label_dram16k8, $8000,$3640 dw $0000, tp_16k tp_16k_256: dw $4000, $C000, label_dram64k1, $a100,$31e0 dw $4000, $C000, label_dram64k2, $c100,$3280 dw $4000, $C000, label_dram64k3, $e100,$3320 dw $4000, $C000, label_dram64k4, $0000,$33c0 dw $4000, $C000, label_dram64k5, $2000,$3460 dw $4000, $C000, label_dram64k6, $4000,$3500 dw $4000, $C000, label_dram64k7, $6000,$35a0 dw $4000, $C000, label_dram64k8, $8000,$3640 dw $4000, $C000, label_dram64k9, $a000,$3230 dw $4000, $C000, label_dram64k10, $c000,$32d0 dw $4000, $C000, label_dram64k11, $e000,$3370 dw $4000, $C000, label_dram64k12, $0100,$3410 dw $4000, $C000, label_dram64k13, $2100,$34b0 dw $4000, $C000, label_dram64k14, $4120,$3550 dw $4000, $C000, label_dram64k15, $6100,$35f0 dw $4000, $C000, label_dram64k16, $8100,$3690 dw $0000, tp_16k_256 set_regs_start: defb 0b5h ;005a io port CRT register select defb 004h ;005b count 4 defb 0cfh ;005c defb 0b8h ;005d defb 037h ;005e defb 0efh ;005f ; defb 0b4h ;0060 io port PIO A data defb 001h ;0061 count 1 defb 001h ;0062 ; defb 0a1h ;0063 io port DART A command defb 006h ;0064 count 6 defb 048h ;0065 defb 048h ;0066 defb 004h ;0067 defb 044h ;0068 defb 005h ;0069 defb 0eah ;006a ; defb 0a3h ;006b io port DART B command defb 008h ;006c count 8 defb 048h ;006d defb 048h ;006e defb 004h ;006f defb 044h ;0070 defb 001h ;0071 defb 000h ;0072 defb 003h ;0073 defb 0c1h ;0074 ; defb 0a5h ;0075 io port SIO A command defb 002h ;0076 count 2 defb 048h ;0077 defb 048h ;0078 ; defb 0a7h ;0079 io port SIO B command defb 002h ;007a count 2 defb 048h ;007b defb 048h ;007c ; defb 0a8h ;007d io port CTC CHANNEL 0 - Communications baud rate defb 002h ;007e count 2 defb 003h ;007f defb 003h ;0080 ; defb 0a9h ;0081 io port CTC CHANNEL 1 - AUX RS-232C baud rate defb 002h ;0082 count 2 defb 003h ;0083 defb 003h ;0084 ; defb 0aah ;0085 io port CTC CHANNEL 2 - Printer baud rate defb 002h ;0086 count 2 defb 057h ;0087 defb 04eh ;0088 ; defb 000h ;0089 io port reset defb 000h ;008a count 0 terminator set_up_crt: ;data to be output to io port B9 14 byte CRT data register defb 069h ;054f defb 050h ;0550 defb 056h ;0551 defb 00bh ;0552 defb 019h ;0553 defb 003h ;0554 defb 018h ;0555 defb 018h ;0556 defb 000h ;0557 defb 00bh ;0558 defb 020h ;0559 defb 000h ;055a defb 000h ;055b defb 000h ;055c include "inc/spt.asm" include "inc/memtestmarch.asm" include "inc/monroecon.asm" include "inc/trs80music.asm"