Editing
SmartBox OS
(section)
Jump to navigation
Jump to search
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
== OS Calls == The OS has calls (ie. a jump instruction which you call, which then calls, via a RAM vector, a routine in the OS) setup near the top of memory, through these calls you do everything associated with the controller. The calls are are such: * OS_PRINTER at address &FFB9 * OS_CALLOS at address &FFBC * OS_SENDBYTE at address &FFBF * OS_READBYTE at address &FFC2 * OS_SENDJOB at address &FFC5 * OS_READJOB at address &FFC8 * OS_DECODEJOB at address &FFCB The address is the one to call for the particular routine. * OS_PRINTER is reserved for future use. * OS_CALLOS calls upon the OS to do various things internally. * OS_SENDBYTE sends a byte out of the serial port. * OS_READBYTE reads a byte from the serial port. * OS_SENDJOB 'sends' a value to the JobCall caller. * OS_READJOB 'reads' a value from the JobCalls caller. * OS_DECODEJOB decodes the Job number held in A and acts on it. Note none of these things should be used in interupt routines, except OS_CALLOS, of any sort, except if YOU know what state the machine is in and WHY. === OS_READBYTE and OS_SENDBYTE: Serial Port === The serial port on the controller is currently based on the 6850 UART, this need not bother you as the OS deals with the thing entirely by itself. The chip is setup by the OS to always have a word format of 8n1 and a baud rate of 9600, this translates to 960cps. The 6850 has two divide rates for the baud rate, the OS only uses one, using the other one is beyond the scope of this document and shouldn't be neccessary to use. Only receive interupts are used, transmission of characters is done on a polled basis. As said, there are two calls OS_READBYTE and OS_SENDBYTE. ==== OS_READBYTE ==== OS_READBYTE tests the serial input buffer and returns the character (if any in the A register), the c flag states whether there was a character returned. {|class="calltable" |Entry|| A, X, Y, c, z = undefined |- |Exit|| * X, Y preserved * z = undefined * if c = 1 (no character received) *: A is preserved * if c = 0 (character received) *: A = character received |} ==== OS_SENDBYTE ==== OS_SENDBYTE sends the character in the A register out of the serial port, taking into consideration flow control etc. {|class="calltable" |Entry|| * A = character to send * X, Y, c, z = undefined |- |Exit|| * A, X, Y, c is preserved * z = undefined |} === OS_READJOB and OS_SENDJOB === To send/receive data from the user (either internally or via the serial port) you call OS_SENDJOB/OS_READJOB for the next byte. If your JobCall requires dynamic use of data, ie. interaction, then a check of the enviroment should be done to check the call came from the serial port. One example of this is the OS JobCall MultipleServer, which requires dynamic use of sending a stream of data until a reaction from the user to tell it to stop. ==== OS_READJOB: Read job value from the user ==== {|class="calltable" |Entry|| * A, X, Y, c, z = undefined |- |Exit|| * A = byte read * X, Y is preserved * c, z = undefined |- |Note|| When coming from the serial port it waits for a character to be received, if you are doing a serial only call and wish to have a loop checking for a character from the user while doing "your own thing", then OS_READBYTE should be used. For internal calls this reads data out of jobin_buf. |} ==== OS_SENDJOB: Give a job value back to the user ==== {|class="calltable" |Entry|| * A = byte to give * X, Y, c, z = undefined |- |Exit|| * A, X, Y is preserved * c, z = undefined |- |Note|| This will send either out to the serial port or place a byte in jobout_buf. For internal calls this stores the value in jobout_buf, which is allocated 128 bytes, no bound checking is done so sending more than 128 bytes to OS_SENDJOB will cause corruption of some memory. |} === OS_DECODEJOB === JobCalls in practise are really only used by the user, JobCalls tend not to call other calls at all, infact you shouldn't really call another call unless you were called from the serial port. If you do need to call another JobCall then you do it like this; with each call you have associated with it a number, and the call might require some data or give some data back or both. With the serial port this is simple, you just send data down and receive data as it is produced. You can't do this with internal calls, and some calls will not let you call them from inside the controller, you HAVE to call them from outside. But for the ones which do let you, you do it with two data blocks, one for input TO the call and one for output FROM the call. These are setup in a position in memory (jobin_buf and jobout_buf), each one has a maximum of 128 bytes and this should not be overflowed (OS_READJOB and OS_SENDJOB do NOT do any bound checking). So to start with you place in the input block the data you want to give the call (if any), call it, and then act on the data in the output block (if any). The OS call OS_DECODEJOB is the one which actually calls the JobCall handler and eventually the actual routine, you tell the JobCall handler which call you want by placing the JobCode in the A register. So for OS_DECODEJOB: {|class="calltable" |Entry|| * A = JobCode * X, Y, c, z = undefined * jobin_buf should contain any input data |- |Exit|| * A = flag * X = number of bytes given back by routine * Y = undefined * c = status, if set JobCall does not exist * z = status, if set JobCall cannot be called internally * jobout_buf contains any data sent from routine |} A typical example would be: <nowiki> LDA #readhimem ; JobCode for ReadHimem JSR OS_DECODEJOB ; Call the JobCall handler LDX jobout_buf ; Read HIMEM from buffer LSB LDY jobout_buf+1 ; Read HIMEM from buffer MSB STX jobin_buf ; Place LSB in input buffer STY jobin_buf+1 ; Place MSB in input buffer LDA #writelomem ; JobCode for WriteLomem JSR OS_DECODEJOB ; Call the JobCall handler</nowiki> which would read HIMEM, and then write LOMEM to be the same value, leaving no spare memory left. The reason why you should not call an internal call from another internal call is that the same buffers (jobin_buf and jobout_buf) would be used for both calls, causing conflict between the two calls, or rather to the originator of the primary call ! The only time it would be safe if is if you have already got all the data you want from jobin_buf and haven't placed any in the jobout_buf (it would be lost if you had done). === OS_CALLOS === This OS call does various calls which are completely linked to the OS, everything from relocating code to reading and writing the hardware ports. As normal, a "function" request value is placed in the A register, any extra data is put in the X and Y registers and a call to OS_CALLOS is made, and data is passed back in X, Y, c and z. The A register will return 0 for all routines except for calls 0 (deemed always to exist anyway), 12 (A is reserved for future use), 14 (returns 1 instead) and 15 (12, 14 and 15 do not return 12, 14, 15 in A though), if the routine passes back the same value in A (the exception being call 0) as you gave it then that OS_CALLOS function is not supported. ==== OS_CALLOS 0: Return the OS version number ==== {|class="calltable" |Entry|| * A = 0 * X, Y, c, z = undefined |- |Exit|| * A = Hardware release version * XY = OS version number * c, z is preserved |- |Note|| * Hardware version 0 is obsolete * Hardware version 1 is SmartBox ** VIA at &8030 ** UART at &8010 ** ADC at &8000 ** AUX_PORT (inputs) at &8020 |} ==== OS_CALLOS 1: Claim a block of JobCodes ==== {|class="calltable" |Entry|| * A = 1 * X = number of JobCodes required * Y, c, z = undefined |- |Exit|| * A = 0 * X = base JobCode, if 0, no big enough block available * Y = Job ID number, 0 if no big enough block * c = set if no big enough block * z is preserved |- |Note|| This call claims JobCodes codes from the JobCode list. JobCodes are in the range 0 to 255, 0 is special and is the JobCall "Blank". All the OS ones are spaced out but an "application" can claim a block of JobCodes, usually just the 1 call. If there is not a contigous block big enough then no JobCodes are allocated and the appropiate result is returned. The Job ID is from 0 to 255, 0 is unallocated, 1 is the OS calls, the rest are external applications, each successful call increments the Job ID returned, meaning a maximum of 255 successful calls (not important as their is not that many free calls available !), the Job ID can be used to check whether a JobCall request is yours. |} ==== OS_CALLOS 2: Handle NameCode request for the application ==== {|class="calltable" |Entry|| * A = 2 * XY = block pointing to block of JobNames * c, z = undefined * jobin_buf contains JobName (terminated by CR) * zero_gp3 = JobId (as returned by CALLOS 1) |- |Exit|| * A = 0 * XY = undefined * z is preserved * if c = 1 (Name not found) * if c = 0 (Name found) * jobin_buf contains the JobCode |- |Note|| Used via the internal_vec to convert from JobName to job code, the table format is just a list of the JobNames (each one CR terminated) terminated by a &FF |} ==== OS_CALLOS 3: Handle CodeName request for the application ==== {|class="calltable" |Entry|| * A = 3 * XY = block pointing to block of JobNames * c, z = undefined * jobin_buf contains JobCode * zero_gp3 = job id (as returned by CALLOS 1) |- |Exit|| * A = 0 * XY = undefined * z is preserved * if c = 1 (JobCode not found) * if c = 0 (JobCode found) *: jobin contains JobName (terminated by CR) |- |Note|| See above |} ==== OS_CALLOS 4: Relocate code ==== {|class="calltable" |Entry|| * A = 4 * XY = execution address (offset from start of code) * c, z = undefined * zero_gp1 = offset address of execution after relocation * zero_gp2 = offset address of relocation BitMap * zero_gp3 = length of code to relocate |- |Exit|| No exit, calls begining of code straight away |- |Note|| See later section on Relocation |} ==== OS_CALLOS 5: Describe the enviroment ==== {|class="calltable" |Entry|| * A = 5 * X, Y, c, z = undefined |- |Exit|| * A = 0 * c, z is preserved * XY = address of table, format as such: * 1st byte: number of bytes (ie. 14 currently) * byte 2+: ** address of VIA ** address of ACIA ** address of ADC ** address of AUX_PORT ** address of jobs_status ** address of jobin_buf ** address of jobout_buf |- |Note|| It is preferred that this call is consulted first if direct use of the hardware is going to be used to get the correct addresses, or use OS_CALLOS 0 and decide what addresses/configuration to use from the Hardware version number. |} ==== OS_CALLOS 6: Read a register in the VIA ==== {|class="calltable" |Entry|| * A = 6 * X = register (0 to 15) * Y, c, z = undefined |- |Exit|| * A = 0 * Y = value read * X, c, z is preserved |- |Note|| The register number is not checked for range. This call allows access to the hardware without actually directly accessing the hardware yourself. |} ==== OS_CALLOS 7: Write to a register in the VIA ==== {|class="calltable" |Entry|| * A = 7 * X = register (0 to 15) * Y = value to write * c, z = undefined |- |Exit|| * A = 0 * X, Y, c, z is preserved |- |Note|| See above |} ==== OS_CALLOS 8: Read a register in the ACIA ==== {|class="calltable" |Entry|| * A = 8 * X = register (0 to 15) * Y, c, z = undefined |- |Exit|| * A = 0 * Y = value read * X, c, z is preserved |- |Note|| See above |} ==== OS_CALLOS 9: Write to a register in the ACIA ==== {|class="calltable" |Entry|| * A = 9 * X = register (0 to 15) * Y = value to write * c, z = undefined |- |Exit|| * A = 0 * X, Y, c, z is preserved |- |Note|| See above |} ==== OS_CALLOS 10: Read a register in the ADC ==== {|class="calltable" |Entry|| * A = 10 * X = register (0 to 15) * Y, c, z = undefined |- |Exit|| * A = 0 * Y = value read * X, c, z is preserved |- |Note|| See above |} ==== OS_CALLOS 11: Write to a register in the ADC ==== {|class="calltable" |Entry|| * A = 11 * X = register (0 to 15) * Y = value to write * c, z = undefined |- |Exit|| * A = 0 * X, Y, c, z is preserved |- |Note|| See above |} ==== OS_CALLOS 12: Read an ADC channel ==== {|class="calltable" |Entry|| * A = 12 * X = channel number to read (0 to 3) * Y, c, z = undefined |- |Exit|| * A = reserved for future use * if c = 0 (8 bit reading) ** Y = reading ** X = undefined * if c = 1 (16 bit reading) ** X = reading (LSB) ** Y = reading (MSB) * z = undefined |- |Note|| The A register MAY not return 0, it is guaranteed though that it will not return 12. |} ==== OS_CALLOS 13: Read a register in the AUX_PORT ==== {|class="calltable" |Entry|| * A = 13 * X = register (0 to 15) * Y, c, z = undefined |- |Exit|| * A = 0 * Y = value read * X, c, z is preserved |- |Note|| See above |} ==== OS_CALLOS 14: Start sensor type checking (OS 2.066+) ==== {|class="calltable" |Entry|| * A = 14 * X, Y, c, z = undefined |- |Exit|| * A = 1 * Y = value read * X, c, z is preserved |- |Note|| A returns 1. This flags the ADC routines to start checking the sensors. After calling this routine, you should poll OS_CALLOS 15 to check when all the sensors have been checked. |} ==== OS_CALLOS 15: Check the status of sensor checking (OS 2.066+) ==== {|class="calltable" |Entry|| * A = 15 * X, Y, c, z = undefined |- |Exit|| * A = status * XY = pointer to sensor types block * c, z is preserved |- |Note|| A does not return 0, though it is guaranteed to not return 15. * Status of 0 = checking finished and no futher check pending * Status of 1 = Waiting for current ADC channel to finish converting before switching sensor checking on * Status of >127 = Checking sensor types The block pointed to by XY consists of 4 bytes, each byte contains the sensor type for the appropiate sensor, a type of 0 means no sensor present |} ==== OS_CALLOS 16: Set the OS' irq mask for the VIA (OS 2.069+) ==== {|class="calltable" |Entry|| * A = 16 * X = EOR mask * Y = AND mask * c, z = undefined |- |Exit|| * A = 0 * X = old mask value * Y = new mask value * c, z is preserved |} ==== OS_CALLOS 17: Set the OS' irq mask for the ACIA (OS 2.069+) ==== {|class="calltable" |Entry|| * A = 17 * X = EOR mask * Y = AND mask * c, z = undefined |- |Exit|| * A = 0 * X = old mask value * Y = new mask value * c, z is preserved |} ==== OS_CALLOS 18: Set the OS' irq mask for the ADC (OS 2.069+) ==== {|class="calltable" |Entry|| * A = 18 * X = EOR mask * Y = AND mask * c, z = undefined |- |Exit|| * A = 0 * X = old mask value * Y = new mask value * c, z is preserved |} ==== OS_CALLOS 19: Set the ACIA's ctrl register and OS' soft copy (OS 2.069+) ==== {|class="calltable" |Entry|| * A = 19 * X = EOR mask * Y = AND mask * c, z = undefined |- |Exit|| * A = 0 * X = old mask value * Y = new mask value * c, z is preserved |} ==== OS_CALLOS 20: Set the reset vector for battery back RAM support (OS 2.069+) ==== {|class="calltable" |Entry|| * A = 20 * XY = address to set reset vector or 0 for read only * c, z = undefined |- |Exit|| * A = 0 * XY = old reset vector address * c, z is preserved |- |Note|| Sets the reset vector to address supplied and sets check bytes in workspace. |} === OS_PRINTER: Place a character in the printer buffer === {|class="calltable" |Entry|| * A = character to send * X, Y, c, z = undefined |- |Exit|| * A, X, Y is preserved * if c = 0 (printed) *: The printer is on and the character was inserted * if c = 1 (not printed) *: The printer is off and the character was forgotten * z = undefined |- |Note|| The character goes into the printer buffer and will be actually sent to the printer when the printer asks for it. If the printer was not awake to begin with, an attempt is made to wake it up, thus meaning that in some circumstances when the printer wasn't ready a character may be lost, this cannot be helped. If the printer is off (via the BCD switch) then the character will be forgotten as the Printer Buffer is inactive. |}
Summary:
Please note that all contributions to Smart Box may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see
Smart Box:Copyrights
for details).
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)
Navigation menu
Personal tools
Not logged in
Talk
Contributions
Create account
Log in
Namespaces
Page
Discussion
British English
Views
Read
Edit
View history
More
Navigation
Main page
Recent changes
Random page
Help about MediaWiki
Tools
What links here
Related changes
Special pages
Page information