Joined: Thu May 28, 2009 9:46 pm Posts: 8177 Location: Midwestern USA
|
akohlbecker wrote: BigDumbDinosaur wrote: My "print string" sub in the POC firmware is similar... Nice documentation! Thanks!
I do that for my own sanity. The system firmware runs to about 13,500 lines of code, with many subroutines. It’s impossible to remember what they all do, so I'm careful to document everything with as much detail as necessary. It’s even more important in some “user-land” programs, one of which runs to nearly 30,000 lines.
Quote: Can I ask about the error codes? How do you do error handling above this function? Any user-land program that calls a firmware API and gets an error return has to decide what to do about it. In the user-land programs I have written, there is an error-handling library function that gets INCLUDEd to decode the error and return a pointer to a terse message. It’s up to the caller to process and/or display the message as needed, and to determine what to do afterward. Here’s the decoding function:
Code: 08740 ;libgerr: GLOBAL ERROR MESSAGE DECODER 08741 ; 08742 ; ——————————————————————————————————————————————————————————————————————— 08743 ; Synopsis: This function returns a 32-bit pointer to the error message 08744 ; corresponding to the error code passed in the accumulator. 08745 ; 08746 ; § The message pointer's LSW will be returned in .X & the MSW 08747 ; in .Y. The MSW will be set to the current execution bank. 08748 ; 08749 ; § Error messages are null-terminated character strings & may 08750 ; be copied, processed and/or printed using other library 08751 ; functions, such as libstrng & libterm. 08752 ; 08753 ; § If the error code passed to this function has not been def- 08754 ; ined, a pointer to “unknown error” will be returned & carry 08755 ; will be set upon exit from this function. 08756 ; 08757 ; § This function must be in the same bank as the process that 08758 ; is using it. 08759 ; 08760 ; § The following files must be INCLUDEd in your program in or- 08761 ; der to use this function: 08762 ; 08763 ; ~/include/sys/gerc.asm 08764 ; 08765 ; gerc.asm is a system file that defines error codes. It 08766 ; should be INCLUDEd in the definitions section of your 08767 ; program. 08768 ; 08769 ; ~/lib/libgerm.asm 08770 ; 08771 ; libgerm.asm contains the text strings & other data to 08772 ; which this function makes reference. libgerm.asm should 08773 ; be INCLUDEd in the static data section of your program. 08774 ; It must be in the same bank as this function. 08775 ; ——————————————————————————————————————————————————————————————————————— 08776 ; Invocation example: LDA #ERRCODE ;error code 08777 ; JSR libgerr 08778 ; BCS UNKNOWN_CODE 08779 ; 08780 ; Exit registers: .A: entry value 08781 ; .B: entry value 08782 ; .X: text string pointer LSW 08783 ; .Y: text string pointer MSW 08784 ; DB: entry value 08785 ; DP: entry value 08786 ; PB: entry value 08787 ; SR: nvmxdizc 08788 ; |||||||| 08789 ; |||||||+———> 0: okay 08790 ; ||||||| 1: unknown error code 08791 ; ||||+++————> entry value 08792 ; |||+———————> 0 08793 ; +++————————> entry value 08794 ; 08795 ; ——————————————————————————————————————————————————————————————————————— 08796 ; 08797 0014B0 C2 11 libgerr rep #m_setx|sr_car ;clear c & x 08798 0014B2 08 php 08799 0014B3 C2 30 rep #m_setr 08800 0014B5 5A phy 08801 0014B6 DA phx 08802 0014B7 48 pha 08803 ; 08804 ;————————————————————————————————————————————————————————— 08805 ; 08806 ;LOCAL STACK DEFINITIONS 08807 ; 08808 0001 .sfbase .= 1 ;base stack index 08809 0001 .sfidx .= .sfbase ;workspace index 08810 ; 08811 ;—————————> register stack frame start <————————— 08812 ; 08813 0001 .reg_c =.sfidx ;.C 08814 0003 .sfidx .= .sfidx+s_word 08815 0003 .reg_x =.sfidx ;.X 08816 0005 .sfidx .= .sfidx+s_word 08817 0005 .reg_y =.sfidx ;.Y 08818 0007 .sfidx .= .sfidx+s_word 08819 0007 .reg_sr =.sfidx ;SR 08820 0008 .sfidx .= .sfidx+s_mpusrx 08821 0008 .reg_pc =.sfidx ;PC 08822 000A .sfidx .= .sfidx+s_mpupcx 08823 ; 08824 ;—————————> register stack frame end <————————— 08825 ; 08826 0009 .s_rsf =.sfidx-.sfbase ;register frame size 08827 000A .sfbase .= .sfidx 08828 ;————————————————————————————————————————————————————————— 08829 ; 08830 0014B8 E2 20 sep #m_seta 08831 0014BA A2 26 00 ldx !#n_glerc-1 08832 ; 08833 0014BD DD 25 4A .main cmp libgelut,x ;look up error code 08834 0014C0 F0 09 beq .main010 ;found it 08835 ; 08836 0014C2 CA dex 08837 0014C3 D0 F8 bne .main ;keep looking 08838 ; 08839 0014C5 A3 07 lda .reg_sr,s ;entry SR 08840 0014C7 09 01 ora #sr_car ;set carry to indicate... 08841 0014C9 83 07 sta .reg_sr,s ;code not found 08842 ; 08843 0014CB C2 20 .main010 rep #m_seta 08844 0014CD 8A txa ;code table index 08845 0014CE 0A asl 08846 0014CF AA tax ;message table index 08847 0014D0 BD 4C 4A lda libgmlut,x ;message pointer 08848 0014D3 83 03 sta .reg_x,s 08849 0014D5 E2 20 sep #m_seta 08850 0014D7 4B phk ;execution bank is... 08851 0014D8 68 pla ;MSW of string address 08852 0014D9 C2 30 rep #m_setr 08853 0014DB 29 FF 00 and !#%11111111 ;mask noise in .B 08854 0014DE 83 05 sta .reg_y,s ;set MSW 08855 0014E0 68 pla 08856 0014E1 FA plx 08857 0014E2 7A ply 08858 0014E3 28 plp 08859 0014E4 60 rts In my applications, after a call is made to the above and the error text has been displayed, the program either prompts the user to repeat input (assuming faulty input is what triggered the error) or a “long jump” is made to a point where the program can gracefully terminate.
The data needed by the above decoding function is as follows:
Code: 27660 ;libgerm: GLOBAL ERROR MESSAGES 27661 ; 27662 ; ——————————————————————————————————————————————————————————————————————— 27663 ; Synopsis: This file defines the error messages known to the global er- 27664 ; ror-handling functions. It consists of three parts: an error 27665 ; code lookup table, a message pointer table, & message text. 27666 ; Entries in the error code LUT are BYTE-sized & entries in the 27667 ; vector table are DWORD-sized. Messages are null-terminated 27668 ; character strings. 27669 ; 27670 ; There is a one-for-one correspondence between entries in the 27671 ; error code lookup table & entries in the message pointer 27672 ; table. Getting one or both tables out of order will cause 27673 ; incorrect error text to be returned by the libgerr function. 27674 ; The message text strings may be in any order. 27675 ; 27676 ; If a new error code is to be created, proceed as follows: 27677 ; 27678 ; 1) Define the new error code in ~/include/sys/gerc.asm. The 27679 ; new error code should be a numeric value that is higher 27680 ; than that of the highest existing code. DO NOT change any 27681 ; existing codes! 27682 ; 27683 ; 2) Add the new error code to the end of the LIBGELUT lookup 27684 ; table (below). Note that entries in this table must be 27685 ; defined with the .BYTE assembler pseudo-op. 27686 ; 27687 ; 3) Add the corresponding message text to the end of the text 27688 ; section (below). It is recommended that message text be 27689 ; succint, not wordy. Note the general form of existing 27690 ; messages. Also note that message text strings are defined 27691 ; with local (.LABEL) labels, not global ones (LABEL). 27692 ; 27693 ; 4) Add a message text pointer to the end of LIBGMLUT (below). 27694 ; Note that entries in this table must be defined as WORDS 27695 ; (16-bit pointers). Also note that entries are local lab- 27696 ; els as explained in 3) above. 27697 ; ——————————————————————————————————————————————————————————————————————— 27698 ; 27699 ;—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-— 27700 ; 27701 ;ERROR CODES 27702 ; 27703 4A25 libgelut =* ;error codes... 27704 .byte e_okay ; no error 27705 .byte e_apiidx ; API index out-of-range 27706 .byte e_memf ; memory fault 27707 .byte e_rtcf ; RTC fault 27708 .byte e_nvrf ; NVRAM fault 27709 .byte e_sscf ; SCSI HBA general fault 27710 .byte e_sscfe ; SCSI HBA FIFO fault 27711 .byte e_sioss ; SIO subsystem not ready 27712 .byte e_sioch ; invalid channel 27713 .byte e_sioror ; receiver data overrun 27714 .byte e_sssnr ; SCSI subsystem not ready 27715 .byte e_sstid ; target ID out of range 27716 .byte e_ssdne ; device not enumerated 27717 .byte e_ssdnp ; device not present 27718 .byte e_sscmd ; illegal controller command 27719 .byte e_ssudf ; unsupported driver function 27720 .byte e_ssudt ; unsupported device type 27721 .byte e_ssubr ; unexpected bus reset 27722 .byte e_ssubp ; unsupported bus phase 27723 .byte e_ssucg ; unsupported command group 27724 .byte e_ssabt ; aborted transaction 27725 .byte e_sschk ; check condition 27726 .byte e_ssblk ; too many blocks 27727 .byte e_parm ; parameter invalid 27728 .byte e_ptrnul ; null pointer 27729 .byte e_strnul ; null string 27730 .byte e_strlen ; string too long 27731 .byte e_elmct ; too many elements in list 27732 .byte e_huge ; number too big 27733 .byte e_inon ; not a number 27734 .byte e_idivz ; division by zero 27735 .byte e_iover ; over-/underflow 27736 .byte e_isizw ; invalid integer size 27737 .byte e_notdsk ; device not a disk 27738 .byte e_devcap ; device capacity 27739 .byte e_mbr ; invalid master boot record 27740 .byte e_dupfsn ; duplicate filesystem name 27741 .byte e_dupvol ; duplicate volume name 27742 .byte e_fsnf ; filesystem not found 27743 ; 27744 ; ——————————————————————————————————— 27745 ; Do not change the below definition! 27746 ; ——————————————————————————————————— 27747 ; 27748 0027 n_glerc =*-libgelut ;number of error codes in table 27749 ; 27750 ;—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-— 27751 ; 27752 ;MESSAGE POINTERS 27753 ; 27754 4A4C libgmlut =* ;message pointers... 27755 .word .okay ; no/unknown error 27756 .word .apiidx ; API index out-of-range 27757 .word .memf ; memory fault 27758 .word .rtcf ; RTC fault 27759 .word .nvrf ; NVRAM fault 27760 .word .sscf ; SCSI HBA general fault 27761 .word .sscfe ; SCSI HBA FIFO fault 27762 .word .sioss ; SIO subsystem not ready 27763 .word .sioch ; invalid channel 27764 .word .sioror ; receiver data overrun 27765 .word .sssnr ; SCSI subsystem not ready 27766 .word .sstid ; target ID out of range 27767 .word .ssdne ; device not enumerated 27768 .word .ssdnp ; device not present 27769 .word .sscmd ; illegal controller command 27770 .word .ssudf ; unsupported driver function 27771 .word .ssudt ; unsupported device type 27772 .word .ssubr ; unexpected bus reset 27773 .word .ssubp ; unsupported bus phase 27774 .word .ssucg ; unsupported command group 27775 .word .ssabt ; aborted transaction 27776 .word .sschk ; check condition 27777 .word .ssblk ; too many disk blocks 27778 .word .parmiv ; parameter invalid 27779 .word .ptrnul ; null pointer 27780 .word .strnul ; null string 27781 .word .strsiz ; string too long 27782 .word .elmct ; too many elements in list 27783 .word .hugenum ; number too big 27784 .word .inon ; not a number 27785 .word .idivz ; division by zero 27786 .word .iover ; integer computation over-/underflow 27787 .word .isizw ; invalid integer size 27788 .word .notdsk ; device not a disk 27789 .word .devcap ; device capacity 27790 .word .mbriv ; invalid master boot record 27791 .word .dupfsn ; duplicate filesystem name 27792 .word .dupvol ; duplicate volume name 27793 .word .fsnf ; filesystem not found 27794 ; 27795 .if {{*-libgmlut}/s_word} != n_glerc 27796 ; 27797 ;—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-— 27798 ; 27799 ;MESSAGE TEXT 27800 ; 27801 .ssabt .byte "Aborted SCSI transaction",0 27802 .sschk .byte "Check condition",0 27803 .iover .byte "Computation out-of-range",0 27804 .devcap .byte "Device capacity exceeded",0 27805 .sstid .byte "Device ID out-of-range",0 27806 .notdsk .byte "Device not a disk",0 27807 .ssdne .byte "Device not enumerated",0 27808 .ssdnp .byte "Device not responding",0 27809 .idivz .byte "Division by zero",0 27810 .dupfsn .byte "Duplicate filesystem name",0 27811 .dupvol .byte "Duplicate volume name",0 27812 .fsnf .byte "Filesystem not found",0 27813 .memf .byte "Hardware: core fault",0 27814 .nvrf .byte "Hardware: NVRAM fault",0 27815 .rtcf .byte "Hardware: RTC fault",0 27816 .sscfe .byte "HBA FIFO fault",0 27817 .sscf .byte "HBA general fault",0 27818 .sscmd .byte "Illegal SCSI controller command",0 27819 .isizw .byte "Illegal integer type",0 27820 .apiidx .byte "Invalid API index",0 27821 .mbriv .byte "Invalid master boot record",0 27822 .parmiv .byte "Invalid parameter",0 27823 .sioch .byte "Invalid SIO channel",0 27824 .inon .byte "Not a number",0 27825 .hugenum .byte "Number magnitude",0 27826 .ptrnul .byte "Null pointer",0 27827 .strnul .byte "Null string",0 27828 .sssnr .byte "SCSI subsystem not ready",0 27829 .sioror .byte "SIO receiver data overrun",0 27830 .sioss .byte "SIO subsystem not ready",0 27831 .strsiz .byte "String too long",0 27832 .ssblk .byte "Too many disk blocks",0 27833 .elmct .byte "Too many elements",0 27834 .okay .byte "Unknown error",0 27835 .ssubr .byte "Unexpected SCSI bus reset",0 27836 .ssubp .byte "Unsupported SCSI bus phase",0 27837 .ssucg .byte "Unsupported SCSI command group",0 27838 .ssudt .byte "Unsupported SCSI device type",0 27839 .ssudf .byte "Unsupported SCSI driver function",0 In the firmware, the situation is a little different. With a few exceptions, internal firmware functions do not call APIs, the above SCPRINT being one of those exceptions (it calls the KSCPUT API to actually write to the console). Therefore, error handling is simplified compared to what would be required if a user-land program calls an API.¹ For example, in the above SCPRINT function, E_STRLEN (string is too long) could only occur when SCPRINT is called from user-land—none of the character strings in the firmware code are too long. Therefore, the possibility of E_STRLEN occurring is ignored in any firmware functions that need to write on the console.
E_SIOCH would occur if the serial I/O (SIO) primitive (KSCPUT) aborted because the selected SIO channel is not present in the system. In practice, such an error will never be returned when reading from or writing to the console. As the console is driven from SIO port A, any SIO setup failure during first-stage POST would halt the system. On the latest POC renditions, the MCE (machine check exception) LED would be illuminated to indicate POST terminated with a fatal error.
———————————————————— ¹Although the machine language monitor, Supermon 816, is part of the firmware, it is actually a user-land program that only accesses the firmware through the documented APIs. Supermon 816’s error-handling is stark, consisting of the text *ERR being printed, followed by a return to the user input loop.
_________________ x86? We ain't got no x86. We don't NEED no stinking x86!
|
|