====== FLOS v612 Kernal Manual ====== The following FLOS kernal routines can be executed simply by using a "CALL name" instruction, with registers pre-set to the routines requirements (Remember to INCLUDE the labels definitions from the equates folder.)\\ EG: --------------------------------------------------------------------------------- LD HL, my_text CALL kjt_print_string [rest of program..] my_text DB "HELLO WORLD!",0 ---------------------------------------------------------------------------------- //Notes//\\ * Kernal calls should not be made when the Video RAM is paged in. The only routine that is guaranteed to work in that situation is "[[kernal_call_manual#kjt_page_out_video]]" * It should be assumed that Kernal calls trash all registers, unless a routine's documentation says otherwise. ===== Kernal Call Index ===== ==== File System Routines ==== |[[kernal_call_manual#kjt_change_dir]]|Change to subdirectory| |[[kernal_call_manual#kjt_change_volume]]|Selects drives VOL0: to VOL7:| |[[kernal_call_manual#kjt_check_volume_format]]|Checks if current volume is formatted to FAT16.| |[[kernal_call_manual#kjt_continue_file_read]]|Same as KJT_READ_FROM_FILE except this does not set the load address/bank (uses working values instead)| |[[kernal_call_manual#kjt_create_file]]|Makes a new file stub| |[[kernal_call_manual#kjt_delete_dir]]|Deletes an (empty) directory| |[[kernal_call_manual#kjt_dir_list_first_entry|kjt_dir_list_first_entry]]|Find first entry in current directory| |[[kernal_call_manual#kjt_dir_list_get_entry]]|Returns data from directory list (see output registers)| |[[kernal_call_manual#kjt_dir_list_next_entry]]|Moves directory list pointer to the next entry| |[[kernal_call_manual#kjt_erase_file]]|Deletes a file| |[[kernal_call_manual#kjt_format_device]]|Formats entire SD card to FAT16| |[[kernal_call_manual#kjt_get_device_info]]|Returns info about the storage devices| |[[kernal_call_manual#kjt_get_dir_name]]|Returns the name of the current directory| |[[kernal_call_manual#kjt_get_dir_cluster]]|Returns the cluster address of the current dir| |[[kernal_call_manual#kjt_get_fs_vars_location]]|Returns address of Filesystem's control variables| |[[kernal_call_manual#kjt_get_total_sectors]]|Returns total sectors on current volume| |[[kernal_call_manual#kjt_get_volume_info]]|Returns data about the volumes mounted| |[[kernal_call_manual#kjt_load_file]]|Loads a file in its entirety from disk to RAM| |[[kernal_call_manual#kjt_make_dir]]|Creates a new sub directory in current directory| |[[kernal_call_manual#kjt_mount_volumes]]|Initializes the attached disk list| |[[kernal_call_manual#kjt_open_file]]|Looks for a file on current disk, resets file pointer etc| |[[kernal_call_manual#kjt_parent_dir]]|Move up a directory level| |[[kernal_call_manual#kjt_root_dir]]|Go to root directory of drive| |[[kernal_call_manual#kjt_read_from_file]]|Reads data from the opened file to RAM| |[[kernal_call_manual#kjt_rename_file]]|Renames files and directories| |[[kernal_call_manual#kjt_restore_dir_position]]|Legacy routine: In preference, use KJT_SET_DIR_CLUSTER with previously saved value in DE| |[[kernal_call_manual#kjt_save_file]]|Creates and saves a file from RAM to disk| |[[kernal_call_manual#kjt_set_dir_cluster]]|Sets the dir from a cluster address| |[[kernal_call_manual#kjt_set_file_pointer]]|Moves the read point from the start of a file| |[[kernal_call_manual#kjt_set_load_address]]|Specifies the load address and bank for a file read (when using KJT_continue_file_read)| |[[kernal_call_manual#kjt_set_read_length]]|Sets the read length of a file transfer to a certain value| |[[kernal_call_manual#kjt_store_dir_position]]|Legacy routine: In preference, Use KJT_GET_DIR_CLUSTER and save DE externally| |[[kernal_call_manual#kjt_write_to_file]]|Appends new data to an existing file| |[[kernal_call_manual#kjt_parse_path]]|Changes volume / directory according to a path string (basically, run the CD command)| ==== Low-Level Sector Access Routines ==== |[[kernal_call_manual#kjt_file_sector_list]]|To list the disk sectors that files occupy| |[[kernal_call_manual#kjt_get_sector_read_addr]]|Returns data and pointers allowing sector buffer relocation etc| |[[kernal_call_manual#kjt_read_sector]]|Loads 512 byte sector to the sector buffer| |[[kernal_call_manual#kjt_write_sector]]|Writes 512 byte sector to the current device| ==== Kernal Serial Comms Routines ==== |[[kernal_call_manual#kjt_serial_receive_header]]|Waits for a file header from serial port| |[[kernal_call_manual#kjt_serial_receive_file]]|Receives serial file data| |[[kernal_call_manual#kjt_serial_rx_byte]]|Wait for a byte from serial port| |[[kernal_call_manual#kjt_serial_send_file]]|Sends a file to serial port (Serial Link App format)| |[[kernal_call_manual#kjt_serial_tx_byte]]|Send a byte to serial port| ==== Kernal Keyboard And Mouse Routines ==== |[[kernal_call_manual#kjt_enable_mouse]]|Activates mouse driver (enables IRQ etc)| |[[kernal_call_manual#kjt_get_key]]|Returns value of key, if one has been pressed (does not wait)| |[[kernal_call_manual#kjt_get_key_buffer]]|Allows monitoring of the keyboard without affecting the buffer| |[[kernal_call_manual#kjt_get_key_mod_flags]]|Returns status of the shift, ctrl, alt etc keys| |[[kernal_call_manual#kjt_get_mouse_position]]|Returns absolute mouse position and button data| |[[kernal_call_manual#kjt_get_mouse_motion]]|Returns relative mouse displacement| |[[kernal_call_manual#kjt_keyboard_irq_code]]|Allows external apps to invoke FLOS keybaord IRQ code| |[[kernal_call_manual#kjt_mouse_irq_code]]|Allows external apps to invoke FLOS mouse IRQ code| |[[kernal_call_manual#kjt_wait_key_press]]|Pauses until a key is pressed| ==== Kernal Text and Display Routines ==== |[[kernal_call_manual#kjt_clear_screen]]|Clears OS screen and sets cursor position to top left (0,0)| |[[kernal_call_manual#kjt_draw_cursor]]|Draws (or removes) the cursor at the current cursor position| |[[kernal_call_manual#kjt_flos_display]]|Renamed to kjt_flos_settings| |[[kernal_call_manual#kjt_get_colours]]|Returns RGB values of the FLOS border, paper, cursor and colour list location| |[[kernal_call_manual#kjt_get_cursor_position]]|Returns the current cursor position| |[[kernal_call_manual#kjt_get_display_size]]|Returns size of OS_window| |[[kernal_call_manual#kjt_get_charmap_addr_xy]]|Returns the charmap address of coordinates x,y| |[[kernal_call_manual#kjt_get_input_string]]|Waits for user to enter a string of characters| |[[kernal_call_manual#kjt_get_pen]]|Returns current pen colour| |[[kernal_call_manual#kjt_patch_font]]|Allows easy (and individual) user defined characters in the FLOS font| |[[kernal_call_manual#kjt_plot_char]]|Prints character at given coords using current pen colours| |[[kernal_call_manual#kjt_print_string]]|Prints ASCII text string at the current cursor position| |[[kernal_call_manual#kjt_scroll_up]]|Scrolls the screen (and character map) up a line| |[[kernal_call_manual#kjt_set_colours]]|Sets FLOS border, paper and cursor colours and writes to the pen colour list| |[[kernal_call_manual#kjt_set_cursor_position]]|Repositions the text printing (cursor) position| |[[kernal_call_manual#kjt_set_pen]]|Changes current pen colour| |[[kernal_call_manual#kjt_wait_vrt]]|Wait for vertical retrace (IE: last scanline of display)| ==== Kernal Memory Management Routines ==== |[[kernal_call_manual#kjt_inc_bank]]|Change to the next bank| |[[kernal_call_manual#kjt_get_bank]]|Returns the current bank number in A| |[[kernal_call_manual#kjt_get_flos_bank]]|Returns the bank seelcted by FLOS before the current command executed| |[[kernal_call_manual#kjt_page_in_video]]|Pages video memory into $2000-$3FFF| |[[kernal_call_manual#kjt_page_out_video]]|Pages system memory into $2000-$3FFF| |[[kernal_call_manual#kjt_read_sysram_flat]]|Read flat system memory location (E:HL) into A| |[[kernal_call_manual#kjt_read_baddr]]|Reads a byte into A from address BANK:ADDRESS| |[[kernal_call_manual#kjt_set_bank]]|Switches the upper RAM page to a specific bank| |[[kernal_call_manual#kjt_write_baddr]]|Writes a byte from A into address BANK:ADDRESS| |[[kernal_call_manual#kjt_write_sysram_flat]]|Write A into flat system memory location (E:HL)| ==== Kernal Misc Routines ==== |[[kernal_call_manual#kjt_ascii_to_hex_word]]|Converts ASCII hex number at HL to numeric 16bit hex in DE| |[[kernal_call_manual#kjt_ascii_to_hex32]]|Converts ASCII hex number at HL to numeric 32bit hex in BC:DE| |[[kernal_call_manual#kjt_bchl_memfill]]|Fill memory with value in accumulator| |[[kernal_call_manual#kjt_compare_strings]]|Compares two ASCII strings| |[[kernal_call_manual#kjt_dont_store_registers]]|Stops FLOS updating the stored register values when program quits| |[[kernal_call_manual#kjt_get_version]]|Returns FLOS and OSCA version| |[[kernal_call_manual#kjt_hex_byte_to_ascii]]|Makes ASCII version of a numeric hex byte| |[[kernal_call_manual#kjt_set_commander]]|Specifies a command string to be run when programs exit| |[[kernal_call_manual#kjt_timer_wait]]|Waits n periods of 16 microseconds and returns| |[[kernal_call_manual#kjt_flos_settings]]|Restores the FLOS video mode, sets up FLOS IRQs, clears keyboard buffer etc| ==== Environment Variable Routines ==== |[[kernal_call_manual#kjt_delete_envar]]|Deletes an environment variable| |[[kernal_call_manual#kjt_get_envar]]|Gets (address of) value of an environment variable| |[[kernal_call_manual#kjt_set_envar]]|Sets/updates an environment variable| \\ ---- ===== File System Related Calls===== __Some Details__:\\ There are two main ways to load a file, a simple single-call approach and a more flexible random-access approach.\\ To do a simple file load, set HL to a zero terminated ASCII filename string, IX to the destination address and B to the destination bank, then call "[[kernal_call_manual#kjt_load_file|kjt_load_file]]" Check the return code - see table below - if the zero flag is set, everything is OK.\\ The more flexible way to load file data is as follows: Set HL to a zero terminated ASCII filename string and call "[[kernal_call_manual#kjt_open_file]]". If the zero flag is set on return, the file was found and the length of the file will be in IX:IY (if the zero flag is not set, check the error code).\\ Next, the following two routines can be called *if required*\\ "[[kernal_call_manual#kjt_set_file_pointer]]" - This allows data to be read from anywhere within a file, instead of right from the start. Registers required:\\ * IX:IY = Offset in bytes from start of file\\ "[[kernal_call_manual#kjt_set_read_length]]" - This allows the length of transfer to be set. Registers required:\\ * IX:IY = Bytes to load\\ Finally, call "[[kernal_call_manual#kjt_read_from_file]]" to transfer the data to memory. Registers required:\\ * HL = Load address\\ * B = Bank of load address\\ Again, on return, if the zero flag is set then the operation completed OK.\\ The file pointer is automatically incremented by the number of bytes transferred, therefore it is not necessary call "[[kernal_call_manual#kjt_set_file_pointer]]" each time if chunks of a file are required sequentially. Attempting to read beyond the end of a file will return an error (code $1B). The load length MUST be set for each read (and load address and bank set appropriately each call).\\ To maintain speed, a fresh seek from the start of the file is not performed each time "[[kernal_call_manual#kjt_read_from_file]]" is called unless the file pointer has been changed. Internal variables must be maintained, therefore do not perform any other disk / serial operations (or anything that changes the sector buffer) between successive calls to this routine.\\ Whenever a disk file transfer reaches address $FFFF, it wraps around to $8000 and continues on into the next bank.\\ Most of the file system kernal calls return one of these standard error codes:\\ * If the zero flag is set, the operation was a success\\ * If the zero flag is not set, there was an error. A = error code:\\ |$01|disk full| |$02|file not found| |$03|(root) dir table is full| |$04|directory requested is actually a file| |$05|can't delete dir, it is not empty| |$06|not a file| |$07|file length is zero| |$08|address error (file too big for memory)| |$09|filename already exists| |$0a|already at root directory| |$0e|invalid volume| |$13|unknown/incorrect disk format| |$1b|requested bytes beyond end of file| |$22|device not present| |$23|directory not found| |$24|end of directory list| |$2e|device does not use MBR| __**Advanced:**__\\ In FLOS v599 the following routines were added to allow external programs to hook into the filesystem variables used by FLOS: [[kernal_call_manual#kjt_get_fs_vars_location]] The data at the returned location (see link for format) can be backed up and restored by a user program, allowing multiple open files to managed etc.\\ //Notes://\\ * When restoring altered variable data, the first byte "fs_filepointer_valid" should always be cleared so that filesystem correctly re-seeks from the start of files. *The current volume number must be handled seperarately if files on multiple volumes are to be handled. Additionally, the following two new routines were added:\\ [[kernal_call_manual#kjt_continue_file_read]]\\ [[kernal_call_manual#kjt_set_load_address]]\\ The normal file read call [[kernal_call_manual#kjt_read_from_file]] requires the bank and address to be specified, which may be a nuisance when working with multiple files. With the [[kernal_call_manual#kjt_continue_file_read]] routine, the file bytes are written to an address from the end of the last read operation. [[kernal_call_manual#kjt_set_load_address]] sets the address and bank to a specific location.\\ \\ ---- === kjt_check_volume_format === Action: Checks if current volume is available and formatted to FAT16\\ //Input Registers :// * None\\ //Output Registers :// * Standard error codes\\ \\ ---- === kjt_change_volume === Action: Selects a new volume (the directory will be that which was last selected in the new volume)\\ //Input Registers ://\\ * A = volume to select //Output Registers ://\\ * Standard error codes //Note:// Will not allow a change to an invalid Volume (non-FAT16 etc)\\ \\ ---- === kjt_format_device === Action: Formats a device (entire drive as single partition, no MBR)\\ //Input Registers ://\\ * A = Device to format (0 = DEV0: (SD_Card), 1 = DEV1: (user driver 1) * HL = Address of desired disk label ASCII string //Output Registers :// * Standard error codes //Note:// It is highly recommended that "[[kernal_call_manual#kjt_mount_volumes]]" is called after this routine.\\ \\ ---- === kjt_make_dir === Action: Creates a new sub directory in current directory\\ //Input Registers ://\\ * HL = zero terminated dir name //Output Registers :// * Standard error codes \\ ---- === kjt_change_dir === Action: Change to subdirectory\\ //Input Registers ://\\ * HL = zero terminated dir name //Output Registers :// * Standard error codes \\ ---- === kjt_parent_dir === Action: Move up a directory level\\ //Input Registers ://\\ * None //Output Registers ://\\ * Standard error codes \\ ---- === kjt_root_dir === Action: Go to root directory of volume\\ //Input Registers ://\\ * None //Output Registers ://\\ * Standard error codes \\ ---- === kjt_delete_dir === Action: Deletes an (empty) subdirectory\\ //Input Registers ://\\ * HL = zero terminated dir name //Output Registers :// * Standard error codes \\ ---- === kjt_erase_file === Action: Deletes a file in the current directory\\ //Input Registers://\\ * HL = zero terminated file name // Output Registers ://\\ * Standard error codes \\ ---- === kjt_get_total_sectors === Action: Returns total sectors on current volume\\ //Input Registers ://\\ * none //Output Registers ://\\ * C:DE = number of sectors\\ \\ ---- === kjt_load_file === Action: Loads the specified file from current directory in its entirity to the specifed address.\\ //Input registers ://\\ * IX = address to load to * B = bank to load to * HL = zero terminated filename // Output registers ://\\ * Standard error codes //Note:// This routine both opens a file and reads all the data to RAM - for more flexibility use "[[kernal_call_manual#kjt_open_file]]", "[[kernal_call_manual#kjt_set_file_pointer]]", "[[kernal_call_manual#kjt_set_read_length]]" and "[[kernal_call_manual#kjt_read_file_data]]"\\ \\ ---- === kjt_save_file === Action: Saves a file to current directory.\\ //Input registers://\\ * IX = Source data start address * B = bank to save data from * C:DE = number of bytes to save * HL = zero terminated filename //Output registers://\\ * Standard error codes //Note:// This routine both creates a new file and saves data to it - it cannot be used append new data to an existing file (will return "file already exists" error if attempted).\\ \\ ---- === kjt_open_file === Action: Looks for a file in current directory and sets internal registers ready for "[[kernal_call_manual#kjt_read_from_file]]" call.\\ //Input Registers ://\\ * HL = pointer to zero terminated filename to look for\\ //Output Registers ://\\ If the Zero Flag is set: All OK. Registers are:\\ * IX:IY = Length of file * DE = First disk cluster used by file If zero flag is not set: standard error codes.\\ //Note:// File pointer is set to 0, default transfer length = total file size\\ \\ ---- === kjt_set_file_pointer === Action: Moves the read point from the start of a file\\ //Input Registers ://\\ * IX:IY = Offset in bytes from start of file. //Output Registers :// * none //Note:// Use after "[[kernal_call_manual#kjt_open_file]]" (if required)\\ \\ ---- === kjt_set_read_length === Action: Forces the read length of the file transfer to a certain value\\ //Input Registers ://\\ * IX:IY = Bytes to load //Output Registers ://\\ * none //Note:// Use after [[kernal_call_manual#kjt_find_file]] (if desired)\\ \\ ---- === kjt_read_from_file === Action: Loads data (from the previously opened file) to a specified address.\\ //Input Registers ://\\ * HL = Destination address * B = Destination bank //Output Registers ://\\ * Standard error codes\\ //Notes// * "[[kernal_call_manual#kjt_open_file]]" MUST be called first before using this routine. * Whenever a disk file transfer reaches address $FFFF, it wraps around to $8000 and continues onto the next bank. \\ ---- === kjt_create_file === Action: Makes a file stub for a new file in current directory.\\ //Input Registers ://\\ * HL = address of zero-terminated filename //Output Registers :// * Standard error codes \\ ---- === kjt_write_to_file === Action: Appends new data to an existing file in current directory.\\ //Input Registers ://\\ * HL = null-terminated ascii filename of file to be appended to * IX = address of source data * B = bank of source data * C:DE = number of bytes to write //Output Registers :// * Standard error codes //Note:// Returns "file not found" error if the file has not been previously created with "[[kernal_call_manual#kjt_create_file]]" or "[[kernal_call_manual#kjt_save_file]]"\\ \\ ---- === kjt_dir_list_first_entry === Action: Finds the first listing of current directory, returns info.\\ //Input registers://\\ * None //Output registers://\\ If zero flag is set:\\ * HL = Location of null terminated filename string * IX:IY = Length of file (if applicable) * B = File flag (1 = directory, 0 = file) If zero flag is not set, standard error codes (EG: $24 = Reached end of directory)\\ \\ ---- === kjt_dir_list_get_entry === Action: Returns data about the entry at the current position in the directory list.\\ //Input registers ://\\ * None //Output registers ://\\ If zero flag is set:\\ * HL = Location of null terminated filename string * IX:IY = Length of file (if applicable) * B = File flag (1 = directory, 0 = file) If zero flag is not set, standard error codes (EG: $24 = Reached end of directory)\\ \\ ---- === kjt_dir_list_next_entry === Action: Moves the internal directory list pointer to the next entry and returns details about the entry found\\ //Input registers ://\\ * None //Output registers://\\ If zero flag is set:\\ * HL = Location of null terminated filename string * IX:IY = Length of file (if applicable) * B = File flag (1 = directory, 0 = file) If zero flag is not set, standard error codes (EG: $24 = Reached end of directory)\\ \\ ---- === kjt_get_dir_name === Action: Returns ascii string of current directory name (null terminated)\\ //Input registers ://\\ * None //Output registers ://\\ If zero flag set:\\ * HL = ascii string If zero flag is not set, standard error codes\\ \\ ---- === kjt_mount_volumes === Action: Reinitializes the drives and mount list\\ //Input registers ://\\ * If A = 1, mount quietly (no text output)\\ //Output registers ://\\ * None //Note:// Also attempts to create the assign Envar 'EX0' for VOL0:COMMANDS (FLOS v609+) \\ ---- === kjt_get_volume_info === Action: Returns info about the volumes mounted.\\ //Input Registers :// * None //Output Registers ://\\ * HL = address of volume mount list * B = Number of volumes mounted * A = currently Selected volume \\ ---- === kjt_get_device_info === Action: Returns info from the device list.\\ //Input Registers ://\\ * None //Output Registers ://\\ * HL = address of device info table * DE = address of driver table * B = number of devices initialized * A = current active driver number \\ ---- === kjt_get_dir_cluster === Action: Returns the location of the directory cluster\\ //Input Registers ://\\ * None //Output Registers ://\\ * DE = cluster pointed at by current directory \\ ---- === kjt_set_dir_cluster === Action: Sets the directory cluster (for use with above command)\\ //Input Registers ://\\ * DE = desired cluster number to be used as current dir //Output Registers ://\\ * None //Note:// The routine attempts to validate the dir by looking for the directory name, if this fails, the dir is set to ROOT and error code $23 is returned (DIR not found). \\ ---- === kjt_rename_file === Action: Rename files / folders.\\ //Input Registers ://\\ * HL = Pointer to filename to change (null terminated ASCII) * DE = Pointer to replacement filename (null terminated ASCII) //Output Registers ://\\ * Standard error codes \\ ---- === kjt_get_fs_vars_location === Action: Sets HL to the address of the filesystem's control variables.\\ //Input Registers ://\\ * None //Output Registers ://\\ * HL = location of the following data structure:\\ |$00 byte|fs_filepointer_valid| |$01 longword|fs_file_pointer| |$05 longword|fs_file_length| |$09 longword|fs_bytes_to_go| |$0d word|fs_file_start_cluster| |$0f word|fs_file_working_cluster| |$11 word|fs_z80_address| |$13 byte|fs_z80_bank| //Note:// When restoring altered data, the first byte "fs_filepointer_valid" should always be cleared. This causes the read operations to cleanly seek from the beginning of files when file transfer (re)commences. (Access will be noticeably slower than a single continuous load.)\\ \\ ---- === kjt_continue_file_read === Action: Same as [[kernal_call_manual#kjt_read_from_file]] except this does not set the load address/bank\\ //Input Registers ://\\ * None //Output Registers ://\\ * Standard error codes \\ ---- === kjt_set_load_address === Action: Specifies the load address and bank for a file read (when using [[kernal_call_manual#kjt_continue_file_read]])\\ //Input Registers ://\\ * HL = Z80 address where data should load * B = FLOS bank where data should load Output// Registers ://\\ * None \\ ---- === kjt_parse_path === (added in FLOS v607)\\ Action: Changes volume and directory according to the path string supplied. This is basically the same as the "CD" command.\\ //Input Registers ://\\ * HL = Address of path string //Output Registers :// * Standard error codes //Note:// If the path is invalid (dir or volume not found) an error code is returned and the dir remains unchanged. \\ ---- ==== Low-Level Disk Sector Access Routines ==== === kjt_read_sector === Action: Loads a 512 byte sector from the device and address selected to the sector buffer\\ //Input registers ://\\ * A = Device number to access (normally 0) * BC:DE = absolute LBA address for desired sector //Output registers ://\\ * Standard error codes (relevant errrors: $1e, $22) \\ ---- === kjt_write_sector === Action: Writes a 512 byte sector from the sector buffer to the device and address selected\\ //Input registers ://\\ * A = Device number to access (normally 0) * BC:DE = absolute LBA address for desired sector //Output registers ://\\ * Standard error codes (relevant errrors: $1e, $22) \\ ---- === kjt_file_sector_list === Action: Retrieves the location of the (next) disk sector that a file occupies.\\ //Input registers://\\ * A = Sector offset (within current cluster) * DE = Cluster number //Output registers://\\ * A = Next sector offset * DE = Updated cluster * HL = Memory address of LSB of 4 byte sector location __How to use:__\\ To obtain the list of sectors that a file uses, first call "[[kernal_call_manual#kjt_find_file]]" with the filename in HL as normal. On exit, DE will be equal the first cluster that the file occupies. Clear the accumulator (as we're starting at the first sector of this cluster), and call "[[kernal_call_manual#kjt_file_sector_list]]". On return A and DE are updated to the values required for the next time the routine is called and HL points to the lowest significant byte of the sector address (LBA0). Next, copy the 4 bytes from HL to HL+3 to your sector list buffer and loop around, calling "[[kernal_call_manual#kjt_file_sector_list]]" for as many sectors as are used by the file (simply subtract 512 from a variable holding the file size every call until variable is = < 0)\\ \\ ---- === kjt_get_sector_read_addr === Action: Returns the address of the selected drive's sector read routine, also LBA variable and sector_location_variable\\ //Input Registers ://\\ * A = Device to access (normally 0) //Output Registers ://\\ * HL = Address of sector read routine * DE = Address of the LSB of the 32bit LBA variable * BC = Address of the sector buffer location variable //Notes//\\ * This routine can be used to allow programs to read sectors directly to an arbitrary location in memory (IE: A program can write to the sector LBA and sector buffer location variables, and then call the low-level sector read routine using the data obtained). *The sector buffer location is automatically reset to the location that the OS requires whenever a filesystem routine is called (this includes the KJT read/write sector calls above.) Similarly, altering the LBA variable manually should not affect normal operation of the filesystem. \\ ---- ===== Serial I/O Routines ===== To load a file serially you would call: kjt_serial_receive_header, setting A and HL as appropriate (see docs below). Once it has been received, [[kernal_call_manual#kjt_serial_receive_file]] may be called (setting B and HL appropriately).\\ As with the disk routines, whenever a serial file transfer command reaches address $FFFF, it wraps around to $8000 and continues onto the next bank.\\ \\ ---- === kjt_serial_receive_header === Action: Waits for a file header from serial port.\\ //Input Registers ://\\ * HL = Location of null terminated filename (filename can be "*" if any file is to be accepted). * A = described in following table\\ |Bits 5:0|Waiting time in seconds before time out error| |Bit 6|Allow abort with Enter Key (if 1)| |Bit 7|Allow abort with ESC Key (if 1)| //Output Registers ://\\ Zero Flag: If set, all OK * IX = location of serial file header (see [[Serial Link Info]] for details) If Zero Flag is NOT set, A = serial error code:\\ |$07|Save length is zero| |$08|File too big (IE: Memory address out of range)| |$0f|Checksum bad| |$11|Comms error| |$14|Time out error| |$25|Filename mismatch| |$2A|Aborted with ESC / Enter key| \\ ---- === kjt_serial_receive_file === Action: Receives serial file data\\ //Input Registers ://\\ * HL = Address to load file to * B = Bank to load file into //Output Registers ://\\ Zero Flag: If set, all OK\\ * IX = location of of serial file header If Zero Flag is NOT set, A = serial error code:\\ |$07|Save length is zero| |$08|File too big (IE: Memory address out of range)| |$0f|Checksum bad| |$11|Comms error| |$14|Time out error| |$25|Filename mismatch|\\ //Note:// "[[kernal_call_manual#kjt_serial_receive_header]]" MUST be called before this routine!\\ \\ ---- === kjt_serial_send_file === Action: Sends a file to serial port (Serial Link App format)\\ //Input Registers ://\\ * HL = filename * C:DE = length of file * B = Bank number that file starts in * IX = Start address //Output Registers ://\\ Zero flag, set if all OK.\\ If zero flag not set, A = serial error code:\\ |$07|Save length is zero| |$08|File too big (IE: Memory address out of range)| |$0f|Checksum bad| |$11|Comms error| |$14|Time out error| |$25|Filename mismatch| \\ ---- === kjt_serial_rx_byte === Action: Wait for a byte from serial port\\ //Input Registers ://\\ * A. Bits described in following table:\\ |[0:5]|max time to wait in seconds| |[6]|If set, the wait can be aborted with the ENTER key| |[7]|If set, the wait can be aborted with ESCAPE key| //Output Registers ://\\ If Carry flag is clear all OK, A = byte received.\\ If Carry flag is set, error code in A as follows:\\ A = $14 - Timed out\\ A = $2A - Aborted with key\\ //Note:// All registers except A are preserved.\\ \\ ---- === kjt_serial_tx_byte === Action: Send a byte to serial port\\ //Input Registers ://\\ * none //Output Registers ://\\ * A = byte to send //Note:// All registers except A preserved.\\ \\ ---- ===== Keyboard And Mouse Routines ===== === kjt_wait_key_press === Action: Pauses until a key is pressed (and returns value)\\ //Input Registers ://\\ * None //Output Registers ://\\ * A = Scancode of key pressed * B = ASCII code (B=$00 if no valid ascii char equivalent.) //Note:// ASCII code is modified by shift / Alt key status\\ \\ ---- === kjt_get_key === Action: Returns value of key, if one has been pressed (does not wait)\\ //Input Registers ://\\ * None //Output Registers ://\\ * A = Scancode of key pressed (A = $00 if no key pressed) * B = ASCII code (B=$00 if no valid ascii char equivalent.) //Note:// ASCII code is modified by shift / Alt key status\\ \\ ---- === kjt_get_key_mod_flags === Action: Returns current status of key modifiers\\ //Input Registers ://\\ * None //Output Registers ://\\ * A, bits: |[0]|left shift| |[1]|left/right ctrl| |[2]|left GUI| |[3]|left/right alt| |[4]|right shift| |[5]|right GUI| |[6]|Apps| \\ ---- === kjt_keyboard_irq_code === Action: Keyboard IRQ handler.\\ When a custom interrupt handler is set up but kernal-based keyboard handling is required, this routine can be called when the keyboard IRQ flag is set. The above kernal keyboard routines will then still work. (The call clears the relevant IRQ flag).\\ \\ ---- === kjt_enable_mouse === Action: Activates mouse pointer (called by MOUSE.EXE) and sets x/y boundaries\\ //Input Registers ://\\ * HL = Window size X * DE = Window size Y //Output Registers ://\\ * None \\ ---- === kjt_get_mouse_position === Action: Returns absolute mouse position and button data Input Registers : none Output Registers : Zero Flag - If not set, the mouse driver was not enabled, otherwise: HL = x coordinate DE = y coordinate A = buttons status The x and y coordinates cannot overflow from the boundaries set with "[[kernal_call_manual#kjt_enable_mouse]]"\\ //Note:// the mouse driver is currently somewhat primative - it may become out of sync with the three-byte packets that the mouse sends if say, interrupts are disabled)\\ \\ ---- === kjt_get_mouse_motion === Action: Returns relative mouse motion and button data\\ //Input Registers ://\\ * none //Output Registers ://\\ Zero Flag: if not set, the mouse driver was not enabled, Otherwise:\\ * HL = x motion since last called * DE = y motion since last called * A = buttons status //Note:// the mouse driver is currently somewhat primitive - it may become out of sync with the three-byte packets that the mouse sends if say, interrupts are disabled\\ \\ ---- === kjt_mouse_irq_code === Action: Mouse IRQ handler\\ When a custom interrupt handler is set up but kernal-based mouse handling is required, this routine can be called when the mouse IRQ flag is set. The above kernal mouse routines will then still work. (The call clears the relevant IRQ flag).\\ \\ ---- === kjt_get_key_buffer === Action: Returns values for monitoring the keyboard buffer\\ //Input Registers ://\\ * None //Output Registers ://\\ * HL = Location of the keyboard buffer WRITE index variable (The actual keyboard buffer starts 32 bytes lower in memory) * A = The value of the keyboard READ index variable. //Note:// On return, if A = (HL) no key has been pressed (IE: the keyboard buffer is empty)\\ \\ ---- ===== Memory Mamagement Routines ===== Under FLOS, Z80 Address space $5000-$FFFF is available for user programs. FLOS allows the upper 32KB of Z80 address space ($8000-$FFFF) to be paged. 15 pages of system RAM can appear in this region, starting at system RAM address $08000 (FLOS does not normally allow the first 32KB of system RAM to be paged into $8000-$FFFF). Therefore, when using the KJT routines for bank management, the figures are as follows:\\ ^Bank^SYSTEM RAM^Z80 ADDRESS| |$00|$08000-$0ffff|$8000-$ffff| |$01|$10000-$17fff|$8000-$ffff| |$02|$18000-$1ffff|$8000-$ffff| |$03|$20000-$27fff|$8000-$ffff| |$04|$28000-$2ffff|$8000-$ffff| |$05|$30000-$37fff|$8000-$ffff| |$06|$38000-$3ffff|$8000-$ffff| |$07|$40000-$47fff|$8000-$ffff| |$08|$48000-$4ffff|$8000-$ffff| |$09|$50000-$57fff|$8000-$ffff| |$0a|$58000-$5ffff|$8000-$ffff| |$0b|$60000-$67fff|$8000-$ffff| |$0c|$68000-$6ffff|$8000-$ffff| |$0d|$70000-$77fff|$8000-$ffff| |$0e|$78000-$7ffff|$8000-$ffff| (Notice that the figures are different to the values used if writing directly to the bank selection hardware port: [[Osca Manual#Port $00|sys_mem_select]]).\\ \\ ---- === kjt_set_bank === Action: Changes the currently selected upper RAM page Input Registers : A = bank number $00 to $0e Output Registers : none Trashes: A \\ ---- === kjt_get_bank === Action: Returns the upper bank number in A Input Registers : none Output Registers : A = current bank number ($00 to $0e) Trashes: none \\ ---- === kjt_inc_bank === Action: change to the next bank Input Registers : none Output Registers : If Zero flag set: all OK, If Zero is not set: A = $08 - bank out of range \\ ---- === kjt_page_in_video === Action: Pages 8KB of video memory specified by (hardware register [[Osca Manual#Register $206|vreg_vidpage]]) into Z80 address space $2000-$3FFF.\\ __//CAUTION://__ This area is used by part of FLOS so ideally no other FLOS call should be made until [[Kernal Call Manual#kjt_page_out_video]] is called.\\ //Input Registers ://\\ * none //Output Registers ://\\ * none //Trashes ://\\ * A \\ ---- === kjt_page_out_video === Action: Pages normal system memory (part of the FLOS!) back into $2000-$3FFF\\ //Input Registers ://\\ * none //Output Registers ://\\ * none //Trashes ://\\ * A \\ ---- === kjt_read_sysram_flat === Action: Reads system memory in a flat, linear addressing mode\\ //Input Registers ://\\ * E:HL = $00000 - $7FFFF (address to read) //Output Registers ://\\ * A (byte read from address) //Trashes :// * BC * DE * HL //Notes//\\ * The routine saves and restores the entire port byte "[[Osca Manual#Port $00|sys_mem_select]]" around the read so make sure any interrupt service routine is in unpaged memory (<$8000) or disable interrupts to avoid problems. * As this routine is very slow, only use if convenience is more important than speed. \\ ---- === kjt_write_sysram_flat === Action: Writes to system memory in a flat, linear addressing mode\\ //Input Registers ://\\ * E:HL = $00000 - $7FFFF (address to write), * A = byte to write //Output Registers ://\\ * None (but see below) //Trashes ://\\ * BC * DE * HL //Notes//\\ * The routine saves and restores the entire port byte "[[Osca Manual#Port $00|sys_mem_select]]" around the write so make sure any interrupt service routine is in unpaged memory (<$8000) or disable interrupts to avoid problems. * As this routine is not fast, only use if convenience is more important than speed. \\ ---- === kjt_read_baddr === Action: Reads a byte from system memory (allows programs in paged RAM (8000-FFFF) to easily read data from a different bank)\\ //Input Registers ://\\ * B = Bank * HL = Address //Output registers ://\\ * A = byte from memory location specified //Notes//\\ * The routine saves and restores the entire port byte "[[Osca Manual#Port $00|sys_mem_select]]" around the read so make sure any interrupt service routine is in unpaged memory (<$8000) or disable interrupts to avoid problems. * As this routine is not fast, only use if convenience is more important than speed. \\ ---- === kjt_write_baddr === Action: Writes a byte to system memory, allows programs in paged RAM (8000-FFFF) to write data to a different bank\\ //Input Registers ://\\ * B = Bank * HL = Address * A = Byte to writes //Output Registers ://\\ * None //Notes//\\ * The routine saves and restores the entire port byte "[[Osca Manual#Port $00|sys_mem_select]]" around the write so make sure any interrupt service routine is in unpaged memory (<$8000) or disable interrupts to avoid problems. * As this routine is not fast, only use if convenience is more important than speed. * Hardware support for writing to alternative pages in provided via the port [[OSCA Manual#Port $0B|sys_alt_write_page]] (see [[OSCA Manual|hardware manual]])\\ \\ ---- === kjt_get_flos_bank === Action: Returns the value of the bank being used by FLOS before the current command executed.\\ This is useful when a location header places a program in paged memory ($8000-$FFFF) thus changing the bank selection to that of the program, but the program wants to act on the memory in the bank selected by FLOS as if it were an internal command.\\ //Input Registers ://\\ * None //Output Registers ://\\ * A - The bank which FLOS was referencing. \\ ---- ===== Text And Display Routines ===== === kjt_print_string === Action: Prints null-terminated ASCII text string at cursor position\\ //Input Registers ://\\ * HL address of string (zero terminated) //Output Registers ://\\ * None //Notes//\\ * ASCII Char $0a = Line Feed * ASCII Char $0d = Carriage Return * ASCII Char $0b = Line Feed and Carriage return * HL returns pointing to the zero byte at end of the string All other registers are preserved by this routine.\\ This routine moves the current cursor position.\\ \\ ---- === kjt_clear_screen === Action: clears OS screen and set cursor position to top left (0,0)\\ //Input Registers ://\\ * None //Output Registers ://\\ * None \\ ---- === kjt_plot_char === Action: Prints ASCII character at supplied coordinates using current pen colours\\ //Input Registers ://\\ * A = ASCII character * B = x coord * C = y coord //Output Registers ://\\ * None //Notes//\\ * Plot_char does not change the current cursor position. * If a coordinate is outside the window, it is taken as zero \\ ---- === kjt_get_pen === Action: Returns current pen colour\\ //Input Registers ://\\ * None //Output Registers ://\\ * A = $nm where "n" is the background and "m" is the foreground colour (see table) Available (default) colours:\\ |0|transparent (shows UI "paper" colour)| |1|black| |2|blue| |3|red| |4|magenta| |5|green| |6|cyan| |7|yellow| |8|white| |9|dark grey| |a|mid grey| |b|light grey| |c|orange| |d|light blue| |e|light green| |f|brown| \\ ---- === kjt_set_pen === Action: Changes current pen colour\\ //Input Registers ://\\ * A = $nm where "n" is the background and "m" is the foreground colour (see table) Available (default) colours:\\ |0|transparent (shows UI "paper" colour)| |1|black| |2|blue| |3|red| |4|magenta| |5|green| |6|cyan| |7|yellow| |8|white| |9|dark grey| |a|mid grey| |b|light grey| |c|orange| |d|light blue| |e|light green| |f|brown| //Output Registers ://\\ * None \\ ---- === kjt_get_colours === Action: Returns the location of the FLOS colour list.\\ //Input registers ://\\ * none //Output registers ://\\ * HL = location of colour list: 18 words (RGB values). //Colour List ://\\ +$00 - Paper\\ +$02 - Border\\ +$04 - Cursor\\ +$06 - 15 pen colours starting with pen 1\\ //Note:// FLOS stores its colour list under the hardware registers so system memory needs to paged into that region if writing directly to the address returned from this call. (Simply reading the list poses no such problem). In all cases, [[Kernal Call Manual#kjt_set_colours]] needs to be called to actually change the palette (unless writing directly to the Hardware Palette Registers)\\ \\ ---- === kjt_set_colours === Action: Sets FLOS border, paper and cursor colours and updates the pen colour list\\ //Input registers ://\\ * HL = location of the colour palette list (18 RGB words) //Colour List ://\\ +$00 - Paper\\ +$02 - Border\\ +$04 - Cursor\\ +$06 - 15 pen colours starting with pen 1\\ //Output registers ://\\ * None Input registers are trashed.\\ //Note:// Changes persist until FLOS restarts (whereas any changes made with the FLOS command "COLOUR" are permanent until reset)\\ \\ ---- === kjt_draw_cursor === Action: Draws (or removes) the cursor at the current cursor position\\ //Input Registers ://\\ * HL = Offset of cursor char image within VRAM font data: |$0000 - $07FF|All zeroes| |$0800 - $0FFF|Raster font image (256 horizontal bytes * 8 vertical bytes)| |$1000 - $17FF|As above but with the bits inverted| |$1800 - $1FFF|All ones| EG: HL = $0000 : No data, IE: Delete the cursor HL = $085f : Underscore cursor ($800-$8ff = top line of ASCII chars 0-255) HL= $1800 : Solid block cursor //Output Registers ://\\ * None //Note:// Remember, [[Kernal Call Manual#kjt_print_string]] moves the cursor position so the cursor image should be deleted before that routine is called.\\ \\ ---- === kjt_get_input_string === Action: waits for user to enter a string of characters followed by Enter (characters appear on screen)\\ //Input Registers ://\\ * A - maximum characters allowed (set to 255 if dont care) //Output Registers ://\\ * HL = string location (zero terminated) * A = number of characters of entered string (zero if aborted by pressing ESCAPE) \\ ---- === kjt_set_cursor_position === Action: Repositions the text printing (cursor) position. If a coordinate is out of range it will be set to 0.\\ //Input Registers ://\\ * B = X coord * C = Y coord //Output Registers ://\\ * Zero flag set if all OK * If zero flag not set: Invalid coordinates \\ ---- === kjt_get_cursor_position === Action: Returns the current cursor position\\ //Input Registers ://\\ * None //Output registers ://\\ * B = x coord * C = y coord \\ ---- === kjt_scroll_up === Action: Scrolls the screen (and character map) up a line, inserting a blank line at the bottom of the screen.\\ //Input Registers ://\\ * None //Output registers ://\\ * None \\ ---- === kjt_get_display_size === Action: Returns size of OS_window.\\ //Input registers ://\\ * None //Output registers ://\\ * B = x width (usually 40) * C = y height (usually 25) Note: All other registers preserved.\\ \\ ---- === kjt_get_charmap_addr_xy === Action: Returns the charmap address of the character at coordinates x,y //Input registers ://\\ * B = x coord * C = y coord //Output registers ://\\ * HL = character map address of coords //Note:// All other registers are preserved. \\ ---- === kjt_wait_vrt === Action: Wait for last scanline of display\\ //Input Registers ://\\ * none //Output Registers ://\\ * none Trashes: * A \\ ---- === kjt_patch_font === Action: Change an individual character in the FLOS font.\\ //Input registers ://\\ * A = char number (must be 0-255, but note: Some chars < 32 are unprintable using "[[Kernal Call Manual#kjt_print_string"]]) * HL = address of new character pattern (8 bytes) //Output registers ://\\ * None \\ ---- ===== Misc Routines ===== === kjt_hex_byte_to_ascii === Action: puts ASCII version of the hex byte value in A at HL (two chars), HL=HL+2\\ //Input Registers ://\\ * A = Hex number to convert //Output Registers ://\\ * None //Note:// HL=HL+2\\ //Trashes :// * A \\ ---- === kjt_ascii_to_hex_word === Action: converts text string version of hex number at HL to actual hex word in DE\\ //Input Registers ://\\ * HL = source text (the routine scans from this location to the first character that is not a space) //Output Registers ://\\ * DE = result * HL = If result OK, location of first space character after the hex string (IE: usually a space or null character) * Zero Flag = set if all OK (also A=$00), Else: |A = $0c|Bad chars for hex| |A = $1A|Number is greater than $FFFF| |A = $1F|No chars found| \\ ---- === kjt_ascii_to_hex32 === Action: converts text string version of hex number at HL to actual hex word in BC:DE\\ //Input Registers ://\\ * HL = source text (the routine scans from this location to the first character that is not a space) //Output Registers ://\\ * BC:DE = Result * HL = If result OK, location of first space character after the hex string (IE: usually a space or null character) * Zero Flag = set if all OK (also A=$00), Else: |A = $0c|Bad chars for hex| |A = $1A|Number is greater than $FFFFFFFF| |A = $1F|No chars found| \\ ---- === kjt_dont_store_registers === Action: Prevents the OS from noting the register values when a program exits and returns to OS.\\ //Input Registers ://\\ * None //Output Registers ://\\ * None //Trashes ://\\ * A \\ ---- === kjt_get_version === Action: Returns FLOS / OSCA / BOOTCODE version values (also reports the V6Z80P PCB version if OSCA > version $673.)\\ //Input Registers ://\\ * none //Output Registers ://\\ * HL = OS version word * DE = Hardware version word * B = V6Z80P PCB version |0|Data is not available (because OSCA < 674 or FLOS < 610)| |1|Original V6Z80P| |2|V6Z80P+| |3|V6Z80P+ V1.1| Also, if C = 0:\\ * IX = Location of bootcode info data structure: |$0 [WORD]|Bootcode version (BCD) (if $0000 = Bootcode is < version $617)| |$2 [BYTE]|Devices available at boot time (Bit 0 = SD card)| |$3 [BYTE]|Device OS booted from (1=SD CARD, 2=EEPROM, 3=SERIAL)| If C <> 0 : FLOS < 610 = data not available\\ \\ ---- === kjt_compare_strings === Action: Compares two ASCII strings (not case sensitive)\\ //Input Registers ://\\ * DE = address of string 1 * HL = address of string 2 * B = maximum number characters to compare //Output Registers ://\\ * Carry flag: Only set if strings are the same. //Notes//\\ * Both strings should be zero terminated. * Compare fails if string lengths are different unless count is reached first. * Original HL/DE values are preserved. \\ ---- === kjt_bchl_memfill === Action: Fill memory with value in accumulator\\ //Input Registers ://\\ * HL = start address * BC = number of bytes to write * A = value to write //Output Registers ://\\ * none //Trashes ://\\ * HL * BC * A //Note:// Does NOT overflow from $FFFF into next bank.\\ \\ ---- === kjt_timer_wait === Action: Waits n x 16 microseconds and returns.\\ //Input Registers ://\\ * A = number of 16 microsecond periods to wait //Output Registers://\\ * None //Note:// Preserves all registers except A\\ \\ ---- === kjt_set_commander === Action: Sets a "permanent" command string that is to be launched when progams exit\\ //Input Registers ://\\ * HL = location of command string (40 chars max) //Output Registers ://\\ * None //Notes//\ * The string at HL will be parsed as a command whenever a program exits back to FLOS unless that program specifically tells FLOS to launch some other program (with A=$FE on exit). In this case, the commander program will eventually launch when controlis passed back to FLOS (IE: A <> $FE on exit) * To remove the commander string, point HL at a null string (a zero byte in memory) and call the routine. * To cancel the commander, press CTRL+C \\ ---- === kjt_flos_settings === Action: Restores the video registers and IRQ vectors/enables to the state used by the OS. Also clears the keyboard buffer. Can be called by programs that have changed the display mode etc before exit so that FLOS does not have to be completely restarted.\\ //Note:// This does not restore the data in the Video RAM area used by FLOS ($10000-$1ffff). //Input registers ://\\ * None //Output registers ://\\ * None \\ ---- ===== Environment Variable Related Calls ===== === kjt_set_envar === Action: Sets an environment variable (or updates a variable if it already exists)\\ //Input Registers ://\\ * HL = name of variable (4 chars max, zero-termination required if less than 4 chars) * DE = address of data for variable (4 bytes) //Output Registers ://\\ * Zero Flag = set if all OK, not set if no space for new variable (A = $2c) \\ ---- === kjt_get_envar === Action: gets (address of) value of an environment variable\\ //Input Registers ://\\ * HL = name of variable (4 chars max, zero-termination required if less than 4 chars) //Output Registers ://\\ * Zero Flag = Set : all OK, HL = address of data for variable (4 bytes) * Zero Flag = Not set: variable was not found, (A = $2b, hl = location of envar list, b = max envars) \\ ---- === kjt_delete_envar === Action: deletes an environment variable\\ //Input Registers ://\\ * HL = name of variable (4 chars max, zero-termination required if less than 4 chars) //Output Registers ://\\ * Zero flag = set if all OK, not set if named variable not found \\ ----