; PDP_MON.mac by John Monahan (S100Computers.com) ; ; Assembled with AsmPDP.exe (windows) assembler. ; Note code cannot contain BASIC names like "PRINT" (Because the compiler was written in basic). ; Best to use lower case labels. ; ; Remember most port I/O's are 8 bits wide. If you send a word to an odd port you will trigger a CPU error/exception. ; Use MOVB x,y and not MOV x,y ; ; >>> For this monitor ALL S100 bus ports range from E000H - FFFFH. (The "Normal" S100 bus address range + E000H) <<< ; ; V0.1 1/11/2017 ;Initial code ; V0.11 3/4/2017 ;Run on V0.8 prototype board ; V0.12 3/4/2017 ;Corrected byte span routines for M,V, F etc and speech synthesis. ; V0.13 3/14/2017 ;Added XModem file download capability ; V1.0 4/3/2017 ;Corrected Serial port initilization for speech synthesizer ; V1.1 6/22/2017 ;Jump table for main menu, (started on TU58 UART) ; V1.11 6/22/2017 ;For XModem, send initial NAK for Telnet Tera Term program ; V1.12 6/30/2017 ;Fill out Interrupt routines in low RAM ; V1.13 6/30/2017 ;Fixed MemMap routine (0FF RAM bytes were showing up as empty) ; V1.14 6/30/2017 ;Continous 5 second beep done using timer on PDP-11 Support board ; V1.15 7/4/2017 ;Started on TU58 UART Interrupts ; V1.15a 7/31/2017 ;More on TU58 UART Interrupts ; V1.2 8/19/2017 ;Startup direct to S100 bus Console IO ; V1.3 10/5/2017 ;Added UART interrupts,enlarged the "W" command ; V1.31 10/8/2017 ;Query Port Output/inputs with 8 or 16 bits ("B" & "O" commands) ; V1.31 10/12/2017 ;Updated Ports I/O Test routine ; V1.41 11/01/2017 ;More extensive ports tests. ; V1.42 11/01/2017 ;TU58 UART Interrupt tests ; V1.43 11/03/2017 ;CON UART Interrupt tests ; V1.5 11/15/2017 ;Added Serial Ports Test. XModem now working correctly with CPU Board UART (9600 baud, 2 stop bits) ; V2.0 11/23/2017 ;Split into High/LOW "Page", Add DEC TU58 Tape Boot Loader code ; V2.1 12/13/2017 ;Added printer routines ; V2.2 12/16/2017 ;Split into HIGH & LOW Page ; V2.3 1/25/2018 ;Added ODT Console UART on Support Board option ; V2.31 1/28/2018 ;Added Global RAM flag (CONSOLE_IO_FLAG) for Console I/O redirection ; V2.32 2/4/2018 ;Updated the Tu58 Tape boot routine to recognize BREAK* function ; V2.33 2/4/2018 ;Updated the Memory Map routine. Move Serial Port test to High Page ; V2.34 2/21/2018 ;Tape boot from Diane's (Neisius) PDP Web Page ; V2.35 5/9/2108 ;Add Display valid I/O ports to 'O' menu ; ; Since V2.0 this monitor is now duplicated into two similar but not identical ; copies. IF you have the V2 PDP11 CPU S100 Board, the 4K monitor can reside in duplicate in an ; 8K 28C64 EEPROM (or 27C64 UV-ROM). There is the "normal" lower 4K monitor where the LA13 ; address line is low. This is the "normal" state upon reset (pin 2 of U12 & U13 is low, thereby ; selecting the lower 4K half of the 8K ROM. If you are using the original S100Computers Z80 CPU board this ; this is the setup. ; If you have the newer V2 board, inputting (anything) from to port E0E4H will raise the LA13 line ; thereby selecting the top 4K of the EEPROM. Inputting from to port E0E5H will bring back ; the lower 4K section again. ; ; So, there will be two "versions" of the monitor; LOW & HIGH. The LOW version will reside ; from 0-FFFH in the 28C64 EEPROM. The HIGH version will reside from 1000H-1FFFFH in ; the same 28C64 EEPROM. Clearly there must be code common to both sections. ; The page switching code is near the start of the monitor. It is ; at the location "PAGE_CHANGE:" and uses the "X" menu command. ; ; Both versions of the monitor have most of the same menu options. The main difference (so far) is ; the "HIGH" page image has the XModem routine (Menu "C") to download files directly into RAM ; from another computer over the ODT serial port, and the ability to boot a TU58 tape OS. The "LOW" page image has ; teh ability to test IO ports and various UART IO tests. ; ; This is the same "X" menu command approach we used for our MASTER Z80 monitor. Unfortunately this trick ; leads to some confusion in the assembly code. Relative jumps can be out of range etc. To help clearify what ; sections are common and those that are unique to the HIGH/LOW pages I use different columns for each component. ;Programming a Wellon VP-290 with 28C64's EEPROMS for HIGH & LOW Pages is quite tricky. You have 4 files in all. ;Burn two ROMs Even & Odd.... ; ;For the LOW PAGE image:- ;Assemble and make a .bin file using "ROM_HIGH_PAGE: equ FALSE". ; ;Do a "normal" EEPROM burn ; ;For File Mode use "Even" and Clear Buffer Options = 0xFF ;For "Leave the "File Address(Hex) as 0000 and the "To Buffer Address (HEX) as 0000H) ;For "Auto Format Detect" use bin ;Set the File size for a 28C64 as 2000H ; ;Repeat for the Odd bytes ;For File Mode use "Odd" and Clear Buffer Options = 0xFF ;For "Leave the "File Address(Hex) as 0000 and the "To Buffer Address (HEX) as 0000H) ;For "Auto Format Detect" use bin ;Set the File size for a 28C64 as 2000H ; ;We now need to ADD to both EEPROMS code for the HIGH page starting at 1000H in the ROM. ;It must not overwrite the LOW page code above. ; ;For the HIGH PAGE image:- ;Assemble and make a .bin file using "ROM_HIGH_PAGE: equ TRUE" ; ;Insert the EVEN Byte ROM and read it. This will place the ROM bytes 0-FFFH in memory. ;Load your HIGH page .bin file with:- ;For File Mode use "Even", and Clear Buffer Options = DISABLED ;Set the "File Address(Hex) as 1000 and the "To Buffer Address (HEX) as 0000H) ;For "Auto Format Detect" use bin ;The File size for a 28C64 is 1000H ; ;Insert the ODD Byte ROM and read it. This will place the ROM bytes 0-FFFH in memory. ;Load your HIGH page .bin file with:- ;For File Mode use "Odd" and Clear Buffer Options = DISABLED ;Set the "File Address(Hex) as 1000 and the "To Buffer Address (HEX) as 0000H) ;For "Auto Format Detect" use bin ;The File size for a 28C64 is 1000H ; ; ; Note the assembler strips off the (3F)xxxx from the I/O addresses xxxx below ; ; so they edffectively become E000-FFFFH and on the S100 bus Ports 0000-1F00H ; ODT_CONIN_STAT: equ &FF70 ; &o17777560 Will be converted to 1F70H by the CPU board ODT_CONIN_DATA: equ &FF72 ; &o17777562 ODT_CONOUT_STAT: equ &FF74 ; &o17777564 ODT_CONOUT_DATA: equ &FF76 ; &o17777566 DEBUG_CONIN_STAT: equ &FF10 ; Will be converted to 1F10H by the CPU board if SB ODT UART is active DEBUG_CONIN_DATA: equ &FF12 ; DEBUG_CONOUT_STAT: equ &FF14 ; DEBUG_CONOUT_DATA: equ &FF16 ; TU58_IN_STAT: equ &FF40 ; &o17777500 Will be converted to 1F40H by the CPU board TU58_IN_DATA: equ &FF42 ; &o17777502 TU58_OUT_STAT: equ &FF44 ; &o17777504 TU58_OUT_DATA: equ &FF46 ; &o17777506 TIMER_ADDRESS: equ &3FFF66 ; &o17777546 Timer port address on Support board (FF66=1F66) PSW: equ &3FFFFE ; CPU Program status word CPU_STACK: equ &BFF0 ; Will place stack below ROMs CONSOLE_IO_FLAG: equ &BFFE ; FFFF = ALL CONSOLE IO TO ODT UART. ANYTHING ELSE THEN SEND TO S100 CONSOLE CON_CHAR_BUFFER: equ &BF80 ; Buffer location to capture characters from CONSOLE UART Interrupt CON_XMT_Flag: equ &BF7E ; RAM location for XMT flag (Byte) TU58_CHAR_BUFFER: equ &BF00 ; Buffer location to capture characters from TU58 UART Interrupt TU58_XMT_Flag: equ &BE7E ; RAM location for XMT flag (Byte) S100_CONIN_STAT: equ &E000 ; S100Computers Console IO Board In Status (translated to 0000H by CPU board) S100_CONIN_DATA: equ &E001 ; S100Computers Console IO Board In Data S100_CONOUT_STAT: equ &E000 ; S100Computers Console IO Board Out Status S100_CONOUT_DATA: equ &E001 ; S100Computers Console IO Board Out Data ACTL: equ &E0A1 ; Serial port on S100Computers Serial Board (Zilog SCC Chip) ADTA: equ &E0A3 BCTL: equ &E0A0 ; S100Computers Serial board speaker, B CTL port (Zilog SCC Chip) BDTA: equ &E0A2 ; S100Computers Speaker B data port ROM_HIGH_PORT: equ &E0E4 ; Port to shadow in ROM High Page in the PDP address space via Port E4H ROM_LOW_PORT: equ &E0E5 ; Port to shadow in ROM Low Page in the PDP address space via Port E5H SW86: equ &E0ED ; Input from this port switches the PDP back to the Z80 in hardware SW86_TM: equ &E0EE ; Output 00H switch the PDP back to Z80 Hardware (on SMB V2,V3 boards) IOBYTE: equ &E0EF ; S100Computers SMB IOBYTE Port #if ST8C4 ; If S100_Parallel_IO Board for PRINTER OUTPUT PRN_CTRL: equ &E0C2 ; ST8C4 Control Port PRN_STATUS: equ &E0C1 ; ST8C4 Status port PRN_OUT: equ &E0C0 ; ST8C4 Data port PRN_ST_LOW: equ &0D ; OUT STROBE LOW PRN_ST_HIGH: equ &0C ; OUT STROBE HIGH #else LP11_DATA: equ &FF4E ; Location for LP11 Printer data port. LP11_STATUS: equ &FF4C ; Location for LP11 Printer Status port. #endif LP11_XMT_Flag: equ &BE7C ; RAM location for Printer ACK flag (Byte) BP_SOH: EQU &0 ; XMODEM equates BP_BLK_NO: EQU &2 ; BP Offset for Recieved Sector Number for XModem BP_INV_BLK_NO: EQU &4 BP_SECT_NO: EQU &6 ; BP Offset for CURRENT SECTOR NUMBER BP_CKSUM: EQU &8 BP_TIMEOUT: EQU &A FiveSeconds: EQU &10 ; Try Modem input for a max of 5 seconds CR: equ &0D LF: equ &0A BELL: equ &07 ESC: equ &1B SPACE: equ &20 SCROLL: equ &01 ; Set scrool direction UP. BELL: equ &08 TAB: equ &09 ; TAB ACROSS (8 SPACES FOR SD-BOARD) FF: equ &0C DELETE_CHAR: equ &7F BACKS: equ &08 SOH: equ &1 ; For Modem etc. EOT: equ &4 ACK: equ &6 NAK: equ &15 BIT7: equ &80 ; &o200 BIT4: equ &10 BIT2: equ &04 BIT1: equ &02 BIT0: equ &01 ROMS: equ TRUE ; <<<<< Set to FALSE for test program running at 1000H in RAM (10000 Octal) >>>>> DETAILED_INTS: equ TRUE ; Set to TRUE for detailed UART Interrupt data display. (Note characters must be entered slowly) ST8C4: equ FALSE ; FALSE if LP11 Printer output. TRUE (only) if output is to the S100_Parallel_IO Board. S100_ONLY: equ FALSE ; <----- If TRUE will skip checking to see if console IO should go to the UART ; will always sent to Console IO board (Switch K10 is ignored on the CPU board). ODT_ONLY: equ FALSE ; <----- If TRUE will skip checking and always send console IO to the ODT UART #if ROMS ORG &C000 ; Location of default onboard ROMS (&o140000) #else ORG &1000 ; Locate at 1000H for testing (Above PDP11 traps etc) #endif ;_______________________________________________________________________________________________________________________ ; Start: MOV #CPU_STACK,SP ; LOW ROM & HIGH PAGEs: Setup stack at BF00H (Below ROM ORG at C000H) MOV #&00E0,@#PSW ; Block ALL Interrupts (Clear bits 7-5) JMP SKIP Align ACTIVATE_HIGH_PAGE: ; SWITCH TO HIGH PAGE ROM MOVB @#ROM_HIGH_PORT,R1 ; Switch the LA13 Address line input to the ROMs HIGH. MUST be to an even byte JMP NoHighPageError ; Will arrive here only IF no address line LA13 switch. Must be inactive (Check JP K12) Align ACTIVATE_LOW_PAGE: ; RETURN BACK TO LOW PAGE ROM NOP NOP ; Not used JMP Loop1 ; <---- Switching back to LOW page will arrive here ;_________________________________THE ABOVE CODE MUST NOT BE CHANGED __________________________________________________ ; SKIP: JSR PC,Set_CONSOLE_IO ; Set Flag for Console IO to ODT UART or S100 Bus MOV #Signon,R5 ; Point to Signon Message JSR PC,PrStr ; Print string MOV SP,R5 ; Show current SP JSR PC,PutWord_R5 MOV #Signon1,R5 ; Point to Signon Message finish JSR PC,PrStr ; Print string Loop1: MOV #MainMenu,R5 ; Point to Main Menu JSR PC,PrStr ; Print string Align Loop: JSR PC,Set_CONSOLE_IO ; Update Flag for Console IO to ODT UART or S100 Bus JSR PC,ConCRLF ; <<<<< THE MAIN MENU LOOP >>>>> MOV #&3E,R0 ; Print '>' JSR PC,CONSOLE_OUT JSR PC,CONSOLE_IN ; Get a menu character (WITH ECHO) to R0 JSR PC,ToUpper ; a-z to A-Z JSR PC,CONSOLE_OUT ; Echo CMP R0,#&40 BLE MenuError CMP R0,#&5A BHI MenuError MOV R0,R1 SUB #&41,R1 ; A-Z ROL R1 ; X2 MOV #JMP_TABLE,R5 ADD R1,R5 MOV (R5),PC JMP Loop ; Just in case Align JMP_TABLE: ; For main Menu commands equw MemMap ; "A" Mem Map equw QPorts_B ; "B" Query Ports (Bytes) equw XModem ; "C", XModem [High page #1] equw DisplayRAM ; "D", Display RAM equw Echo ; "E", Echo equw FillRAMB ; "F", Fill RAM (Bytes) equw RAM_ADDRESS ; "G", GOTO an Address equw FillRAMW ` ; "H", Fill RAM (Words) equw IOByte ; "I", IO Byte equw TU58_OS_BOOT ; "J" Boot tape drive equw DisplayMenu ; "K", CR,LF,Display Menu equw Timer_Test ; "L" Timer Test equw MoveRAM ; "M", Move RAM equw DisplayRAMW ; "N" Display RAM in words equw IO_Tests ; "O" IO Ports test [High page #0] equw TestSerial ; "P" Test Serial Port [High page #2] equw QPorts_W ; "Q", Query Ports (Words) equw IntsOn ; "R" Setup Int vector table AND turn on equw SubsRAMB ; "S", Subs RAM (Byte) equw ARAM ; "T", Ascii in RAM equw Talk ; "U" speaker test equw VerifyRAM ; "V", Verify RAM equw TU58_Menu ; "W", TU58 menu equw NotDone ; "X" Spare equw IntsOff ; "Y" Inactivate ALL interrupts equw ReturnZ80 ; "Z", CR,LF,Return to Z80 Align NotDone: MOV #NotDoneMsg,R5 ; Point to CMD not done yet Message JSR PC,PrStr ; Print string LoopDone: JMP Loop Align IO_Tests: MOVB #&0,R3 ; Jumps to HIGH PAGE code with 0 in R2 (See PDP_MON_HIGH_PAGE.MAC) JMP ACTIVATE_HIGH_PAGE Align XModem: MOVB #&1,R3 ; Jumps to HIGH PAGE code with 1 in R2 (See PDP_MON_HIGH_PAGE.MAC) JMP ACTIVATE_HIGH_PAGE Align TestSerial: MOVB #&2,R3 ; Jumps to HIGH PAGE code with 2 in R2 (See PDP_MON_HIGH_PAGE.MAC) JMP ACTIVATE_HIGH_PAGE MenuError: MOV #Menu_Error,R5 ; Point Error Message JSR PC,PrStr ; Print string JMP Loop NoHighPageError: MOV #NoHighPageMsg,R5 ; "No address line LA13 switch active" JSR PC,PrStr ; Print string JMP Loop ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> MENU COMMAND ROUTINES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< MemMap: ; Menu A command MOV #MM_Text,R5 ; Point to MemMap Message JSR PC,PrStr ; Print string MOV #0,R5 ; Set up start address MOV #16,R4 ; Characters across count Map1: JSR PC,PutWord_R5 ; Print HEX word value in R5 Map2: MOV #SPACE,R0 JSR PC,CONSOLE_OUT ; Send a space NotEmpty: MOV (R5),R0 ; Bring in the data MOV R0,R1 ; Store it MOV R0,R2 ; Also store it here INC R2 INC (R5) ; Inc RAM WORD CMP R2,(R5) ; Did if increase BNE IsROM ; Must be ROM (or Empty) MOV R1,(R5) ; Put back the origional data MOV #&52,R0 JSR PC,CONSOLE_OUT ; Send a 'R' BR Map3 IsROM: CMP #&FFFF,(R5) ; Is it Empty BNE NEmpty CMP #&FFFF,2(R5) ; Check next higher word BNE NotEmpty CMP #&FFFF,4(R5) ; Check next higher word BNE NotEmpty MOV #&2E,R0 ; Probably not RAM or ROM JSR PC,CONSOLE_OUT ; Send a '.' BR Map3 NEmpty: CMP #&C000,R5 ; Are we in the PDP Monitor ROM area BEQ ROM_AREA CMP #&E000,R5 ; Are we in the PDP Monitor ROM area BEQ PORTS_AREA MOV #&70,R0 JSR PC,CONSOLE_OUT ; Send a 'p' Map3: ADD #&100,R5 ; Next 100H bytes DEC R4 ; Count characters across BNE Map2 JSR PC,ConCRLF ; Show CR,LF MOV #16,R4 ; Characters across count BR Map1 ROM_AREA: MOV #ROM_AREA_MSG,R5 ; Say "--- ROM MONITOR ---" JSR PC,PrStr ; Print string JMP Loop PORTS_AREA: MOV #PORTS_AREA_MSG,R5 ; Say --- I/O PORTS ---" JSR PC,PrStr ; Print string JMP Loop ; ----------------------------- DISPLAY MENU ---------------------------------------------- DisplayMenu: JSR PC,ConCRLF ; Show CR,LF MOV #MainMenu,R5 ; Point to Main Menu JSR PC,PrStr ; Print string JMP Loop ; ----------------------------- DISPLAY RAM BYTES ---------------------------------------------- DisplayRAM: ; Menu D command JSR PC,GetWord_R5 CMPB #ESC,R0 BEQ DisplayError ; Abort if ESC returned MOV R5,R3 ; Store start location in R3 JSR PC,GetWord_R5 CMPB #ESC,R0 BEQ DisplayError ; Abort if ESC returned CMPB #CR,R0 BNE DisplayError ; Abort if not CR set MOV R5,R4 ; Store end location in R4 CMP R3,R4 BEQ DisplayError ; If the same abort RAM1: JSR PC,ConCheckESC ; Was the ESC key pressed CMPB #ESC,R0 BEQ DisplayError JSR PC,ConCRLF ; Show CR,LF MOV R3,R5 JSR PC,PutWord_R5 JSR PC,ConSPACE2 ; Send 2 SPACEs MOV #16,R1 ; Bytes across count RAM2: MOVB (R3)+,R5 ; <<<< NOTE BYTE >>>>> JSR PC,PutByte_R5 JSR PC,ConSPACE1 ; Send 1 SPACE DECB R1 TSTB R1 BNE RAM2 CMP R4,R3 ; Are we there yet (note unsigned compare) BHI RAM1 DisplayError: JSR PC,ConCRLF ; Show CR,LF JMP Loop ; ----------------------------- DISPLAY RAM WORDS ---------------------------------------------- DisplayRAMW: ; Menu N command JSR PC,GetWord_R5 CMPB #ESC,R0 BEQ DisplayError ; Abort if ESC returned MOV R5,R3 ; Store start location in R3 JSR PC,GetWord_R5 CMPB #ESC,R0 BEQ DisplayError ; Abort if ESC returned CMPB #CR,R0 BNE DisplayError ; Abort if not CR set MOV R5,R4 ; Store end location in R4 CMP R3,R4 BEQ DisplayError ; If the same abort RAM1: JSR PC,ConCheckESC ; Was the ESC key pressed CMPB #ESC,R0 BEQ DisplayError JSR PC,ConCRLF ; Show CR,LF MOV R3,R5 JSR PC,PutWord_R5 JSR PC,ConSPACE2 ; Send 2 SPACEs MOV #8,R1 ; 2X Bytes across count RAM2: MOV (R3)+,R5 ; <<< NOTE WORD >>>>>>> JSR PC,PutWord_R5 JSR PC,ConSPACE1 ; Send 1 SPACE DECB R1 TSTB R1 BNE RAM2 CMP R4,R3 ; Are we there yet (note unsigned compare) BHI RAM1 DisplayError: JSR PC,ConCRLF ; Show CR,LF JMP Loop ; ----------------------------- DISPLAY MEMORY ASCII ---------------------------------------------- ARAM: ; Menu T command (Display ASCII in RAM) JSR PC,GetWord_R5 CMPB #ESC,R0 BEQ AError ; Abort if ESC returned MOV R5,R3 ; Store start location in R3 JSR PC,GetWord_R5 CMPB #ESC,R0 BEQ AError ; Abort if ESC returned CMPB #CR,R0 BNE AError ; Abort if not CR set MOV R5,R4 ; Store end location in R4 CMP R3,R4 BEQ AError ; If the same abort ARAM1: JSR PC,ConCheckESC ; Was the ESC key pressed CMPB #ESC,R0 BEQ AError JSR PC,ConCRLF ; Show CR,LF MOV R3,R5 JSR PC,PutWord_R5 JSR PC,ConSPACE2 ; Send 2 SPACEs MOV #64,R1 ; Bytes across count (This will be a minimum!) ARAM2: MOVB (R3)+,R0 CMP #&20,R0 BGE ARAM3 CMP #&7f,R0 BEQ ARAM3 ARAM5: JSR PC,CONSOLE_OUT BR ARAM4 ARAM3: MOVB #&2E,R0 ; Use '.' for non text characters BR ARAM5 ARAM4: DECB R1 TSTB R1 BNE ARAM2 CMP R4,R3 ; Are we there yet (note unsigned compare) BHI ARAM1 AError: JSR PC,ConCRLF ; Show CR,LF JMP Loop Echo: ; Menu E command MOV #Echo_Text,R5 ; Point to MemMap Message JSR PC,PrStr ; Print string Echo1: JSR PC,CONSOLE_IN CMPB #ESC,R0 ; Was an abort requested BEQ EchoDone JSR PC,CONSOLE_OUT ; Echo data BR Echo1 EchoDone: JMP Loop ; ----------------------------- FILL RAM WORDS ---------------------------------------------- FillRAMW: ; Menu H command (Fill RAM, words) JSR PC,GetWord_R5 CMPB #ESC,R0 BEQ FillError ; Abort if ESC returned MOV R5,R3 ; Store start location in R3 JSR PC,GetWord_R5 CMPB #ESC,R0 BEQ FillError ; Abort if ESC returned MOV R5,R4 ; Store end location in R4 JSR PC,GetWord_R5 CMPB #ESC,R0 BEQ FillError ; Abort if ESC returned MOV R5,R2 ; Store Fill word in R2 CMP R3,R4 BEQ FillError ; If the same abort Fill2: MOV R2,(R3)+ ; Fill one word (only) CMP R4,R3 ; Are we there yet (note unsigned compare) BHI Fill2 FillError: JSR PC,ConCRLF ; Show CR,LF JMP Loop ; ----------------------------- FILL RAM BYTES ---------------------------------------------- FillRAMB: ; Menu F command (Fill RAM, bytes) JSR PC,GetWord_R5 CMPB #ESC,R0 BEQ FillError ; Abort if ESC returned MOV R5,R3 ; Store start location in R3 JSR PC,GetWord_R5 CMPB #ESC,R0 BEQ FillError ; Abort if ESC returned MOV R5,R4 ; Store end location in R4 JSR PC,GetByte_R5 CMPB #ESC,R0 BEQ FillError ; Abort if ESC returned MOVB R5,R2 ; Store Fill word in R2 CMP R3,R4 BEQ FillError ; If the same abort Fill3: MOVB R2,(R3)+ ; Fill one byte (only) CMP R4,R3 ; Are we there yet (note unsigned compare) BHI Fill3 BR FillError ; ----------------------------- MOVE RAM ---------------------------------------------- MoveRAM: ; Menu M command JSR PC,GetWord_R5 CMPB #ESC,R0 BEQ MoveError ; Abort if ESC returned MOV R5,R3 ; Store start location in R3 JSR PC,GetWord_R5 CMPB #ESC,R0 BEQ MoveError ; Abort if ESC returned MOV R5,R4 ; Store end location in R4 JSR PC,GetWord_R5 CMPB #ESC,R0 BEQ MoveError ; Abort if ESC returned MOV R5,R2 ; Store new location in R2 CMP R3,R4 BEQ MoveError ; If the same abort CMP R3,R2 BEQ MoveError ; If the same abort Move2: MOVB (R3)+,(R2)+ ; Move one byte at a time CMP R4,R3 ; Are we there yet (note unsigned compare) BHI Move2 MoveError: JSR PC,ConCRLF ; Show CR,LF JMP Loop ; ----------------------------- VERIFY RAM ---------------------------------------------- VerifyRAM: ; Menu M command JSR PC,GetWord_R5 CMPB #ESC,R0 BIC #&01,R5 ; Round down to even boundry MOV R5,R3 ; Store start location in R3 JSR PC,GetWord_R5 CMPB #ESC,R0 BEQ VerifyError ; Abort if ESC returned MOV R5,R4 ; Store end location in R4 JSR PC,GetWord_R5 CMPB #ESC,R0 BEQ VerifyError ; Abort if ESC returned MOV R5,R2 ; Store new location in R2 CMP R3,R4 BEQ VerifyError ; If the same abort CMP R3,R2 BEQ VerifyError ; If the same abort Ver2: JSR PC,ConCheckESC ; Was the ESC key pressed CMPB #ESC,R0 BEQ VerifyError CMPB (R3)+,(R2)+ BNE MisMatch Ver3: CMP R4,R3 ; Are we there yet (note unsigned compare) BHI Ver2 VerifyError: JSR PC,ConCRLF ; Show CR,LF JMP Loop MisMatch: MOV #VerMsg0,R5 ; Print "Mismatch found at " JSR PC,PrStr ; Print string DEC R3 MOV R3,R5 INC R3 JSR PC,PutWord_R5 MOV #VerMsg3,R5 ; Print "H,CR,LF" JSR PC,PrStr ; Print string JMP Ver3 ; Go to next byte ; ----------------------------- SUBSTITUTE RAM BYTES ---------------------------------------------- SubsRAMB: ; Menu S command (Subs RAM Bytes) JSR PC,GetWord_R5 CMPB #ESC,R0 BEQ SubsErrorB ; Abort if ESC returned MOV R5,R3 ; Store start location in R3 SubsB1: MOV #&8,R4 ; Store char count in R4 JSR PC,ConCRLF ; Show CR,LF MOV R3,R5 JSR PC,PutWord_R5 ; Show current location JSR PC,ConSPACE1 SubsB2: MOVB (R3),R5 JSR PC,PutByte_R5 ; Show current value JSR PC,ConSPACE1 JSR PC,GetByte_R5 ; Get new value (Byte) CMPB #ESC,R0 BEQ SubsErrorB ; Abort if ESC returned CMPB #SPACE,R0 ; Continue if a space BEQ SubsB3 CMPB #CR,R0 ; Continue if a CR BNE SubsB4 SubsB3: JSR PC,ConSPACE1 SubsB4: MOVB R5,(R3)+ DEC R4 BEQ SubsB1 BR SubsB2 SubsErrorB: JSR PC,ConCRLF ; Show CR,LF JMP Loop ; ----------------------------- SUBSTITUTE RAM WORDS ---------------------------------------------- SubsRAMW: ; Menu S command (Subs RAM Words) JSR PC,GetWord_R5 CMPB #ESC,R0 BEQ SubsErrorW ; Abort if ESC returned MOV R5,R3 ; Store start location in R3 SubsW1: MOV #&8,R4 ; Store char count in R4 JSR PC,ConCRLF ; Show CR,LF MOV R3,R5 JSR PC,PutWord_R5 ; Show current location JSR PC,ConSPACE1 SubsW2: MOV (R3),R5 JSR PC,PutWord_R5 ; Show current value JSR PC,ConSPACE1 JSR PC,GetWord_R5 ; Get new value (word) CMPB #ESC,R0 BEQ SubsErrorW ; Abort if ESC returned CMPB #SPACE,R0 ; Continue if a space BEQ SubsW3 CMPB #CR,R0 ; Continue if a CR BNE SubsW3 JSR PC,ConSPACE1 SubsW3: MOV R5,(R3)+ DEC R4 BEQ SubsW1 BR SubsW2 SubsErrorW: JSR PC,ConCRLF ; Show CR,LF JMP Loop ; ----------------------------- QUERY PORTS ---------------------------------------------- QPorts_B: ; Menu B command use "BI,port# of BO,port #,byte" JSR PC,CONSOLE_IN ; Get a menu character (WITH ECHO) to R0 JSR PC,ToUpper ; a-z to A-Z JSR PC,CONSOLE_OUT ; Echo CMPB #&49,R0 ; 'I' BEQ InPort_B CMPB #&4F,R0 ; 'O' BEQ OutPort_B MOV #&3F,R0 ; '?' JSR PC,CONSOLE_OUT JSR PC,ConCRLF ; Show CR,LF JMP Loop InPort_B: JSR PC,GetWord_R5 ; Get port number (note, WORD) CMPB #ESC,R0 BEQ PortError ; Abort if ESC returned MOVB (R5),R4 ; In Port to R4 reg (note, BYTE) MOV #VerMsg2,R5 ; Print " = " JSR PC,PrStr ; Print string MOV R4,R5 ; Get back port # JSR PC,PutByte_R5 MOV #VerMsg3,R5 ; Print "H ",CR,LF JSR PC,PrStr ; Print string JMP Loop PortError: JSR PC,ConCRLF ; Show CR,LF JMP Loop OutPort_B: JSR PC,GetWord_R5 ; Get port number (note, WORD) CMPB #ESC,R0 BEQ PortError ; Abort if ESC returned MOV R5,R4 ; Store Out Port in R4 JSR PC,GetByte_R5 ; Get Byte value to be sent to port (R4) CMPB #ESC,R0 BEQ PortError ; Abort if ESC returned MOVB R5,(R4) ; (note, BYTE) JMP Loop QPorts_W: ; Menu Q command use "QI,port# of QO,port #,word" JSR PC,CONSOLE_IN ; Get a menu character (WITH ECHO) to R0 JSR PC,ToUpper ; a-z to A-Z JSR PC,CONSOLE_OUT ; Echo CMPB #&49,R0 ; 'I' BEQ InPort_W CMPB #&4F,R0 ; 'O' BEQ OutPort_W MOV #&3F,R0 ; '?' JSR PC,CONSOLE_OUT JSR PC,ConCRLF ; Show CR,LF JMP Loop InPort_W: JSR PC,GetWord_R5 ; Get port number (note, WORD) CMPB #ESC,R0 BEQ PortError ; Abort if ESC returned MOV (R5),R4 ; In Port to R4 reg (note, WORD) MOV #VerMsg2,R5 ; Print " = " JSR PC,PrStr ; Print string MOV R4,R5 ; Get back port # JSR PC,PutWord_R5 MOV #VerMsg3,R5 ; Print "H ",CR,LF JSR PC,PrStr ; Print string JMP Loop OutPort_W: JSR PC,GetWord_R5 ; Get port number (note, WORD) CMPB #ESC,R0 BEQ PortError ; Abort if ESC returned BITB #BIT0,R5 ; Check bit0 is 0 (Even address only for words) BNE ODD_ADDRESS MOV R5,R4 ; Store Out Port in R4 JSR PC,GetWord_R5 ; Get Word value to be sent to port (R4) CMPB #ESC,R0 BEQ PortError ; Abort if ESC returned MOV R5,(R4) ;(note, WORD) JMP Loop ODD_ADDRESS: MOV #OddAddressMsg,R5 ; Print "Port must be an an even address",CR,LF JSR PC,PrStr ; Print string JMP PortError ; ----------------------------- RETURN TO Z80 COMMAND ---------------------------------------------- ReturnZ80: ; Menu 'Z' Command. (Return to Z80) MOV #Z80Msg,R5 ; Show going back to Z80 JSR PC,PrStr ; Print string MOVB @#(SW86),R0 ; This switches control back over to Z80 (Old SMB) MOVB #0,R0 ; Or reset TMA-O back to Z80 control. (New V3 SMB) MOVB R0,@#(SW86_TM) MOV #10000,R0 Z80A: DEC R0 ; Slight delay -- just in case BNE Z80A JMP Loop ; ----------------------------- IOBYTE COMMAND ---------------------------------------------- IOByte: ; Menu 'I' Command (Display IOByte) MOV #IOByteMsg,R5 ; Show IO Byte Msg JSR PC,PrStr ; Print string MOVB @#(IOBYTE),R5 JSR PC,PutBits_R5 JSR PC,ConCRLF JMP Loop ; ----------------------------- TEST SPEECH SYNTHIZER ---------------------------------------------- Talk: ; Menu 'U' command (Speaker systhesis test) MOV #WillSpeak,R5 ; Show speech string to be sent JSR PC,PrStr ; Print string JSR PC,InitSerialB ; Initilize serial port B MOV #BCTL,R5 ; Note all ports are E000H + Port# MOVB (R5),R0 ; CMPB #&C5,R0 ; Check port is valid (Possibly other values are also fine, you can comment out if necessary) ; BNE TalkError MOV #TestSpeak,R5 ; Pick up test speech string in R5 JSR PC,SpeakStr ; Talk string JMP Loop TalkError: MOV #BadPort,R5 ; Print "Port Inactive " JSR PC,PrStr ; Print string JMP Loop ; ----------------------------- UART & PRINTER Test Routines (HIGH PAGE) -------------------------- Align TU58_Menu: MOV #TU58_MenuString,R5 ; Point to TU58 Menu JSR PC,PrStr ; Print string JSR PC,ConCRLF ; Show CR,LF MOV #&3E,R0 ; Print '>' JSR PC,CONSOLE_OUT JSR PC,CONSOLE_IN ; Get a menu character (WITH ECHO) to R0 JSR PC,ToUpper ; a-z to A-Z MOV R0,R1 CMPB #ESC,R0 BEQ TU58_Loop1 JSR PC,CONSOLE_OUT ; Echo TU58B: CMP R1,#&40 ; Test ASCII A - O BLE TU58_MenuError CMP R1,#&50 ; BHI TU58_MenuError SUB #&41,R1 ; A-O ROL R1 ; X2 MOV #TU58_TABLE,R5 ADD R1,R5 MOV (R5),PC ; Always, jump to routine TU58_MenuError: MOV #TU58_Menu_Error,R5 ; "Not a valid Tu58 menu Option" JSR PC,PrStr ; Print string TU58_Loop1: JMP ACTIVATE_LOW_PAGE ; Back to low page Align TU58_TABLE: ; For main Menu commands equw TU58_Out_Test ; "A", Send '3's' continously to TU58 UART equw TU58_In_Test ; "B", TU58 UART input test (Status bit only) equw TU58_Echo_Test ; "C", TU58 UART Output test (Using status bits) equw ODT_Out_Test ; "D", Send 3's continously to ODT UART equw ODT_In_Test ; "E", Input character from ODT UART (Using status bit) equw ODT_Echo_Test ; "F" Output keyboard characters on ODT UART (Using status bits) equw TU58_INT_In_Test ; "G", TU58 UART input test (Interrupt test) equw TU58_INT_Out_Test ; "H", TU58 UART output test (Interrupt test) equw CON_INT_In_Test ; "I", CONSOLE UART input test (Interrupt test) equw CON_INT_Out_Test ; "J", CONSOLE UART output test (Interrupt test) equw TestPrinter ; "K" In Memu routine to test printer equw TestPrinterInt ; "L" In Memu routine to test printer (Interrupt test) equw DEBUG_Out_Test ; "M", Send '3's' continously to TU58 UART equw DEBUG_In_Test ; "N", TU58 UART input test (Status bit only) equw DEBUG_Echo_Test ; "O", TU58 UART Output test (Using status bits) TU58_Out_Test: ; TU58 Menu 'A' Command (Send ASCII character '3' to TU58 UART) MOV #UART_OUT_Msg,R5 ; Say "Send character '3' to UART OUT_DATA port, 80 times." JSR PC,PrStr ; Print string MOV #81,R4 ; Do 80 characters TU58_Out_Test1: DEC R4 BEQ TU58_Test_Done MOV #&33,R0 JSR PC,TU58_UART_OUT BR TU58_Out_Test1 TU58_Test_Done: MOV #CMD_Done,R5 ; "Test Done" JSR PC,PrStr ; Print string JMP TU58_Menu TU58_In_Test: ; "Menu B", TU58 UART input test (Status check only) MOV #UART_IN_Msg,R5 ; Say "Input characters from UART IN_DATA port. ESC to Abort" JSR PC,PrStr ; Print string TU58_In_Test1: JSR PC,TU58_UART_IN CMPB #ESC,R0 BEQ TU58_Test_Done ; Abort if ESC returned JSR PC,CONSOLE_OUT BR TU58_In_Test1 TU58_Echo_Test: ; "Menu C", TU58 UART Send characters to UART MOV #UART_Echo_Msg,R5 ; Say "Send characters on UART. ESC to Abort (Status Driven)" JSR PC,PrStr ; Print string TU58_Echo_Test1: JSR PC,CONSOLE_IN CMPB #ESC,R0 BEQ TU58_Test_Done ; Abort if ESC returned JSR PC,TU58_UART_OUT ; Echo back character JMP TU58_Echo_Test1 TU58_In_Test_Done: MOV #CMD_Done,R5 ; "Test Done" JSR PC,PrStr ; Print string JMP TU58_Menu ODT_Out_Test: ; TU58 Menu 'D' Command (Send ASCII cgaracter '3' to ODT UART) MOV #ODT_OUT_Msg,R5 ; Say "Send character '3' to UART OUT_DATA port, 80 times" JSR PC,PrStr ; Print string MOV #81,R4 ; Do 80 characters ODT_Out_Test1: DEC R4 BEQ ODT_Out_Test_Done MOV #&33,R0 JSR PC,ODT_CONSOLE_OUT BR ODT_Out_Test1 ODT_Out_Test_Done: MOV #CMD_Done,R5 ; "Test Done" JSR PC,PrStr ; Print string JMP TU58_Menu ODT_In_Test: ; "TU58 Menu 'E', ODT UART input test (Status check only) MOV #ODT_IN_Msg,R5 ; Say "Input characters from UART IN_DATA port. ESC to Abort" JSR PC,PrStr ; Print string ODT_In_Test1: JSR PC,ODT_CONSOLE_IN CMPB #ESC,R0 BEQ ODT_In_Test_Done ; Abort if ESC returned JSR PC,CONSOLE_OUT BR ODT_In_Test1 ODT_Echo_Test: ; "TU58 Menu 'F', ODT UART Echo test MOV #ODT_Echo_Msg,R5 ; Say "Send characters on UART. ESC to Abort (Status Driven)" JSR PC,PrStr ; Print string ODT_Echo_Test1: JSR PC,CONSOLE_IN CMPB #ESC,R0 BEQ ODT_In_Test_Done ; Abort if ESC returned JSR PC,ODT_CONSOLE_OUT ; Echo back character JMP ODT_Echo_Test1 ODT_In_Test_Done: MOV #CMD_Done,R5 ; "Test Done" JSR PC,PrStr ; Print string JMP TU58_Menu ; <<<<<<<<<<<<<< TU58 INTERRUPT DRIVEN TESTS >>>>>>>>>>>>>>>>> TU58_INT_In_Test: ; "TU58 Menu 'G', TU58 UART Input test >> WITH INTERRUPTS << MOV #ActivateInInt,R5 ; Say "we are activating the UART RCV Interrupt" JSR PC,PrStr ; Print string MOV #TU58_CHAR_BUFFER,R0 ;<--- A buffer routine is not done yet! MOV #&80,R1 Cint0: MOVB #0,(R0)+ ; Clear buffer area DEC R1 TSTB R1 BNE Cint0 MOV #TU58_CHAR_BUFFER,R0 MOV R0,(R0) ; Save buffer pointer in first word of buffer JSR PC,Setup_Activate_Ints MOV #ActivateInPort,R5 ; Say "we are activating the UART RCV Enable bit" JSR PC,PrStr MOV #&40,TU58_IN_STAT MOV #Ints_In_Ready,R5 ; Say "Monitoring RCV Interrupt characters arriving from UART. ESC to abort" JSR PC,PrStr JSR PC,ConCRLF ; Show CR,LF ; >>>>>>>> LOOP <<<<<<<<<<< Cint1: JSR PC,S100_ConCheckESC ; Tight loop while waiting for interrupt at 38H, ESC to abort BCS Cint2 ; If ESC entered then abort MOVB #&2E,R0 JSR PC,CONSOLE_OUT ; Put a '.' character on screen BR Cint1 ; >>>>>>>> LOOP <<<<<<<<<<< Cint2: JSR PC,ConCRLF ; Send CR,LF MOV #Off_Ints_Msg,R5 ; Say "All interrupts off. Timer Inactivated" JSR PC,PrStr ; Print string MOV #&00E0,@#PSW ; Block ALL Interrupts (Set bits 7-5) MOV #&0,R0 ; <--- Pulse bit 6 LOW MOVB R0,@#TIMER_ADDRESS JMP TU58_Menu ; Back to main TU58 Menu TU58_INT_Out_Test: ; "TU58 Menu 'H', TU58 UART Output test >> WITH INTERRUPTS << MOV #ActivateOutInt,R5 ; Say "Activating UART XMT Interrupt (Also Timer Interrupts)." JSR PC,PrStr ; Print string MOV #TU58_CHAR_BUFFER,R0 ; <-- A buffer routine is not done yet! MOV #&80,R1 Cint3: MOVB #0,(R0)+ ; Clear buffer area DEC R1 TSTB R1 BNE Cint3 MOV #TU58_CHAR_BUFFER,R0 MOV R0,(R0) ; Save buffer pointer in first word of buffer MOVB #&0,@#TU58_XMT_Flag ; Clear flag that indicates the TU58 UART can send another character JSR PC,Setup_Activate_Ints MOV #ActivateOutPort,R5 ; Say "Activating UART XMT enable bit" JSR PC,PrStr MOV #&40,TU58_OUT_STAT MOV #Ints_Out_Ready,R5 ; "Monitoring XMT Interrupt characters to UART. ESC to abort. Enter character" JSR PC,PrStr ; Print string JSR PC,ConCRLF ; >>>>>>>> LOOP <<<<<<<<<<< Cint4: JSR PC,CONSOLE_IN ; Loop to send character to UART CMPB #ESC,R0 BEQ Cint5 ; If ESC entered then abort MOV R0,R1 ; Store character Cint6: CMPB #&0,@#TU58_XMT_Flag ; Is XMT on UART ready to send another character BEQ Cint7 ; If ready do it MOV #UART_BusyMsg,R5 ; Say "UART XMT Flag = Busy" JSR PC,PrStr BR Cint6 Cint7: MOVB #&0ff,@#TU58_XMT_Flag ; Set flag that indicates the TU58 UART CANNOT send another character - yet MOV R1,R0 MOVB R0,@#TU58_OUT_DATA ; Send Character in R0 to TU58 UART JSR PC,CONSOLE_OUT ; Also place on Console BR Cint4 ; >>>>>>>> LOOP <<<<<<<<<<< Cint5: JSR PC,ConCRLF ; Send CR,LF MOV #Off_Ints_Msg,R5 ; Say "All interrupts off. Timer Inactivated" JSR PC,PrStr ; Print string MOV #&00E0,@#PSW ; Block ALL Interrupts (Set bits 7-5) MOV #&0,R0 ; <--- Pulse bit 6 LOW MOVB R0,@#TIMER_ADDRESS JMP TU58_Menu ; Back to main TU58 Menu CON_INT_In_Test: ; "Menu I", V2 CPU Board UART Input test >> WITH INTERRUPTS << MOV #ActivateInInt,R5 ; Say "we are activating the UART RCV Interrupt" JSR PC,PrStr ; Print string MOV #CON_CHAR_BUFFER,R0 ; <--- A buffer routine is not done yet! MOV #&80,R1 CintA: MOVB #0,(R0)+ ; Clear buffer area DEC R1 TSTB R1 BNE CintA MOV #CON_CHAR_BUFFER,R0 MOV R0,(R0) ; Save buffer pointer in first word of buffer JSR PC,Setup_Activate_Ints MOV #ActivateInPort,R5 ; Say "we are activating UART RCV Enable bit" JSR PC,PrStr MOV #&40,ODT_CONIN_STAT MOV #Ints_In_Ready,R5 ; Say "Monitoring RCV Interrupt characters arriving from UART. ESC to abort" JSR PC,PrStr JSR PC,ConCRLF ; Show CR,LF ; >>>>>>>> LOOP <<<<<<<<<<< CintB: JSR PC,S100_ConCheckESC ; Tight loop while waiting for interrupt at 30H, ESC to abort BCS CintC ; If ESC entered then abort MOVB #&2E,R0 JSR PC,CONSOLE_OUT ; Put a '.' character on screen BR CintB ; >>>>>>>> LOOP <<<<<<<<<<< CintC: JSR PC,ConCRLF ; Send CR,LF MOV #Off_Ints_Msg,R5 ; Say "All interrupts off. Timer Inactivated" JSR PC,PrStr ; Print string MOV #&00E0,@#PSW ; Block ALL Interrupts (Set bits 7-5) MOV #&0,R0 ; <--- Pulse bit 6 LOW MOVB R0,@#TIMER_ADDRESS JMP TU58_Menu ; Back to main TU58 Menu CON_INT_Out_Test: ; "TU58 Menu 'J', ODT UART Output test >> WITH INTERRUPTS << MOV #ActivateOutInt,R5 ; Say "Activating UART XMT Interrupt (Also Timer Interrupts)." JSR PC,PrStr ; Print string MOV #CON_CHAR_BUFFER,R0 ; <-- A buffer routine is not done yet! MOV #&80,R1 CintD: MOVB #0,(R0)+ ; Clear buffer area DEC R1 TSTB R1 BNE CintD MOV #CON_CHAR_BUFFER,R0 MOV R0,(R0) ; Save buffer pointer in first word of buffer MOVB #&0,@#CON_XMT_Flag ; Clear flag that indicates the TU58 UART can send another character JSR PC,Setup_Activate_Ints MOV #ActivateOutPort,R5 ; Say "Activating UART XMT enable bit" JSR PC,PrStr MOV #&40,ODT_CONOUT_STAT MOV #Ints_Out_Ready,R5 ; "Monitoring XMT Interrupt characters to UART. ESC to abort. Enter character" JSR PC,PrStr ; Print string JSR PC,ConCRLF ; >>>>>>>> LOOP <<<<<<<<<<< CintE: JSR PC,CONSOLE_IN ; Loop to send character to UART CMPB #ESC,R0 BEQ CintF ; If ESC entered then abort MOV R0,R1 ; Store character CintG: CMPB #&0,@#CON_XMT_Flag ; Is XMT on UART ready to send another character BEQ CintH ; If ready do it MOV #UART_BusyMsg,R5 ; Say "UART XMT Flag = Busy" JSR PC,PrStr BR CintG CintH: MOVB #&0ff,@#CON_XMT_Flag ; Set flag that indicates the TU58 UART CANNOT send another character - yet MOV R1,R0 MOVB R0,@#ODT_CONOUT_DATA ; Send Character in R0 to CONSOLE UART JSR PC,CONSOLE_OUT ; Also place on Console BR CintE CintF: JSR PC,ConCRLF ; Send CR,LF MOV #Off_Ints_Msg,R5 ; Say "All interrupts off. Timer Inactivated" JSR PC,PrStr ; Print string MOV #&00E0,@#PSW ; Block ALL Interrupts (Set bits 7-5) MOV #&0,R0 ; <--- Pulse bit 6 LOW MOVB R0,@#TIMER_ADDRESS JMP TU58_Menu ; Back to main TU58 Menu TestPrinter: ; TU58 Menu 'K' Command (Send ASCII characters to Printer) MOV #PrnOutMsg,R5 ; Say "Send characters to printer" JSR PC,PrStr ; Print string #if ST8C4 ; If S100_Parallel_IO Board for PRINTER OUTPUT MOVB #&08,@#PRN_CTRL ; Initilize the ST8C4 PC-Printer Port IO NOP NOP #endif MOV #PrnTestStr,R5 ; Load up test string Printer_Test1: MOVB (R5)+,R0 ; >>> Print String Routine to Printer BEQ Printer_Test_Done JSR PC,LP11_OUT BR Printer_Test1 Printer_Test_Done: JSR PC,Flush_Printer MOV #CMD_Done,R5 ; "Test Done" JSR PC,PrStr ; Print string JMP TU58_Menu ; Back to main TU58 Menu TestPrinterInt: ; TU58 Menu 'L' Command (Send ASCII characters to Printer -- With ACK* interrupt) MOV #PrnIntOutMsg,R5 ; Say "Send characters to printer (with ACK* Interrupt)" JSR PC,PrStr ; Print string #if ST8C4 ; If S100_Parallel_IO Board for PRINTER OUTPUT MOVB #&08,@#PRN_CTRL ; Initilize the ST8C4 PC-Printer Port IO NOP NOP #endif JSR PC,Setup_Activate_Ints MOV #ActivatePrnPort,R5 ; Say "we are activating the Printer Enable bit" JSR PC,PrStr MOV #&40,LP11_STATUS ; Activate ACK* Interrupt MOV #PrnTestStr,R5 ; Load up test string Printer_Test1: MOVB (R5)+,R0 ; >>> Print String Routine to Printer BEQ Printer_Test_Done JSR PC,LP11_OUT BR Printer_Test1 Printer_Test_Done: JSR PC,Flush_Printer MOV #CMD_Done,R5 ; "Test Done" JSR PC,PrStr ; Print string JMP TU58_Menu ; Back to main TU58 Menu DEBUG_Out_Test: ; TU58 Menu 'M' Command (Send ASCII character '3' to Debug UART) MOV #Debug_OUT_Msg,R5 ; Say "Send character '3' to UART OUT_DATA port, 80 times." JSR PC,PrStr ; Print string MOV #81,R4 ; Do 80 characters DEBUG_Out_Test1: DEC R4 BEQ DEBUG_Test_Done MOV #&33,R0 JSR PC,DEBUG_UART_OUT BR DEBUG_Out_Test1 DEBUG_Test_Done: MOV #CMD_Done,R5 ; "Test Done" JSR PC,PrStr ; Print string JMP TU58_Menu DEBUG_In_Test: ; "Menu N", Debug UART input test (Status check only) MOV #Debug_IN_Msg,R5 ; Say "Input characters from UART IN_DATA port. ESC to Abort" JSR PC,PrStr ; Print string DEBUG_In_Test1: JSR PC,DEBUG_UART_IN CMPB #ESC,R0 BEQ DEBUG_Test_Done ; Abort if ESC returned JSR PC,CONSOLE_OUT BR DEBUG_In_Test1 DEBUG_Echo_Test: ; "Menu O", debug UART Send characters to UART MOV #Debug_Echo_Msg,R5 ; Say "Send characters on UART. ESC to Abort (Status Driven)" JSR PC,PrStr ; Print string DEBUG_Echo_Test1: JSR PC,CONSOLE_IN CMPB #ESC,R0 BEQ DEBUG_Test_Done ; Abort if ESC returned JSR PC,DEBUG_UART_OUT ; Echo back character JMP DEBUG_Echo_Test1 ; ----------------------------- BOOT TAPE DRIVE (TU58) Routines @@@@ -------------------------- ; This source code is taken from PDP bootloader code from Peter Schranz ; ; init: equ &o04 ; RSP init command (04H) boot: equ &o010 ; RSP boot command (08H) TU58_OS_BOOT: MOV #TAPE_BOOT_MSG,R5 ; " <--- TU58 Tape Boot loading location". JSR PC,PrStr ; Print string clr r0 ; r0 = unit # mov #TU58_IN_STAT,r1 ; r1 = reciever CSR mov #TU58_OUT_STAT,r3 ; r3 = transmitter CSR ; r2 = byte count (see below) ; for better readability of the octal code, only r1 is used. reset mov sp,r5 mov #&800,sp ;(Octal 4000) inc (r3) clr r2 jsr pc,SEND4 clr (r3) tst 02(r1) mov #&804,r2 ; (Octal 4004) jsr pc,SEND2 mov r0,r2 jsr pc,SEND1 clr r2 ; (0H in RAM) SEND0: tstb (r1) bpl SEND0 movb 02(r1),(r2)+ cmp #&200,r2 ; (0-200H in RAM, Octal 1000) bhi SEND0 MOV #TAPE_DONE_MSG,R5 ; Say we are done, ask to activate JSR PC,PrStr ; Print string JSR PC,CONSOLE_IN ; See if we get a 'Y' JSR PC,ToUpper ; a-z to A-Z JSR PC,CONSOLE_OUT ; Echo CMP R0,#&59 BEQ GoToTape JSR PC,ConCRLF mov r5,sp ; Restore old stack just in case JMP Loop1 ; If Not 'Y' abort GoToTape: JSR PC,ConCRLF mov r5,sp ; Restore old stack mov #&o000000,r0 ; r0 = unit # mov #TU58_IN_STAT,r1 ; r1 = reciever CSR mov #&o001000,r2 ; 200H mov #TU58_OUT_STAT,r3 ; r3 = transmitter CSR mov #&o000000,r4 ; Set other registers as Peter has his. mov #&o132520,r5 mov #&o132520,r6 mov #&o165554,r7 clr pc ; <-- Jump to bootstrap at 0H in RAM when done. SEND4: jsr pc,(pc) jsr pc,(pc) SEND2: jsr pc,(pc) SEND1: tstb (r3) bpl SEND1 movb r2,02(r3) swab r2 rts pc ; ----------------------------- JUMP TO RAM ADDRESS ---------------------------------------------- RAM_ADDRESS: ; Menu G command (Go to a RAM Address) JSR PC,GetWord_R5 CMPB #ESC,R0 BEQ AddressErr1 ; Abort if ESC returned MOV R5,R3 ; Save it MOV #JMP_Msg,R5 ; "Will Jump to " JSR PC,PrStr ; Print string MOV R3,R5 JSR PC,PutWord_R5 ; Print HEX word value in R5 JSR PC,ConCRLF MOV R3,PC ; Jump directly to that address AddressErr1: JMP FillError ; ---------------------------------- SPEAK STRING ---------------------------------------------- SpeakStr: ; Send speech data (in R5) to port up to end with '0' MOV #BDTA,R3 ; Point to serial data port MOV #BCTL,R4 ; Point to serial status port Speak0: MOV #100,R1 ; Retry count Speak1: MOVB (R4),R0 BITB #BIT2,R0 ; Test bit-2/ready BNE Speak2 ; busy-loop while bit-7 is 0 DEC R1 BEQ TalkError1 BR Speak1 ; Try 100 times Speak2: MOVB (R5)+,R0 ; get a character TSTB R0 ; Finish if terminating 0 BEQ SpeakDone CMPB #&20,R0 ; Skip < SPACE BGT Speak2 CMPB #&7F,R0 ;Skip < DEL BEQ Speak2 MOV #5000,R1 ; Not clear why I need this delay. I think my code above for Speak3: DEC R1 ; checking the status port is incorrect (Note also had a problem with this BNE Speak3 ; in the Z80 monitor. (See SPEAKER_STS: in that code). MOVB R0,(R3) ; Send Character to talker data port BR Speak0 ; Next Character SpeakDone: MOVB #&0D,(R3) ; Must end with a 0D Character to data port for speaker to actully speak RTS PC ; Routine return TalkError1: MOV #TimeoutPort,R5 ; Print "Talk Port Timeout " JSR PC,PrStr ; Print string RTS PC ; Routine return InitSerialB: ; Initilize the S100Computers serial board speaker port MOVB #BCTL,R1 ; Serial board speaker CTL port (Zilog SCC Chip) MOVB #&04,(R1) ; Point to WR4 MOVB #&44,(R1) ; X16 clock,1 Stop,NP MOVB #&03,(R1) ; Point to WR3 MOVB #&C1,(R1) ; Enable reciever, Auto Enable, Recieve 8 bits MOVB #&05,(R1) ; Point to WR5 MOVB #&EA,(R1) ; Enable, Transmit 8 bits MOVB #&0B,(R1) ; Set RTS,DTR, Enable. Point to WR11 MOVB #&56,(R1) ; Recieve/transmit clock = BRG MOVB #&0C,(R1) ; Point to WR12 ; MOVB #&02,(R1) ; Low byte 38,400 Baud MOVB #&06,(R1) ; Low byte 19,200 Baud <<<<<<<<<<< Speech chip speed MOVB #&0D,(R1) ; Point to WR13 MOVB #&00,(R1) ; High byte for Baud MOVB #&0E,(R1) ; Point to WR14 MOVB #&01,(R1) ; Use 4.9152 MHz Clock. MOVB #&0F,(R1) ; Point to WR15 MOVB #&00,(R1) ; Generate Int. with CTS going high RTS PC ; Return ;>>>>>>>>>>>>>>>>>>>>>>>>>> Timer Test Routines & Functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Timer_Test: ; Timer test routine MOV #Timer_Status_Msg,R5 ; Status msg "Timer Status Port (3FFF66 -> 1F66H) = " JSR PC,PrStr ; Print string MOVB @#TIMER_ADDRESS,R5 ; Get current Status JSR PC,PutBits_R5 MOV #Activate_Timer_Msg,R5 ; Say "Activating Timer (Bit 6). Will read port 20 times" JSR PC,PrStr ; Print string MOV #&40,R0 ; <--- Pulse bit 6 HIGH MOVB R0,@#TIMER_ADDRESS MOV #12,R1 ; read 12 times Timer1: MOV #Timer_Status_Msg,R5 ; "Timer Status Port (1F66H) = " JSR PC,PrStr ; Print string MOVB @#TIMER_ADDRESS,R5 ; Get current Status JSR PC,PutBits_R5 DEC R1 BNE Timer1 JSR PC,Setup_Activate_Ints ; <<<<<<<<<< MOV #TimerActive,R5 ; Say "The Event timer is now active independently triggering. (Will beep every ~5 seconds)" JSR PC,PrStr ; Print string (PSW= ) JMP Loop IntsOn: ; Setup low RAM interrupt/trap vector pointers JSR PC,Setup_Activate_Ints ; <<<<<<<<< JMP Loop IntsOff: MOV #Off_Ints_Msg,R5 ; Say "All interrupts off. Timer Inactivated" JSR PC,PrStr ; Print string MOV #&00E0,@#PSW ; Block ALL Interrupts (Set bits 7-5) MOV #&0,R0 ; <--- Pulse bit 6 LOW MOVB R0,@#TIMER_ADDRESS JMP Loop Setup_Activate_Ints: MOV #SetupIntsMsg,R5 ; "Setting up Interrupt Vectors in RAM at 0-100H" JSR PC,PrStr ; Print string MOV #&0,R5 ; Setup low RAM Interrupt & Trap vectors (MAKE SURE TO USE THE '#') Trap1: MOV #CatchAllRoutine,(R5)+ ; Fill in with the default routine MOV #&00E1,(R5)+ ; Default, Block off all Ints, set CARRY CMP #&100,R5 ; Fill 40-FFH with catch-all trap H routine BHI Trap1 MOV #CPU_Err_Routine,@#&04 ; CPU Error reoutine (whenever the CPU calls the "Red Flag Error vector" @ 04H in RAM) MOV #TrapRoutine,@#&1C MOV #EventRoutine,@#&40 ; VIP vector, needs special treatment MOV #&0,@#&44 ; Special case for Event routine. Remember we had the vector setup to set the carry increment MOV #&0,@#&46 ; so this is an location 104 and carry over the overflow to carry and then adds it to 106 MOV #PIRRoutine,@#&A0 MOV #FPERoutine,@#&A4 MOV #CON_RCV_Routine,@#&30 ; Console UART Recieve in (Digital UNIBUS Console/Keyboard) MOV #CON_XMT_Routine,@#&34 ; Console UART Transmitt out (Digital UNIBUS Console CRT/punch) MOV #TU58_RCV_Routine,@#&38 ; TU58 UART Recieve in (Digital UNIBUS PC11 Tape reader) MOV #TU58_XMT_Routine,@#&3C ; TU58 UART Out (Digital UNIBUS PC11 tape punch) MOV #LP11_XMT_Routine,@#&80 ; LP11 Printer Out (Digital UNIBUS LP11/LS11) MOV #Unassigned_Vector,@#&78 ; S0-S2 code has not yet been given a vector on the V2 CPU board U25 CPLD MOV #Ints_Before_Msg,R5 ; Say "All interrupts will be recognized (PSW bits 7-5 = 011), "CPU PSW (Before) = " JSR PC,PrStr ; Print string (PSW= ) MOVB @#PSW+1,R5 ; Get High Byte of PSW JSR PC,PutBits_R5 MOVB @#PSW,R5 ; Get low byte JSR PC,PutBits_R5 BICB #&80,@#PSW ; Allow ALL Interrupts (Clear bits 7-5) MOV #Ints_After_Msg,R5 ; Show "CPU PSW (Now) = " JSR PC,PrStr MOVB @#PSW+1,R5 ; Get High Byte of PSW JSR PC,PutBits_R5 MOVB @#PSW,R5 ; Get low byte JSR PC,PutBits_R5 RTS PC ; Return align Unassigned_Vector: ; Arrive here from 78H (170 Octal) in RAM. An unassigned S0,S1,S2 code was presented MOV R5,-(SP) ; This location is assigned "User Reserved" by Digital MOV R4,-(SP) MOV R0,-(SP) MOV PC,R4 SUB #&6,R4 ; Location or this vector MOV #S0S3_Err_Msg,R5 ; Point to Unassigned S0-S2 vector " JSR PC,PrStr ; Print string MOV (SP)+,R0 MOV (SP)+,R4 MOV (SP)+,R5 RTI align CatchAllRoutine: MOV R5,-(SP) MOV R4,-(SP) MOV R0,-(SP) MOV PC,R4 SUB #&6,R4 ; Location or this vector MOV #CatchAllMsg,R5 ; Point to Catch All Message "Undefined Interrupt detected at " JSR PC,PrStr ; Print string MOV (SP)+,R0 MOV (SP)+,R4 MOV (SP)+,R5 RTI align EventRoutine: MOV R0,-(SP) ; Arrive here from Interrupt vector at 40H in RAM (100 Octal) ADC @#&44 ; Remember we had the vector setup to set the carry so this is a increments ADC @#&46 ; location 44H (104 octal) and carry over the overflow to carry and then adds it to 46H ; so this is a sneak incremenet of a 32-bit integer (you can’t use the INC ; instruction as it does not update the carry bit). Can count to over 8 days! ; (Trick from Peter Schranz) CMPB #&01,@#&45 ; We get to 00000010,00000000 for RAM at 45+44 in ~ 5 seconds BHI Event1 CLR @#&44 ; Reset Timer MOV #&07,R0 ; Send Bell/beep to CRT about every 5 seconds JSR PC,CONSOLE_OUT Event1: MOV (SP)+,R0 RTI align CPU_Err_Routine: ; Typically the CPU would come here if the is an undefined I/O port MOV R5,-(SP) ; This is the "Abort" interrupt location MOV R4,-(SP) MOV R0,-(SP) MOV PC,R4 SUB #&6,R4 ; Location or this vector MOV #CPU_ERR_Msg,R5 ; CPU Error msg JSR PC,PrStr ; Print string MOV (SP)+,R0 MOV (SP)+,R4 MOV (SP)+,R5 RTI align CON_RCV_Routine: ; CONSOLE UART (on CPU board) RCV Int will arrive here from 30H in RAM MOV R0,-(SP) #if DETAILED_INTS MOV R5,-(SP) MOV R4,-(SP) MOV #CON_RCV_Msg,R5 ; Point to RCV Message JSR PC,PrStr ; Print string MOV (SP)+,R4 MOV (SP)+,R5 #endif ; JSR PC,ODT_CONSOLE_IN MOVB @#ODT_CONIN_DATA,R0 ; UART ASCII to R0 reg JSR PC,S100_CONSOLE_OUT ; Just dump it on console (Later can use buffers etc. ) MOV (SP)+,R0 RTI align CON_XMT_Routine: ; CONSOLE XMT Int will arrive here from 34H in RAM MOV R0,-(SP) #if DETAILED_INTS MOV R5,-(SP) MOV R4,-(SP) MOV #CON_XMT_Msg,R5 ; Point to XMT Message JSR PC,PrStr ; Print string MOV (SP)+,R4 MOV (SP)+,R5 #endif MOVB #&0,@#CON_XMT_Flag ;Indicate the CONSOLE UART can send another character MOV (SP)+,R0 RTI align TU58_RCV_Routine: ; TU58 RCV Int will arrive here from 38H in RAM MOV R0,-(SP) #if DETAILED_INTS MOV R5,-(SP) MOV R4,-(SP) MOV #TU58_RCV_Msg,R5 ; Point to RCV Message JSR PC,PrStr ; Print string MOV (SP)+,R4 MOV (SP)+,R5 #endif MOVB @#TU58_IN_DATA,R0 ; UART ASCII to R0 reg JSR PC,CONSOLE_OUT ; Just dump it on console (Later can use buffers etc. ) MOV (SP)+,R0 RTI align TU58_XMT_Routine: ; TU58 XMT Int will arrive here from 3CH in RAM MOV R0,-(SP) #if DETAILED_INTS MOV R5,-(SP) MOV R4,-(SP) MOV #TU58_XMT_Msg,R5 ; Point to XMT Message JSR PC,PrStr ; Print string MOV (SP)+,R4 MOV (SP)+,R5 #endif MOVB #&0,@#TU58_XMT_Flag ;Indicate the TU58 UART can send another character MOV (SP)+,R0 RTI align LP11_XMT_Routine: ; LP11 XMT Int will arrive here from 80H in RAM MOV R0,-(SP) #if DETAILED_INTS MOV R5,-(SP) MOV R4,-(SP) MOV #LP11_XMT_Msg,R5 ; Point to XMT Message JSR PC,PrStr ; Print string MOV (SP)+,R4 MOV (SP)+,R5 #endif MOVB #&0,@#LP11_XMT_Flag ;Indicate the ACK returned from Printer MOV (SP)+,R0 RTI align AbortRoutine: MOV R5,-(SP) MOV R4,-(SP) MOV R0,-(SP) MOV PC,R4 ADD #&6,R4 ; Location or this vector MOV #AbortMsg,R5 ; Point to Abort Message JSR PC,PrStr ; Print string MOV (SP)+,R0 MOV (SP)+,R4 MOV (SP)+,R5 RTI align IllegalOpcodeRoutine: MOV R5,-(SP) MOV R4,-(SP) MOV R0,-(SP) MOV PC,R4 ADD #&6,R4 ; Location or this vector MOV #OPCodeMsg,R5 ; Point to Abort Message JSR PC,PrStr ; Print string MOV (SP)+,R0 MOV (SP)+,R4 MOV (SP)+,R5 RTI align TrapRoutine: MOV R5,-(SP) MOV R4,-(SP) MOV R0,-(SP) MOV PC,R4 ADD #&6,R4 ; Location or this vector MOV #TrapMsg,R5 ; Point to Abort Message JSR PC,PrStr ; Print string MOV (SP)+,R0 MOV (SP)+,R4 MOV (SP)+,R5 RTI align PIRRoutine: MOV R5,-(SP) MOV R4,-(SP) MOV R0,-(SP) MOV PC,R4 ADD #&6,R4 ; Location or this vector MOV #PIRMsg,R5 ; Point to Abort Message JSR PC,PrStr ; Print string MOV (SP)+,R0 MOV (SP)+,R4 MOV (SP)+,R5 RTI align FPERoutine: MOV R5,-(SP) MOV R4,-(SP) MOV R0,-(SP) MOV PC,R4 ADD #&6,R4 ; Location or this vector MOV #FPEMsg,R5 ; Point to Abort Message JSR PC,PrStr ; Print string MOV (SP)+,R0 MOV (SP)+,R4 MOV (SP)+,R5 RTI ;--------------------------- ROUTINES TO GET AND PUT AND SHOW BYTE/WORD VALUES FOR REGESTERS ------------------- GetWord_R5: ; Get a WORD HEX value from Console to R5 CLR R0 CLR R5 GetWord1: JSR PC,GetNibble_R5 CMPB #CR,R0 BEQ GetWordDone CMPB #SPACE,R0 BEQ GetWordDone CMPB #ESC,R0 BEQ GetWordDone BR GetWord1 ; Note will return the last 4 valid hex characters GetWordDone: ; up to a CR, ',' or SPACE RTS PC ; 0 in R0 if all OK, ESC if invalid character GetByte_R5: ; Get a BYTE HEX value from Console to R5 CLR R0 CLR R5 JSR PC,GetNibble_R5 CMPB #CR,R0 BEQ GetByteDone CMPB #SPACE,R0 BEQ GetByteDone CMPB #ESC,R0 BEQ GetByteDone JSR PC,GetNibble_R5 CMPB #ESC,R0 BEQ GetByteDone ; Abort if ESC returned JSR PC,CONSOLE_IN ; Character to R0 GetByteDone: RTS PC ; N clear if all OK, N set if invalid character GetNibble_R5: ; Get a NIBBLE HEX CHARACTER from Console to R5 CLR R0 JSR PC,CONSOLE_IN CMPB #ESC,R0 ; Was an abort requested BEQ NibbleError CMPB #CR,R0 BEQ NibbleCR CMPB #SPACE,R0 BEQ NibbleSPACE CMPB #&2C,R0 ; Check for ',' BEQ NibbleCOMMA JSR PC,ToUpper JSR PC,CONSOLE_OUT ; Echo data SUB #&30,R0 ; '0' to 0, '1' to 1... BLT NibbleError CMPB #&09,R0 BGE NibbleDone SUB #&7,R0 CMPB #&0F,R0 ; Greater than 'F' in invalid BLT NibbleError NibbleDone: ASL R5 ; Shift R5 up a nibble ASL R5 ASL R5 ASL R5 BIS R0,R5 ; OR in the high nibble of what will be the high byte CLR R0 RTS PC ; Return with Nibble in R5, 0 in R0 NibbleCR: MOV #CR,R0 RTS PC ; Return with CR in R0 NibbleSPACE: JSR PC,CONSOLE_OUT ; Echo data MOV #SPACE,R0 RTS PC ; Return with SPACE in R0 NibbleCOMMA: JSR PC,CONSOLE_OUT ; Echo data MOV #CR,R0 RTS PC ; Return with CR in R0 NibbleError: MOV #&3F,R0 ; Send "?' JSR PC,CONSOLE_OUT MOV #ESC,R0 RTS PC ; Return with ESC in R0 PutWord_R5: ; Print HEX Word value in R5 SWAB R5 ; Value in R5 is retained JSR PC,PutByte_R5 ; Print HEX byte value in R5 SWAB R5 JSR PC,PutByte_R5 RTS PC PutByte_R5: ; Print HEX Byte value in R5 CLR R0 ; Clear R0 MOVB R5,R0 ; Origional number to R0 ROR R0 ; Shift upper byte to lower 4 bits ROR R0 ROR R0 ROR R0 ; Upper nibble is now lower nibble JSR PC,HexOut MOV R5,R0 JSR PC,HexOut RTS PC HexOut: ; Print Hex Byte value in R0 BICB #&F0,R0 ; Clear upper nibble ADD #&30,R0 ; CONVERT TO ASCII CMPB #&39,R0 ; See if > 9 BGE HexOK ADD #&07,R0 ; Add to make 10=A, 11=B... HexOK: JSR PC,CONSOLE_OUT RTS PC PutBits_R5: ; Print 8 bits in R5. MOV R2,-(SP) MOV R3,-(SP) MOV R4,-(SP) MOVB #8,R2 ; 8 bits across MOVB #&80,R3 ; test bit MOVB R5,R4 BitTst: BITB R3,R4 BEQ Bit8L MOVB #&31,R0 ; '1' BR Bits8 Bit8L: MOVB #&30,R0 ; '0' Bits8: JSR PC,CONSOLE_OUT CLC RORB R3 ; Shift test bit right one bit DECB R2 BNE BitTst MOV (SP)+,R4 MOV (SP)+,R3 MOV (SP)+,R2 RTS PC ToUpper: ; >>> ;a-z to A-Z CMP #&61,R0 ; less than 'a' BGT SkipToU CMP #&7A,R0 ; Greater tha 'z' BLT SkipToU SUB #&20,R0 ; Adjust SkipToU: RTS PC And_R0_R1: ; Bitwise AND r0 and r1, result in R1 COM R0 COM R1 BIS R0,R1 COM R1 RTS PC ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ODT & S100 BUS CONSOLE I/O ROUTINES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< PrStr: MOVB (R5)+,R0 ; >>> Print String Routine to ODT (or S100 Console) BEQ PrStr1 JSR PC,CONSOLE_OUT BR PrStr ; Next character PrStr1: RTS PC ; return S100_PrStr: MOVB (R5)+,R0 ; >>> Print String Routine direct to S100 Console BEQ PrStr2 JSR PC,S100_CONSOLE_OUT BR S100_PrStr PrStr2: RTS PC ; return ConSPACE2: ; >>> Send SPACE+SPACE to ODT or S100 console MOVB #SPACE,R0 JSR PC,CONSOLE_OUT ConSPACE1: MOVB #SPACE,R0 JSR PC,CONSOLE_OUT RTS PC ; Note R0 contains ASCII ctaracter (as a Byte) HConCRLF: ; >>> Send 'H' to ODT or S100 console MOVB #&48,R0 ; then fall through to CR/LF JSR PC,CONSOLE_OUT ConCRLF: ; >>> Send CR+LF to ODT or S100 console MOVB #CR,R0 JSR PC,CONSOLE_OUT ConLF: ; >>> Send LF to ODT or S100 console MOVB #LF,R0 JSR PC,CONSOLE_OUT RTS PC ; Note R0 contains ASCII character (as a Byte) ;----------------------------------------------------------------------------------------------------------- Set_CONSOLE_IO: ; Set FLAG in RAM to decide where Console IO is directed. CMPB #&FF,@#DEBUG_CONOUT_STAT ; See if Port FF14 is present. (Will be FF if no Support Board present) BEQ NO_SBoard BITB #BIT0,@#DEBUG_CONOUT_STAT ; See if input comes from the S100 Bus (Support Board present) BEQ SET_S100_CONSOLE SET_ODT_CONSOLE: MOV #&FFFF,@#CONSOLE_IO_FLAG ; FFFF = ALL CONSOLE IO TO ODT UART. ANYTHING ELSE THEN SEND TO S100 CONSOLE RTS PC ; Note R0 contains ASCII character (as a Byte) SET_S100_CONSOLE: MOV #&0000,@#CONSOLE_IO_FLAG ; FFFF = ALL CONSOLE IO TO ODT UART. ANYTHING ELSE THEN SEND TO S100 CONSOLE RTS PC ; Note R0 contains ASCII character (as a Byte) NO_SBoard: BITB #BIT0,@#ODT_CONOUT_STAT ; Input comes from from the CPU Board UART (No Support Board Present) BEQ SET_S100_CONSOLE BR SET_ODT_CONSOLE CONIN_STATUS: ; Check if Character at Console, Set Carry if true #if S100_ONLY BR S100_CONIN_STATUS ; Force input from S100 bus always #endif #if ODT_ONLY BR ODT_CONIN_STATUS ; Force input from ODT UART always #endif CMP #&FFFF,@#CONSOLE_IO_FLAG ; FFFF = ALL CONSOLE IO TO ODT UART. ANYTHING ELSE THEN SEND TO S100 CONSOLE BEQ ODT_CONIN_STATUS BR S100_CONIN_STATUS ; If not go to the default ODT routine in the CPU S100_CONIN_STATUS: BITB #BIT1,@#S100_CONIN_STAT ; Check bit-1/ready of Propeller board Console In port (0H) ODT_STAT1: BEQ S100_Nothing ; Nothing there while bit-1 is 0 SEC ; Set Carry Flag if ESC RTS PC ; Return with Carry Set if a character is available S100_Nothing: CLC ; Return with Carry flag cleared RTS PC ; Return ODT_CONIN_STATUS: BITB #BIT7,@#ODT_CONIN_STAT ; Check bit-7/ready of xmt status reg BR ODT_STAT1 ;----------------------------------------------------------------------------------------------------------- ConCheckESC: ; Check if ESC key was pressed on console #if S100_ONLY BR S100_ConCheckESC ; Force input to S100 bus always #endif #if ODT_ONLY BR ODT_ConCheckESC ; Force input to ODT UART always #endif CMP #&FFFF,@#CONSOLE_IO_FLAG ; FFFF = ALL CONSOLE IO TO ODT UART. ANYTHING ELSE THEN SEND TO S100 CONSOLE BEQ ODT_ConCheckESC BR S100_ConCheckESC ; If not go to the default ODT routine in the CPU S100_ConCheckESC: BITB #BIT1,@#S100_CONIN_STAT ; Check bit-1/ready of Propeller board Console In port (0H) BEQ S100_NoESC ; Nothing there while bit-1 is 0 MOVB @#S100_CONIN_DATA,R0 ; ASCII to R0 reg CMPB #ESC,R0 BNE S100_NoESC SEC ; Set Carry Flag if ESC RTS PC ; Return with ESC in R0 S100_NoESC: CLC ; Return with Carry flag cleared RTS PC ; Return ODT_ConCheckESC: BITB #BIT7,@#ODT_CONIN_STAT ; Check bit-7/ready of xmt status reg BEQ ODT_NoESC ; busy-loop while bit-7 is 0 MOVB @#ODT_CONIN_DATA,R0 ; ASCII to R0 reg CMPB #ESC,R0 BNE ODT_NoESC SEC ; Set Carry Flag if ESC RTS PC ; Return with ESC in R0 ODT_NoESC: CLC ; Return with Carry flag cleared RTS PC ; Return ;----------------------------------------------------------------------------------------------------------- CONSOLE_OUT: ; >>> MAIN Console output routine. Data in R0, return unchanged <<<< #if S100_ONLY BR S100_CONSOLE_OUT ; <<< Force output to S100 bus always #endif #if ODT_ONLY BR ODT_CONSOLE_OUT ; Force output to ODT UART always #endif CMPB #&FFFF,@#CONSOLE_IO_FLAG ; FFFF = ALL CONSOLE IO TO ODT UART. ANYTHING ELSE THEN SEND TO S100 CONSOLE BEQ ODT_CONSOLE_OUT BR S100_CONSOLE_OUT ; If not go to the default ODT routine in the CPU S100_CONSOLE_OUT: ; S100 Bus Console output routine <<<< BITB #BIT2,@#S100_CONOUT_STAT ; Check bit-2/ready of Propeller board Console Out port (0H) BEQ S100_CONSOLE_OUT ; busy-loop while bit-2 is 0 MOVB R0,@#S100_CONOUT_DATA ; Send ASCII to Propeller board Console Out port (01H) RTS PC ; Note R0 contains ASCII ctaracter (as a Byte) ODT_CONSOLE_OUT: ; ODT Console Out Routine BITB #BIT7,@#ODT_CONOUT_STAT ; Check bit-7/ready of xmt status reg BEQ ODT_CONSOLE_OUT ; busy-loop while bit-7 is 0 MOVB R0,@#ODT_CONOUT_DATA ; send ASCII to xmt data reg RTS PC ; Note R0 is still valid (as a Byte) TU58_UART_OUT: BITB #BIT7,@#TU58_OUT_STAT ; Check bit-7/ready of TU58 xmt status reg BEQ TU58_UART_OUT ; busy-loop while bit-7 is 0 MOVB R0,@#TU58_OUT_DATA ; Send ASCII to TU58 xmt data reg RTS PC ; Note R0 is still valid (as a Byte) DEBUG_UART_OUT: ; Out Routine BITB #BIT7,@#DEBUG_CONOUT_STAT ; Check bit-7/ready of xmt status reg BEQ DEBUG_UART_OUT ; busy-loop while bit-7 is 0 MOVB R0,@#DEBUG_CONOUT_DATA ; send ASCII to xmt data reg RTS PC ; Note R0 is still valid (as a Byte) ;----------------------------------------------------------------------------------------------------------- CONSOLE_IN: ; >>> MAIN Console input routine. Data in R0, return unchanged <<<< #if S100_ONLY BR S100_CONSOLE_IN ; Force input to always come from teh S100 bus #endif #if ODT_ONLY BR ODT_CONSOLE_IN ; Force input to always come from ODT UART #endif CMPB #&FFFF,@#CONSOLE_IO_FLAG ; FFFF = ALL CONSOLE IO TO ODT UART. ANYTHING ELSE THEN SEND TO S100 CONSOLE BEQ ODT_CONSOLE_IN BR S100_CONSOLE_IN ; If not go to the default ODT routine in the CPU S100_CONSOLE_IN: ; S100 Bus Console input routine <<<< BITB #BIT1,@#S100_CONIN_STAT ; Check bit-1/ready of Propeller board Console In port (0H) BEQ S100_CONSOLE_IN ; Nothing there while bit-1 is 0 MOVB @#S100_CONIN_DATA,R0 ; Get ASCII from Propeller board Console In port (01H) RTS PC ; Note R0 contains ASCII ctaracter (as a Byte) ODT_CONSOLE_IN: ; ODT Console In Routine BITB #BIT7,@#ODT_CONIN_STAT ; Check bit-7/ready of xmt status reg BEQ ODT_CONSOLE_IN ; Nothing there while bit-7 is 0 MOVB @#ODT_CONIN_DATA,R0 ; ASCII to R0 reg RTS PC ; Return TU58_UART_IN: ; TU58 UART In Routine BITB #BIT7,@#TU58_IN_STAT ; Check bit-7/ready of TU58 xmt status reg BEQ TU58_UART_IN ; Nothing there while bit-7 is 0 MOVB @#TU58_IN_DATA,R0 ; ASCII to R0 reg RTS PC ; Return DEBUG_UART_IN: ; In Routine BITB #BIT7,@#DEBUG_CONIN_STAT ; Check bit-7/ready of xmt status reg BEQ DEBUG_UART_IN ; Nothing there while bit-7 is 0 MOVB @#DEBUG_CONIN_DATA,R0 ; ASCII to R0 reg RTS PC ; Return ;---------------------------------------------------------------------------------------------- LP11_OUT: ; Printer output routine <<<< #if ST8C4 ; If S100_Parallel_IO Board for Printer output MOVB #PRN_ST_HIGH,@#PRN_CTRL ; Make sure strobe is high NOP NOP MOVB R0,@#PRN_OUT ; Send Data from [C] MOVB #PRN_ST_LOW,@#PRN_CTRL ; Lower strobe NOP NOP MOVB #PRN_ST_HIGH,@#PRN_CTRL ; return strobe high ; JSR PC,CONSOLE_OUT RTS PC ; Note R0 is still valid (as a Byte) #else ; All the code below resides in the LOW ROM page ; BITB #BIT2,@#S100_CONOUT_STAT ; For debugging send to console ; BEQ S100_CONSOLE_OUT MOVB R0,@#LP11_DATA ; Send ASCII to LP11 Printer Out port (FF4EH) RTS PC ; Note R0 contains ASCII ctaracter (as a Byte) #endif Flush_Printer: MOV #Flush_Msg,R5 ; "FF to Printer " JSR PC,PrStr MOVB #&0C,R0 ; Send a Form Feed to LaserJet Printer JSR PC,LP11_OUT RTS PC ; Note R0 contains FF ASCII ctaracter (as a Byte) ;_____________________________________________________________________________________________________________ ; Align Signon: equs CR,LF,"PDP-11 Monitor V2.35 John Monahan 5/10/2018. (SP = ",0 Signon1: equs "H)",CR,LF,0 Align MainMenu: equs CR,LF equs "A=Memmap BI,O=Port(B) C=[XMODEM] D=RAM Bytes E=Echo",CR,LF equs "F=Fill RAM(B) G=Goto RAM H=Fill RAM(W) I=IOBYTE J=Boot TU58 OS",CR,LF equs "K=Menu L=Timer M=Move RAM N=RAM Words O=[IO Tests]",CR,LF equs "P=[Serial Test] QI,O=Port(W) R=Ints ON S=Subs RAM T=ASCII RAM",CR,LF equs "U=Speech V=Verify RAM W=TU58 Menu Y=Ints OFF Z=Back to Z80",CR,LF,LF,0 Align TU58_MenuString: equs CR,LF equs "UART MENU.",CR,LF equs "A = 3's to TU58 UART",CR,LF equs "B = Input from TU58 UART (Status bit)",CR,LF equs "C = Chars on TU58 UART",CR,LF equs "D = 3's to Current CONSOLE UART",CR,LF equs "E = Input from Current CONSOLE UART (Status bit)",CR,LF equs "F = Chars to Current CONSOLE UART",CR,LF equs "G = Input from TU58 UART (Interrupts)",CR,LF equs "H = Chars to TU58 UART (Interrupts)",CR,LF equs "I = Input from Current CONSOLE UART (Interrupts)",CR,LF equs "J = Chars to Current CONSOLE UART (Interrupts)",CR,LF equs "K = Test string to LP11 Printer",CR,LF equs "L = Test string to LP11 Printer (Interrupts)",CR,LF equs "M = 3's to Debug UART",CR,LF equs "N = Input from Debug UART (Status bit)",CR,LF equs "O = Chars on Debug UART",CR,LF equs "ESC = To Main Menu",CR,LF,0 MM_Text: equs CR,LF,"Memory Map (64K)",CR,LF,0 Echo_Text: equs CR,LF,"Enter Chars (ESC to abort)",0 VerMsg0: equs CR,LF,"Mismatch found at ",0 VerMsg1: equs "H = ",0 VerMsg2: equs " = ",0 VerMsg3: equs "H ",0 WillSpeak: equs CR,LF,"Will speak string--> " TestSpeak: equs "1 2 3 4 5 6 7 8 9",CR,0 BadPort: equs CR,LF,"Inactive Talk Port",0 TimeoutPort: equs CR,LF,"Talk Port Timeout",0 Z80Msg: equs CR,LF,"Back To Z80",CR,LF,0 IOByteMsg: equs CR,LF,"IOBYTE = ",0 NotDoneMsg: equs CR,LF,"Command code not yet done!",0 OddAddressMsg: equs CR,LF,"Port must be an even address for word I/O",0 CMD_Done: equs CR,LF,"Test Finished",CR,LF,0 IOTestMsg: equs CR,LF,"Char string to port E001H, 80 times",CR,LF,0 TestStr: equs CR,LF," !#$%&'()*+,-./0123456789@ABCDEF",CR,LF,0 Flush_Msg: equs CR,LF,"FF to Printer",CR,LF,0 CatchAllMsg: equs CR,LF,"Undefined Interrupt",CR,LF,0 S0S3_Err_Msg: equs CR,LF,"Unassigned vector for S0,S1,S2",CR,LF,0 EventTimerMsg: equs CR,LF,"Event Timer Interrupt detected",CR,LF,0 AbortMsg: equs CR,LF,"Abort Interrupt. (Check access to Odd Port).",CR,LF,0 OPCodeMsg: equs CR,LF,"Illegal Opcode",CR,LF,0 TrapMsg: equs CR,LF,"Trap Instruction",CR,LF,0 PIRMsg: equs CR,LF,"PIR Interrupt",CR,LF,0 FPEMsg: equs CR,LF,"FP Error",CR,LF,0 CPU_ERR_Msg: equs CR,LF,"CPU Error/Invalid Port",CR,LF,0 Menu_Error: equs CR,LF,"Menu error",CR,LF,BELL,0 Timer_Status_Msg: equs CR,LF,"Timer Status Port (1F66H) = ",0 Activate_Timer_Msg: equs CR,LF,"Activating Timer (Bit 6). Will read port 12 times",0 SetupIntsMsg: equs CR,LF,"Setting Interrupts in RAM at 0-100H",0 Ints_Before_Msg: equs CR,LF,"All interrupts now active, including timer. (PSW bits 7-5 = 011)" equs CR,LF,"CPU PSW (Before) = ",0 Ints_After_Msg: equs CR,LF,"CPU PSW (Now) = ",0 TimerActive: equs CR,LF,"Event timer on. (Will beep every 5 seconds)",0 Off_Ints_Msg: equs CR,LF,"Interrupts off. (Timer Inactivated)",CR,LF,0 NO_ROM_MSG: equs CR,LF,"Code not in ROM",CR,LF,BELL,0 JMP_Msg: equs CR,LF,"Will Jump to ",0 UART_OUT_Msg: equs CR,LF,"'3's to UART (TU58_OUT_DATA port), 80 times.",CR,LF,0 UART_IN_Msg: equs CR,LF,"Input from UART IN_DATA port. ESC to Abort",CR,LF,0 UART_Echo_Msg: equs CR,LF,"Chars to UART. ESC to Abort (Status Driven)",CR,LF,LF,0 Debug_OUT_Msg: equs CR,LF,"Send '3's to UART (DEBUG_OUT_DATA port), 80 times.",CR,LF,0 Debug_IN_Msg: equs CR,LF,"Input from Debug UART IN_DATA port. ESC to Abort",CR,LF,0 Debug_Echo_Msg: equs CR,LF,"Chars to Debug UART. ESC to Abort (Status Driven)",CR,LF,LF,0 ActivateInInt: equs CR,LF,"Activating UART RCV Interrupt (Also Timer Interrupts).",CR,LF,0 ActivateInPort: equs CR,LF,"Activating UART RCV enable bit",CR,LF,0 ActivateOutInt: equs CR,LF,"Activating UART XMT Interrupt (Also Timer Interrupts).",CR,LF,0 ActivateOutPort: equs CR,LF,"Activating UART XMT enable bit",CR,LF,0 ODT_OUT_Msg: equs CR,LF,"'3's to V2 CPU Board UART (ODT_OUT_DATA port), 80 times",CR,LF,0 ODT_IN_Msg: equs CR,LF,"Input from UART CON_IN_DATA port. ESC to Abort",CR,LF,0 ODT_Echo_Msg: equs CR,LF,"Chars to UART CON_IN_DATA port. ESC to Abort (Status Driven)",CR,LF,LF,0 Ints_In_Ready: equs CR,LF,LF,"RCV Interrupts arriving from UART. ESC to abort",CR,LF,0 Ints_Out_Ready: equs CR,LF,LF,"XMT Interrupts to UART. ESC to abort" equs CR,LF,"Enter character to send ",0 PrnOutMsg: equs CR,LF,"Printer test running.",CR,LF,0 PrnIntOutMsg: equs CR,LF,"Printer test running (with ACK* Interrupt).",CR,LF,0 PrnTestStr: equs CR,LF,"This is a printer test. First line 1234567890",CR,LF equs CR,LF,"This is a printer test. Second line 1234567890",CR,LF equs CR,LF,"End of printer test.",CR,LF,0 ActivatePrnPort: equs CR,LF,"Activating LP11 Printer enable bit",CR,LF,0 TU58_Menu_Error: equs CR,LF,"Not a valid Menu option. Returning to the Monitor Main Menu",CR,LF,LF,BELL,0 Timer_Status_Msg: equs CR,LF,"Timer Status Port (1F66H) = ",0 Activate_Timer_Msg: equs CR,LF,"Activating Timer (Bit 6). Will read port 12 times",0 SetupIntsMsg: equs CR,LF,"Setting up Interrupts in RAM at 0-100H",0 CON_RCV_Msg: equs CR,LF,"@ 30H (CONSOLE RCV Routine)",CR,LF,0 CON_XMT_Msg: equs CR,LF,"@ 34H (CONSOLE XMT Routine)",CR,LF,0 TU58_RCV_Msg: equs CR,LF,"@ 38H (TU58 RCV Routine)",CR,LF,0 TU58_XMT_Msg: equs CR,LF,"@ 3CH (TU58 XMT Routine)",CR,LF,0 LP11_XMT_Msg: equs CR,LF,"@ 80H (PRINTER XMT Routine)",CR,LF,0 UART_BusyMsg: equs CR,LF,"UART XMT Flag = Busy",CR,LF,0 NoHighPageMsg: equs CR,LF,"ROM Address LA13 switch not active (Check JP K12)",CR,LF,BELL,0 TAPE_BOOT_MSG: equs "TU58 Tape Boot loading at 0H in RAM.",0 TAPE_DONE_MSG: equs CR,LF,LF,"Tape Data Loaded. Jump to 0000H ? (Y/N) ",0 ROM_AREA_MSG: equs "--- ROM MONITOR ---" equs CR,LF,"D000 --- ROM MONITOR ---" equs CR,LF,"E000 " PORTS_AREA_MSG: equs "--- I/O PORTS ---" equs CR,LF,"F000 --- I/O PORTS ---",CR,LF,0 Align ;Code currently resides from C000H to about DDxxH in ROM #if ROMS END_OF_LOW_ROM: equs "EENNDD__OOFF__LLOOWW__RROOMM ((EOVDEDN BBYYTTEESS)) @@ CC000000HH ------>>",0 #else END_OF_LOW_ROM: equs "EENNDD__OOFF__LLOOWW__RROOMM ((EOVDEDN BBYYTTEESS)) @@ 11000000HH ------>>",0 #endif ;END