diff --git a/.gitattributes b/.gitattributes index 5f4f21206543abb51052959d389f5ae2ba055822..1f1c38906f45bb91c386016e0deff32c3d821a1a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,4 @@ hdr/** gitlab-language=armasm linguist-language=armasm linguist-detectable=true +s/** gitlab-language=armasm linguist-language=armasm linguist-detectable=true +**/s/** gitlab-language=armasm linguist-language=armasm linguist-detectable=true +*,ffb gitlab-language=bbcbasic linguist-language=bbcbasic linguist-detectable=true diff --git a/Changes b/Changes new file mode 100644 index 0000000000000000000000000000000000000000..ce02a7a31786628b5344fd9dc8b3462d2bd39cbb --- /dev/null +++ b/Changes @@ -0,0 +1,1471 @@ +> Text.Changes List for Proto-Arfur. + + +Versions up to .078 are ancient history, man. + +Version .078 +============ + +Bugfix of environment string setting + +Version .079 +============ + +Converted to new error header +Top bit R0 error indicator support removed +Flags added to ReadLine : bit 31 R0 set => don't reflect chars not going + into the buffer + bit 30 set => any reflection done with char in R4 + +Heap robustification : checks that hpds, etc are in existing LogRam + +New heap call : ExtendHeap, takes hpd in R1, size to change by in R3. Gives +two errors : BadExtend for wally changes (i.e. end moves outside existing +RAM), and ExcessiveShrink for end moved below area in use. The heap end has +been moved as far as possible in the second case. R3 returned as amount +actually changed by. + +Default Sys$DateFormat set up to give string identical to Master TIME$. + +Version .08 +=========== + +Heap changes bugfixed +*con. monitortype added +Default screen on 512K Weed is 80K +If no keyboard (on ANY reset), it autoboots irrespective of other state. + +Version .081 +============ + +Overlong environment strings / errors don't overwrite your breaklist. +Service_Memory issued when AplWork size being changed : error given if +service is claimed. Service therefore means "are you using the AplWork?" +R2 contains the address of the currently active object, so winge if this +address is within your code. + +Sources changed : conditional flags for native VDU, tube connected removed ; +it didn't stand a chance of working anyway if you changed either flag. + +New Tim stuff : key up/down events, Con. monitortype does things. +SWI to set handlers with workspace added : handlers yet to change. +New fileswitch : buffering buggette fixed + +Version .082 +============ + +Configured sizes are now "PageSize" (8 or 32K) units. +Vset returns from module Init bugfixed. +VSets in RMTidy better +Bug in WriteI fixed (if an error occurred, it poked the stacked R14 with the +error pointer, rather than the stacked R0!) +Utility open file with winge has had open bits added (nodir,mustopen) + +Major bash of handlers, also 3 escapes aborting removed. +SWI OS_ChangeEnvironment added : calls the envchange vector, default owner of +which sets the handlers. Give handler number in R0 (see hdr.envnumbers), +address in R1, workspace pointer in R2 (if used), buffer pointer in R3 (if +used). All old handler setting SWIs call this internally. + + +Version .083 +============ + +Rationalised version number (cor). +Escape handler calling bugfix + + +Version .084 +============ + +ValidateAddress acts sensibly for zero-length ranges. +New TimStuff +Kludge for now : workspace for error handler passed in in R0. +Help Commands lists *Modules and *Configure. +Assembly flag ; can assemble versions that convert exceptions into errors +with negative numbers +ValidateAddress allows the part of PhysRam that's in the screen. +Bugfixes of callback, breakpoint handler setting +*GO doesn't screw with your error handler, and supervisor doesn't reset the +world every time it panics. +New FileSwitch +Default PrinterType$4 variable +*Error and *Eval +Aliasing bugfix : *fred. doesn't match Alias$Fred +*Create bug fixed : *create jim now works +All files closed on all resets +Changes to CMOS reset : station ID unmolested (use magic Set transient!), and + Sync state is TOGGLED rather than set. Do R-power on twice if necessary! + +Version .085 +============ + +INKEY -256 bugfix + + +Version .09 +=========== + +Version number rationalised! +Configure language added. +Configured language used, which meant changes to module entering : +this sets up the envstring from anything after the filename on RMRun, +or from the string pointed at by R2 on Enter. +New Timstuff, new fileswitch +Attempts to restore registers 10-12, lr on exceptions. + +.09/a +===== + +Bugfix of cmd tail on *Go. +Monotonically increasing time added, + SWI to read it. +*GOS starts up the Supervisor application, which lives in the utility module + +.09/b +===== + +Oscli Bugfix : *Volume127 not OK. +SWI Module doesn't enable interrupts for claim, release and describe ops +New Timstuff : should beep! + +.09/c +===== + +Bugfix of errors from exceptions +Ballsup in ReadLine removed! +Sam hack of Beep code to make it beep at least a bit. +*Unplug etc. added. + +.09/d +===== + +Beep on hard reset moved. +Sound CMOS set on CMOS reset : speaker 1, volume 7, channel 1. +Reducing RMA / sysheap updates hpd proply. +RMTidy tries to shrink RMA if tidy successful + +.09/e : Hard reset beep moved a bit more. +.09/f : Silly screensizes converted to as close to 20K as poss + Optional 325 speed for a1 roms. +.09/g : Reset initialises timer0 so can use CMOS RAM read write. +.09/h : IOC Control set to FF on reset, new Tim code to do spastic things + with Break key. +.09/i : Nibble mode ROM speed removed from A1 version! + Better Tim code, new fileswitch +.09/j : RMReInit reports errors when inserting unplugged modules. +.09/k : Allowed to con. screensize 0-127, max screen actually set up 480K + Bug in Create fixed. Dump now allows tbs -> printable masking + Entry Envstring for RMRun fixed. + Entry to Supervisor always by RMEntering utilitymod. + ValidateAddress allow super stack + Net EX/CAT CMOS reset better + Status/configure when listing all goes into paged mode +.09/l : Soft break possible : FileSwitch tried and found Guilty of corrupting + system heap. + New Tim stuff, + weird country stuff in init. +.09/m : Basic SWI code doesn't change FIQ bit. + Can set dump area for default exception handlers. + *Help says "Help on keyword flurgle" instead of just flurgle. + Oscli terminators table adjusted. +.09/n : Minor help text changes + Fixed module command tails + New Tim doobries : no chars from Rodent buttons! + *Dump given offset=filesize winges "Outside File" +.09/o : New fileswitch ; *Copy. + *Shadow implemented + " :" changed to ":" + Paged mode in *Show + New TimStuff +.09/x : Timstuff +.09/y : Show pagemode bugfix + Country CMOS reset to 1 + New fileswitch +.1 : Too much optimism and new Tim stuff +.11 : Keyboard code in reset fixed. + <65junk> will expand variable 65junk + Syntax/help messages tidied up + *Time, *Ignore added + New Tim stuff + Conversion SWIs added + Vectored SWIs (notably osbyte) can only affect C and V +.12 : Exception errors put PC on error msg. + *Shadow (no param) works, *ignore 3please faulted +.13 : Conversions point R1 at 0 +.20 : New fileswitch + Language 3 set on CMOS wotsit +.21 : PrinterType$4 not set by MOS. + ChangeDynamicArea does nothing if attempt to extend a heap too far. + Also always leaves one page in AplWork + Enters configured doodad if error on autoboot. + Redundant bits removed. +.22 : Wierd terminator chars removed from ReadUnsniged, bit 29 flag added: + restrict range to 0..r2 (inclusive). Used in SWI naming stuff (won't + say "OK" to "Econet_&FFFFFFFF" etc. + Unknown SWI error gives SWI number. +.23 : CMOS reset TV is 0,1 + Configured RMASize is amount free in RMA after mos initialisation. + Fixed tbs restrict in PrintCharInGSFormat + Errors propagated back in utilities from file closure. + Exception register dump area only reset on break. +.30 : V set return from Help_Is_Keyword code not ignored + Nude flieswitch + R12 to Help_Is_Keyword code correct + Bugfix of OS_ConvertNetStation : no explosion for bad net + New glue together +.31 : XOS_Heap(DescribeHeap) subs 4 off right value. + Setting Restrict Range to R2 flag in ReadUnsigned meant only base 10 OK + Default R12 for event/escape handlers = -1 + XOS_Heap(ExtendBlock) by 0 works, valid block checking better. + First version multiple incarnations, podule support. + *Modules gives numbers + DFlynn/AThomas memory page/size evaluation used. MOS now pagesize + independant. + Can assemble a multiple keyboard version + *net: bye etc fixed. + SWI dispatch immeasurably improved + Module LookupName added + Bugfix of *Status <module keyword> + Module prefixes on oscli added: can specify command only comes from + (a particular incarnation of) a particular module + Bugfix of 239: wrch errors not being dealt with + New fileswitch; oscli also reads any secondary FS command table + Interrupts enabled in SWI name <-> number conversions + SWI PrettyPrint & SubstituteArgs +.32 New fileswitch +.33 New Tim stuff: SWIs Plot & WriteN. + Slight changes to allow service calls to be issued before modules are + initialised. Note may get modechange service before Service_Reset. +.34 Configured lang was out by 1. + SysHeap is shrunk to minimum, then configured extra size added (after + main initialisation). Should give about 16K extra on 305/310 + Service_UKConfig conforms to (latest PRM) spec. + SubstituteArgs terminator corrected. +.35 Nude TimBits: optimised plots, etc. + ValidateAddress looks up screensize in VDU workspace + ChangeDynamic funkyfied +.36 ADev versions hurl abuse at 3 micron ARMs. + OS_Claim frees any links with same values first. + OS_AddToVector has old Claim semantics + INKEY-256 returns &A1 + RMReInit clears CMOS of unpluggies before initialisation. + *ROMModules added as a replacement for *ROMS + EnumerateROM_Modules reason code for OS_Module + Bugfix of init strings on rmreinit. + Order of files changed: in * prompt, utilitymod should always be CAO + ChangeDynamic involving screen removes the cursors + SpriteSize is a 6-bit field in Status/Configure + Write0 shortened! +.37 VecSwi call shortened. + Stu did something to FileSwitch - R6 not wally for some entries. +.38 Obscuro bug in heap block extension - made RM manager free workspace + while checking block validity! + If ExtendBlock frees the whole block, it updates the returned block + pointer to -1 (i.e. really naff ptr). + RMClear doesn't kill podule modules. + New TMD stuff (some RS423 bugs fixed, faster this and that). +.39 New big version (new DeskTop, Wimp,...) + New block copy/move code + SpriteV added + Escape purging of sound now uses duration 1 (at request of DFlynn) +1.00 New RS423, FileSwitch, ADFS ... + CMOS reset sets 1987 + V not cleared for CallAVector + Configure mode allows up to 23 + PrettyPrint reads window width +1.01 Status/Configure deals better with Wrch errors. + Modules " (Tutu number output fixed). + Guess what; ReadUnsniged fixed AGAIN !!! ... + FileSwitch Opt 1,n bug fixed + {on} in Count + SWI WriteEnv invented for JGT use in debungler + New TimBits: fix embarrasment with lines, palette +1.10 Apparently this is a more aesthetically appealing version number. + Nuder TimBit: service_prereset lives! +1.11 OSGBPB 5,6,7 r6 bug fixed + MOS 2 micronised. Default callback shrank! +1.12 Dump code shortened + gives better error response for IsDir etc + Another (nastier) FileSwitch Opt 1,n bug fixed + Module handler returns proper w'space contents for LookUpName + Installing keyboard handler might work now says Tim + More FileSwitch changes. And yet more. Dump fixed. +1.20 another release, another number +1.21 Oscli whinges about *net#arf:thing etc. + *Modules counter doesn't wrap at 256 (and neither does *ROMModules) + Module init failure: doesn't free incarnation node twice, and + doesn't poo in the system heap. + RdArgs SWI added, NoSuchSWI error made non-dynamic + timbits/fileswitch +1.22 Added code to issue service call on RMA claim fail, as requested for + ADFS. Not actually assembled in though! + Module death can now be recursive + Header fields checked for validity: word-aligned where appropriate, + and within code length + CAO during startup=32M: allow overwriting of MOSROM modules. + Module SWI lookup much faster: enter into hash table on init + Added SWI OS_ReadRAMFsLimits + Looks for keypad * pressed on reset; drops into supervisor. + T,Delete and Copy power-on added. + List, Type use RdArgs (File/A,TabExpand/S), and expand tabs into + 8 spaces. + Buggette in Module handler: recursive death may lead to operating + on a module with 0 incarnations. + SWI despatcher goes into caller's IRQ state; individual SWIs yet to be + inspected. + Supervisor doesn't reference ESCCNT or ESCFLG any more. + Vecnum=Swinum SWIs enable IRQs, except for Byte & Word which disable + them. + Module SWI enables IRQs explicitly except for heap ops. +1.23 SWI Mouse disables IRQs + Bugfix of Oscli: copes with buffer overflow in alias expansion + parm substitution. +1.24 Simon Smith and his Amazing Dancing IRQ Despatcher! New SWIs to claim + and release "devices" (i.e. bits in IOC interrupt registers A and B, + with the podule device the only one capable of having multiple owners). + EnumerateROMModules call (and so Rommodules) fixed. + Workspace reordered so can call handlers by LDMIA R12, {R12, PC} + *RMFaster added. + Link passed to module SWIs has correct IRQ state. + Interruptible (and also bug-fixed) heap manager incorporated. + New Tim stuff +1.25 Default IRQ2V clears the appropriate mask bit, returns. + SWI ModHand: ExtendBlock will return V set if appropriate. + Register dumping changed; may save right registers for FIQ/IRQ. + ValidateAddress fixed for screen memory. + New Timstuff; ECF origin settable. +1.26 MOS help messages tidied up. + Redirection errors better. + Alias terminators same as module command terminators. + Scratchspace sorting out: "bad number of parameters" error + constructed in an Oscli buffer. + Stack full error in Oscli has a sensible number; HelpBuffer + allocated on the stack. + Redirection handles made byte-sized. + MOS buffers rationalised; there's now an enormous amount of sharing. + SWI not known error contains SWI number if it wasnt done under + interrupt. + Backspace in readline = delete +1.27 Modules can refuse to initialise again. + Background FIQ handling done; Service_ClaimFIQ and Service_ReleaseFIQ + now come round immediately after Service_Reset, to set up the + default handler. + Stuart's HeapSort SWI added + SWI ExitAndDie added + SWIs to delink and relink application vectors added + Configure keyword MouseStep added; can also do nK on size fields. + ChangeDyn file improved; if cam map corrupted, necessary registers + pulled. + SWIs to allow user CAM-bashing; soft reset makes the application + space contiguous again. + ChangeEnvironment has a new reason code to allow setting of the + application space size. + Reset code masks CMOS; if top bit of CMOS gets set, used to be in + a state where lots of memory was allocated, but *status said little + was being requested. + SWI number->name conversion uses hashtab. + FE0-FFF initialisation removed. +1.28 TV configure syntax nitpicked. + New FileSwitch +1.29 Monotonically increasing time move to &10C; now a public location. + *key fixed; (re)uses EnvString + as does *show +1.30 *show prettified + FIQ downgrade highest priority interrupt. + MOS FIQ claim/release handling altered; now should cope with + background claims and/or releases occuring during a foreground + claim. + New extensions to callback; can now ask to be put on a vector. + Hacked source.pmf.key so it calls the callback vector (but NOT + the callback handler) in readc/inkey, if its bored. + ChangeDynamicArea falls at the first fence if an IRQ is threaded. + SWI despatch in RAM; 10% faster StoreHD. + Bugfix of SWI node release on module death; bugfix of error percolation + in new incarnations. +1.31 Supervisor printing of time taken ditched; bottom 32K, sysheap, cursor + user-write-protected. + Processor-speed dependant waits in NewReset now use Tim's magic + delay routine. + New TimStuff. +1.32 Bugfix of heap block extension. + Dynamic SWI not known built in better buffer. + Vector stasher always terminates the buffer (unless totally spastic + buffer size). + Improvement of heap block extension; will extend into preceding block + if poss. Also fix of code spotting interrupted heap ops (from 1.30). + PrettyPrint bugfix: hard space after tab. + Writeability of CAO (for WIMP) via changeenv. + Checks for keypad 0,1,2 on "power-on" resets, and sets monitor type + accordingly. + ReadBlockSize reason code added to heapman. + New fileswitch. + ROM speed slugged. + Bugfix of SetMemMapEntries, soft reset copes with many pages mapped + to the same address. + Defined R0-R3 corruptible for IRQ processes. +1.33 Cam bashing revisited; PPL kept in soft copy too. + ChangeDynamicArea also understands that the sysheap should be kept + protected too. + Dynamic "SWI not known" error fixed. + Doesn't go address exception if no kbd. +1.34 Another instruction removed from SWI despatch. + Times CPU and susses in spec ROM speed at reset + Old style handler setters don't poo on r12 value. + New fileswitch & timstuff: VDU output to sprites. + RAMfs space protected. + ReadDefaultHandler SWI added; pass number from hdr.env*, returns + R1=address, R2=workspace, R3=buffer. 0 means not relevant. + CAM soft copy size doubled; 8Mbyte may work. +1.35 New fileswitch. +1.36 MOS Default FIQ ownership fixed. + New Timstuff: window width obscurities, border stuff. +1.37 CAM bashing revisited for 8M; next bit up now included. Ta Jamie! + Bugfix of SubstituteArgs. + New Timstuff. + Service offered after ChangeDynamic has moved stuff. + When copying (if screen is being extended), ChangeDynamic copies + from a PhysRam address. The last page of application workspace is + copied into, so this MUST NOT be doubly mapped in MEMC. + Bugfix of RMtidy: checks CAO in RMA again. +1.38 SWI despatch understands that modules may have zero incarnations. + Ballsup of ReadDefault corrected. +1.39 ChangeDynamic overhauled: changing screensize cooperates better with + VDU drivers. + Setting of variables uses a stack buffer; scratchspace use across + sysheap extension a nono. + R0 in Service_Memory corrected. Always issues post-service, even if + error/nothing to move. + Monitortype bits expanded in status/configure. + r1 uncorrupted in OS_Exit for HMeekings. +1.40 Help matches against module titles as a postscan, giving keywords + recognised in the module. + Bottom 32K protection removed. +1.41 Soft break forces noprot on application space. + ChangeDynamicArea rejects out of range area numbers (instead of + crashing). + SWI Module does better when block extension has to try and extend the + RMA. + Exported HLINE takes colour information. + ROM unplug bits extended by using original Master frugal bits. +1.42 Setting of numeric variables fixed. +1.43 Default CMOS: NewADFSCMOS+2=1, DumpFormat=4. + Much molested prettyprint. +1.44 DrawV added. +1.45 New fileswitch. + PrettyPrint allows you to specify the MOS dictionary by setting r1=0. + Saved a word in CallVector (2 micron needed); stopped error gen if + vector number > NVectors + (defined r0-r3,r12 trashable on IRQ vectors) +1.46 Made IRQ vector claim force release of any previous entries. + SubstituteArgs: tbs r0 on entry => don't tack any unused part of the + line on the end. + New HeapSort which can shuffle data/build array pointers for you + Much munged help text. + BGet cache put into kernel so we save about 4us per call (saves + branches, temp register pushes). New FileSwitch +1.47 ROMModules fixed. + Added default handler for EconetV for Bruce + Minor speedups/space savers from Stu. + Fixed module name match: adfs. no longer matches adfs +1.48 Removed fast entry for Args/GBPB/File/FSControl as it was dangerous + new fileswitch that matches the above, so default vechandlers changed + *Quit migrated. + BPut cache migrated into kernel; removed VecFSSwi code +1.49 Fixed syntax message expansion. +1.50 ChangeDynamic has 3 = Sprite area +1.60 Richard III is dead + New serial stuff, apart from XON/XOFF + InstallKeyHandler with R0=1 => read keyboard id +1.61 Default osbyte vec has r12=OsbyteVars + Error returns for bad RMA heap claim/extend improved. + RMA block extension needing RMA extension fixed. + Doesn't corrupt end of physram on reset. + System heap not protected just because there are idiots instead of + programmers out there. + RMEnsure. SystemSpeed CMOS removed. + Noo really dangerous FoolSwatch +1.70 New title for release +1.71 Heap Extend wallyism removed. + System heap protection really removed. + Changed help for load/save/create etc. to keep DBell happy + New FileSwitch + CRC stored in pair of bytes at end of each ROM image + HeapSort now does B SLVK rather than LDR pc, =BranchToSwiExit + Exception handlers disable FIQ asap, shorter + Interrupt handling fix: DiscChanged on Archie became winnie IRQ! + Memory speed/MEMC1a flag (tbs) saved in RAM at &110. + CMOS resetting modo-fied a la Tim Caspell - R/T-power-on don't reset + harddiscs or country, or time; DEL/COPY zap harddiscs/country, but also + leave the time alone. + ****** N. B. ********* harddiscs not being reset may lead to long waits the + first time a named disc is used: on current ADFSs, it will be an + infinite wait. + Added help on Break, Reset and PowerOn. + Module handler fudged a bit for modules with 0 incarnations; tidier + after somebody explodes in Initialisation/Finalisation. + "Module postfix given" now reads "'%' in module title". + Even newer FileSwitch + SYS OS_ReadSysInfo: give it 0 in R0, it returns what screensize is + set by CTRL-BREAK. + *type/list with only one param assume it's a filename. + Made memory speed a halfword; MEMC1A flag now bit 16. + Byte at &107 is an inconsistency semaphore; if non-zero at reset, + hard reset is forced. ALWAYS lower and raise with IRQ disabled. + New monitor type 2, compatible with UNIX monitor (mode 23 only). + Minisculely faster floodfill. + SWI OS_Confirm. + New multi-threadable FileSwitch (actually saved code and store !) + SKS fixed SWI OS_Confirm - it never cleared Z or C ! It also used wrong + exit criteria; &1B does not necessarily mean an escape condition exists + it also corrupted r3. + SKS fixed SWI OS_ReadSysInfo; it actually preserved r0! +1.72 New FileSwitch + loads of modules for yet another release + SWI ClipBox + Fixed FileSwitch howler +1.73 Help terminates on escape. + Autoboots if unrecognised keyboard too. + New FileSwitch + CAM remapping don't fiddle with the interrupt state; caller must think + this through themselves. + Default CMOS sez ArthurLib + Added periods to end of configuration help where they were missing + Moved more supervisor stuff into Super1 + ReadLineV default owner gets called with suitable r12 + Attempt to fix *-reset by delay loop + Calling of CallEvery events fixed; CallAfter/CallEvery SWIs don't + corrupt r1. + Made keyboard + printer buffers bigger, cut down Sound0,1,2,3,Speech + Reduced *-reset delay loop; moved Inter+IntKeyModules higher in list + Added ConvertFileSize+Fixed, CRC swi + IRQs off when entering callback handler. +1.75 Made a500 version for release + Fixed Copy use of WimpFreeMemory <-- NB. A500 versions are wrong + and set SlotSize 0. Sorry chaps. +1.76 should have been set AS SOON AS THE CODE WAS CHANGED (Stuart). + Extended RESET helptext. MouseStep all one word. + Mutter mutter. Explicitly reeenable irq before waiting for metrognome + change. Fixed power-on monitor type reconfigures +1.77 Status doesn't say 0K for screen. + Moved OPT code to kernel so *opt1 etc. valid. Shortened PrintR0Decimal +1.78 Made a500/a1 versions for release + Fixed conversion swi number to name to recognises new swis + New FileSwitch + After looking at the MOS irq device handlers, we'd better define r11 + to be trashable on IRQ device handlers as well as r0-r3,r12! Also IRQ1 + Default IRQ shorter - people on IRQ2V must preserve all except r12! + Defining r3 -> IOC for all IRQ handlers would be a very good move + Compressed SysComms, added MakeErrors in most of MOS + FileSwitch + FileSwitch now has path: stuff + Fixed default callback handler + Make redirection work with INKEY as well as RDCH +1.79 Bugfix ReadArgs; non-abbreviated keywords with aliases now work. + Made RMEnsure scan for digit after getting to 16th col in module + help string anyway; means we can rmensure the current clib. + *Error GSTranses the error string. + Callbacks will be processed before calling the error handler. + Put in new SLVK exits to save space + Nude fileswitch + Fixed SWI OS_GenerateEvent so can call from non-SVC mode. + Should we define r9 trashable on module SWI calls ??? + Move V test into RAM SWI area + Default event vector call with appropriate r12 + Faster BPut; we have deviant wp in top vector node + Made error handler shorter + New entry to PMFWrch, gets OsbyteVars up its' entry point + Removed error on setting callback handler if callback outstanding; + came in earlier in 1.79. + Improved 'RM not found' and RMEnsure errors. + SWI OS_ServiceCall instead of BL Issue_Service in reset. +1.80 Made image for release +1.81 Faster SWI OS_CRC by TMD + Padded OS_Confirm pointer shape, put the active point on the right. + Added an upcall handler. + Font cache at 30M; ValidateAddress modified. + Reason code 4 in ChangeDynamic = font cache + SWI OS_ReadDynamicArea. + Regard keyboards with ids 1-31 as the same. + Got a dozen spare vectors +1.82 *Time copes with oswrod errors + CallAVector internally preserves caller's interrupt state. +1.83 Fix to ChangeDynamic of font area. + Fixed PIRQ/PFIQ despatch for case when LSB of B CONT ~= 0 + Also made the above faster/shorter +1.84 Fixed ChangeDynamic for sprite area; used to indirect into deep space + Also allow APL/BottomWS to shrink to 32K + Fixed ReadArgs to allow y and z in keywords. + Fixed code in heap block extension to satisfy comment. + Changed default Sys$DateFormat to "%24:%mi:%se %dy-%m3-%ce%yr" + Changed *Time to use OSWord 14,0 + ExtendHeap was total garbage! + Make MODE 23 Unix compatible +1.85 ReadDynamicArea returns start of screen address + ChangeDynamic safe in conjunction with background heap ops + New FileSwitch + Moved Quit in command table to alphabetic place + Put a B in TimeCPU to make result more accurate +1.86 OS_ReleaseDeviceVector disables IRQs. + OS_AddCallBack disables IRQs earlier. + OS_Confirm mouse shape has no colour 2 + Flushing the printer buffer makes it dormant if not a stream + CheckModeValid works properly with a user monitor type + A500 keyboard changed + Mouse buffer not flushed when new bounding box set, instead coords are + clipped against the current bounding box when read out of the buffer. + MODEs 21 (multisync) and 24 added + Set DomainId to 0 at reset + Made process_callback_chain disable IRQs round updating head^ so we + didn't lose callback vector requests when processing the chain; saved + 2 instructions in AddCallback + Maximum configurable mode is the max mode the MOS implements + ChangeDynamic can do RAMFS if no files in it. + Heap Extension call rounds size to words correctly (always towards + zero). + Handlers zapped to defaults if app starts and exit handler belongs + to supervisor. + VGA modes (25..28) added + ChangedBox fixed for VDU 5 8x8 and 8x16 text +1.87 Hi-Res-Mono palette changed so PP field returned is &10 or &11 or &12 + Also changed to return full black or full white for the RGB fields, not + red. + Bugfix in *Help; Escape while printing a module summary gave a random + error message. + Swapped silly name for another silly name. +1.88 Heap manager size call fix. +1.89 TimeCpu code was wrong (misordered merge of 2 8-bits) and had wrong + cutoff point for MEMC1a +1.90 New week number code - now conforms to BS4760 (supposedly) + New FileSwitch with file buffering fixed +2.00 (15 Sep 88) + Econet background FIQ problem fixed + NetStatus and Hourglass error handling improved + Kernel locks out background FIQ claims while the release service call + is in progress. +2.00 (03 Oct 88) + New FileSwitch - default run action for text files is now *Type + New NetFiler - version in previous MOS was out-of-date +2.00 (04 Oct 88) + New ADFS (Winnie podule problem fixed) + New TaskManager (doesn't claim null events when window not open) +Note: Change all occurrences of GoVec(2) + May also note that default vector owners can trash r10, r11 IFF + they claim the vector... + +2.01 (02 Mar 89) + New version of ChangeDynamicArea which reenables interrupts. + Heap manager optimised in a few places. + Fixed bug in extend heap call (stack imbalance when returning + 'No RAM for extending heap' error) + Heap manager extend block has improved IRQ latency. +2.01 (29 Mar 89) + Fixed "*%" (LDREQB not LDREQ). +2.01 (31 Mar 89) + Fixed OS_ReadArgs with a /E argument that evaluates to a string (always + used to give 'Buffer full' - also fixed 2 other bugs lurking in the + background, viz. did STRB of buffer addr assuming it was non-zero to + indicate a string, and didn't allow for length and type bytes in amount + free value. +2.01 (11 May 89) + Fixed OS_Word &15 reason code 4 (Read unbuffered mouse position) + - it used to generate undefined instruction trap due to stack mismatch. + Fixed OS_SWINumberToString with negative numbers. +2.01 (16 May 89) + Fixed ROMModules never saying 'Running'. + Fixed bug which occasionally left soft cursors on the screen. +2.01 (23 May 89) + Made OS_SpriteOp reentrant by pushing register dump area on stack. + Fixed sideways scroll by one 'byte' in MODEs 3 and 6. +2.01 (26 May 89) + Made OS_Byte &87 restore caller's IRQ state during call. +2.01 (30 May 89) + Made OS_Word &0E,0 enable IRQs during call. + Made OS_Word &15,0 enable IRQs during call. +2.01 (01 Jun 89) + Fixed incarnation names being terminated by 1st character. + Fixed *Unplug using address as extra terminator for module name. +2.01 (30 Jun 89) + Fixed podule IRQ despatcher corrupting R0 (prevented it from + correctly disabling the podule IRQ (or podule FIQ-as-IRQ) interrupt + if no handler) + Fixed rename incarnation bug. +2.01 (01 Sep 89) + Added help on LEN in *Help Eval. +2.01 (04 Sep 89) + Fixed bug in prefer incarnation which returned duff error pointers. +2.01 (06 Sep 89) + Changed BadTime error message from null string to + 'Invalid time interval' + Fixed bug in CallAfter/Every which returned duff error pointers. +2.01 (11 Sep 89) + Fixed bug in AddCallBack which freed the wrong heap node. +2.01 (12 Sep 89) + Fixed bug in monadic plus/minus in EvaluateExpression (eg *Eval 50*-3) +2.01 (25 Sep 89) + Fixed bug in GSRead with quoted termination. + Fixed bug in keyboard driver (pressing Break (as escape) key when + keyboard buffer full did nothing) +2.01 (27 Sep 89) + Added SWI OS_ChangeRedirection +2.01 (06 Oct 89) + Optimised ConvertTo5Byte routine +2.01 (10 Oct 89) + Took new FileSwitch from Neil +2.01 (12 Oct 89) + Added SWI OS_RemoveCallBack +2.01 (19 Oct 89) + Added code to poke VIDC clock latch from bits 9 + 10 of control + register. + Modified FIFO request pointer algorithm to new one, also taking the + VIDC clock speed into account. + Changed INKEY-256 to &A2. +2.01 (23 Oct 89) + Changed memory sizing routine to cope with 12 and 16MBytes (but CAM map + still needs extending!). + Added keypad-4 reset to select monitor type 4 (super-VGA). +2.01 (26 Oct 89) + Put in variables for pointer to CAM map and number of CAM pages. + Recoded ChangeDyn and NewReset to set these up and use them. + CAM map is now either in low-down area for up to 8MBytes, or just above + IRQ stack for 12 or 16MBytes. +2.01 (27 Oct 89) + Added new VDU variable VIDCClockSpeed(172), the current VIDC clock + speed in kHz. +2.01 (02 Nov 89) + Added ModeExtend pixel rate specification interface. +2.01 (03 Nov 89) + Changed fast CLS code so it can cope with screens which aren't a + multiple of 256 bytes long (eg 800x600x4bpp). +2.01 (07 Nov 89) + Put in code to handle sync polarity programming (including ModeExtend + interface). +2.01 (08 Nov 89) + Fixed over-zealous fast CLS code. + Made a 4MBit EPROM image of this. +2.02 (09 Nov 89) + Changed start-up message to "RISC OS+" (removed flag Fix0). + Started test software integration. +2.02 (10 Nov 89) + Incorporated new screen modes from Paul Swindell. +2.02 (20 Nov 89) + Changed RS423 RXIRQ routine to process the 'serial input ignored' + OS_Byte flag after checking for XON/XOFF characters. +2.03 (21 Nov 89) + Changed !Draw and !Paint run file WimpSlots +2.04 (30 Nov 89) + Got new headers (including new Hdr.CMOS). + Removed initialisation of CatalogCMOS and ExamineCMOS in R-poweron. + Optimised PushModeInfoAnyMonitor so it doesn't set up VIDC stuff - this speeds + up SWI OS_ReadModeVariable enormously (this had slowed down due to VIDC tables + now being different for different monitor types). +2.04 (01 Dec 89) + Fixed OS_Word &07 (SOUND) needing a word-aligned control block. + Added SWI OS_FindMemMapEntries. +2.04 (04 Dec 89) + Changed SWI OS_FindMemMapEntries to new spec. +2.04 (07 Dec 89) + Modified SpriteLoad/SpriteMerge to use OS_File instead of OS_Find/OS_Args/OS_GBPB + - this means the Econet broadcast loader doesn't have to sit on SWI OS_SpriteOp. +2.05 (08 Feb 90) + Updated *Help PowerOn to mention 4 key on numeric keypad. +2.05 (01 Mar 90) + Put in code for handling squeezed modules. Bit 31 of init entry set + => module is squeezed (bits 0.30 are the length of the module, at + the end of which are the unsqueeze information words. + Bit 31 of die entry set => module is not killed by RMClear (the + unsqueezed module image normally has this bit set). +2.05 (05 Mar 90) + Changed title back to "RISC OS" from "RISC OS+". +2.06 (27 Jun 90) (some intermediate versions missing) + New screen mode parameters - letter box modes for VGA + OS_Byte &7C and &7D changed to use SWI XOS_SetCallBack rather than + poking to the callback flag themselves (other bits are used in this + flag) + OS_ChangeDynamicArea now checks explicitly for areas trying to grow + beyond their maximum possible size (necessary for machines with + more than 4MBytes) + OS_ReadDynamicArea specification changed: if bit 7 of r0 set on + entry, then on exit r2 holds the maximum size of the area (and r0, + r1 are set up as per usual) +2.06 (16 Aug 90) + Fixed bug when configured screensize is less than 20K. + Started splitting off MEMC-specific stuff. +2.07 (08 Oct 90) + Fixed bug in OS_ReadVarVal when you test for presence of a variable with + R2<0 and R4=VarType_Expanded and the variable is a macro. +2.07 (30 Oct 90) + Made errors from unknown OS_Module call and unknown dynamic area in + OS_ChangeDynamicArea be "Unknown OS_Module call" and "Unknown + dynamic area" respectively rather than "" and "" respectively! + (They share the same error number). +2.08 (31 Oct 90) + Fixed three bugs in the *Help code, to do with correctly handling + errors from OS_WriteC (via OS_PrettyPrint). +2.08 (16 Nov 90) + Changed module handler to call Podule manager to translate podule + number into hardware address, rather than doing it itself. + OS_ValidateAddress now issues Service_ValidateAddress when area + appears to be invalid, so modules can add valid areas. +2.08 (19 Nov 90) + Fixed two bugs in RMEnsure; (a) no help string (b) help string shorter + than 16 chars +2.08 (27 Nov 90) + Added 3 more bytes of unplug CMOS +2.08 (28 Nov 90) + Divorced kernel from FileSwitch (BGET and BPUT now always go thru vector) +2.08 (08 Jan 91) + Fixed bug in OS_Module 11 (copied extra word, which could corrupt RMA) +2.08 (15 Jan 91) + Fixed bug in OS_Module 17 (corrupted R9 on exit) + Changed OS_Module 17 to cope with extension ROM modules (including directly executables). +2.08 (23 Jan 91) + Changed OS_Module 19 to cope with extension ROM modules + Added OS_Module 20 (same as 19 but also returns version number) + Fixed zero-effect bug in OS_Module dispatcher - if called with maxreason+1 it jumped off the end of the table - + into the unknown reason code routine! + SpriteOps 60 and 61 (switch output to sprite/mask) now issue Service_SwitchingOutputToSprite after switching + Issue Service_PostInit after all modules have been initialised +2.08 (01 Feb 91) + Added *RMInsert command + Finished off extension ROM code (hopefully!) +2.08 (06 Feb 91) + Changed keyboard code to only send LED changes when state has actually changed +2.08 (07 Feb 91) + Made hardware address of extension ROMs zero +2.08 (13 Feb 91) + Made OS_ReadSysInfo return screensize in step with real algorithm, ie a) ignore top bit of CMOS, b) if less than 20K, + add in extra pages until >= 20K +2.08 (01 Mar 91) + DoMicroDelay optimised by Ran Mokady + Started to put in Configure Mode/MonitorType/Sync Auto. + Conditionally remove parallel/serial drivers + Stopped *Configure allowing garbage on end of command, eg *Configure Delay 30 this is rubbish + Fixed *Status TV corrupting error pointer while printing "TV " +2.08 (04 Mar 91) + Merged Configure Mode and Configure WimpMode + Set 'DriversInKernel' flag for now + Added OS_ReadSysInfo(1) - return configured mode/wimpmode value (with Auto expanded) + Fixed OS_ReadSysInfo(>1) so it returns an error properly +2.08 (08 Mar 91) + Put in Configure PrinterBufferSize and support code +2.08 (11 Mar 91) + Used to change screen mode and print "RISC OS xK" before module initialisation. Now it changes screen mode before + (in case modules print during init), and afterwards (in case a module has provided a new screen mode), and then prints + the message. + Also after a monitor type reconfigure, selects default mode, not mode 0. +2.09 (12 Mar 91) + Fixed *Status MouseStep corrupting error pointer while printing "MouseStep ". + Fixed *Status corrupting error pointer from module code. +2.09 (15 Mar 91) + Put in IOEB and LC detection, and monitor lead type detection. +2.09 (19 Mar 91) + Completed monitor lead type interface. + Changed default Language to 4 (which is new Desktop module number). +2.09 (21 Mar 91) + Improved monitor lead detection of Hsync. + Made InitialiseROMModule return errors correctly. +2.09 (25 Mar 91) + Fixed bug in OS_SWINumberFromString to do with checking for valid module SWI chunk. + Fixed loads of other bugs in SWI OS_SWINumberFromString. +2.09 (26 Mar 91) + Fixed similar bugs in SWI OS_SWINumberToString. +2.11 (02 Apr 91) + RM - Changed time calls to use TerritoryManager calls to cope with local time. + OS_ConvertDateAndTime now calls Territory_ConvertDateAndTime + Changes made in: Source.PMF.osword and in Source.PMF.convdate. +2.11 (05 Apr 91) + Finished putting in 82C710 detection and configuration. +2.11 (12 Apr 91) + Put in support for new serial drivers. +2.11 (18 Apr 91) + Moved Service_PostInit to after filing system selection. +2.12 (26 Apr 91) + Put in SWI XPortable_Speed in RDCH/INKEY. + Made *Modules and *ROMModules check Escape flag. +2.12 (29 Apr 91) + TestSrc.* (Power-on Selftest) + - 82C710 changes addressing for FDD inuse light + - Validation of CMOS checksum + - Disables long memory test (blue phase) if Misc1CMOS bit 7 is set + NewReset + - Checks CMOS checksum on Power-on{delete/copy/r/t}. Forces complete (including Econet + station number) reset if checksum is corrupt. + - Initializes checksum if CMOS reinitialised. + Source.PMF.i2cutils + - Addition of ValChecksum and MakeChecksum + - 'Write' now maintains checksum byte. Checksum byte itself may be changed. + Hdr.A1 + - Addition of ChecksumCMOS switch. FALSE removes checksum maintenance. +2.12 (02 May 91) + Changed default configured caps setting to NOCAPS. +2.12 (07 May 91) + CMOS checksum seed changed to 1 (CMOSxseed in Hdr.CMOS) + Selftest reports CMOS failure to user only if IIC fault occurs + Space reserved for processor test removed from TestSrc.Begin +2.13 (13 May 91) + Put in code to read unique ID +2.13 (20 May 91) + Added new characters to system font +2.13 (23 May 91) + Put in debugging for forced hard reset + Updated *Help Power-on + Fixed bug: if configured monitortype is unknown, uses naff VIDC parameters +2.14 (05 Jun 91) + Put in hex digit pairs for characters 80..8B, corrected location of new characters. +2.16 (12 Jul 91) + Changed default buffer flags for MOS buffers. +2.16 (18 Jul 91) + Changed default 82C710 configuration. +2.17 (26 Jul 91) + Adjusted Error_Code to place constructed error at GeneralMOSBuffer+4 + rather than GeneralMOSBuffer to avoid clashes with default error + handler's use of GeneralMOSBuffer. +2.17 (26 Jul 91) + Adjusted default owner of error vector to copy the error text limited + to 252 characters, truncating if necessary. Avoids duff error blocks + destroying the system. +2.17 (26 Jul 91) + Fix display of error by default error handler - it used to not put + the error number out. +2.17 (30 Jul 91) + Changed the value of INKEY(-256) to &A3. + Modified DoInsertESC (OS_Byte 153) to only do special things on buffers 0 or 1. +2.17 (05 Aug 91) + Changed default CMOS settings. +2.18 (12 Aug 91) + OS_Byte(2,non-zero) code now checks if serial stream open before trying to open it again. +2.18 (13 Aug 91) + Changed Messages file: removed extra space in "Extn", added space on end of "EXTROM", "PODROM". +2.18 (16 Aug 91) + Added code to respond to service DeviceFSCloseRequest to close printer and serial streams. +2.18 (19 Aug 91) + Changed *Error to use MessageTrans error buffers. Avoids numerous clashes in GeneralMOSBuffer. +2.18 (23 Aug 91) + Made ErrorSemaphore a byte, not a word. + Added PortableFlag so that we don't issue more than one abortive SWI Portable_Speed. + Change RS423Vdu to not put bytes in the serial output buffer if + couldn't open serial stream, and also to report any error. +2.18 (30 Aug 91) + Change error "System variable not found" to "System variable 'blah' not found" +2.19 (05 Sep 91) + Change monitor type for superVGA monitor ID to 1 for LiteOn monitor. +2.19 (06 Sep 91) + Added an extra space on end of "Result: Result is %0, value :" message. +2.19 (10 Sep 91) + Fixed kernel messages not translated after soft reset bug. +2.19 (11 Sep 91) + Fixed Configure Mode Auto always using 27. +3.00 (25 Sep 91) + Amber release. +3.01 (07 Oct 91) + Fixed bug A-RO-9984 (requests to close kernel device streams didn't work). + Removed redundant non-functional code from DoOsbyteVar which tried to close the + serial output stream if WrchDests no longer included serial - this code is not + needed because the kernel now responds to the DeviceFSCloseRequest service. + Put in checks on OS_SpriteOp for SLoad/SMerge. +3.01 (15 Oct 91) + Fixed bug RP-0039 (OS_ChangeDynamicArea goes wrong when amount to change = &80000000). + Removed redundant copy of month names table from kernel. +3.01 (17 Oct 91) + Added DebugHeaps option to initialise used and freed blocks in heaps. + Changed OS_SpriteOp check: it used to check that offset to first + sprite = 16, but this is too stringent - there are silly files out + there that have extension words in the header - so now it just + checks that the offset is within the file. +3.01 (21 Oct 91) + Put in support for 82C711 (including OS_ReadSysInfo(3)). +3.03 (11 Nov 91) + Enhance system variables: increase allowable length from 256 to + 16M; don't assign if going to overflow (found to be bad in + practice). + Split Arthur2 into system variable stuff (GSTrans etc, + OS_ConvertBinaryToDecimal, OS_ReadVarVal etc) and Utility, the + start of the utility module. +3.03 (13 Nov 91) + Change palette code to use PaletteV. +3.03 (18 Nov 91) + Added support for module to tell OS the real VIDC clock speed. +3.03 (22 Nov 91) + Added bit in CMOS that is set on a CMOS reset, and cleared on any other + reset. +3.03 (25 Nov 91) + Added new screen mode 22 for visually disabled - 768 x 288 x 4bpp, XEIG=0, YEIG=1, + for monitor types 0 and 1. +3.04 (20 Dec 91) + Fixed system SetVarVal to no GSTrans a string result from + EvaluateExpression (ie fix *SetEval). As a consequence a new + SetEval type allowed: VarType_LiteralString - string without + GSTransing. +3.04 (15 Jan 92) + Added OS_SetColour. + Switching output to a sprite takes into account Fg/BgPattern setup by OS_SetColour. +3.05 (21 Jan 92) lrust + Changed mouse buffer routines to BufferManager block transfer buffers to improve + interrupt latency. +3.05 (24 Jan 92) JRoach + Increase default mouse step from 2 to 3 as per ECR. +3.05 (28 Jan 92) LRust + Changed OS_Claim/Release code to restore IRQ state prior to releasing + vector node to system heap (conditional on IrqsInClaimRelease) to + improve interrupt latency. +3.05 (30 Jan 92) LRust + Changed ProcessTickEventChain to re-enable IRQ's while returning ticker nodes + to the system heap (conditional on TickIrqReenter). CallEvery/After events + are now processed last in centisecond clock interrupt. +3.06 (14 Feb 92) TDobson + Fixed dotted line bug (dotted lines with a dot pattern length > 32 + which start outside the window where the number of undisplayed + pixels modulo the dot pattern length exceeds 32 go wrong). +3.06 (14 Feb 92) LRust + OK lets start with the easy ones! Fixed bug report RP-0387. + Change *Error syntax in 'HelpStrs' to show error number as optional. +3.06 (18 Feb 92) LRust + Fixed RP-1299 - stack imbalance for OS_Word &0F under error conditions +3.06 (19 Feb 92) TDobson + Added Welsh characters and swapped direction of hex number characters + in kernel system font. +3.06 (19 Feb 92) LRust + Fix RP-0617. TranslateError now preserves callers IRQ state +3.06 (20 Feb 92) JRoach + Install an index on system variables to speed their assignment and + access. +3.06 (20 Feb 92) LRust + Invoke Service_SyntaxError from OS_CLI if command syntax error +3.06 (26 Feb 92) LRust + Fix RP-0609 and RP-0370. Callback handler only entered if SVC stack is + empty. RTC day/months of 0 are forced to 1 +3.07 (03 Mar 92) LRust + Setup of printer buffer uses internal CMOS read routines, not OS_Byte + which enable interrupts. This prevents system hanging during start-up + if keys are pressed. Fixes RP-0990 etc. +3.07 (03 Mar 92) LRust + Fixed OS_Word 11 to return palette data to r1+1, fixing RP-1429 +3.07 (04 Mar 92) LRust + OS_GSInit now only resets the evaluation stack (in system workspace) + if the string contains a '<' character. This prevents contention between + high level calls to OS_GSTrans and low level use by FileSwitch while + opening message files. This fixes RP-1483 + OS_SetVarValue fixed to use XOS_GSTrans (was non X form) + OS_SetVarVal now returns correct error if string is bad +3.07 (05 Mar 92) LRust + OS_Confirm now reads Yes/No characters from message file. The + pointer shape to be displayed is now read from the Wimp sprite pool, + RMA first followed by ROM, looking for 'ptr_confirm'. Fixes RP-1449 +3.07 (06 Mar 92) LRust + OS_Byte 129,0,255 now returns version number &A4 (was &A3) fixing RP-1638. +3.07 (06 Mar 92) TDobson + Sprite load/merge now only checks offset to first sprite is < length of file, + fixing bug RP-0589. +3.07 (09 Mar 92) TDobson + Don't reset keyboard on OS_InstallKeyHandler if we've only just got the + keyboard ID. +3.07 (17 Mar 92) JRoach + Postpone error lookup in ChangeDynamicArea to after the + reconstruction of the RAM and System Heaps. Prevents double-mapping + of pages resulting in a dead system. G-RO-5512. +3.08 (23 Mar 92) LRust + OS_EvaluateExpression now returns R1 = 0 (no returned string) if the expression + evaulated by GSTrans overflowed the internal buffer. This ensures that *IF + reports the buffer overflow error message instead of "not a string", fixing RP-1534 +3.08 (01 Apr 92) TDobson + Added code to switch into user mode and issue a dummy SWI just after Service_PostInit, + so that any pending callbacks get serviced (fixes RP-1812). +3.08 (02 Apr 92) TDobson + Added screen blanking code. +3.08 (03 Apr 92) LRust + RMTidy copies errors during die to GeneralMOSBuffer to ensure not overwritten + during re-initialisation. +3.08 (07 Apr 92) TDobson + Fixed DebugHeaps code in ExtendHeap (used to overwrite data below base of heap). +3.09 (23-Apr-92) LRust + * Fixed CTRL-Break/Reset causing CMOS corruption by doing 16 IIC + start/stop sequences after reset to allow RTC to shift out any + data requested. + * IIC start sequence extended to allow BMU to detect a start. + * IIC read/write now disable IRQs during clock and data hi times + to prevent erroneous idle sequence detection by BMU. +3.09 (24-Apr-92) TDobson + Removed range checking of buffer number in OS_Byte &15 (flush buffer). +3.10 (30-Apr-92) + Disable interrupts around IIC receive to aid BMU start/stop detection + by preventing idle periods (clock & data hi). + +-- RISC OS 3.10 released to public -- + +3.20 (xx-Apr-93) JRoach + Added read option to OS_SetColour + +3.20 (15-Apr-93) TDobson + Made OS_CRC return an error if increment is zero, rather than looping forever. + +< lots of Medusa work > + +3.21 (21-Jul-93) TDobson + First Medusa release + +3.22 (09-Aug-93) AGlover + vdugrafg/vdugrafdec: Fix bug in putsprite|mask when LH edge obscured + vdugrafh: Fix bug in SwitchOutputToMask when calculating mask size + + (18-Aug-93) TDobson + RMA, System heap, Sprite area, Font cache, RAM disc are now new-style areas. + Sprite area, Font cache, RAM disc, Free pool maximum sizes are now dynamic (ie total ram size), + and their base addresses are allocated at run-time. + Doubly-mapped areas are now supported, but known bug exists if + screen grows and needs pages in use by a doubly-mapped area. + Spec change to OS_DynamicArea (Create dynamic area): if workspace pointer passed in is -1, the + value used is the base address of the area (this is important if the base address is being + allocated by RISC OS). + + (20-Aug-93) TDobson + New addition to OS_ReadDynamicArea: if r0 on entry is -1 then + information is returned on application space: + r0 = base address (&8000) + r1 = current size (excluding bottom 32K) + r2 = maximum size (excluding bottom 32K) + + (23-Aug-93) AGlover + vdugrafK: Ensure new format sprites aren't screensaved with palettes + + (03-Sep-93) TDobson + Areas which require particular physical pages should now work. + LateAborts assembly option added (untested). + + (03-Sep-93) SCormie + Memory information SWI (OS_Memory) added (file MemInfo). + Processor vector indirection added, including SWI OS_ClaimProcessorVector (file ExtraSWIs). + + -- Version 3.23 released -- + + (17-Sep-93) AGlover + (vdugrafdec, vdugrafj vdugrafk) Sort out screenloading of sprites with new mode format + mode words (untested at present). + (20-Sep-93) TDobson + Screen is now a new style area. + All old-style area code now removed. + Fixed bug MED-00488 (composite sync inverted). + Fixed bug MED-00583 (modes with line length > 4Kbytes didn't work). + (21-Sep-93) TDobson + Fixed bug MED-00395 (OS_Byte 70 and 71 corrupting r5). + Made kernel enable cache and write-buffer again. + (22-Sep-93) TDobson + Removed old screen modes 47-51 and put in new modes 47 (PCSoft) and 48,49 (Games). + Fixed DataControlRegister programming so that eg mode 29 works with 2M VRAM. + Late abort option enabled. + + -- Version 3.24 released + + (01-Oct-93) TDobson + After pre-shrink handler is called, round down shrink value returned to a page multiple. + (07-Oct-93) TDobson + Fix MED-00626: RMReInit should only write to CMOS if module was unplugged to start with + (solves FSLock problem). + (08-Oct-93) TDobson + Bottom level DPMS control put in - byte at location &147D controls DPMS state on blanking. + Modified OS_Word(&15,4) (Read unbuffered mouse position) to call PollPointer, so that if + no flyback IRQs happen (because hsyncs have been turned off), moving the mouse pointer + still unblanks the screen. + + -- Version 3.25 released + + (19-Oct-93) TDobson + Fix MED-00523: Remove pointer if would be completely off LHS of screen, otherwise can + upset display if it straddles hsync pulse. + Fix MED-00637: Creating dynamic area of zero maximum size now works. + Screen mode 32 changed to NColour=63 and ModeFlags=0, like all other numbered 256 colour + modes. + + -- Version 3.26 released + + (21-Oct-93) SCormie + *Configure MouseType should have called OS_Pointer. + (25-Oct-93) SCormie + NewReset now waits up to 1 sec for keyboard present. + (25-Oct-93) TDobson + Fix bug MED-00811 - initialise SpriteSize to zero on reset. + (25-Oct-93) JRoach + Fix bug MED-00680 - *Save syntax message not tokenised properly. + (26-Oct-93) JRoach + Fix bug MED-00570 - delete-power-on gives 1997. Problem was + delete-power-on set base to 1994 and so when the modulo of '3' came + out of the clock the kernel thought it had to be 1997. + (26-Oct-93) TDobson + Fix bug MED-00301 - mode selector block now alternates between two + overlapping ones, so that returned mode number changes each mode + change (although if someone goes eg M%=MODE:MODE 12:...:MODE M% it + will use the block specified by M%). + (28-Oct-93) AGlover : vduswis, vdudriver, vdugrafj, vdugrafk + Bugfixing session on sprites. Major points:- + Screensave works, and gives old format sprites where possible. + Screenload works, and no longer believes the mode number in the + sprite - it will always build a mode selector to suit the sprite. + EIG 0 and EIG 3 sprites supported - fixes DragASprite leaving + trails on-screen in these modes. + Mode 32 is now the monitor type 4 256 colour substitute mode. + GetSprite(User) ensures no LH wastage on new format sprites. + Screensave now copes with saving a full entry 256 colour palette. + Whenever possible GetSprite will make an old format sprite - if + you must have a new format sprite make it first with CreateSprite. + + While there are four of us intermittently touching bits of the kernel + please say which files you've actually altered. Thanks. amg + + (03-Nov-93) AGlover : vdugrafj + Change substitute mode numbers used for 90 x 90 dpi sprites to 25-28 + instead of 18-21. + + (04-Nov-93) JRoach : GetAll, Kernel + Enable IncludeTestSrc and make Reset vector for resetting work in + conjunction with the test source. + + (08-Nov-93) TDobson : vdudecl, vdudriver + Complete kernel support for DPMS. + + (10-Nov-93) TDobson : source.pmf.osbyte + Fix bug MED-00963: INKEY(-256) now returns &A5. + + (11-Nov-93) TDobson : source.vdumodes + Fix bug MED-?????: mode 32 now same timings as modes 29-31. + + (12-Nov-93) AGlover : source.vdugrafg + Fix bug MED-01112 : 32K/16M sprites not working with SpriteOp ReadPixelColour (41) + Fix bug MED-????? : Correct the routine which bounces palettes on new format sprites + +-- Version 3.27 build + + (18-Nov-93) AGlover : source.vdugrafh, source.vduswis, source.vdudriver, source.vdugrafj + Fix bug MED-01130 : GetMaskSpWidth was going wrong when mask exactly fitten in a word + Change handling of sprite type so that unknown types are handled as 32bpp - will make + life easier for people adding new types that the OS doesn't handle. + + (23-Nov-93) AGlover : source.vdugrafg, source.vdugrafh, source.vdugrafi + Fix bug MED-01281 : return an error when I should for spriteops given new format + masks. + + (24-Nov-93) AGlover: source.vdugrafg + Fix bug MED-????? : sprite name matching code was being broken by changed + lowercase macro. Code now uses uk_lowercase which retains the original + behaviour of the macro keeping the sprite stuff compatible with 3.10 + + (25-Nov-93) TDobson: source.vdumodes + Fix mode definition for mode 47 (PCEm mode 360 x 480) to have sync polarity 3, + so it gives correct height on VGA-only monitors. + + (26-Nov-93) SCormie: Source.PMF.key, Source.PMF.osinit + Keyboard driver and key handler now trigger each other correctly during reset. + Change default serial threshold from 9 to 17. + + (30-Nov-93) AGlover: source.vdu23, source.vduwrch + Fix bug MED-01141: Split CompileTextFgBg into two separate routines and only call + the one actually relevant. This prevents spurious colour changes when a text colour + set by OS_SetColour is changed using VDU 17 or VDU 23,17 (what used to happen is + that because the Fore/Back Col and Tint words didn't produce the colour in use (which + had been modified directly by OS_SetColour) it was replacing it with whatever the + ForeCol and Tint produced. Note: Doing a VDU 23,17 before the first VDU 17 will still + go wrong - but I don't think it's worth fixing. + + (30-Nov-93) TDobson: source.vdumodes + Change XEigFactor for games modes 48,49 to 2 (from 1) at the request of Ran Mokady. + + (01-Dec-93) TDobson: source.pmf.osword + Fix bug MED-00355: OS_Word(&0F) no longer requires a terminating + character after string (it now pushes the string on the stack and + terminates it, before calling the TerritoryManager). + + (01-Dec-93) TDobson: NewReset + Fix bug MED-01513: now prints eg "RISC OS 10MB" on startup. + + (02-Dec-93) TDobson: ModHand + Fix bug MED-01229: now uses 8 bytes of unplug CMOS for podules, + 1 for network card + + (06-Dec-93) JRoach: NewReset + Correct mouse step default to 2 for faster mice we'll be using. + + (07-Dec-93) AGlover: source.vdugrafj, source.vdugrafk + Fix bug MED-?????: make sure screensave and getsprite(user) don't permit palettes + on sprites which it can't force back to an old screen mode + + (09-Dec-93) TDobson: source.vdudriver, source.vduswis + Use Roger's algorithm for default XEigFactor, YEigFactor for mode selectors. + + (13-Dec-93) TDobson: GetAll + Set AddTubeBashers flag to FALSE. + + (15-Dec-93) TDobson: GetAll, NewReset + Set DebugROMInit and DebugROMErrors flags to FALSE. + Fix bug MED-01774: Change default FontSize to 64K. + +-- 3.28 build + + (21-Dec-93) AGlover: source.vdugrafj + Change screenload so that should the mode selector it made fail, and the + sprite has a mode number, it will select that mode as a fallback. Note: + this won't work fully until OS_ScreenMode correctly returns VS for a mode + it can't do. Bug MED-01895. + + (21-Dec-93) OLove: Messages + Changed 'Memory cannot be moved' error message. + +-- New version 3.29 spuriously created by Owen Love 21-Dec-93 + + (21-Dec-93) AGlover: arthur3 + Fix bug MED-01583 - *eval 9999999999999 was calling msgtrans twice to return error + + (06-Jan-94) TDobson: Kernel, Source.PMF.Key, SWINaming + Added SWI OS_Reset - part of fix for MED-01397. + + (10-Jan-94) BCockburn: Middle + Fixed Ethernet address generation to use the correct base + (&0000A4100000) value rather than the value &0000A4000000 as found + in the Dallas chip itself. + + (10-Jan-94) TDobson: source.vdudriver, source.vduswis + Fixed bug MED-00563: invalid mode selector should return error from + mode change, not select mode 0. + If current monitor type is a file, now uses VGA substitute table for + unavailable mode numbers - eg if you select mode 16, you now get + mode 27, rather than mode 0. + + (10-Jan-94) TDobson: source.vdudriver + Fixed bug MED-00483: "mode selector" not on a word boundary (eg + sprite mode word) is now not offered round to Service_ModeExtension, + so should now give error, rather than data aborts. + + (12-Jan-94) JRoach: GetAll + Fixed bug MED-00585: configured language wasn't 10, and now is. + + (13-Jan-94) TDobson: GetAll, ModHand + Introduced conditional flag RMTidyDoesNowt - if true (which it is on Medusa), + then RMTidy returns having done nothing. This is because it would always + fail anyway, because FSLock always refuses to die. Fixes MED-02125. + + (14-Jan-94) SCormie: source.PMF.osinit + Changed combo chip configure sequence so that 710 configuration doesn't put + 665 into a strange state if receiving at the same time (caused chip to generate + an interrupt which could not be cleared. + + (14-Jan-94) JRoach: Arthur2 + Changed GSInit/GSRead to use its stack memory as a wrapping buffer. + This means GSInit doesn't need to flatten it before starting which + means recursive calls the GSTrans work. + + (17-Jan-94) TDobson: ARM600, ChangeDyn + Put in semaphore, so that OS_ChangeDynamicArea will fail if it is already threaded. + (Data abort handler clears it, in case area handler goes bang!) + + (17-Jan-94) TDobson, AGlover: source.vdugrafj + Fixed the 21-Dec-93 fix so it assembles and hopefully works! + + (18-Jan-94) TDobson: ARM600, Kernel, SWINaming + Added soft copy for MMU control register, and SWI OS_MMUControl to update it. + + (19-Jan-94) AGlover: source.vdugrafg + Fix bug MED-02210 - plot mask for 1bpp masks was going wrong when plotting clipped. + + (19-Jan-94) JRoach: NewReset + Correct CMOS default for textured window background to match the CMOS spec. + (The spec says set bit 7 of &8c to 0 to turn on textured window backgrounds). + + (19-Jan-94) JRoach: NewReset + Correct CMOS default for desktop font to '8' which is still Homerton.Medium. + Changed needed as Darwin has been removed and so the numbers change. + + (19-Jan-94) TDobson: ARM600 + Fixed bug MED-02452: make BangCamUpdate check if oldaddr=newaddr, + and don't remove page from old address if so. + + (19-Jan-94) TDobson: source.vdudriver + Changed notional operational range for VCO to 55-110MHz (from 40-80MHz). + + (21-Jan-94) TDobson: ARM600 + Changed ROM access speed to 156.25ns (from 187.5ns) + + (21-Jan-94) TDobson: source.vdudriver + Changed ComputeModuli to only use R-values up to 16 (not 64), to + improve minimum comparison frequency. + Change FIFO load position algorithm to use table produced by Peter + Watkinson. + + (24-Jan-94) TDobson: GetAll, source.vdudriver, source.vduswis + Conditionally reversed change to XEig/YEig algorithm back to what it was + in 3.27. + + (25-Jan-94) TDobson: source.vdudriver + Fixed FIFO load position table to use correct units. + +-- New version 3.30 created by JRoach + + (28-Jan-94) AGlover: syscomms, source.vdugrafj + Fix bug MED-01570 (syscomms), and various bugs reports involving + 1bpp 2 x 2 eig modes (vdugrafj: sanitizesgetmode was mishandling + double pixel modes) + + (28-Jan-94) TDobson: source.vdumodes + Update kernel's hard-wired mode tables to use new VCO range. + + (28-Jan-94) TDobson: TickEvents + Fixed bug MED-02498: OS_CallAfter/Every and OS_RemoveTickerEvent problems. + + (31-Jan-94) TDobson: TickEvents + Fixed register corruption in above fix. + + (01-Feb-94) AGlover: hdr:sprite, vdugrafdec, vdugrafj, vdugrafk, vdugrafl + Fix bug MED-02160. Make switching output to, and screenloading of, a + 256 colour 8bpp sprite work. The hdr change is because the value of + MaxSpritePaletteSize has been updated. + + (03-Feb-94) TDobson: ARM600, ChangeDyn, GetAll + Fix bugs MED-00793, MED-01846. Dynamic areas which may require + specific physical pages must now have a new bit set in the dynamic + area flags. As a result, other areas can perform large grows in one + chunk, rather than being split up, because it is not necessary to + set up the page blocks etc. Therefore a) dragging RAMFS bar is much + faster and b) there's no chance that intermediate reinits of RAMFS + can steal pages that were to be used for subsequent chunks. + +-- New version 3.31 built by TMD + + (08-Feb-94) AGlover: source.vdugrafh + Fix bug MED-01885. WritePixelColour wasn't working correctly for + 8bpp full palette sprites. + + (09-Feb-94) TDobson: Messages + Fix part of bug MED-02389 by changing system heap full message. + + (10-Feb-94) AGlover: source.vdugrafh + More on MED-01885. AddTintToColour decides what to do by NColour, rather + that SprRdNColour which is correct for Write/ReadPixel in sprite. + Set NColour to SprRdNColour for the call and then restore it afterwards. + The scope of the bug was more than first thought - it affected writing to + any 8bpp sprite in anything other than an 8bpp screen mode. + + (11-Feb-94) TDobson: NewReset + Limit maximum size of RAM disc to 16MB, because FileCore can't cope + with some larger sizes. + +-- New version 3.32 built by TMD + + (14-Feb-94) TDobson: NewIRQs + Fix bug MED-02859 - Unknown IRQ code now copes with DMA IRQs. + + (17-Feb-94) AGlover: source.vdugrafk + Fix bug MED-02895 - *screenload was discarding the error pointer + on an error return from WritePaletteFromSprite + + (18-Feb-94) AGlover: source.vdugrafj + Secondary fix for MED-02895. WritePaletteFromSprite was actually + destroying the error pointer. Remove the change to vdugrafk. + +====> Medusa OS build <========================================================== + + (28-Apr-94) AGlover: source.vdugrafj + Fix screenloading of 8bpp non-full palette sprites (deferred fix from Medusa + freeze). MED-03186 + (28-Apr-94) AGlover: source.vdugrafh + Fix spriteop readpixel for 256 colour full palette modes (deferred fix from + Medusa freeze). MED-03090 + (28-Apr-94) AGlover: source.vduswis + Fix readmodevariable returning 63 instead of 255 for a sprite mode word. + MED-03265 + (25-May-94) AGlover: source.vdugrafg,j,k + Changes to allow palettes on new format sprites of 8bpp and below. Also + William Turner's vdugrafh,i. + +**** this has been superceded by the +log file - no further entries here. +(amg: 21st September 1994) + \ No newline at end of file diff --git a/Doc/!ReadMe b/Doc/!ReadMe new file mode 100644 index 0000000000000000000000000000000000000000..522352ed4961c755696bdf4b41f51a2fec9f54de --- /dev/null +++ b/Doc/!ReadMe @@ -0,0 +1,57 @@ +> !ReadMe + +Instructions on how to make/modify Arthur. + +Directory Asm contains the Exec files. + +Asm.A500 assembles the A500 kernel and then does *Asm.BuildA500 +Asm.BuildA500 glues modules to the kernel to make an image for 27512's. +Asm.BigA500 glues modules to the kernel to make an image for 1Mbit devices. + +Asm.Test assembles the Archimedes kernel, for 300 and 400 series machines. + NB. This uses Hdr.Archie, not Hdr.Test !!! +Asm.Test2 glues modules to the kernel to make an image for 1Mbit devices. + +Asm.MoveFS takes a new copy of FileSwitch (and headers) from the net. +Asm.TransTim takes a new copy of Tim's stuff from the net. + + +Directory Hdr has the header files for the various assemblies. + + +Directory Text has various files, only one of which is important: +Text.Changes should be updated whenever changes are made to Arthur. +Text.Still has my list of things still to do. + + +Quick guide to the source files: + +Kernel is the first, and has the SWI dispatcher, plus the initialized variables +to copy into RAM, plus some Brazil swi handlers. + +Middle contains the rest of the Brazil swi stuff, plus supervisor routines. + +NewReset is the reset code - if you need to change this, you will need to use +the AddTubeBashers flag, which lives in Kernel. The TubeChar macro should then +function. + +Super1 is the supervisor loop, plus more Brazil oddsnsods. + +ArthurSWIs is ReadUnsigned, vectors, services, ValidateAddress. Note that +the version of ChangeDynamic in here is NOT the one that's assembled. + +Arthur2 is variables, GSTRANs + +Arthur3 is command code, including Status/Configure. + +Other files are hopefully obvious from their names. + + +Backing Up. +=========== + +You need to copy the whole tree from $.Kernel to the backup medium. +You also need to take a copy of all the current header files from $.Hdr. +A copy of all the tools in $.Library and $.Utils would also be handy. + + Have fun! diff --git a/Doc/0197276.02 b/Doc/0197276.02 new file mode 100644 index 0000000000000000000000000000000000000000..8ec4977270d2baebb4ab83d0b5e3263efcb84459 --- /dev/null +++ b/Doc/0197276.02 @@ -0,0 +1,1400 @@ + +Copyright (C) Acorn Computers Ltd. 1993 0197,276/FS Issue 2 **Live** + + Medusa Memory Management Software Functional Specification + ========================================================== + + ----------------------------------------- + | Drawing No : 0197,276/FS | + | Issue : 2 **Live** | + | Date : 15th April 1993 | + | Author : Tim Dobson | + | Sheets : n | + | Last Issue: ? | + ----------------------------------------- + + Contents + ======== + + 1 History + + 2 Outstanding Issues + + 3 Overview + + 4 Technical Background + + 5 User Interface + 5.1 TaskManager and large RAM sizes + + 6 Programmer Interface + 6.1 Logical memory map + 6.2 Free pool + 6.3 New SWI: OS_DynamicArea + 6.3.1 Reason codes + 6.3.1.1 Create dynamic area + 6.3.1.2 Remove dynamic area + 6.3.1.3 Return information on dynamic area + 6.3.1.4 Enumerate dynamic areas + 6.3.1.5 Renumber dynamic area + 6.3.2 Dynamic area handler routine + 6.3.2.1 PreGrow + 6.3.2.2 PostGrow + 6.3.2.3 PreShrink + 6.3.2.4 PostShrink + 6.3.3 Sequence Of Actions When OS_ChangeDynamicArea Is Called + 6.3.3.1 Service_PagesUnsafe + 6.3.3.2 Service_PagesSafe + 6.3.4 Implementation Notes for OS_ChangeDynamicArea + 6.3.5 OS_DynamicArea Service Calls + 6.3.5.1 Service_DynamicAreaCreate (&90) + 6.3.5.2 Service_DynamicAreaRemove (&91) + 6.3.5.2 Service_DynamicAreaRenumber (&92) + 6.4 New SWI: OS_Memory + 6.4.1 OS_Memory Reasons 0-5: Convert Memory Address + 6.4.2 OS_Memory Reasons 6-8: Physical Memory + 6.4.2.1 Read Physical Memory Arrangement Table Size + 6.4.2.2 Read Physical Memory Arrangement Table + 6.4.2.3 Read Amounts Of Various Sorts Of Memory + 6.4.3 I/O Space Information + 6.4.3.1 Read Controller Presence + 6.5 Old SWI OS_SetMemMapEntries (&53) + 6.6 Old SWI OS_ReadDynamicArea (&5C) + 6.7 New SWI OS_ClaimProcessorVector + + 7 External Dependancies + + 8 Development Test Strategy + + 9 Organisation + + 10 Future Enhancements + 10.1 Abort trappping + 10.1.1 Technical background + 10.1.2 New SWI: OS_AbortTrap + 10.1.2.1 Add abort trap + 10.1.2.2 Remove abort trap + + + 1. History + ========== + + TMD 05-Nov-92 Started initial draft + TMD 08-Mar-93 More detail added + Issue A TMD 21-Apr-93 Released for initial review + JSR 11-May-93 Input from review entered + JSR 24-May-93 Adjustments to area grow and deletion + behaviour. + Add 2 controllers to list: VIDC1 and VIDC20 to + allow ScreenTricks module to operate. + JSR 02-Jun-93 Added section to development test strategy for + Wimp and Switcher testing. + JSR 04-Jun-93 Comments on Issue 1 spec from DLowdell. + + 2. Outstanding Issues + ===================== + + What if anything should be done to the task manager's task display to cope + with large memory sizes? + + The handling of Wimp_ClaimFreeMemory. This SWI claims the free pool making + it available for data transfers. The Wimp used to implement this by putting + the free memory on the end of the current task. This is no longer + necessarily going to work as there may not be any free space beyond the end + of the current task's memory. Also, it is quite likely that there won't be + enough space for all the free memory. + + + 3. Overview + =========== + + This specification covers changes to the memory management system in RISC + OS for Medusa platforms. + + The main features of Medusa platforms which require changes to RISC OS's + memory management are as follows:- + + 1) Ability to cope with RAM sizes up to 256+2Mbytes, rather than the + current maximum of 16Mbytes; + + 2) Ability to control DMA; + + 3) Requirements for second processor card drivers to claim memory; + + 4) Physical RAM no longer contiguous; + + 5) ARM600 MMU requires page table allocation; + + 6) Logical memory map expansion due to 32-bit address space. + + 7*) Changes to support emulation of VIDC1; + + 8*) Changes to support line-doubling; + + Note: The implementation of the starred items above (VIDC1 emulation, + line-doubling) are not part of the Medusa project; however it is an aim of + the memory management work that it should be possible to implement these in + a soft-loaded module at a later date. + + 4. Technical Background + ======================= + +In RISC OS 2 and 3 (version 3.10) the memory management task was divided +between the kernel and the wimp. The kernel ordered the memory into dynamic +areas and an application space, and the wimp then bludgeoned the kernel into +not getting in the way of the wimp's model of having a free pool and +multiple application spaces, rather than just the one application space +which had all spare memory in it. For Medusa the free pool management will +be moved into the kernel so that there isn't such a wrestling match between +the kernel and the wimp. The wimp will still manage the multiple application +spaces - it being the module responsible for constructing and managing tasks +in the desktop. The main kernel interface for memory management was +OS_ChangeDynamicArea which simply allowed the resizing of dynamic areas. +This has been added to for Medusa with the OS_DynamicArea SWI for the +control, creation and deletion of dynamic areas. + +The dynamic area management in RISC OS 2 and 3 (version 3.10) was somewhat +tied together with the dynamic area clients. The change dynamic area SWI +specifically called other modules depending on which dynamic area was being +resized. The result was that there was no flexibility with how dynamic areas +were used. + +Other memory related services were not available. For example it was not +possible to find out what memory or hardware was available on the system +without knowing a great deal about the platform. + +Memory is referred to in three ways: physcial address, logical address and +physical page number. The first two refer to the address of the memory in +the physical address space (what IOMD presents to ARM) and logical address +space (what the ARM memory manager presents to the ARM core) respectively. +The physical page number is an arbitrary number assigned to RAM pages. It is +necessary to have this last abstraction to save space. If it weren't there +then the storage and management overheads would be prohibitive on a small +memory machine, which, as Medusa is targetted at under 1000 pounds, is +likely to be a majority of users. The way physical page numbers are +allocated is that all the contiguous RAM section in physical address space +are bunched together and the page numbers allocated from 0 upwards. + +There are several interfaces described here which use Page blocks. These are +tables of 3-word records: + word use + 0 Physical page number + 1 logical address + 2 physical address +That is, a block of memory 12*N bytes big where N is the number of records +in the block. They are used to pass round lists of addresses or pages. + + + 5. User Interface + ================= + + 5.1 TaskManager and large RAM sizes + ----------------------------------- + + The TaskManager module's 'Task display' window does not cope well in this +area at present. The combination of a 16-fold increase in maximum RAM size +and an 8-fold decrease in page size means that the existing linear 1 +pixel-per-page model will not be practical on large memory machines. A +number of options are possible:- + + a) Do nothing. It is rare that anyone will want to manually drag an area's +size to anything particularly big. Most big programs will set their own +Wimp slot size; + + b) Allow the user to click in the number fields and enter a number +(presumably still in K); + + c) Make the scale exponential (ie at the small sizes it goes in units of +4K, but when the area gets bigger go in larger and larger steps). + + d) Make the scale a modified exponential (1+log(x)/c). + + + 5.2 *-Command *Cache On/Off + --------------------------- + + A module will be provided to give this functionality. It will switch both +caching and write-buffering on and off. The corresponding SWIs will not be +supplied as they are inapplicable to an ARM600/700 based system. + + + 6. Programmer Interface + ======================= + + 6.1 Logical Memory Map + ---------------------- + + Address Size Use Public? + + 00000000 16k System workspace Private + 00004000 16k Scratch space Public(1) + 00008000 28M-32k Application space Public + 01C00000 8k SVC stack Public(2) + 01C02000 2M-8k System heap Private + 01E00000 8k Undefined stack Public(2) + 01E02000 1M-8k Soft CAM map Private + 01F00000 32k Cursor/sound etc Private + 01F08000 32k "nowhere" Private + 01F10000 1M-64k Reserved for fake screen (480k) Private + 02000000 12M RMA Public(3) + 02C00000 4M Level 2 page tables Private + 03000000 4M I/O space Private(4) + 03400000 1M Reserved for VIDC1 emulation Private + 03500000 1M VIDC20 Private + 03600000 1M Reserved for Vinit &c emulation Private + 03700000 1M Reserved for 2nd Proc ctrl regs Private + 03800000 8M ROM Private + 04000000 2G-64M Dynamic areas Public(5) + 80000000 512M Copy of physical space Private + A0000000 1 1/2 G More dynamic areas Public(5) + +Notes: +1) This may be used by any module. The rules for its use are: + Not in an IRQ routine + Not if you're going to call something which might use it while you + are +Example clients are: FileCore to hold structures whilst working out how to +allocate some free space; Filer to hold structures for OS_HeapSort. +2) It may be assumed that these end on a 1M boundary and will exception if +accessed beyond that end. However, the exact location of these stacks should +not be assumed. +3) The location of RMA and its maximum size may not be assumed. However, it +is guaranteed that it will be in low 64MBytes (ie can execute 26 bit code). +4) Except where particular device drivers export hardware addresses. +5) Only in so far as a client may make its own dynamic area. + + + 6.2 Free pool + ------------- + + Large RAM sizes pose a problem for RISC OS, because the existing metaphor + that all spare memory lives in application space breaks down. The current + limit on application space size is 16MB, whereas the maximum RAM size on + Medusa platforms is 258MB. Although this limit can be moved up a little by + moving other areas out of the way, it is not possible to extend it enough + (eg I/O still has to live at &03000000 onwards). + + To cope with this a new dynamic area is created, known as the "free pool" + (area number 6). The operation of SWI OS_ChangeDynamicArea is modified as + follows:- + + a) When an area (other than the free pool) is grown, memory is taken from + the free pool, if any exists (the current application is not notified + of this). + + If having shrunk the free pool to zero size, there is still not enough + memory for the growth, the kernel attempts to remove pages from the + application space as it does under existing versions of RISC OS. + + b) When an area (other than the free pool) is shrunk, the pages recovered + are added to the free pool. The current application is not consulted. + + c) If the free pool itself is grown, pages are taken from application + space to put in it (and the application consulted beforehand). + + d) If the free pool is shrunk, the recovered pages are added to + application space (the application is consulted beforehand). + + The WindowManager module also changes, to take this into account. In some + ways its operation is simplified, as it no longer needs to maintain its own + free pool. However the implementation of the following SWIs needs to + change:- + + Wimp_TransferBlock at present puts all used task memory into application + space, and then copies the relevant bits over. It cannot do this any more, + as the total used task memory may not fit into application space. Instead + it must do the following:- + + Split the transfer into chunks of no more than half of the maximum + application memory size. For each chunk, put the appropriate pages of the + source block in at the start of application space, and the appropriate + pages of the destination block above these, then perform the transfer. + After all chunks have been done, restore the current task's pages in + application space. + + Wimp_ClaimFreeMemory needs to be modified, because the Wimp no longer + maintains control of the free pool. + + + 6.3 New SWI: OS_DynamicArea (&66) + --------------------------------- + + This SWI performs miscellaneous operations on dynamic areas. + + On entry, r0 provides a reason code which determines which operation is + performed. + + Note that as all operations on dynamic areas work in physical page numbers + it is not possible to map anything other than RAM pages (DRAM and VRAM) + into a dynamic area. In particular EASI space cannot be mapped in. + + 6.3.1 Reason codes + ------------------ + + 6.3.1.1 Create dynamic area + --------------------------- + + This call creates a new dynamic area. + + On entry: r0 = 0 (reason code) + r1 = new area number (-1 => RISC OS should allocate number) + (must not be 128-255 - see section 6.6) + r2 = initial size of area (in bytes) + r3 = base logical address of area (-1 => OS should allocate + base address) + r4 = area flags + bits 0..3 = access privileges to be given to each page + in the area (same format as for + OS_Read/SetMemMapEntries) + + bit 4 = 0 => area is singly mapped + = 1 => area is doubly mapped + + bits 5..31 must be zero + + r5 = maximum size of area, or -1 if the area should be + capable of growing to the total RAM size of the + machine + r6 -> area handler routine, or 0 for no routine + r7 = workspace pointer to be passed in r12 on entry to + area handler (should be 0 if r6=0) + r8 -> area description string (null terminated), eg + "Font cache". This string will be displayed in the + TaskManager window. + + On exit: r1 = allocated area number + r3 = specified or allocated base address of area + r5 = specified or allocated maximum size of area + r0,r2,r4,r6-r8 preserved + + An error will be returned if: + + * the given area number clashes with an existing area, or + + * the logical address space occupied by the area at maximum size would + intersect with any other area at maximum size, or + + * there is not enough contiguous logical address space to create the + area, or + + * there is not enough memory in the free pool to allocate level 2 page + tables to cover the area at maximum size. + + If r1 is -1 on entry the RISC OS will allocate an area number itself. + This will be greater than or equal to 256. This means (see section 6.6) + that OS_ReadDynamicArea on these areas will always return with r2 + being the maximum area size. + + For singly mapped areas the base logical address is the lowest logical + address used by that area. The area grows by adding pages at the high + address end. + + For doubly mapped areas the base logical address is the (fixed) boundary + between the two mappings: the first mapping ends at r3-1, and the second + starts at r3. When one of these areas grows the pages in the first copy + move down to accommodate the new pages at the end, and the second copy + simply grows at the end. + + On entry, r6 points to the area handler routine which gets called with + various reason codes when an an area is grown or shrunk. If zero is + passed in, then no routine will be called, and any shrink or growth will + be allowed. + + Details of the entry and exit conditions for this routine are given + in section 6.3.2 below. + + The area is created initially with size zero (ie no pages assigned to + it), and is then grown to the size specified in size r2, which involves + the area handler being called in the same way as if + OS_ChangeDynamicArea was called to grow the area. + + The area is created with a maximum size equal to either the amount given + in r5 on entry, or the total RAM size of the machine, if this is + smaller. If r5 is -1 on entry, then the maximum size will be set to the + total RAM size of the machine. + + If r3 on entry is -1, then RISC OS allocates a free area of logical + address space which is big enough for the maximum size of the area. + + Once the area has been created Service_DynamicAreaCreate will be issued + to inform the rest of the system about this change. + + Notes for application writers + ----------------------------- + + The following facilities: + + * the ability to create areas with specific area numbers + * the ability to create areas at specific logical addresses + * the ability to create doubly-mapped areas + + are intended for internal system use only. + + Applications should in general create only singly-mapped areas, and + request that RISC OS allocate area numbers and logical addresses. + + This will prevent clashes of area numbers or addresses. + + 6.3.1.2 Remove dynamic area + --------------------------- + + This call removes a previously created dynamic area. + + On entry: r0 = 1 (reason code) + r1 = area number + + On exit: All registers preserved + + An error is returned if the area was not removed for any reason. + + Before the area is removed, RISC OS attempts to shrink it to zero size. + This is done using ChangeDynamicArea. If the ChangeDynamicArea returns + an error then the area will be grown back to its original size using + ChangeDynamicArea and the remove dynamic area call will return with an + error. If the ChangeDynamicArea to reduce the area to 0 size worked then + the area will be removed. + + Once the area has been removed Service_DynamicAreaRemove will be issued + to inform the rest of the system about this change. + + + 6.3.1.3 Return information on dynamic area + ------------------------------------------ + + This call returns various information on a dynamic area. + + On entry: r0 = 2 (reason code) + r1 = area number + + On exit: r2 = current size of area (in bytes) + r3 = base logical address of area + r4 = area flags + r5 = maximum size of area + r6 -> area handler routine + r7 = workspace pointer for area handler + r8 -> area description string (null terminated) + + Note that for doubly-mapped areas, r3 on exit from this call returns the + address of the boundary between the first and second copies of the area, + whereas OS_ReadDynamicArea returns the start address of the first copy + (for backwards compatibility). + + 6.3.1.4 Enumerate dynamic areas + ------------------------------- + + On entry: r0 = 3 (reason code) + r1 = area number or -1 + + On exit: r1 = next area number or -1 + + This allows an application to find out what dynamic areas are defined. + -1 is used to start the enumeration and -1 indicates that the + enumeration has finished. + + + 6.3.1.5 Renumber dynamic area + ----------------------------- + + This call renumbers a dynamic area. + + On entry: r0 = 4 (reason code) + r1 = old area number + r2 = new area number + + On exit: All registers preserved + + An error is returned if the area specified by the old area number does + not exist or if the new number clashes with an existing area. + + This call is intended for system use only. + + Once the dynamic area has been renumbered Service_DynamicAreaRenumber + will be issued to inform the rest of the system about this change. + + + 6.3.1.6 Read size of application space + -------------------------------------- + + This call returns the maximum size of application space + + On entry: r0 = 5 (reason code) + + On exit: r5 = maximum size of application space + + This call is intended for system use only. + + + + 6.3.2 Dynamic area handler routine + ---------------------------------- + + This section describes the reason codes passed to the dynamic area handler + routine, with their entry and exit conditions. + + This routine is called when the size of an area is being changed. + + On entry, r0 contains a reason code, which describes what is happening. + + It should be noted that when called, OS_ChangeDynamicArea is currently at + work and will reject requests to resize dynamic areas. As a consequence + any SWIs which might resize a dynamic area should be avoided. Such things + as OS_Module to claim some workspace are an example, and hence most file + operations should be avoided (although I/O on an existing file is more + safe than other operations). + + The reason codes are as follows:- + + 6.3.2.1 PreGrow (0) + ------------------- + + This reason code is issued when a call to OS_ChangeDynamicArea results + in an area growing. It is called before any pages are actually moved. It + allows the handler to specify particular physical pages if it needs them + (eg for the screen area), or to object to the size change. + + On entry: r0 = 0 (reason code) + r1 -> Page block + The physical page number entries will be set to -1 + r2 = number of entries in Page block (= number of pages + area is growing by) + r3 = number of bytes area is growing by (= r2 * pagesize) + r4 = current size of area (bytes) + r5 = page size + r12 -> workspace + + On exit: If the growth is OK, then + r0 is preserved + If particular physical page numbers are required then all + the physical page number entries must be filled in with + the required pages. The other entries must be left alone. + V = 0 + else + r0 -> error to return, or zero to return generic error + V = 1 + endif + All other registers preseved + + This call permits the dynamic area handler to request that specific + pages be used for growing the area. If this is the case then all pages + must be specified. The correspondence between the Page block and memory + is that the first entry in the page block corresponds to the lowest + memory address of the extension, and the last entry in the Page block + the highest memory address. + + If an error is returned, then the area will not change size. + + 6.3.2.2 PostGrow (1) + -------------------- + + This reason code is issued when a call to OS_ChangeDynamicArea results + in an area growing. It is called after the PreGrow reason code has been + issued successfully and the memory pages have been moved. It provides + the handler with a list of which physical pages have been moved into the + area. + + On entry: r0 = 1 (reason code) + r1 -> Page block + Only the physical page number entries are defined + r2 = number of entries in Page block (= number of pages + area grew by) + r3 = number of bytes area grew by + r4 = new size of area (bytes) + r5 = page size + r12 -> workspace + + On exit: All registers preserved + + 6.3.2.3 PreShrink (2) + --------------------- + + This reason code is issued when a call to OS_ChangeDynamicArea results + in an area shrinking. It is called before any pages are moved. It allows + the handler to limit the amount of memory moved out of the area, or to + object to the size change altogether. The shrink amount alowed as + returned by this reason code is permitted to be a non-page multiple. The + ChangeDynamicArea code will ensure the shrink permitted is rounded down + to a page multiple before it is actioned. + + On entry: r0 = 2 (reason code) + r3 = number of bytes area is shrinking by + r4 = current size of area (bytes) + r5 = page size + r12 -> workspace + + On exit: If shrink (even by reduced amount) is OK, then + r0 preserved + r3 = number of bytes area can shrink by. This must be less + than or equal to r3 on entry. + V = 0 + else + r0 -> error block, or zero to return generic error + r3 = 0 + V = 1 + endif + All other registers preserved + + 6.3.2.4 PostShrink (3) + ---------------------- + + This reason code is issued when a call to OS_ChangeDynamicArea results + in an area shrinking. It is always called after the PreShrink reason + code has been issued successfully even if the memory pages can't be + moved. + + On entry: r0 = 3 (reason code) + r3 = number of bytes area shrunk by + r4 = new size of area (bytes) + r5 = page size + r12 -> workspace + + On exit: All registers preserved + + + 6.3.3 Sequence Of Actions When OS_ChangeDynamicArea Is Called + ------------------------------------------------------------- + + This section has been provided to give an overview of what happens when a + dynamic area's size is changed. This is presented as pseudo-code for + clarity. + + Check IRQSemaphore - reject CDA if set + + Growing free pool: + (no check for page availability - do as much as possible!) + Application space being shrunk - confirm it's OK: + If CAO in application space then + UpCall_MovingMemory (asks application if it consents to + memory move) + If UpCall *not* claimed Then reject CDA + Else + Service_Memory (asks modules for objectors to the memory + move) + If Service *is* claimed then reject CDA + EndIf + Move pages from application space end to free pool + + Growing other dynamic area: + Check for page availability - if not enough available bounce CDA with + error + Table of pages prepared: + Allocates memory + Fills in -1s for 'any page' + PreGrow is called: + replaces -1s if it wants + objects about resize amount perhaps + Check for unavailable pages: + If there is a non -1 which can't be grabbed then reject CDA + Check for application space resizing: + If free pool < amount needed then + If CAO in application space then + UpCall_MovingMemory (asks application if it consents to + memory move) + If UpCall *not* claimed Then reject CDA + Else + Service_Memory (asks modules for objectors to the memory + move) + If Service *is* claimed then reject CDA + EndIf + EndIf + Page replacements determined: + Work out swap sequences on all non -1s + Replace all -1s with actual pages + Pages get grabbed first from the free pool, then underflowing into + the application space + Issue Service_PagesUnsafe (only if PreGrow specified pages) + Pages get moved around: + Do the page moving/swapping (don't swap if pages requested are in + free pool) + Issue Service_PagesSafe (only if PreGrow specified pages) + PostGrow is called: + Sorts out structures for the new size + + Shrinking free pool: + Check if application space OK to grow: + If application space < maximum then + If CAO in application space then + UpCall_MovingMemory (asks application if it consents to + memory move) + If UpCall *not* claimed Then reject CDA + Else + Service_Memory (asks modules for objectors to the memory + move) + If Service *is* claimed then reject CDA + EndIf + EndIf + Move pages from free pool to application space + + Shrinking other dynamic area: + PreShrink is called: + objects about resize amount perhaps, or gives larger allowed size + Sorts out structures for the new smaller size as the shrink + will definitely go ahead. + Pages get moved around: + Move pages from dynamic area to free pool + PostShrink is called: + Keep subsystem informed. + + + + It should be noted that the system stack is used for the page structure + passed to the PreGrow routine. As a consequence there is a limit to the + amount that an area can be grown by at one time. To get round this problem + an area grow request of a large amount will be performed in several + steps. If one of these steps fails then the grow will terminate early with + the area grown by however much was achieved, but not by the full amount + requested. + + You will notice two new service calls were used here: + Service_PagesUnsafe + Service_PagesSafe + which are issued around page swapping to inform any DMA subsystems (eg + IOMD DMA or second processor) that some pages are being swapped around. + Here is the detailed description of these service calls: + + 6.3.3.1 Service_PagesUnsafe + --------------------------- + + On entry: r1 = Service_PagesUnsafe + r2 = Page block filled in by the PreGrow routine with the + two address fields filled in too. + r3 = number of entries in Page block + + On exit: All registers preserved + + The recipient of this service call is being told that the pages + specified are about to be swapped around. Direct memory access + activities involving the specified pages should be suspended until + Service_PagesSafe has been received indicating the pages are safe. + + + 6.3.3.2 Service_PagesSafe + ------------------------- + + On entry: r1 = Service_PagesSafe (&8F) + r2 = Number of entries in each Page block + r3 -> Page block before move + r4 -> Page block after move + + On exit: All registers preserved + + The recipient of this service call is being told that the pages + specified have been swapped for different pages and what those different + pages are. Note that the logical addresses in both Page blocks will + match. The 'before' Page block will contain the physical page numbers + and physical addresses of the pages which were replaced, and the 'after' + block the page numbers and physical addresses of the pages which + replaced them. + + 6.3.4 Implementation Notes for OS_ChangeDynamicArea + --------------------------------------------------- + +There is an issue with OS_ChangeDynamicArea when a particular page is +requested by the growing dynamic area which is currently in use by the page +tables. The problem is that moving pages that themselves control where the +pages are is a tricky operation. This is exacerbated on level 1 page tables +even more because these are 16k (4 pages) big and must be 16k aligned. This +means that if a level 1 page table needs moving then another 4 page block +needs to be found - potentially resulting in more page swapping to make such +a gap. Level 2 page tables don't have this problem as they're 4k (1 page) +big. + +Having said this, unless some mobility is permitted the minimum +configuration which would permit a '486 second processor to work would be +4MBytes. In a 2MByte machine 1M is left free of page tables to allow the +screen to grow, and the 2nd MByte would, as a consequence, be 'contaminated' +with page tables and so would be unavailable for the 2nd processor. If the +page tables could be moved they could reside in the 'screen' MByte as they +could be moved freely about if the screen needed to grow. + + 6.3.5 OS_DynamicArea Service Calls + ---------------------------------- + + These service calls are designed to keep the rest of the system informed + about changes to the dynamic areas. Their primary customer is the task + manager, although other modules could make use of them. + + 6.3.5.1 Service_DynamicAreaCreate (&90) + --------------------------------------- + + On entry: r1 = Service_DynamicAreaCreate (&90) + r2 = area number of area just created + + On exit: All registers preserved + This service must not be claimed + + This service is issued just after the successful creation of a dynamic + area. + + + 6.3.5.2 Service_DynamicAreaRemove (&91) + --------------------------------------- + + On entry: r1 = Service_DynamicAreaRemove (&91) + r2 = area number of area about to be removed + + On exit: All registers preserved + This service must not be claimed + + This service is issued just before the removal of a dynamic + area. It is issued during a call to OS_DynamicArea(1), after the area has + been successfully reduced to zero size, but before it has been removed + completely. + + + 6.3.5.2 Service_DynamicAreaRenumber (&92) + ----------------------------------------- + + On entry: r1 = Service_DynamicAreaRenumber (&92) + r2 = old area number + r3 = new area number + + On exit: All registers preserved + This service must not be claimed + + This service is issued during a call to OS_DynamicArea(2), ie when an area + is being renumbered. + + + 6.4 New SWI: OS_Memory + ---------------------- + +This SWI performs miscellaneous operations for memory management. + +On entry: r0 = reason code and flags. Bits o-7 are the reason code, bits + 8-31 are the flags which may be specific to the reason code. + The other registers are specific to the reason code. + +On exit: The returned values are specific to the reason codes. + +Here are the defined reason codes: + +0-5: Page block Operations +0 - General Page block Operation +1-5 - reserved + +6-8 - physical memory: +6 - read physical memory arrangement table size +7 - read physical memory arrangement table +8 - read amounts of various sorts of memory + +9-? - I/O space information: +9 - read controller presence + +The details of these are given below. + + 6.4.1 OS_Memory Reason 0: General Page block Operation + ------------------------------------------------------ + + This reason code is used to convert between representations of memory + addresses. The different memory spaces are logical memory, physical + memory and physical pages. + + On entry: r0 = flags: + bit meaning + 0-7 reason code (0-5) + 8-9 which entry is defined in the Page block: + 0 - Physical page number + 1 - Logcial address + 2 - Physical address + 10 Physical page number will be filled in when set + 11 Logical address will be filled in when set + 12 Physical address will be filled in when set + 13-14 Cachability control: + 0 - no change + 1 - no change + 2 - disable caching on these pages + 3 - enable caching on these pages + 15-31 reserved - set to 0 + r1 -> Page block + r2 = number of entries in page block + + On exit: Page block updated as necessary + + The Page block will be scanned and the specified operations applied to + it. It is possible to do address conversions and control the cachability + on a per-page basis. If any page is found to be unconvertable or + non-existent then an error will be returned and the cachability will be + unaffected. Cachability is accumulated for each page. So, for example, if + there are 5 clients which need caching turned off on a page then each of + them must turn caching back on individually for that page actually to + become cached again. + + Where an ambiguity may occur, for example in doubly-mapped areas such as + the screen, one of the possible results will be chosen and filled in. + + This will only handle RAM addresses. The address fields may be non-page + aligned. + + 6.4.2 OS_Memory Reasons 6-8: Physical Memory + -------------------------------------------- + + These are provided to enable a program to find out what physical + memory there is and its arrangement. The first two calls provide + complete information on the available memory. The information is provided + in the form of a table, with each page of physical memory space having + one entry in the table. Due to the large number of pages the table is + packed down to only 4 bits per page. In each byte of the table the low + order 4 bits correspond to the page before the high order 4 bits, ie it + is little-endian. This is the meaning of a nibble in the table: + + bit meaning + 0-2 type of memory: + 0 not present + 1 DRAM + 2 VRAM + 3 ROM + 4 I/O + 5-7 Undefined + 3 0 - Page available for allocation + 1 - Page not available for allocation + + The page availability is based on whether it is RAM, and whether it has + already been allocated in such a way that it can't be replaced with a + different RAM page eg the OS's page tables or screen memory. + + The third call gives a summary of available memory. + + + 6.4.2.1 Read Physical Memory Arrangement Table Size + --------------------------------------------------- + + On entry: r0 = 6 (bits 8-31 clear) + + On exit: r1 = table size (bytes) + r2 = page size (bytes) + + This returns information about the memory arrangement table. + + + 6.4.2.2 Read Physical Memory Arrangement Table + ----------------------------------------------- + + On entry: r0 = 7 (bits 8-31 clear) + r1 = pointer to table to be filled in + + On exit: registers preserved + + This returns the physical memory arrangement table in the block of memory + pointed at by r1. Note the information about page availability may well + change between this being called before a OS_ChangeDynamicArea and the + PreGrow routine being called, in particular it may have been necessary + for OS_ChangeDynamicArea to allocate level 2 page tables for the grown + area, and these are not available for allocation. Hence, for + applications which require, say, all pages from physical address 0 + onwards their PreGrow handler must make this call, rather than the + information being extracted and held before OS_ChangeDynamicArea being + called. + + + 6.4.2.3 Read Amounts Of Various Sorts Of Memory + ----------------------------------------------- + + On entry: r0 = bits meaning + 0-7 must be 8 - its the reason code + 8-11 the type of memory: + 1 - DRAM + 2 - VRAM + 3 - ROM + 4 - I/O + 12-31 reserved - set to 0 + + On exit: r1 = number of pages of that sort of memory + r2 = page size (in bytes) + + + 6.4.3 I/O Space Information + --------------------------- + + These give information about the I/O space. Controllers are identified by + type and sequence number so that a machine could be constructed with, + say, more than one IDE controller in it. + + 6.4.3.1 Read Controller Presence + -------------------------------- + + On entry: r0 = 9 (bits 8-31 clear) + r1 = controller ID + bit meaning + 0-7 controller sequence number + 8-31 controller type: + 0 - EASI card access speed control + 1 - EASI space + 2 - VIDC1 + 3 - VIDC20 + + On exit: r1 = controller base address or 0 if not present. + + This returns the location of a controller on the given machine. For + example the EASI space gives the base address of podule N where N is + the sequence number given. This reason code is provided for internal + use only and is documented here for completeness' sake. In particular + you must use the Podule manager to get at this information and to + control your podule's EASI space access speed. + + 6.5 Old SWI OS_SetMemMapEntries (&53) + ------------------------------------- + + As noted in the RISC OS 3 PRMs -1 should be used to indicate that a page + should become inaccessible, for future compatibility. In the Medusa kernel + the future has arrived - only -1 will work! + + 6.6 Old SWI OS_ReadDynamicArea (&5C) + ------------------------------------ + + As noted in the RISC OS 3 PRMs if bit 7 of the dynamic area number is set + then r2 will be returned with the maximum area size. This is being changed + slightly to be that if the dynamic area number passed in is greater than or + equal to 128 then r2 will be returned as the dynamic area size. Also, if + the dynamic area number passed in is between 128 and 255 inclusive then the + information will be returned for the area whose number is 128 less than the + passed-in value. The net result is that for old dynamic area numbers (0-5) + the functionality is unchanged, but the number-space impact of the + interface is minimised - it was prety horrible to have to force bit 7 of + all dynamic area numbers to be clear just for this SWI, so we just prohibit + a small patch of low numbers instead. + + 6.7 New SWI OS_ClaimProcessorVector + ----------------------------------- + + + In + r0=Vector and flags + bit meaning + 0-7 Vector number: + 0 - 'Branch through 0' vector + 1 - Undefined instruction + 2 - SWI + 3 - Prefetch abort + 4 - data abort + 5 - address exception (only on ARM 2 & 3) + 6 - IRQ + 7+ - reserved for future use + 8 0=release, 1=claim + 9-31 reserved, must be 0 + r1=replacement value + r2=value which should currently be on vector (only needed for release) + Out + r1=value which has been replaced (only returned on claim) + + This SWI provides a means whereby a module can attach itself to one of the + processor's vectors. This is a direct attachment - you get no environment + except what the processor provides. As such, claiming and releasing the + vectors is somewhat primitive - the claims and releases must occur in the + right order (the release order being the reverse of claim order). + + On release if the value in r2 doesn't match what is currently on the vector + then an error will be returned. This ensures correct chaining of claims and + releases. + + [ Implementation note: + On break the 1st ROM instruction gets copied to location 0 and branched to + (MOV pc, #0). This used to be a branch direct (B thing) instruction, but + will be changed to a branch indirect (LDR pc, [pc, #thing]). This means the + indirection vector must be filled in with the correct reset address. Hence, + the reset vector must be a different indirection vector to the 'Branch + through 0' one. + ] + + + + 7. External Dependencies + ========================= + +The development of the new memory management system relies upon the +availability of ARM600 (or 610) processor boards for A540s. + +The Window Manager will need modification to cope with the changed memory +management system. In particular it will need to: + Cope with the free pool being external to the wimp + Change how it does TransferBlock operations + Change how it gets the pages for new tasks + + + 8. Development Test Strategy + ============================= + +PHTester scripts will be writen to exercise the following SWIs: +OS_Memory + All reasons (0-9) +In range, edge of range, just outside range and wildly out of range values +will be tried. Where buffer contents are returned the buffer will be output. + +OS_AbortTrap +Where this implemented then the test strategy would be as follows. Due to the +nature of this SWI unsupported PHTester scripts will not be able to do the +job properly. A piece of support code will be written which can be loaded +into RMA and will monitor calls to the abort trapper. A PHTester script will +be written which will load this trapper, add it, exercise it and monitor the +results. The trapper will then be removed twice to make sure the correct +behaviour results. + +OS_ChangeDynamicArea +Again, this is hard to test with straight PHTester scripts. Under normal +circumstance the presence of PHTester running will prohibit dynamic areas +growing, however, this can be got around by growing a dynamic area before +PHTester starts, starting the script then shrink the dynamic area thus +giving the system a free pool (PHTester will refuse to allow the application +space to resize and thus the memory will be pushed into the free pool). +Support code will be writen which will monitor service calls and upcalls and +will exercise the various cases. This act of exercising must be done without +PHTester running. + +OS_DynamicArea +Again, support code will be needed for PHTester to be usable. With this +support code PHTester scripts will be writen to add (twice) and remove +(twice) a dynamic area. This area will then be resized testing success and +failure of both grow and shrink, failing because of either not enough memory +or unavilable specific pages being requeested. A straight PHTester script +will be used to exercise enumeration, readinfo and renumber operations. + + + +Testing the Wimp and Switcher + +Wimp: + +SWI Wimp_SlotSize + +The behaviour of this SWI depends on a number of external (To the task and calling parameters) factors: + - Environment, particularly MemoryLimit and ApplicationSpace + - Machine state, eg. remaining amount of memory + - Page size, to compare with ARM 3 systems units of 32K should be used + +Shrinking a slot: + Needs to be tested when MemLimit <> AppSpace, when MemLimit=AppSpace < RealSpace + where RealSpace is actual memory mapped in- This feature is used extensively by flex. + When a shrink succeedes, the free pool should grow by the shrinkage and the RMA by a roughly + proportional ammount (for slot being reduced) + +Growing a slot: + Again Different environments need testing, but also effects near total memory usage: + Eg. A large increase is requested, but only a smaller amount is available. Also when the + area has been grown, there may not be enough RMA to extend the Memory Map slot and so the + slot shrinks by a page. + +In both cases the SWI should return with the environment set to the real size and a message sent +to the switcher. + +Application testing. + As mentioned above, flex makes good use of the features of this SWI. Loading a file into !Draw +or !Paint should make the slot grow by a comparable amount to the file size (taking into account the +internal storage methods). When the document is discarded the slot should reduce to the value it was +before (unless flex/malloc usage makes this impossible) and total RMA/system memory should be roughly +what it was, though of course for a first document load the application may claim additional memory. + A small application could be written to do similar things repeatedly and could this give a +measure to memory leaks etc. Medusa is bound to be slower because of smaller page size, more pages (which +need to be scanned when growing a slot) and Log-Phys map (Level 2 table) being in RAM rather than on +chip. + +SWI Wimp_TransferBlock + +Many possible cases: + Should always be possible even if no free memory. + For tasks a,b,c (c is current task) + a <-> b a <-> c c <-> c + For small and large lengths (eg. 1K or 8Meg) + For when c takes up all/most of app space + For when transfers occur to/from non application space (eg. RMA) + For non word aligned/ size transfers + For transfers involving over-the-page memory, eg. 34k-38k (32-36,36-40 pages) + +Application testing. + RAM transfer from !Paint to !Draw (this is c->a,small, prob aligned) + Use of !SqlFiler and !Faults (this c(RMA)->a,small, prob aligned) + Some combinations can only be tested on real Medusa's with 32Meg memory. + +SWI Wimp_ClaimFreeMemory + Only claimable once at a time, memory should be accessible and remain intact until free'd + (incidentally can be freed by any task). + +System testing + *copy, *compact ? + +Mode changing: + +SWI Wimp_SetMode, *wimpmode + numbers 0-255 as before (testable by script which then checks screen memory usage and VDU +variables) and new style configuration (again script can work out from config the mem usage and VDU +vars). Wimp should shrink screen memory as much as possible and send mode changed message to all tasks + +Switcher: + Dynamic areas used to be scanned (finding addresses for all the system pages) now RDA is used. +Dynamic areas (all, including app-created areas) should update when window is open and a task calls +CDA successfully. Areas which are non-fixed should be draggable, should reflect/update area as seen +by a task. Dragging bars should update memory text as appropriate, on medusa platforms with more than +4Meg this should be logarithmic for large values. Switcher should behave as before on non medusa platforms. + + + + 9. Organisation + ================ + + The software described herein resides in the RISC OS ROM. + + 10. Future Enhancements + ======================= + +Some sort of system to request memory to be freed in cases of memory +shortage might be nice. + +OS_Heap to be extended to allow allocation of anchored moveable blocks. This +would be used to prevent heap fragmentation. + + 10.1 New SWI: OS_AbortTrap (&67) + -------------------------------- + + This has been moved to the future enhancements section as this is not + required by the project specification, there is insufficient time to do it + and it can be added later if needed. Also, there are some unresolved issues + regarding handling aborts of writes to &00-&1f and handling of coprocessor + data transfer operations. + + 10.1.1 Technical background + --------------------------- + + The extra processor modes in the ARM6 and ARM7 processor cores allow for + complete recovery from data aborts, even if the abort happens while in + privileged modes, such as supervisor mode. This was not possible on + earlier processors, because when the abort was taken, the return address + (and condition codes) was placed in r14_svc, thereby corrupting it. + + This allows for (amongst other things) complete software emulation of + hardware devices (apart from devices which cause interrupts, or which are + very time-critical). In particular, it becomes possible to write a module + which emulates VIDC1 on systems which are VIDC20 based (provided that the + address map is set up so that the address where VIDC1 is accessed + (&03400000) causes a data abort when written to). + + In order to facilitate this kind of activity, RISC OS allows a module to + provide a trap routine for accesses within specified address ranges. This + is an additional feature over and above the usual abort handlers which are + owned by the current application. + + When a data abort happens, the OS works out the range of addresses + accessed by the instruction. + + It then looks through its MMU page tables, and splits the range into + sub-ranges which correspond to accesses within one page or section, as + appropriate. + + For each sub-range, it then checks the access privileges to see if the + access was valid. If so, it performs the access itself. (For a load, it + transfers the data into a temporary stack frame from which the register(s) + will be subsequently loaded. For a store, the stack frame is already set + up with the register(s) to be stored.) + + If the sub-range corresponds to a page or section which would have caused + an abort, the sub-range is then checked against its list of abort traps. + Starting with the lowest address in the sub-range, if the address is + contained within any of the address ranges specified in the list, then + the corresponding routine is called. The registers on entry and on exit + are as follows:- + + On entry: r0 = flags + bits 1,0 = 00 undefined + 01 store + 10 load + 11 SWP + + bit 2 = 0 => user mode access + 1 => privileged mode access + + bits 3..31 undefined + + r1 -> block of registers to be transferred to/from + r2 = lowest address which faulted in the specifed address range + r3 = number of transferred bytes which fall within the specified address range + r4 -> instruction which aborted + r12 = workspace ptr specified in node + SVC26 (at the moment - I might change this to SVC32 at some stage) + + On exit: VC => instruction processed, please complete writeback + VS => instruction shouldn't be allowed - generate exception + All registers preserved (apart from PSR) + + If the routine wishes to accept the transfer as valid, it must perform the + transfer itself by transferring the data (of length r3 bytes) in or out of + the block pointed to by r1. (In the case of the SWP instruction it must + transfer data out of, then into the block). It should then exit with V=0. + + The OS will then advance its address pointer by the number of bytes + processed by this routine, and continue with the next sub-range (if there + are any more to do). + + If the routine wishes to fault the transfer after all, it should exit with + V=1. This will cause the OS to call the normal data abort handler. (This + also happens if an address in a sub-range which faulted does not lie in + any address range on the list). + + Note: this behaviour currently precludes having two or more abort traps on + the list which have overlapping address ranges, where each trap actually + is interested in a subset of accesses within that range. At the moment, + the OS faults if any trap routine exits VS, whereas it could carry on down + the list looking for further trap ranges containing the address. But then + you would have to have some way of returning saying you had done part of + the transfer. + + In addition to trapping page and section faults, the OS has special code + to deal with writes to addresses in the range &00 to &1F inclusive, which + cause aborts on ARM6/7 when the processor is executing in a 26-bit PC mode + (assuming we are in the 32-bit PC configuration, which we are). + + If the address range for the transfer includes an address in the range + 0-&1F, and the aborting instruction is within the RISC OS "ROM" image, + then RISC OS executes the transfer itself (in 32-bit PC mode), as ROM code + is considered kosher. This is mainly to allow FIQ claimants such as ADFS + floppy drivers or Econet to set up their FIQ code while executing in + 26-bit PC mode. It also allows the FPE to set up the undefined instruction + vector (although of course the FPE still has to know that it will get + called in undef_32 mode). + + If the aborting instruction is not in the ROM image, then the usual abort + list is checked. If however the address is not in the list, or the routine + exits with V set, then instead of calling the current data abort handler, + the OS calls its default data abort handler (this was so I could then do a + *ShowRegs and find out where the program went bang, rather than have the C + exception handler swallow it up). + + Note that if you set up a node to respond to vector poking, and you want + to accept the transfer, you'll have to switch to SVC32 to execute it (this + is why I may change the entry to be called in SVC32. + + 10.1.2 New SWI: OS_AbortTrap (&66) + ---------------------------------- + + SWI OS_AbortTrap provides calls to add or remove abort trap routines. + + On entry, r0 provides a reason code which determines which operation is + performed. + + 10.1.2.1 Add abort trap (0) + --------------------------- + + This reason code adds a trap routine to RISC OS's list. + + On entry: r0 = 0 (reason code) + r1 = lowest trapped address + r2 = highest trapped address +1 + r3 = address of trap routine + r4 = workspace pointer for trap routine + + On exit: All registers preserved + + The entry and exit conditions for the trap routine are described in + section x.y.z. + + 10.1.2.2 Remove abort trap (1) + ------------------------------ + + This reason code removes a trap routine from RISC OS's list. + + On entry: r0 = 1 (reason code) + r1 = lowest trapped address + r2 = highest trapped address +1 + r3 = address of trap routine + r4 = workspace pointer for trap routine + + On exit: All registers preserved + + Registers r1 to r4 on entry should be identical to those previously + passed to reason code 0. diff --git a/Doc/5thColumn/Manual b/Doc/5thColumn/Manual new file mode 100644 index 0000000000000000000000000000000000000000..49e9e68f415959d99f2e37ea9452f1f58d7f0574 --- /dev/null +++ b/Doc/5thColumn/Manual @@ -0,0 +1,323 @@ +; > 5thColumn + + RISC OS Support for extension ROMs + ================================== + + Author: Tim Dobson + Status: Draft + Issue: 0.03 + History: + + Date Revision Changes + + 11-Oct-90 0.00 Started + 16-Oct-90 0.01 Completed first draft + 08-Feb-91 0.02 Updated to reflect reality + 23-Apr-91 0.03 Added note about directly executable + extension ROMS + +This document describes the enhancements to RISC OS to support extension (or +"5th column") ROMs. + +Extension ROMs are ROMs fitted in addition to the main ROM set, which +provide software modules which are automatically loaded by RISC OS on +power-on. + +The availability, size and number of extension ROM sockets depends on which +type of RISC OS computer you are using. + +In general, however, RISC OS recognises extension ROMs or ROM sets which are +8, 16 or 32 bits wide, provided the ROM adheres to the specification below. + +32 bit wide extension ROM sets are directly executable in place, saving on +user RAM. 8 or 16 bit wide sets have to be copied into RAM to execute. + + Creating an extension ROM + ========================= + +Extension ROMs appear in the ROM area of the memory map, ie between +&03400000 and &03FFFFFF. An extension ROM set must end on a 64K boundary or +at the start of another extension ROM. This is normally not a problem as it +is unlikely you would want to use a ROM smaller than a 27128 (16K), and the +normal way of addressing this would mean that the ROM would be visible in 1 +byte out of each word, ie within a 64K addressable area. + +Extension ROMs have a header at the end of the ROM image which indicates the +presence of a valid extension ROM. The header is at the end because RISC OS +scans the ROM area downwards from the top. + +At the end of each ROM set of size 'n' bytes must be a 16-byte header as +follows:- + + Byte address Contents + + n-16 1-word size field containing n + n-12 1-word checksum (bottom 32 bits of the sum of all + words from addresses 0 to n-16 inclusive) + n-8 2-word id "ExtnROM0" indicating a valid extension + ROM, ie + + n-8 &45 ; "E" + n-7 &78 ; "x" + n-6 &74 ; "t" + n-5 &6E ; "n" + n-4 &52 ; "R" + n-3 &4F ; "O" + n-2 &4D ; "M" + n-1 &30 ; "0" + +Note that the ROM header will not necessarily appear in the memory map in +the last 16 bytes if the ROM set is 8 or 16 bits wide. In the 8-bit case, +the header will appear in one of the four byte positions of the last 16 +words, and in the 16-bit case, in one of the two half-word positions of the +last 8 words. However, RISC OS copes with this. + +Extension ROMs also have a header at the *start* of the ROM set, which is +identical to the format of an expansion card's identity space. This is +because the Podule manager module handles much of the extension ROM +processing. + +The format of the header at the start is as follows:- + + Byte address Contents Meaning + + 0 &00 Extended expansion card identity, + not requesting IRQ or FIQ + 1 &03 bit 0 set => there is a chunk + directory + bit 1 set => interrupt status + pointers defined (necessary because + bit 0 is set) + bits 2,3 = 0 => 8-bits wide (NB this + should be set to 0 irrespective of + the actual width of the ROM set) + 2 &00 Reserved, must be zero + 3 &87 Product type (lo-byte) + 4 &00 Product type (hi-byte) + See below + 5 Manuf(lo) Manufacturer code (lo-byte) + 6 Manuf(hi) Manufacturer code (hi-byte) + See below + 7 Country Country code - see below + + 8 to 15 &00 Interrupt status pointers (extension + ROMs do not generate interrupts!) + 16 onwards Chunk directory - see below + +Product type code: Note that &0087 has been allocated as a product type code +for all extension ROMs. + +Manufacturer code: All manufacturers of expansion cards and/or extension +ROMs should have a code for manufacturer. If you have not already been +allocated one, you should consult Acorn. + +Country code: Every extension ROM should have a code for the country of +origin. These match those used by the International module, except that the +UK has a country code of 0 for expansion cards and extension ROMs. If you do +not already know the correct country code for your country, you should +consult Acorn. + +The chunk directory in an extension ROM is identical to that in an expansion +card - see the chapter "Expansion Cards: Technical Details" in the RISC OS +Programmer's Reference Manual. + + Note + ==== + +In extension ROMs which are directly executable (ie which are 32 bits wide), +the word immediately preceding the start of each module must contain (size +of module +4), ie an offset from itself to the first word after the module. +It is recommended that all extension ROMs be created like this, irrespective +of whether they are directly executable. + + Additional interfaces to support extension ROMs + =============================================== + + Changes to Podule manager + ========================= + +The Podule manager module is responsible for recognising extension ROMs, +although it is the kernel which is responsible for loading modules contained +in them. + +The numbering scheme for expansion card slots has been extended to include +extension ROMs. The numbers for extension ROMs are -2, -3, -4... (-1 is +reserved for the main ROM, although the Podule manager itself does not +accept -1 for any of its SWI calls). + +All Podule manager SWIs which take an expansion card slot number as a +parameter allow an extension ROM specifier instead. + +The SWIs Podule_ReadID, Podule_ReadHeader, Podule_EnumerateChunks, +Podule_ReadChunk operate as one would expect when presented with an +extension ROM specifier. + +The SWIs Podule_ReadBytes, Podule_WriteBytes, Podule_CallLoader will +normally fail because extension ROMs have no code space or loader. + +SWI Podule_RawRead will read successive bytes out of the extension ROM, +taking the ROM width into account. + +SWI Podule_RawWrite must not be used with an extension ROM specifier, as +writing to the ROM area can reprogram the memory and video controllers. + +SWI Podule_HardwareAddress returns the base address of the specified +extension ROM, although this is not in general useful as the ROM width can +vary. + + New SWIs + -------- + +SWI Podule_EnumerateChunksWithInfo + + in: R0 = chunk number (zero to start) + R3 = expansion card slot number or extension ROM number + + out: R0 = next chunk number (zero if final chunk enumerated) + R1 = size (in bytes) if R0<>0 on exit + R2 = operating system identity byte if R0<>0 on exit + R4 = pointer to a copy of the module name if the chunk is a relocatable module, else preserved + R5 = pointer to a copy of the module's help string if the chunk is a relocatable module, else preserved + R6 = address of module if the chunk is a directly executable relocatable module + or 0 if the chunk is a non-directly-executable relocatable module + else preserved + +SWI Podule_HardwareAddresses + + in: R3 = expansion card slot number or extension ROM number + + out: R0 = raw hardware address + R1 = combined hardware address + +For an expansion card, the "raw hardware address" is the base address of the +expansion card, and the "combined hardware address" is the raw hardware +address (in bits 12-25) combined with the base address of the expansion +card's private CMOS RAM (in bits 0-11) (as returned by SWI +Podule_HardwareAddress). + +For an extension ROM, the two addresses are the same, and are the start +address of the extension ROM (ie the address of the first byte of the ROM). + + Star commands + ------------- + +*Podules now displays the extension ROMs in the system as well as expansion cards. + + Changes to kernel + ================= + + SWI OS_Module + ------------- + +OS_Module 17 (Add expansion card module) - This call now allows R3 to be +either an expansion card slot number or an extension ROM number. + +OS_Module 19 (Enumerate ROM modules) - This call now enumerates +over all ROM sections, ie extension ROM modules as well as main ROM and +expansion card modules. R2 on entry now specifies the ROM section number to +start scanning from, with the order of enumeration as follows:- + +-1 (main ROM), 0, 1, 2, 3 (expansion cards), -2, -3, -4,... (extension ROMs) + +Edition 1 of the PRM is incorrect when it states that on exit R1 (the +module number to scan from) is incremented and R2 (the expansion card number +to scan from) is preserved. + +In fact R1 returns the module number of the found module plus one, where +modules are numbered from zero within each ROM section, and R2 returns the +ROM section number of the found module, which may be in a different ROM +section from the value passed in R2 on entry, if there are insufficient +modules in the specified section. + +The values returned in R1 and R2 are therefore set up for the next call to +OS_Module 19. + +The call returns the error "No more modules" (error number &107) if there +are no more modules from the point specified in the ordering. + + New call + -------- + +OS_Module 20 (Enumerate ROM modules with version) + +This call is identical to OS_Module 19, except that on exit R6 holds a BCD +(binary coded decimal) form of the module's version number, as derived from +the module's help string. The top 16 bits of this value hold the integer +part of the version number, and the bottom 16 bits hold the fractional part, +eg if the version number of the module is "3.14" then the value returned +would be &00031400. + + Module initialisation + --------------------- + +The way in which the kernel initialises modules has been changed. If there +is more than one version of the same module present in the ROM (which +includes all ROM sections) then only the newest version of the module is +initialised, where newest means the version with the highest version number. +(If there are two copies of the same version, then directly executable +versions (ie in main ROM or in a 32-bit wide extension ROM) are considered +"newer". If they are equal in this respect, then the later one in scanning +order is considered to be newer.) + +The kernel first scans down the list of modules in the main ROM. For each +module in this list, the kernel initialises the newest version of that +module. + +For each module in the main ROM, the newest version of that module + If an extension ROM contains a newer version of a module in the +main ROM, then the newer version will be initialised at the point in the +initialisation sequence where the main ROM version would have been +initialised. This allows main ROM modules to be replaced without the +problems associated with initialisation order. + +The kernel then applies the same rule to all of the expansion cards in turn. +In each case the newest version of the module is initialised, but with the +hardware address (in R11) corresponding to that of the expansion card. + +The kernel finally initialises any extension ROM modules that are the newest +versions, but which have not already been initialised in lieu of a module in the +main ROM or on an expansion card. + + Star commands + ------------- + +*ROMModules now displays the version number of each module, as well as the +other information. Extension ROM modules are now included in the list. Note +that extension ROMs are numbered 1, 2, 3... in this command - these +correspond to ROM section numbers -2, -3, -4... respectively. + +*Unplug can now unplug extension ROM modules, as well as modules in the main +ROM or in expansion cards. The syntax is now + + *Unplug [<moduletitle> [<ROM section number>]] + +*Unplug with no parameters does the same as it used to, ie display any +unplugged modules. + +*Unplug with a module name but no ROM section number specified unplugs all +versions of that module in the system, and kills off any active module of +that name. + +If a ROM section number is specified then only versions of that module +in that ROM section are unplugged. + +The action of *RMReInit has changed slightly. If the specified module is +active, then the effect is as before, ie the module is killed and then +re-initialised. + +If the specified module is not active, but is in the ROM, then the unplug +bit in CMOS RAM is cleared for all versions of the specified module, and +then the newest version of the module is initialised. + + New star command + ---------------- + +*RMInsert <moduletitle> [<ROM section number>] + +If no ROM section number is specified, then this command clears the unplug +bit for all versions of the specified module, without reinitialising any of +them. + +If a ROM section number is specified, then this command clears the unplug +bit for all versions of the specified module present in the given section, +without reinitialising any of them. diff --git a/Doc/A540Extend b/Doc/A540Extend new file mode 100644 index 0000000000000000000000000000000000000000..a342ca6776d7401df5cf80a6f5856ac7628ded2c --- /dev/null +++ b/Doc/A540Extend @@ -0,0 +1,118 @@ +; A540Extend + + Title: A540Extend + Author: Tim Dobson + Version: 1.01 + Started: 01-Nov-90 + Last updated: 25-Nov-91 + Status: Release + History: + 01-Nov-90 TMD Created + 25-Nov-91 TMD Updated for RISC OS 3.03 + +Additions to the mode extension system for A540 and similar machines +==================================================================== + +This document describes extensions to the RISC OS mode extension system for +machines which have programmable VIDC clock speeds and sync polarities, such +as the A540. Familiarity with the RISC OS 2.00 mode extension system is +assumed (this is described in the existing Programmer's Reference Manual). + +The A540 has extra hardware to allow the selection of different VIDC clocks +and to determine the polarity of the sync lines. VIDC uses its clock +together with a set of internal dividers to provide a range of pixel rates. + +The format of the "VIDC list" returned from Service_ModeExtension (&50) has +been extended to allow the pixel rate and sync polarities to be specified. + +On original Archimedes machines, the VIDC clock is fixed at 24MHz, and the +pixel rate is only determined by VIDC's internal dividers, as specified in +bits 0 and 1 of the Control Register (VIDC address &E0). This would be +stored in the VIDC list as a word of the form &E00000xx. + +RISC OS now supports two different format VIDC lists. + +The original (type 0) VIDC list format is as follows:- + + Offset Value + + 0 0 + 4 VIDC base mode + 8 VIDC parameter + 12 VIDC parameter + .. .. + n -1 + +The new (type 1) VIDC list format is as follows:- + + Offset Value + + 0 1 + 4 VIDC base mode + 8 VIDC parameter + 12 VIDC parameter + .. .. + n -1 + n+4 Extended parameter + n+8 Extended parameter + .. .. + m -1 + +where extended parameters are of the form + + (0 << 24) + (pixel rate in kHz) + +or + + (1 << 24) + (sync polarity) + +or + + (2 << 24) + (true VIDC clock rate in kHz) + ** This option available only from RISC OS 3.03 onwards ** + +The sync polarity is defined as follows:- + + bit 0 = 0 => HSync +ve (as on a standard Archimedes) + = 1 => HSync -ve + + bit 1 = 0 => VSync +ve (as on a standard Archimedes) + = 1 => Vsync -ve + + bits 2..23 must be zero + +A pixel rate specifier in a type 1 VIDC list will override the settings of +bits 0 and 1 of a Control Register specifier in the main body of the list. +If no pixel rate is specified, then the VIDC clock is set to 24MHz, and the +settings of the divider in the Control Register are used as normal. + +The A540 hardware provides the following pixel rates:- + + 24000 kHz, 25175 kHz, 36000 kHz with a multiplier of 2/2 + 16000 kHz, 16783 kHz, 24000 kHz with a multiplier of 2/3 + 12000 kHz, 12587 kHz, 18000 kHz with a multiplier of 1/2 + 8000 kHz, 8392 kHz, 12000 kHz with a multiplier of 1/3 + +If the pixel rate specified is not achievable with the hardware on the +machine, the nearest available pixel rate is used. + +Note: when specifying a pixel rate for a hi-res-mono display, the pixel rate +specified should be the actual pixel rate divided by 4, ie 24000 not 96000. + +If no sync polarity is specified, a default of 0 is used (ie the same as a +normal Archimedes). + +The true VIDC clock rate specifier (only on RISC OS 3.03 or later) is +intended to be used in systems where the clock rate fed to VIDC is under the +control of some external device, rather than being selected by the clock +select latch. (For example, on the portable machine, the LCD ASIC feeds +either 8MHz or 16MHz into VIDC when LCD modes are selected). + +The values programmed into the clock select latch and the VIDC divider are +still determined either from the control register specifier or a pixel rate +specifier assuming the same range of clock speeds as on the A540, but the +VIDC clock rate specifier is used to determine the video memory rate, +which in turn determines the VIDC FIFO Request Pointer values (bits 4 and 5 +of the VIDC control register). The VIDC clock rate specifier is also stored +in VDU variable VIDCClockSpeed (&AC), which is used by the SoundDMA module +to determine the VIDC Sound Frequency Register value. diff --git a/Doc/Kernel b/Doc/Kernel new file mode 100644 index 0000000000000000000000000000000000000000..562f477d7e8397eeefb8a506b8d203b8b5bd4c88 --- /dev/null +++ b/Doc/Kernel @@ -0,0 +1,162 @@ +> net#arf:$.a500.RiscOS+.doc.Kernel + + Description: Documentation of changes to kernel for PRM + Author: Tim Dobson + Status: Preliminary + History: + 06-Oct-89 TMD Created + 13-Oct-89 TMD Added documentation of OS_RemoveCallBack + 27-Oct-89 TMD Added documentation of VDU variable VIDCClockSpeed + 01-Dec-89 NRaine Added documentation of OS_FindMemMapEntries + 04-Dec-89 TMD Documentation of OS_FindMemMapEntries updated slightly + +The description of bug fixes below is in a very rough state at the moment - +it will need to be tidied up before publication. Not all of the information +below is relevant to the average user. + + Documentation updates since RISC OS 2.00 release + ------------------------------------------------ + + Changes applying to RISC OS 2.01 + -------------------------------- + +A new SWI, OS_ChangeRedirection, has been added, to allow the reading and +writing of the handles associated with OS_CLI input/output redirection. This +call was provided for future versions of the task window module, so that +these handles can be made local to the task running in a task window. + + SWI OS_ChangeRedirection + + Read or write OS_CLI input/output redirection handles + +in: R0 = new input handle (0 => not redirected, -1 => leave alone) + R1 = new output handle (0 => not redirected, -1 => leave alone) + +out: R0 = old input handle (0 => not redirected) + R1 = old output handle (0 => not redirected) + +**************************************************************************** + +In RISC OS 2.00, the SWI OS_AddCallBack allowed interrupt routines to +request a callback, which was granted later when RISC OS was about to +exit to a user mode routine with IRQs enabled. However there was no way to +cancel a callback request before it was granted. This could cause problems, +for example if a module is being killed, and it has outstanding callback +requests, it must refuse to die, otherwise the callback may be granted after +that memory has been reused for something else. For this reason a new SWI, +OS_RemoveCallBack, has been added. + + SWI OS_RemoveCallBack + + Remove a transient callback from the list + +in: R0 = address that was to be called + R1 = value of R12 that the routine was to be called with + +out: R0 = preserved + R1 = preserved + +**************************************************************************** + +A new VDU variable, VIDCClockSpeed (variable number 172), has been added. +The value of this variable is the current VIDC clock rate, in kHz. This +value changes when a screen mode is selected which requires a different +clock rate. The value is read in the same way as other VDU variables, by +issuing the SWI OS_ReadVduVariables. + +Typical values are 24000 (ie 24MHz) for TV standard modes, 25175 (ie +25.175MHz) for VGA modes, and 36000 (ie 36MHz) for super-VGA modes. + +**************************************************************************** + +A number of routines were changed to improve IRQ latency:- + +a) New version of ChangeDynamicArea which reenables interrupts. + +b) Heap manager extend block has improved IRQ latency. + +c) Made OS_Byte &87 restore caller's IRQ state during call. + +d) Made OS_Word &0E,0 enable IRQs during call. + +e) Made OS_Word &15,0 enable IRQs during call. + +The heap manager has been optimised in a few places. + +The routine that converts a date and time value (in hours, minutes, seconds +etc) into a 5-byte centisecond value has been made smaller and much faster. + + Bug fixes + --------- + +Fixed bug in extend heap call (stack imbalance when returning 'No RAM for +extending heap' error) + +Fixed "*%" (LDREQB not LDREQ). + +Fixed OS_ReadArgs with a /E argument that evaluates to a string (always used +to give 'Buffer full' - also fixed 2 other bugs lurking in the background, +viz. did STRB of buffer addr assuming it was non-zero to indicate a string, +and didn't allow for length and type bytes in amount free value. + +Fixed OS_Word &15 reason code 4 (Read unbuffered mouse position) - it used +to generate undefined instruction trap due to stack mismatch. + +Fixed OS_SWINumberToString with negative numbers. + +Fixed ROMModules never saying 'Running'. + +Made OS_SpriteOp reentrant by pushing register dump area on stack. + +Fixed sideways scroll by one 'byte' in MODEs 3 and 6. + +Fixed incarnation names being terminated by 1st character. + +Fixed *Unplug using address as extra terminator for module name. + +Fixed podule IRQ despatcher corrupting R0 (prevented it from correctly +disabling the podule IRQ (or podule FIQ-as-IRQ) interrupt if no handler) + +RR-2047: Fixed bug in GSRead with quoted termination. + +RR-2060: Fixed bug in AddCallBack which freed the wrong heap node. + +RR-2066: Fixed bug which occasionally left soft cursors on the screen. + +RR-2067: Fixed bug in keyboard driver (pressing Break (as escape) key when +keyboard buffer full did nothing) + +RR-2079: Fixed bug in CallAfter/Every which returned duff error pointers. +Changed error message from null string to 'Invalid time interval'. + +RR-2080: Fixed rename incarnation bug. + +RR-2099: Fixed bug in monadic plus/minus in EvaluateExpression (eg *Eval +50*-3) + +RR-2105: Added help on LEN in *Help Eval. + +RR-2108: Fixed bug in prefer incarnation which returned duff error pointers. + + + Changes applying to RISC OS 2.04 + -------------------------------- + +A new SWI OS_FindMemMapEntries has been added to allow fast scanning of the +soft CAM map to find the correct page numbers for a given range of addresses. +For efficiency, the caller supplies the probable page numbers as well as the +addresses, so that the routine can take a quick look to check if the page +number is already correct before scanning the rest of the CAM map. + + SWI OS_FindMemMapEntries + In: R0 -> table of 12-byte page entries + +0 4 probable page number (0..npages-1) (use 0 if no idea) + +4 4 logical address to match with + +8 4 undefined + terminated by a single word containing -1 + Out: table of 12-byte entries updated: + +0 4 actual page number (-1 => not found) + +4 4 address (preserved) + +8 4 page protection level + terminator preserved + diff --git a/Doc/KernlSplit b/Doc/KernlSplit new file mode 100644 index 0000000000000000000000000000000000000000..8859fa751600f4d4c5bbb54df7ab605a32298223 --- /dev/null +++ b/Doc/KernlSplit @@ -0,0 +1,45 @@ +; > KernlSplit + +Feasibility of splitting the RISC OS kernel +=========================================== + +Author: Tim Dobson +Name: KernlSplit +Document version: 0.01 +Last modified: 19-Apr-90 + +Cbange record: + + Date Name Description of change + ---- ---- --------------------- + 19-Apr-90 TDobson Started + +This document discusses the feasibility of splitting the RISC OS kernel into +separate modules/code segments for each device driver. + +Suggested device drivers to be split off:- + + VDU + Screen hardware drivers + VIDC + Pointer + Palette + Hardware scroll/multiple display banks + Allocation of screen memory + Bitmap manipulation + Wrch + Sprites + Draw + Fonts + ColourTrans + + Keyboard/mouse + + IIC + Real time clock + CMOS RAM + Serial + + Centronics + + Memory control diff --git a/Doc/MMUControl b/Doc/MMUControl new file mode 100644 index 0000000000000000000000000000000000000000..277832f72984cd1cd80cd6f5abf27b692d27ac3a --- /dev/null +++ b/Doc/MMUControl @@ -0,0 +1,35 @@ +; Available from RISC OS 3.30 onwards + + SWI OS_MMUControl (&6B) + + On entry: + R0 = reason code/flags (must be zero) + R1 = XOR mask + R2 = AND mask + + On exit: + R1 = old value of control register + R2 = new value of control register + + Interrupts: + Interrupt status is undefined + Fast interrupts are enabled + + Processor mode: + Processor is in SVC mode + + Re-entrancy: + Not defined + + Use: + This call performs a read-modify-write operation on the ARM MMU + control register. The new value of the register is + + ((old value AND R2) XOR R1) + + The old value of the register is returned in R1, and the new value + in R2. If the call results in the C (Cache enable) bit being + changed, the cache is flushed. + + This call is intended for internal system use only. Users wishing to + enable or disable the cache should use the *Cache command instead. diff --git a/Doc/MemMaps/130 b/Doc/MemMaps/130 new file mode 100644 index 0000000000000000000000000000000000000000..8d44fc29a6f951fa135ea5cf910392d69598cbe4 --- /dev/null +++ b/Doc/MemMaps/130 @@ -0,0 +1,38 @@ + 000 App space + 01C System heap/svc stack + 01E Soft CAM copy/und stack + 01F Sound/pointer/random + 020 RMA + 02C L2PT and L1PT + 030 I/O + 038 ROM + 040 Screen + 060 Free pool + 0E2 Sprites + 164 Font cache + 1E6 RAM disc + 268 Another area 1 + 2EA Another area 2 + 36C Another area 3 + 3EE Another area 4 + 470 Another area 5 + 4F2 Another area 6 + 574 Another area 7 + 5F6 Another area 8 + 678 Another area 9 + 6FA Another area 10 + 77C Another area 11 + 7FE Nothing + 800 Phys space copy + A00 Another area 12 + A82 Another area 13 + B04 Another area 14 + B86 Another area 15 + C08 Another area 16 + C8A Another area 17 + D0C Another area 18 + D8E Another area 19 + E10 Another area 20 + E92 Another area 21 + F14 Another area 22 + F96 Nothing diff --git a/Doc/MemMaps/258 b/Doc/MemMaps/258 new file mode 100644 index 0000000000000000000000000000000000000000..86cfa15e3c3ab8adbfe162c3d52f8c9b9139a41d --- /dev/null +++ b/Doc/MemMaps/258 @@ -0,0 +1,24 @@ + 000 App space + 01C System heap/svc stack + 01E Soft CAM copy/und stack + 01F Sound/pointer/random + 020 RMA + 02C L2PT and L1PT + 030 I/O + 038 ROM + 040 Screen + 060 Free pool + 162 Sprites + 264 Font cache + 366 RAM disc + 468 Another area 1 + 56A Another area 2 + 66C Another area 3 + 76E Nothing + 800 Phys space copy + A00 Another area 4 + B02 Another area 5 + C03 Another area 6 + D04 Another area 7 + E05 Another area 8 + F06 Nothing diff --git a/Doc/Mode22 b/Doc/Mode22 new file mode 100644 index 0000000000000000000000000000000000000000..be09035166f22f66cd2ceddddd3d3627d9a673e9 --- /dev/null +++ b/Doc/Mode22 @@ -0,0 +1,64 @@ + + Title: Mode22 + Author: Tim Dobson + History: + 05-Dec-91 TMD Created + +From RISC OS 3.03 onwards a new screen mode (22) is available, on monitor +types 0 and 1 only, which is suitable for use by visually impaired people. + +In terms of pixels and colours the mode is equivalent to mode 35 (an +overscan mode), ie 16 colours, 768 pixels by 288 rows. + +However, the ratio of OS coordinates to pixels is changed so that instead of +the screen being 1536 by 1152 coordinates like mode 35, it is only 768 by +576 coordinates. This results in most text and graphics in the desktop being +drawn twice as large in both X and Y directions, thus making them easier to +see. + +There are currently a number of problems associated with this mode:- + + a) The desktop tool sprites (ie the sprites used in window borders and the +like) are inappropriate for this mode, causing some horizontal lines to +become double thickness, and some vertical lines to disappear entirely. + + b) Some applications (including those in the ROM) create windows of a +certain size without scroll bars, and assume that the screen will be big +enough in one or both directions to accommodate the whole of the window. +Some parts of these windows may then be inaccessible. + + Examples of this are:- + + Filer windows with 'Full info' selected + !Alarm 'Setup','Set clock', 'Set alarm' (particularly repeating alarms) + windows + !Chars window + !Draw toolbox (goes partly off bottom) + !Edit 'Find text' window (particularly with 'Magic characters' or + 'Wildcarded expressions' turned on + + + c) Some applications may create windows and then assume that the +window has been created that size, and then create icons in that +window assuming that size. The icons will then appear in the wrong +place, eg overlapping other icons. + + Examples of this are:- + + !Paint tool window with various tools selected (eg use sprite as brush) + + d) Some applications may create windows aligned with the bottom of the +screen, such that the title bar goes completely off the top of the screen. +The window therefore cannot be moved. + + Examples of this are:- + + Some !Impression windows. + + e) Some applications which use sprites to update their windows, always use +a fixed number of pixels for their windows. The inside of the window +therefore does not appear double size. + + Examples of this are:- + + PC emulator (in a window). diff --git a/Doc/Modes b/Doc/Modes new file mode 100644 index 0000000000000000000000000000000000000000..78347140335aced1819663692dd6fa12f2ccb500 --- /dev/null +++ b/Doc/Modes @@ -0,0 +1,40 @@ +Modes we can do: + +DRAM-only system: Peak bandwidth used (x 1E6 bytes/sec) +Total bandwidth available + = 46.5E6 bytes/sec + + 640 x 480 (72Hz) at 8bpp 31.5 + + 800 x 600 (56Hz) at 8bpp 36 + 800 x 600 (60Hz) at 8bpp 40 + 800 x 600 (72Hz) at 4bpp 25 + + 1024 x 768 (60Hz) at 4bpp 32.5 + 1024 x 768 (70Hz) at 4bpp 37.5 + +1M VRAM system: +Total bandwidth available += 80E6 bytes/sec + + 640 x 480 (72Hz) at 16bpp 63 + + 800 x 600 (56Hz) at 16bpp 72 + 800 x 600 (60Hz) at 16bpp 80 + 800 x 600 (72Hz) at 8bpp 50 + + 1024 x 768 (60Hz) at 8bpp 65 + 1024 x 768 (70Hz) at 8bpp 75 + +2M VRAM system: +Total bandwidth available += 160E6 bytes/sec + + 640 x 480 (72Hz) at 32bpp 126 + + 800 x 600 (56Hz) at 32bpp 144 + 800 x 600 (60Hz) at 32bpp 160 + 800 x 600 (72Hz) at 16bpp 100 + + 1024 x 768 (60Hz) at 16bpp 130 + 1024 x 768 (70Hz) at 16bpp 150 diff --git a/Doc/MonLead b/Doc/MonLead new file mode 100644 index 0000000000000000000000000000000000000000..4acaf4afbaa7b95a671b16d2d070c06cb97260e3 --- /dev/null +++ b/Doc/MonLead @@ -0,0 +1,108 @@ +; > Doc.MonLead + + Title: MonLead + Author: Tim Dobson + Version: 0.04 + Started: 19-Mar-91 + Last updated: 24-Apr-92 + Status: Incomplete + History: + 19-Mar-91 TMD Created + 19-Mar-91 TMD Updated + 10-Apr-91 TMD Added documentation of Service_MonitorLeadTranslation + 24-Apr-92 TMD Corrected information to match bodge for LiteOn monitor + + Automatic detection of monitor type from monitor lead ID pins + ============================================================= + +Some RISC OS computers have circuitry which allows the detection of the +state of ID pins on the monitor connector. This allows the computer to +distinguish between most types of monitor, and adjust its video output +accordingly. + +To support this, a number of changes have been made to RISC OS:- + +a) To simplify the interface, the commands *Configure Mode and +*Configure WimpMode have been merged. Both commands control the same CMOS +location. Therefore the same screen mode will be selected on startup +irrespective of whether the desktop is being used. + +b) The commands *Configure Mode/WimpMode, *Configure MonitorType, and +*Configure Sync now take the keyword Auto as an alternative to a numeric +parameter. If this option is configured, then RISC OS will determine a +reasonable default for the particular parameter, based on the type of +monitor plugged in. + +As the default is for all three to be set to Auto, the user should only have +to change the settings if he has a type of monitor which is not recognised +properly, or if he wishes to use a different screen mode from the chosen +default. + +c) The effect of holding certain keys down on power-on is slightly changed:- + +Key held down on power-on Settings of CMOS RAM + +R or Delete MonitorType Auto, Mode/WimpMode Auto, Sync Auto, and all the rest it used to +T or Copy MonitorType Auto, Mode/WimpMode Auto, Sync 0 (separate syncs), and all the rest +Keypad 0 to 9 MonitorType 0 to 9 +Keypad dot MonitorType Auto, Mode/WimpMode Auto, Sync Auto + +d) A new service has been added which allows unknown values of the monitor +ID to be recognised by modules and converted into the appropriate monitor +type number, sync type and default mode, as follows:- + +Service_MonitorLeadTranslation (&76) + + in: R1 = service code (&76) + R2 = monitor lead ID (see below) + + out: If monitor lead ID is recognised, then the module should set + R1 = 0 (claim service) + R3 = default screen mode number to use on this type of monitor + R4 = monitor type number to use (as used in *Configure MonitorType) + R5 = sync type to use on this type of monitor + (0 => separate syncs, 1 => composite sync) + All other registers must be preserved. + + If the monitor lead ID is not recognised, the module should preserve + all registers. + +The monitor connector provides 4 ID pins, ID0-ID3. Each of these may be +connected to 0v, +5v or to the Hsync pin. The monitor lead ID therefore +represents the state of the 4 ID pins by 8 bits as follows:- + + Bit 0 Bit 1 State of ID0 + Bit 2 Bit 3 State of ID1 + Bit 4 Bit 5 State of ID2 + Bit 6 Bit 7 State of ID3 + + 0 0 Tied to 0v + 1 0 Tied to +5v + 0 1 Tied to Hsync + 1 1 Inderminate - either the state is fluctuating + or machine is not capable of reading the ID + +The service is issued when SWI OS_ReadSysInfo is called with R0=1 (see +document 'ReadSysInf') if any of the configured Mode/MonitorType/Sync are +set to Auto. + +If the service is not claimed, then RISC OS checks the monitor lead ID +against the following list of recognised IDs:- + +Monitor ID pins Monitor type Sync type Default mode +0=0v,1=+5v,H=Hsync, +X=don't care + Pin 0 1 2 3 + + 1 1 H X 1 (Multisync) 1 (composite) 27 + 1 0 1 X 3 (Mono VGA) 0 (separate) 27 + 0 1 1 X 3 (Colour VGA) 0 (separate) 27 + 0 1 0 X 1 (Multisync) * 0 (separate) 27 + H 1 1 X 0 (TV standard) 1 (composite) 12 + +For all other ID values RISC OS uses the TV standard monitor settings. + +* This entry should really be monitor type 4 (Super VGA). However the LiteOn +monitor returns this monitor ID, even though it can do the TV standard +modes. RISC OS therefore selects monitor type 1 instead, so the TV standard +and VGA standard modes can be selected on this monitor. diff --git a/Doc/PaletteV b/Doc/PaletteV new file mode 100644 index 0000000000000000000000000000000000000000..ca729cda3d7a15d41507c305d6185998b6bcde2a --- /dev/null +++ b/Doc/PaletteV @@ -0,0 +1,120 @@ + + Title: PaletteV + Author: Tim Dobson + History: + 11-Nov-91 TMD Adapted from ColourTrans.Doc.PaletteV + 25-Nov-91 TMD Changed a bit about setting flashing colours + +From RISC OS 3.03 onwards, the kernel has a default entry on PaletteV. Also, +a number of additional reason codes have been added, to facilitate the +implementation of the LCD drivers for Perth. + +The new specification for PaletteV is as follows:- + +R4 holds a reason code on entry to the vector. Any owner of the vector which +has carried out the operation requested should set R4 to zero and claim the +vector. + + Reason codes + ============ + + 1 - Read palette + + in: R0 = logical colour + R1 = type of colour (16,17,18,24,25) + R4 = 1 (reason code) + + out: R2 = 1st flash colour (&BBGGRRSS) - device colour + R3 = 2nd flash colour (&BBGGRRSS) - device colour + R4 = 0 => operation complete + + 2 - Set palette + + in: R0 = logical colour + R1 = type of colour (16,17,18,24,25) + R2 = &BBGGRRSS - device colour + R4 = 2 (reason code) + + out: R4 = 0 => operation complete + + 3 - Set first flash state + + in: R4 = 3 (reason code) + + out: R4 = 0 => operation complete + + 4 - Set second flash state + + in: R4 = 4 (reason code) + + out: R4 = 0 => operation complete + + 5 - Set default palette + + in: R4 = 5 (reason code) + + out: R4 = 0 => operation complete + + 6 - Blank/unblank screen (only available from RISC OS 3.08 onwards) + + in: R0 = -1 (read blank state) + or 0 (unblank screen) + or 1 (blank screen) + R4 = 6 (reason code) + + out: R0 = old state (0=unblanked, 1=blanked) + R4 = 0 => operation complete + + This call blanks or unblanks the screen, independently of the current + palette settings. + +In the SS bits mentioned in calls 1 and 2 above, bit 7 is the current +supremacy bit, other bits are reserved. + + How old OS calls map onto PaletteV + ---------------------------------- + +Initial suggestions were that VDU 19 and OS_Word(12) should ignore the +bottom 4 bits of RGB values passed to them, and duplicate the top 4 bits in +the bottom 4 bits before calling PaletteV. This was so that old style +programs which set the low nybbles to zero would work correctly on machines +with 8-bit per gun palette hardware. + +However, I believe that this damages the usefulness of the above calls +unnecessarily. As long as the default palettes read back true 8-bit values, +and the PaletteUtil module duplicates the nybbles when setting the colours, +it should not be necessary to alter the parameters to VDU 19 and +OS_Word(12). + +So the OS will pass the values through to PaletteV, and, assuming there is +no-one else on the vector, will get the values itself. At this point it will +just store the top 4 bits of each value in its soft copy, and in the +hardware if appropriate (when setting the 1st and 2nd flashing colours it +only updates the hardware if that flash state is current). + +The calls to read the palette on earlier versions of the OS return a value +which corresponds to how the palette entry was programmed, ie 0..15 if a BBC +style colour was selected, 16 if steady RGB colours were used, 17 or 18 for +flashing colours, 24 for border colours and 25 for pointer colours. + +Since PaletteV does not return this information, the OS will try to make up +this information itself. It can easily cope with the 24,25 cases. If the two +colours returned are different, it will substitute 17 or 18 as appropriate, +otherwise it will use 16. It will no longer return values in the range 0 to +15. + +Also, when setting the palette, PaletteV does not understand BBC colours +0..15. In order to provide the necessary functionality, the OS calls to set +the palette will trap these values and convert them to type 16 calls (for +0..7) or pairs of type 17 and type 18 calls. + +This requires a slight change to the specification of what type 17 and 18 +calls do. At the moment, these calls NEVER update the VIDC palette, instead +they only update the relevant soft copy, and when/if the flash state +changes, the colours are updated. But programming a BBC flashing colour +takes effect immediately even if the flash state is 'frozen'. + +I therefore propose to make the 17 and 18 calls also update the VIDC palette +if the current state is 1st or 2nd respectively. It's still not quite ideal +because you really want to update both flash colours atomically, in case the +state changed in between the two calls. diff --git a/Doc/PrivDoc/5thColumn/Concept b/Doc/PrivDoc/5thColumn/Concept new file mode 100644 index 0000000000000000000000000000000000000000..50565e9ee4f86bf5c823004ce45efa1b33673ea8 --- /dev/null +++ b/Doc/PrivDoc/5thColumn/Concept @@ -0,0 +1,59 @@ +; > 5thColumn.Concept + + RISC OS Support for extension ROMs + ================================== + + Author: Tim Dobson + Status: Draft + Issue: 0.02 + History: + + Date Revision Changes + + 11-Oct-90 0.00 Started + 16-Oct-90 0.01 Completed first draft + 04-Feb-91 0.02 Updated to reflect reality + +This document describes the purpose of the extension ROM system and +discusses various design issues. For the full technical documentation, refer +to the document "5thColumn.Manual". + +The extension ROM system allows the development of hardware platforms fitted +with a normal 32 bit wide RISC OS ROM set plus one or more 8, 16 or 32 bit +ROMs or EPROMs containing software modules which add to or replace modules +in the main ROM set. This allows the same main ROM set to be used in a wider +variety of hardware platforms, removing the extra cost and lead times of +re-romming, and possibly reducing costs by allowing bulk purchase of the +main ROM set. + +The extension ROM(s) appear in the memory map in unused parts of the low +(&03400000 to &037FFFFF) or high (&03800000 to &03FFFFFF) ROM areas. A 32 +bit wide extension ROM set is directly executable in place, saving on user +RAM. 8 or 16 bit wide sets have to be copied into RAM to execute. By using +the low ROM area (whose access time is programmable independently from the +high area containing the main ROM set) slow EPROMs can be used. + +A particularly attractive configuration might be to have 8 ROM sockets on +the board, 4 for the main ROM set, and the other 4 capable of taking either +one 32 bit wide set (eg a large set of applications eg Internet) or up to 4 +individual 8 bit wide ROMs containing smaller applications or utilities. + +The scheme also allows a machine to have limited protection against +unauthorised access, if the extension ROM contains a module which requires a +password to be entered before continuing. + +In order to allow different sizes of EPROMs to be used without having to +have links on the board, the software will look for extension ROMs at higher +addresses first, and work backwards. This means that the high order address +lines (which should be tied to +5v on smaller sizes of EPROM) will be pulled +high initially, although they will be pulled low later on when looking for +further extension ROMs. + +The way in which the kernel initialises modules has been changed. If there +is more than one version of the same module present in the ROM (which +includes the main ROM, expansion card ROMs and extension ROMs) then only the +newest version of the module is initialised. If an extension ROM contains a +newer version of a module in the main ROM, then the newer version will be +initialised at the point in the initialisation sequence where the main ROM +version would have been initialised. This allows main ROM modules to be +replaced without the problems associated with initialisation order. diff --git a/Doc/PrivDoc/MMPM b/Doc/PrivDoc/MMPM new file mode 100644 index 0000000000000000000000000000000000000000..57ea4e00e28908930be310fcfdf1554b9d1343e6 --- /dev/null +++ b/Doc/PrivDoc/MMPM @@ -0,0 +1,54 @@ +; > PrivDoc.MMPM + +Still to do on memory management, as of 26-May-93: + +; Must be TMD + + + Make SoftCAMMap variable size + + Finish routine to allocate backing L2 for an area + + Write routine to allocate logical addresses for areas + + Write routine to check for overlapping areas + + Complete Create dynamic area routine + (done apart from final OS_ChangeDynamicArea to get required size) + + Write Remove dynamic area routine + (done apart from initial OS_ChangeDynamicArea to shrink to zero size) + + Write Return info on dynamic area routine + + Write Enumerate dynamic areas routine + + Write Renumber dynamic areas routine + + Change OS_ReadDynamicArea to use new list + + Change OS_ValidateAddress to use new list + + Put in new error messages properly + * If CreateArea fails to grow area to required size, it should kill area and return error + * Change ChangeDynamicArea code to use lists: + + Check enough is working for Wimp_ClaimFreeMemory to use OS_DynamicArea(create) + * Check PreShrink and PostShrink work completely OK + * Check PreGrow and PostGrow work (apart from passing in page blocks) + * Migrate existing areas to new world: + * Update InitDynamicAreas initially to fake up a node for the RMA, and check it works + * Use DynamicArea_Create to create RMA from scratch (if feasible) + * Update InitDynamicAreas to fake up a node for the system heap + check it (no way of using create routine) + * Change OS_ReadRAMFsLimits to use OS_ReadDynamicArea + * Write RAMFS area handlers + * Create RAMFS dynamic area using DynamicArea_Create, + check it works + * Do similar for font cache, sprite area + + * Put in code to split grow block into chunks, and create page blocks (without checking for updates from PreGrow) + * Put in checks for PreGrow requesting particular pages, and call alternative code: + * Do the double shuffle + * Issue Service_PagesUnsafe/Safe + * Stop it getting the static pages (esp. cursor/sound page, L1 and maybe L2) + * Put in extra code to cope with doubly-mapped areas + * Write area handlers for screen, and move it to new world + * Change size of application space to 24M (check all refs to 16M in whole image) + * Put in indirections for hardware vector poking + * Change FPE to use indirections (KWelton) + * Move RMA to &02100000, and change size of app space to 28M + * Conversion to do late aborts + +; Could be done by ANOther + + * OS_Memory: + a) conversion bits + b) read phys.memory arrangement + c) read amounts of various sorts of memory + d) read controller addresses \ No newline at end of file diff --git a/Doc/PrivDoc/ScreenMode b/Doc/PrivDoc/ScreenMode new file mode 100644 index 0000000000000000000000000000000000000000..410e776aa196e18598fbb2f5ecd24d2c92acf93e --- /dev/null +++ b/Doc/PrivDoc/ScreenMode @@ -0,0 +1,92 @@ +; > PrivDoc.ScreenMode + +Still to do on screen mode selection, as of 21-Jul-93: + +Key: + Done and tested + - Done but not tested + * Still to do + x Not done for a good reason + + + Make OS_ReadModeVariable work with mode selectors + + OS_ScreenMode(ReturnMode) + + OS_ScreenMode(EnumerateModes) + + Create variable holding video bandwidth + + Add this reason code to just load up video bandwidth, VideoSize and issue service + + Service_ModeExtension additions + + Load up r4 and r5 with video bandwidth, VideoSize respectively + + Change vdugrafg:SetUpSprModeData:04 to check for mode selector, and goto 10 if so + + Check other occurrences of BranchIfKnownMode to look for similar bits + + Put code to handle new sprite mode word into PushModeInfo (any monitor only?) + + Remove new sprite mode word fudging in vdugrafg:SetupSprModeData and + vdugrafl:SwitchOutputToSprite + + Make SwitchOutputToSprite(new format) set up ECFIndex (it doesn't at the moment!) + + Make sure tests for equal mode numbers don't assume equal ptrs to mode selectors are equivalent + + Modify NewModes module to respond to Service_EnumerateScreenModes, to test enumeration. + + OS_ScreenMode(SetMonitorType) + + Allocate soft copy for monitortype + + Write routine to update soft copy from CMOS + + Call this routine in initialisation + + Make *Configure MonitorType update soft copy + + Change ReadMonitorType to read from soft copy + + Add this reason code to either store given value or update from CMOS + + Make sprites which have mode selectors as their mode word illegal + + Move conversion of mode selectors to new format sprite mode words + into PreCreateHeader, rather than PostCreateHeader, so that it + doesn't call SetupSprModeData with a (now illegal) mode selector + -> MT ScreenModes module + + -> AG Make switch output to sprite for a new format sprite make mode selector for current mode? + + -> AG *ScreenSave in mode 50 seems to produce a sprite with a palette. + + -> NK Trying to set a WimpMode with XEigFactor=27 caused data abort. + Investigate and/or range-limit values. + + -> AG Put in support for returning errors from PushModeInfo (for bad mode + selectors and new format sprite mode words): + + Make mode change routine check for error from PushModeInfo and FindOKMode + + Make FindSubstitute check errors from PushModeInfo + + Make FindOKMode check errors from FindSubstitute + + Make CheckModeValid check errors from FindOKMode + + Make SetupSprModeData capable of returning errors: + + Ditto SpriteV handler (already OK) + + Ditto PreCreateHeader + + Ditto CreateHeader + + Ditto GetSprite + -> AG Make SwitchOutputToSprite/Mask check errors from PushModeInfo + + - Design and code algorithm for working out FIFO reload position for VIDC20 + (Still need explanation from ARM of why 7 quad-words doesn't always work) + + * OS_ScreenMode(SelectMode) + + Make normal mode selection routine into a subroutine + + Write veneers to put round call to this in OS_ScreenMode(SelectMode) + * Change actual mode change code to cope with mode selectors + + Prevent main routine looking at shadow bit in mode selector + + Modify FindOKMode to cope with mode selector + + Modify OS_CheckModeValid to cope with mode selector + + Make all pushed mode variables into words (not bytes) + + Modify PushModeInfo to cope with mode selector + + Make YEigFactor default to 2 if yres < xres/2 (and change spec. to reflect that) + + Make numbered modes work after loading mode file + + Allocate space for OS copy of mode selector + x Make OS mode selector part of saved VDU context + (not needed since sprites can't have mode selectors as their mode) + x Sort out internal mode variables PalIndex, ECFIndex wrt + converting existing mode numbers into mode selectors (no need, still use old workspace-getting code) + x Make mode selector blocks for all existing numbered modes + (no need, constructed on fly since only needed during svc call) + * Check that copying mode selector has no adverse effects + * Sort out why issuing a mode change with invalid mode selector doesn't give error + * Modify FindOKMode to cope with 16 and 32 bpp modes somehow + + * Prevent pointer position from going into the sync pulse (causes screen picture disruption) + + * Adjust borders on all modes, to cope with VIDC20 problem + (Needs algorithm from ARM that works!) + + * Mode change happily passes round any old rubbish to Service_ModeExtension - it should:- + * First check that value is word-aligned - if not it may be a new sprite mode word + * Do a Validate_Address on fixed bit of block? + + * What should *ScreenLoad do with a new format sprite? diff --git a/Doc/ReadSysInf b/Doc/ReadSysInf new file mode 100644 index 0000000000000000000000000000000000000000..ee05c1a7e2aa20f1fa21d61f535f7b7df18f42ea --- /dev/null +++ b/Doc/ReadSysInf @@ -0,0 +1,129 @@ +; > Doc.ReadSysInf + + Title: ReadSysInf + Author: Tim Dobson + Version: 0.03 + Started: 19-Mar-91 + Last updated: 21-Oct-91 + Status: Preliminary + History: + 19-Mar-91 TMD Created + 04-Apr-91 TMD Updated OS_ReadSysInfo(2) + + Extensions to SWI OS_ReadSysInfo in RISC OS 2.11 and later versions + =================================================================== + +SWI OS_ReadSysInfo has been extended since RISC OS 2.00 - the full +specification is as follows:- + +***************************************************************************** + + SWI OS_ReadSysInfo - Read various system information + + in: R0 = reason code + + out: Depends on reason code + + Reason codes:- + +------------------------------------------------------------------------- + + in: R0 = 0 + out: R0 = amount of configured screen memory, in bytes + +This sub-call is the same as on RISC OS 2.00, with the exception that two +bugs in the call have been fixed:- + + a) It no longer goes wrong if less than 20K configured on 8K or 16K page +size machine; + + b) It now properly ignores the top bit of the CMOS location holding the +configured value. + +------------------------------------------------------------------------- + + in: R0 = 1 + out: R0 = Configured Mode/WimpMode + R1 = Configured MonitorType + R2 = Configured Sync + +Note that from RISC OS 2.09 onwards, the configured Mode and WimpMode have +been merged. Both *Configure Mode and *Configure WimpMode control the same +CMOS RAM location. + +Note also that if any of Mode/WimpMode, MonitorType or Sync have been +configured to Auto (see "Doc.MonLead"), then the appropriate value for the +attached monitor will be returned. + +------------------------------------------------------------------------- + + in: R0 = 2 + out: R0 = IOEB ASIC presence flag + 0 => absent + 1 => present (type 1) + Other values are reserved for future versions of IOEB which are + not backwards compatible. + + R1 = 82C710 (or similar) presence flag + 0 => absent + 1 => present + + R2 = LCD ASIC presence flag + 0 => absent + 1 => present (type 1) + Other values are reserved for future versions of LCD ASIC which + are not backwards compatible. + + R3 = word 0 of unique machine ID + R4 = word 1 of unique machine ID + +Some RISC OS computers are fitted with a chip providing a machine ID number +which is unique to each computer. Machines not fitted with an ID will return +zero in both R3 and R4. + +------------------------------------------------------------------------- + + in: R0 = 3 (*** Only available from RISC OS 3.01 onwards ***) + out: R0 = 82C710/82C711 basic features mask 82C710 82C711 + Bits 0..3 Basic IDE type 1 1 + Bits 4..7 Basic FDC type 1 1 + Bits 8..11 Basic parallel port type 1 1 + Bits 12..15 Basic 1st serial port type 1 1 + Bits 16..19 Basic 2nd serial port type 0 1 + Bits 20..23 Basic Configuration type 1 2 + Bits 24..31 Reserved + + R1 = 82C710/82C711 extra features mask + Reserved for upwards compatible additional functionality + + R2-R4 Undefined (reserved for future expansion) + +The 82C710 family of chips are composed of several sub-units, each of which +might change under future revisions of the chip. Current sub-units are as +follows: + + IDE hard disc interface + Floppy disc interface + Parallel port + Serial port 1 + Serial port 2 (only present in 82C711) + Chip configuration (different on 82C710 and 82C711) + +New versions of the chip may have some sub-units which are incompatible with +earlier versions, while leaving the functionality of other sub-units +unchanged. + +This call allows drivers which are only interested in particular sub-units +to tell whether they can work on the particular hardware running in the +machine. + +Different values of each sub-field correspond to incompatible versions of +the corresponding sub-unit. A sub-field of zero indicates that the sub-unit +is not present. + +If a sub-unit gains additional backwards-compatible functionality in future +versions of the chip, this will be indicated by having bits set in the value +returned in R1. + +Information on extra sub-units will be accomodated in the remaining bits of +R0, or in R2-R4. diff --git a/Doc/TVmodesMed,dde b/Doc/TVmodesMed,dde new file mode 100644 index 0000000000000000000000000000000000000000..8ab0e2848118bca337597ed6eb457f4139824bb3 --- /dev/null +++ b/Doc/TVmodesMed,dde @@ -0,0 +1,1337 @@ +%OP%VS4.13 (28-Apr-92), Tim Dobson, R4001 0202 1006 4799 +%OP%FGTrinity.Medium +%OP%FS12000 +%OP%WC162,1898,210,1494,1,22,0,0 +%CO:A,2,0%%CO:B,17,72%Medusa screen modes + +This spreadsheet gives the horizontal and vertical timings for the Medusa screen modes. +For the numbered screen modes, these timings are almost identical to the RISC OS 3 timings. + +However, on VIDC1 the horizontal front and back porch timings are forced to be an odd +number of pixel times, whereas on VIDC20 they have to be even, therefore all horizontal back +porch timings have been reduced by one pixel, and front porch timings increased by one pixel. + +The figures below show that our timings for the 800 x 600 modes differ from the VESA +manufacturing guidelines in that we have hsync=100, hbpch=100, whereas they have +hsync=72, hbpch=128; ie the total times are the same, and the time from the start of the hsync +pulse to the start of the display area is the same, but our sync is wider. It is likely that I will +change RISC OS to match the VESA standard - I don't believe this will have an effect on the +horizontal position of the display (this is something I will have to check out). + +It is likely that as well as adding the VESA modes described below, RISC OS will also +provide several modes obtained by doubling the dot frequency of standard modes, eg 1280 x +480, 1600 x 600, 2048 x 768. + +It may also be possible to provide 1280 x 1024 at some pixel depths, although this may +involve running VIDC20 and/or the VCO out of specification. I don't have any timing +diagrams for 1280 x 1024; if you can get hold of these (is there a VESA standard for this?) it +would help establish the feasibility of this (the Taxan 875 Plus LR monitor spec. gives the line +frequency for this at 60 and 70Hz frame rates, but not the detailed timings (eg the dot +frequency)). + +Tim (22-Mar-93). + +Horizontal parameters for Monitortype 1 modes + + + +0,3,4,8,11,12,14,15 + + +1,2,5,6,7,9,10,13 + + +16,17,24 + + +33,34,35,36 +(overscan) + +18,19,20,21 + + +25,26,27,28 +(VGA) + +29,30,31 +(SVGA) + +37,38,39,40 +(DTP - ega) + +41,42,43 +(EGA - pcemu) + +44,45,46 +(CGA - pcemu) + +800 x 600 (56 Hz) +VESA guideline + +800 x 600 (60 Hz) +VESA guideline + +800 x 600 (72 Hz) +VESA standard + +1024 x 768 (60 Hz) +VESA guideline + +1024 x 768 (70 Hz) +VESA standard + + + +Vertical parameters + +0,1,2,4,5,8,9,10 +12,13,15,16,24 + +3,6,7,11,14,17 + + 33,34,35,36 + +18,19,20,21 + +25,26,27,28 + +29,30,31 + +37,38,39,40 + +41,42,43 + +44,45,46 + +800 x 600 (56 Hz) +VESA guideline + +800 x 600 (60 Hz) +VESA guideline + +800 x 600 (72 Hz) +VESA standard + +1024 x 768 (60 Hz) +VESA guideline + +1024 x 768 (70 Hz) +VESA standard +%CO:C,6,60% + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sync + +%V%%R%%D0%72 +%V%%R%C34/M34*1000 + +%V%%R%%D0%36 +%V%%R%C37/M37*1000 + +%V%%R%%D0%108 +%V%%R%C40/M40*1000 + +%V%%R%%D0%76 +%V%%R%C43/M43*1000 + +%V%%R%%D0%56 +%V%%R%C46/M46*1000 + +%V%%R%%D0%96 +%V%%R%C49/M49*1000 + +%V%%R%%D0%100 +%V%%R%C52/M52*1000 + +%V%%R%%D0%118 +%V%%R%C55/M55*1000 + +%V%%R%%D0%76 +%V%%R%C58/M58*1000 + +%V%%R%%D0%72 +%V%%R%C61/M61*1000 + +%V%%R%%D0%72 +%V%%R%C64/M64*1000 + +%V%%R%%D0%128 +%V%%R%C67/M67*1000 + +%V%%R%%D0%120 +%V%%R%C70/M70*1000 + +%V%%R%%D0%136 +%V%%R%C73/M73*1000 + +%V%%R%%D0%136 +%V%%R%C76/M76*1000 + + + +(rasters) + +%V%%R%%D0%3 + + +%V%%R%%D0%3 + +%V%%R%%D0%3 + +%V%%R%%D0%3 + +%V%%R%%D0%2 + +%V%%R%%D0%2 + +%V%%R%%D0%3 + +%V%%R%%D0%3 + +%V%%R%%D0%3 + +%V%%R%%D0%2 + + +%V%%R%%D0%4 + + +%V%%R%%D0%6 + + +%V%%R%%D0%6 + + +%V%%R%%D0%6 +%CO:D,6,48% + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + porch + +%V%%R%%D0%62 +%V%%R%D34/M34*1000 + +%V%%R%%D0%30 +%V%%R%D37/M37*1000 + +%V%%R%%D0%72 +%V%%R%D40/M40*1000 + +%V%%R%%D0%82 +%V%%R%D43/M43*1000 + +%V%%R%%D0%112 +%V%%R%D46/M46*1000 + +%V%%R%%D0%46 +%V%%R%D49/M49*1000 + +%V%%R%%D0%100 +%V%%R%D52/M52*1000 + +%V%%R%%D0%58 +%V%%R%D55/M55*1000 + +%V%%R%%D0%36 +%V%%R%D58/M58*1000 + +%V%%R%%D0%162 +%V%%R%D61/M61*1000 + +%V%%R%%D0%128 +%V%%R%D64/M64*1000 + +%V%%R%%D0%88 +%V%%R%D67/M67*1000 + +%V%%R%%D0%64 +%V%%R%D70/M70*1000 + +%V%%R%%D0%160 +%V%%R%D73/M73*1000 + +%V%%R%%D0%144 +%V%%R%D76/M76*1000 + + + + + +%V%%R%%D0%16 + + +%V%%R%%D0%16 + +%V%%R%%D0%19 + +%V%%R%%D0%18 + +%V%%R%%D0%32 + +%V%%R%%D0%22 + +%V%%R%%D0%9 + +%V%%R%%D0%9 + +%V%%R%%D0%34 + +%V%%R%%D0%22 + + +%V%%R%%D0%23 + + +%V%%R%%D0%23 + + +%V%%R%%D0%29 + + +%V%%R%%D0%29 +%CO:E,6,36% + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + border + +%V%%R%%D0%88 +%V%%R%E34/M34*1000 + +%V%%R%%D0%44 +%V%%R%E37/M37*1000 + +%V%%R%%D0%106 +%V%%R%E40/M40*1000 + +%V%%R%%D0%0 +%V%%R%E43/M43*1000 + +%V%%R%%D0%0 +%V%%R%E46/M46*1000 + +%V%%R%%D0%0 +%V%%R%E49/M49*1000 + +%V%%R%%D0%0 +%V%%R%E52/M52*1000 + +%V%%R%%D0%0 +%V%%R%E55/M55*1000 + +%V%%R%%D0%0 +%V%%R%E58/M58*1000 + +%V%%R%%D0%0 +%V%%R%E61/M61*1000 + +%V%%R%%D0%0 +%V%%R%E64/M64*1000 + +%V%%R%%D0%0 +%V%%R%E67/M67*1000 + +%V%%R%%D0%0 +%V%%R%E70/M70*1000 + +%V%%R%%D0%0 +%V%%R%E73/M73*1000 + +%V%%R%%D0%0 +%V%%R%E76/M76*1000 + + + + + +%V%%R%%D0%17 + + +%V%%R%%D0%20 + +%V%%R%%D0%0 + +%V%%R%%D0%0 + +%V%%R%%D0%0 + +%V%%R%%D0%0 + +%V%%R%%D0%0 + +%V%%R%%D0%0 + +%V%%R%%D0%0 + +%V%%R%%D0%0 + + +%V%%R%%D0%0 + + +%V%%R%%D0%0 + + +%V%%R%%D0%0 + + +%V%%R%%D0%0 +%CO:F,6,24% + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +display + +%V%%R%%D0%640 +%V%%R%F34/M34*1000 + +%V%%R%%D0%320 +%V%%R%F37/M37*1000 + +%V%%R%%D0%1056 +%V%%R%F40/M40*1000 + +%V%%R%%D0%768 +%V%%R%F43/M43*1000 + +%V%%R%%D0%640 +%V%%R%F46/M46*1000 + +%V%%R%%D0%640 +%V%%R%F49/M49*1000 + +%V%%R%%D0%800 +%V%%R%F52/M52*1000 + +%V%%R%%D0%896 +%V%%R%F55/M55*1000 + +%V%%R%%D0%640 +%V%%R%F58/M58*1000 + +%V%%R%%D0%640 +%V%%R%F61/M61*1000 + +%V%%R%%D0%800 +%V%%R%F64/M64*1000 + +%V%%R%%D0%800 +%V%%R%F67/M67*1000 + +%V%%R%%D0%800 +%V%%R%F70/M70*1000 + +%V%%R%%D0%1024 +%V%%R%F73/M73*1000 + +%V%%R%%D0%1024 +%V%%R%F76/M76*1000 + + + + + +%V%%R%%D0%256 + + +%V%%R%%D0%250 + +%V%%R%%D0%288 + +%V%%R%%D0%512 + +%V%%R%%D0%480 + +%V%%R%%D0%600 + +%V%%R%%D0%352 + +%V%%R%%D0%352 + +%V%%R%%D0%200 + +%V%%R%%D0%600 + + +%V%%R%%D0%600 + + +%V%%R%%D0%600 + + +%V%%R%%D0%768 + + +%V%%R%%D0%768 +%CO:G,6,30% + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + border + +%V%%R%%D0%88 +%V%%R%G34/M34*1000 + +%V%%R%%D0%44 +%V%%R%G37/M37*1000 + +%V%%R%%D0%106 +%V%%R%G40/M40*1000 + +%V%%R%%D0%0 +%V%%R%G43/M43*1000 + +%V%%R%%D0%0 +%V%%R%G46/M46*1000 + +%V%%R%%D0%0 +%V%%R%G49/M49*1000 + +%V%%R%%D0%0 +%V%%R%G52/M52*1000 + +%V%%R%%D0%0 +%V%%R%G55/M55*1000 + +%V%%R%%D0%0 +%V%%R%G58/M58*1000 + +%V%%R%%D0%0 +%V%%R%G61/M61*1000 + +%V%%R%%D0%0 +%V%%R%G64/M64*1000 + +%V%%R%%D0%0 +%V%%R%G67/M67*1000 + +%V%%R%%D0%0 +%V%%R%G70/M70*1000 + +%V%%R%%D0%0 +%V%%R%G73/M73*1000 + +%V%%R%%D0%0 +%V%%R%G76/M76*1000 + + + + + +%V%%R%%D0%17 + + +%V%%R%%D0%20 + +%V%%R%%D0%0 + +%V%%R%%D0%0 + +%V%%R%%D0%0 + +%V%%R%%D0%0 + +%V%%R%%D0%0 + +%V%%R%%D0%0 + +%V%%R%%D0%0 + +%V%%R%%D0%0 + + +%V%%R%%D0%0 + + +%V%%R%%D0%0 + + +%V%%R%%D0%0 + + +%V%%R%%D0%0 +%CO:H,6,20% + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + porch + +%V%%R%%D0%74 +%V%%R%H34/M34*1000 + +%V%%R%%D0%38 +%V%%R%H37/M37*1000 + +%V%%R%%D0%88 +%V%%R%H40/M40*1000 + +%V%%R%%D0%98 +%V%%R%H43/M43*1000 + +%V%%R%%D0%88 +%V%%R%H46/M46*1000 + +%V%%R%%D0%18 +%V%%R%H49/M49*1000 + +%V%%R%%D0%24 +%V%%R%H52/M52*1000 + +%V%%R%%D0%28 +%V%%R%H55/M55*1000 + +%V%%R%%D0%16 +%V%%R%H58/M58*1000 + +%V%%R%%D0%146 +%V%%R%H61/M61*1000 + +%V%%R%%D0%24 +%V%%R%H64/M64*1000 + +%V%%R%%D0%40 +%V%%R%H67/M67*1000 + +%V%%R%%D0%56 +%V%%R%H70/M70*1000 + +%V%%R%%D0%24 +%V%%R%H73/M73*1000 + +%V%%R%%D0%24 +%V%%R%H76/M76*1000 + + + + + +%V%%R%%D0%3 + + +%V%%R%%D0%3 + +%V%%R%%D0%2 + +%V%%R%%D0%1 + +%V%%R%%D0%11 + +%V%%R%%D0%1 + +%V%%R%%D0%0 + +%V%%R%%D0%0 + +%V%%R%%D0%25 + +%V%%R%%D0%1 + + +%V%%R%%D0%1 + + +%V%%R%%D0%37 + + +%V%%R%%D0%3 + + +%V%%R%%D0%3 +%CO:I,6,10% + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Total + +%V%%R%%D0%sum(C34H34) +%V%%R%I34/M34*1000 + +%V%%R%%D0%sum(C37H37) +%V%%R%I37/M37*1000 + +%V%%R%%D0%sum(C40H40) +%V%%R%I40/M40*1000 + +%V%%R%%D0%sum(C43H43) +%V%%R%I43/M43*1000 + +%V%%R%%D0%sum(C46H46) +%V%%R%I46/M46*1000 + +%V%%R%%D0%sum(C49H49) +%V%%R%I49/M49*1000 + +%V%%R%%D0%sum(C52H52) +%V%%R%I52/M52*1000 + +%V%%R%%D0%sum(C55H55) +%V%%R%I55/M55*1000 + +%V%%R%%D0%sum(C58H58) +%V%%R%I58/M58*1000 + +%V%%R%%D0%sum(C61H61) +%V%%R%I61/M61*1000 + +%V%%R%%D0%sum(C64H64) +%V%%R%I64/M64*1000 + +%V%%R%%D0%sum(C67H67) +%V%%R%I67/M67*1000 + +%V%%R%%D0%sum(C70H70) +%V%%R%I70/M70*1000 + +%V%%R%%D0%sum(C73H73) +%V%%R%I73/M73*1000 + +%V%%R%%D0%sum(C76H76) +%V%%R%I76/M76*1000 + + + + + +%V%%R%%D0%sum(C83H83) + + +%V%%R%%D0%sum(C86H86) + +%V%%R%%D0%sum(C88H88) + +%V%%R%%D0%sum(C90H90) + +%V%%R%%D0%sum(C92H92) + +%V%%R%%D0%sum(C94H94) + +%V%%R%%D0%sum(C96H96) + +%V%%R%%D0%sum(C98H98) + +%V%%R%%D0%sum(C100H100) + +%V%%R%%D0%sum(C102H102) + + +%V%%R%%D0%sum(C105H105) + + +%V%%R%%D0%sum(C108H108) + + +%V%%R%%D0%sum(C111H111) + + +%V%%R%%D0%sum(C114H114) +%CO:J,4,0% + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +pix +usec + +pix +usec + +pix +usec + +pix +usec + +pix +usec + +pix +usec + +pix +usec + +pix +usec + +pix +usec + +pix +usec + +pix +usec + +pix +usec + +pix +usec + +pix +usec + +pix +usec +%CO:K,6,42% + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + H Freq + KHz +%V%%R%%D3%1000/I35 + + +%V%%R%%D3%1000/I38 + + +%V%%R%%D3%1000/I41 + + +%V%%R%%D3%1000/I44 + + +%V%%R%%D3%1000/I47 + + +%V%%R%%D3%1000/I50 + + +%V%%R%%D3%1000/I53 + + +%V%%R%%D3%1000/I56 + + +%V%%R%%D3%1000/I59 + + +%V%%R%%D3%1000/I62 + + +%V%%R%%D3%1000/I65 + + +%V%%R%%D3%1000/I68 + + +%V%%R%%D3%1000/I71 + + +%V%%R%%D3%1000/I74 + + +%V%%R%%D3%1000/I77 + + + + + + +%V%%R%1000000/I35/I83 + + +%V%%R%1000000/I38/I86 + +%V%%R%1000000/I44/I88 + +%V%%R%1000000/I47/I90 + +%V%%R%1000000/I50/I92 + +%V%%R%1000000/I53/I94 + +%V%%R%1000000/I56/I96 + +%V%%R%1000000/I59/I98 + +%V%%R%1000000/I62/I100 + +%V%%R%1000000/I65/I102 + + +%V%%R%1000000/I68/I105 + + +%V%%R%1000000/I71/I108 + + +%V%%R%1000000/I74/I111 + + +%V%%R%1000000/I77/I114 +%CO:L,6,32% + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + disp + cntr + usec +%V%%R%(C34+D34+E34+F34/2)/M34*1000 + + +%V%%R%(C37+D37+E37+F37/2)/M37*1000 + + +%V%%R%(C40+D40+E40+F40/2)/M40*1000 + + +%V%%R%(C43+D43+E43+F43/2)/M43*1000 + + +%V%%R%(C46+D46+E46+F46/2)/M46*1000 + + +%V%%R%(C49+D49+E49+F49/2)/M49*1000 + + +%V%%R%(C52+D52+E52+F52/2)/M52*1000 + + +%V%%R%(C55+D55+E55+F55/2)/M55*1000 + + +%V%%R%(C58+D58+E58+F58/2)/M58*1000 + + +%V%%R%(C61+D61+E61+F61/2)/M61*1000 + + +%V%%R%(C64+D64+E64+F64/2)/M64*1000 + + +%V%%R%(C67+D67+E67+F67/2)/M67*1000 + + +%V%%R%(C70+D70+E70+F70/2)/M70*1000 + + +%V%%R%(C73+D73+E73+F73/2)/M73*1000 + + +%V%%R%(C76+D76+E76+F76/2)/M76*1000 + + + + + + +Hz + + +Hz + +Hz + +Hz + +Hz + +Hz + +Hz + +Hz + +Hz + +Hz + + +Hz + + +Hz + + +Hz + + +Hz +%CO:M,6,22% + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pix + clock + KHz +%V%%R%%D0%16000 + + +%V%%R%%D0%8000 + + +%V%%R%%D0%24000 + + +%V%%R%%D0%16000 + + +%V%%R%%D0%24000 + + +%V%%R%%D0%25175 + + +%V%%R%%D0%36000 + + +%V%%R%%D0%24000 + + +%V%%R%%D0%2*25175/3 + + +%V%%R%%D0%16000 + + +%V%%R%%D0%36000 + + +%V%%R%%D0%40000 + + +%V%%R%%D0%50000 + + +%V%%R%%D0%65000 + + +%V%%R%%D0%75000 + + + + + vert + center +%V%%R%%D0%(C83+D83+E83+F83/2) + + +%V%%R%%D0%(C86+D86+E86+F86/2) + +%V%%R%%D0%(C88+D88+E88+F88/2) + +%V%%R%%D0%(C90+D90+E90+F90/2) + +%V%%R%%D0%(C92+D92+E92+F92/2) + +%V%%R%%D0%(C94+D94+E94+F94/2) + +%V%%R%%D0%(C96+D96+E96+F96/2) + +%V%%R%%D0%(C98+D98+E98+F98/2) + +%V%%R%%D0%(C100+D100+E100+F100/2) + +%V%%R%%D0%(C102+D102+E102+F102/2) + + +%V%%R%%D0%(C105+D105+E105+F105/2) + + +%V%%R%%D0%(C108+D108+E108+F108/2) + + +%V%%R%%D0%(C111+D111+E111+F111/2) + + +%V%%R%%D0%(C114+D114+E114+F114/2) +%CO:N,8,0% \ No newline at end of file diff --git a/HelpStrs b/HelpStrs new file mode 100644 index 0000000000000000000000000000000000000000..cc9947038e83a7e8d4a8d0c3efc61d5f2c2ce94d --- /dev/null +++ b/HelpStrs @@ -0,0 +1,544 @@ + SUBT => HelpStrs + + [ International_Help=0 +Break_Help + = "The ",TokenEscapeChar,Token0," key either acts like Escape, or" + = " like the Reset key. ",13 + +Reset_Help + = "When Reset is pressed, the following " + = " keys have an effect:",13 + = "SHIFT causes an autoboot (unless Boot is configured).",13 + = "CTRL causes more of the machine to be reset.",13 + = "keypad-* causes the supervisor to be run rather than the configured" + = " language.",13 + = "See also *Help PowerOn.",0 + +PowerOn_Help + = "When the machine is switched on, the following " + = " keys have an effect:",13 + = "R causes the operating system's CMOS RAM to be reset.",13 + = "DELETE causes all the machine's CMOS RAM to be reset.",13 + = "T and COPY are similar to R and DELETE, but set the opposite" + = " configured sync.",13 + = "0 to 9 on the keypad reset (just)" + = " the configured monitor type." + = " Keypad dot sets the configured mode, sync and monitor type to Auto." + = 13,"See also *Help Reset and *Help Break."0 + +RMEnsure_Help + = "*",TokenEscapeChar,Token0 + = " checks that a module is present and is the given version," + = " or a more modern one." + = " The command is executed if this is not the case.",13 +RMEnsure_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <moduletitle> <version number> [<*command>]",0 + +Syntax_Help + = "Symbols used in syntax descriptions:",13 + = "<> mark sections to be filled in, eg. <filename> indicates" + = " that a filename should be supplied here.",13 + = "[] mark optional sections.",13 + = "| indicates a choice, e.g. ""A|B"" means ""A or B"".", 0 + +Quit_Help + = "*",TokenEscapeChar,Token0 + = " leaves the current application.",13 + +GOS_Syntax +Modules_Syntax +Quit_Syntax + = "Syntax: *",TokenEscapeChar,Token0, 0 + +RMFaster_Help + = "*",TokenEscapeChar,Token0 + = " moves a module from ROM to RAM.",13 +RMFaster_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <moduletitle>", 0 + +RMKill_Help + = "*",TokenEscapeChar,Token0 + = " kills and deletes a relocatable module.",13 +RMKill_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <moduletitle>", 0 + +RMLoad_Help + = "*",TokenEscapeChar,Token0 + = " loads and initialises a relocatable module.",13 +RMLoad_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <filename>", 0 + +RMRun_Help + = "*",TokenEscapeChar,Token0 + = " runs a relocatable module.",13 +RMRun_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <filename>", 0 + +RMTidy_Help + = "*",TokenEscapeChar,Token0 + = " compacts the RMA and reinitialises all the modules.",13 +RMTidy_Syntax + = "Syntax: *",TokenEscapeChar,Token0, 0 + +RMClear_Help + = "*",TokenEscapeChar,Token0 + = " deletes all relocatable modules from the RMA.",13 +RMClear_Syntax + = "Syntax: *",TokenEscapeChar,Token0, 0 + +RMReInit_Help + = "*",TokenEscapeChar,Token0 + = " reinitialises a relocatable module," + = " reversing the action of *Unplug if appropriate.",13 +RMReInit_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <moduletitle>", 0 + +ROMModules_Help + = "*",TokenEscapeChar,Token0 + = " lists the relocatable modules currently in ROM, along with" + = " their status.",13 + = "See also *Modules.",13 +ROMModules_Syntax + = "Syntax: *",TokenEscapeChar,Token0, 0 + +Set_Help + = "*",TokenEscapeChar,Token0 + = " assigns a string value to a system variable." + = " Other types of value can be assigned with *",TokenEscapeChar,Token0 + = "Eval and *",TokenEscapeChar,Token0 + = "Macro.",13 +Set_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <varname> <value>", 0 + +SetMacro_Help + = "*",TokenEscapeChar,Token0 + = " assigns a macro value to a system variable." + = " Other types of value can be assigned with *Set and *SetEval.",13 +SetMacro_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <varname> <value>", 0 + +SetEval_Help + = "*",TokenEscapeChar,Token0 + = " evaluates an expression and assigns it to a system variable." + = " Other types of value can be assigned with *Set and *SetMacro.",13 + = """*Help Eval"" describes the expression syntax.",13 +SetEval_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <varname> <expression>", 0 + +Show_Help + = "*",TokenEscapeChar,Token0 + = " lists system variables matching the name given," + = " or all system variables if no name is specified." + = " Variables can be set with *Set, *SetEval and *SetMacro.",13 +Show_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " [<variablespec>]", 0 + +Time_Help + = "*",TokenEscapeChar,Token0 + = " displays the time and date.",13 +Time_Syntax + = "Syntax: *",TokenEscapeChar,Token0,0 + +Unset_Help + = "*",TokenEscapeChar,Token0 + = " deletes a system variable.",13 +Unset_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <varname>", 0 + +Echo_Help + = "*",TokenEscapeChar,Token0 + = " sends a string to the VDU, after transformation by GSRead.",13 + = "Syntax: *",TokenEscapeChar,Token0 + = " <string>",0 + +Ignore_Help + = "*",TokenEscapeChar,Token0 + = " sets the printer ignore character.",13 +Ignore_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " [<number>]",0 + +IF_Help + = "*",TokenEscapeChar,Token0 + = " conditionally executes another command" + = " depending on the value of an expression.",13 +IF_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <expression> THEN <command> [ELSE <command>]", 0 + +Status_Help + = "*",TokenEscapeChar,Token0 + = " shows the selected CMOS RAM options." + = " Use *Configure to set the options.",13 + = "Syntax: *",TokenEscapeChar,Token0 + = " [<option>]",0 + +Unplug_Help + = "*",TokenEscapeChar,Token0 + = " stops the given ROM module being initialised.",13 + = "*",TokenEscapeChar,Token0 + = " with no argument lists the unplugged ROM modules.",13 +Unplug_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " [<moduletitle> [<podule number>]]",0 + +RMInsert_Help + = "*",TokenEscapeChar,Token0 + = " reverses the effect of *Unplug, but does not reinitialise" + = " the specified ROM module.",13 +RMInsert_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <moduletitle> [<podule number>]",0 + +Error_Help + = "*",TokenEscapeChar,Token0 + = " generates an error with the given number and text. ",13 +Error_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " [<number>] <text>",0 + +Eval_Help + = "*",TokenEscapeChar,Token0 + = " evaluates an integer or string expression. ",13 + = "The expression analyser has the following operators:",13 + = "+",9,9,9,"addition or string concatenation",13 + = "-, *, /, MOD",9,9,"integer operations",13 + = "=, <, >, <=, >=, <>",9,"string or integer comparison",13 + = ">>, <<",9,9,9,"arithmetic shift right and left",13 + = ">>>",9,9,9,"logical shift right",13 + = "STR, VAL",9,9,"conversion between strings and integers",13 + = "AND, OR, EOR, NOT",9,"(bitwise) logical operators",13 + = "RIGHT, LEFT",9,9,"substring extraction",13 + = "LEN",9,9,9,"length of a string",13,13 + = "Brackets can also be used.", 0 +Eval_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <expression>",0 + +GO_Help + = "*",TokenEscapeChar,Token0 + = " [<address>] [; environment] " + = " - go to address (hexadecimal), default &8000. " + = " Text after ';' is environment string.", 0 + +GOS_Help + = "*",TokenEscapeChar,Token0 + = " enters the supervisor. Use *Quit to exit.", 0 + +Append_Help + = "*",TokenEscapeChar,Token0 + = " opens an existing file and subsequent lines of keyboard input are" + = " appended to it, input being terminated by ESCAPE.",13 +Append_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <filename>", 0 + +Build_Help + = "*",TokenEscapeChar,Token0 + = " opens a new file and subsequent lines of keyboard input are" + = " directed to it, input being terminated by ESCAPE.",13 +Build_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <filename>", 0 + +Close_Help + = "*",TokenEscapeChar,Token0 + = " closes all files on the current filing system.",13 +Close_Syntax + = "Syntax: *",TokenEscapeChar,Token0,0 + +Create_Help + = "*",TokenEscapeChar,Token0 + = " reserves space for the named file, optionally giving it" + = " load and execution addresses. No data is transferred to the file." + = " Length and addresses are in hexadecimal.",13 +Create_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <filename> [<length> [<exec addr> [<load addr>]]]", 0 + +Delete_Help + = "*",TokenEscapeChar,Token0 + = " tries to delete the named file, returning an error if the file" + = " does not exist.",13 + = "See also *Remove and *Wipe.",13 +Delete_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <filename>", 0 + +Dump_Help + = "*",TokenEscapeChar,Token0 + = " displays the contents of the file as a hex and ASCII dump." + = " The file offset and start address are in hexadecimal.",13 +Dump_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <filename> [<file offset> [<start address>]]", 0 + +Exec_Help + = "*",TokenEscapeChar,Token0 + = " <filename> directs the operating system to take further input" + = " from the given file.",13 + = "*",TokenEscapeChar,Token0 + = " with no filename causes the exec file to be closed.",13 +Exec_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " [<filename>]", 0 + +FX_Help + = "*",TokenEscapeChar,Token0 + = " r0 [[,] r1 [[,] r2]] calls OS_Byte.", 0 + +FX_Syntax + = "*",TokenEscapeChar,Token0 + = " needs 1 to 3 numeric parameters.", 0 + +Key_Help + = "*",TokenEscapeChar,Token0 + = " sets the function keys.",13 +Key_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <keynumber> [<value>]", 0 + +List_Help + = "*",TokenEscapeChar,Token0 + = " displays the contents of the file in the configured GSRead format." + = " Each line is preceded with a line number.",13 + = "See also *Print and *Type.",13 +List_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " [-File] <filename> [-TabExpand]", 0 + +Load_Help + = "*",TokenEscapeChar,Token0 + = " with no specified address loads the named file at its own" + = " load address. If a load address (hexadecimal) is specified," + = " it will be used instead.",13 +Load_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <filename> [<load addr>]", 0 + +Print_Help + = "*",TokenEscapeChar,Token0 + = " displays the contents of a file by sending each byte to the VDU.",13 + = "See also *List and *Type.",13 +Print_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <filename>", 0 + +Opt_Help + = "*" + = TokenEscapeChar,Token0 + = " controls various filing system actions." + = 13,"Opt 1 <n>",31 + = "Set the filing system message level (for Load/Save/Create):" + = 13,9,"0",9,"No filing system messages" + = 13,9,"1",9,"Filename printed" + = 13,9,"2",9,"Filename,hexadecimal addresses and length printed" + = 13,9,"3",9,"Filename,datestamp and length printed" + = 13,"Opt 4 <n>",31 + = "Set the filing system boot option:" + = 13,9,"0",9,"No boot action" + = 13,9,"1",9,"*Load boot file" + = 13,9,"2",9,"*Run boot file" + = 13,9,"3",9,"*Exec boot file" + = 13 +Opt_Syntax + = "Syntax: *" + = TokenEscapeChar,Token0 + = " [<x> [[,] <y>]]",0 + +Remove_Help + = "*",TokenEscapeChar,Token0 + = " tries to delete the named file without returning an error" + = " if the file does not exist.",13 + = "See also *Delete and *Wipe.",13 +Remove_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " <filename>", 0 + +Save_Help + = "*",TokenEscapeChar,Token0 + = " copies the given area of memory to the named file." + = " Length and addresses are in hexadecimal.",13 + = "Syntax: *",TokenEscapeChar,Token0 + = " <filename> <start addr>" + = " <end addr> [<exec addr> [<load addr>]]",13 + = 31, 31, 31, 31, " or *",TokenEscapeChar,Token0 + = " <filename> <start addr>" + = " + <length> [<exec addr> [<load addr>]]", 0 + +Shadow_Help + = "*",TokenEscapeChar,Token0 + = " makes subsequent mode changes use the other screen bank.",13 +Shadow_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " [0|1]", 0 + +Spool_Help + = "*",TokenEscapeChar,Token0 + = " <filename> opens a new file and causes subsequent VDU output" + = " to be directed to it, subject to the current *fx 3 status.",13 + = "*",TokenEscapeChar,Token0 + = " with no filename causes the spool file to be closed.",13 +Spool_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " [<filename>]", 0 + +SpoolOn_Help + = "*",TokenEscapeChar,Token0 + = " <filename> opens an existing file and causes subsequent VDU output" + = " to be appended to it, subject to the current *fx 3 status.",13 + = "*",TokenEscapeChar,Token0 + = " with no filename causes the spool file to be closed.",13 +SpoolOn_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " [<filename>]", 0 + +TV_Help + = "*",TokenEscapeChar,Token0 + = " [<vertical position> [[,] <interlace>]]" + = " sets the position of the display on the screen.", 0 + +TV_Syntax + = "*",TokenEscapeChar,Token0 + = " needs 0 to 2 parameters.", 0 + +Type_Help + = "*",TokenEscapeChar,Token0 + = " displays the contents of the file" + = " in the configured GSRead format.",13 + = "See also *List and *Print.",13 +Type_Syntax + = "Syntax: *",TokenEscapeChar,Token0 + = " [-File] <filename> [-TabExpand]", 0 + +Help_Help + = "*",TokenEscapeChar,Token0 + = " <subjects> attempts to give useful information" + = " on the selected topics. Special keywords include:",13 + = "Commands", 9, "List all the available utility commands",13 + = "FileCommands", 9 + = "List all the filing system-specific commands",13 + = "Modules", 9, 9, "List the module titles",13 + = "Syntax", 9, 9, "Explain the syntax message format",0 + | +Break_Help DCB "HUTMBRK", 0 +Reset_Help DCB "HUTMRES", 0 +PowerOn_Help DCB "HUTMPOW", 0 +RMEnsure_Help DCB "HUTMRME", 0 +RMEnsure_Syntax DCB "SUTMRME", 0 +Syntax_Help DCB "HUTMSYN", 0 +Quit_Help DCB "HUTMQUI", 0 +GOS_Syntax DCB "SUTMGOS", 0 +Modules_Syntax DCB "SUTMMOD", 0 +Quit_Syntax DCB "SUTMQUI", 0 +RMFaster_Help DCB "HUTMRMF", 0 +RMFaster_Syntax DCB "SUTMRMF", 0 +RMKill_Help DCB "HUTMRMK", 0 +RMKill_Syntax DCB "SUTMRMK", 0 +RMLoad_Help DCB "HUTMRML", 0 +RMLoad_Syntax DCB "SUTMRML", 0 +RMRun_Help DCB "HUTMRRN", 0 +RMRun_Syntax DCB "SUTMRRN", 0 +RMTidy_Help DCB "HUTMRMT", 0 +RMTidy_Syntax DCB "SUTMRMT", 0 +RMClear_Help DCB "HUTMRMC", 0 +RMClear_Syntax DCB "SUTMRMC", 0 +RMReInit_Help DCB "HUTMRMR", 0 +RMReInit_Syntax DCB "SUTMRMR", 0 +ROMModules_Help DCB "HUTMROM", 0 +ROMModules_Syntax DCB "SUTMROM", 0 +Set_Help DCB "HUTMSET", 0 +Set_Syntax DCB "SUTMSET", 0 +SetMacro_Help DCB "HUTMSTM", 0 +SetMacro_Syntax DCB "SUTMSTM", 0 +SetEval_Help DCB "HUTMSTE", 0 +SetEval_Syntax DCB "SUTMSTE", 0 +Show_Help DCB "HUTMSHO", 0 +Show_Syntax DCB "SUTMSHO", 0 +Time_Help DCB "HUTMTIM", 0 +Time_Syntax DCB "SUTMTIM", 0 +Unset_Help DCB "HUTMUNS", 0 +Unset_Syntax DCB "SUTMUNS", 0 +Echo_Help DCB "HUTMECH", 0 +Ignore_Help DCB "HUTMIGN", 0 +Ignore_Syntax DCB "SUTMIGN", 0 +IF_Help DCB "HUTMIF", 0 +IF_Syntax DCB "SUTMIF", 0 +Status_Help DCB "HUTMSTA", 0 +Unplug_Help DCB "HUTMUNP", 0 +Unplug_Syntax DCB "SUTMUNP", 0 +RMInsert_Help DCB "HUTMRMI", 0 +RMInsert_Syntax DCB "SUTMRMI", 0 +Error_Help DCB "HUTMERR", 0 +Error_Syntax DCB "SUTMERR", 0 +Eval_Help DCB "HUTMEVL", 0 +Eval_Syntax DCB "SUTMEVL", 0 +GO_Help DCB "HUTMGO", 0 +GOS_Help DCB "HUTMGOS", 0 +Append_Help DCB "HUTMAPP", 0 +Append_Syntax DCB "SUTMAPP", 0 +Build_Help DCB "HUTMBUI", 0 +Build_Syntax DCB "SUTMBUI", 0 +Close_Help DCB "HUTMCLO", 0 +Close_Syntax DCB "SUTMCLO", 0 +Create_Help DCB "HUTMCRE", 0 +Create_Syntax DCB "SUTMCRE", 0 +Delete_Help DCB "HUTMDEL", 0 +Delete_Syntax DCB "SUTMDEL", 0 +Dump_Help DCB "HUTMDMP", 0 +Dump_Syntax DCB "SUTMDMP", 0 +Exec_Help DCB "HUTMEXE", 0 +Exec_Syntax DCB "SUTMEXE", 0 +FX_Help DCB "HUTMFX", 0 +FX_Syntax DCB "SUTMFX", 0 +Key_Help DCB "HUTMKEY", 0 +Key_Syntax DCB "SUTMKEY", 0 +List_Help DCB "HUTMLST", 0 +List_Syntax DCB "SUTMLST", 0 +Load_Help DCB "HUTMLOD", 0 +Load_Syntax DCB "SUTMLOD", 0 +Print_Help DCB "HUTMPRI", 0 +Print_Syntax DCB "SUTMPRI", 0 +Opt_Help DCB "HUTMOPT", 0 +Opt_Syntax DCB "SUTMOPT", 0 +Remove_Help DCB "HUTMREM", 0 +Remove_Syntax DCB "SUTMREM", 0 +Save_Help DCB "HUTMSAV", 0 +Save_Syntax DCB "SUTMSAV", 0 +Shadow_Help DCB "HUTMSHA", 0 +Shadow_Syntax DCB "SUTMSHA", 0 +Spool_Help DCB "HUTMSPL", 0 +Spool_Syntax DCB "SUTMSPL", 0 +SpoolOn_Help DCB "HUTMSPO", 0 +SpoolOn_Syntax DCB "SUTMSPO", 0 +TV_Help DCB "HUTMTV", 0 +TV_Syntax DCB "SUTMTV", 0 +Type_Help DCB "HUTMTYP", 0 +Type_Syntax DCB "SUTMTYP", 0 +Help_Help DCB "HUTMHLP", 0 + ] + +modules_help1 DCB "HUTMMOD", 0 +commands_helpstr + DCB "HUTMCOM", 0 +fscommands_helpstr + DCB "HUTMFSC", 0 +modjack_hstr DCB "HUTMMD", 0 +modjack_comms DCB "HUTMCM", 0 +modjack_filecomms + DCB "HUTMFS", 0 +modjack_confs DCB "HUTMCK", 0 +modjack_aob DCB "HUTMHK", 0 + + END diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2645f117307f6219900406431c200c0380fafc9f --- /dev/null +++ b/Makefile @@ -0,0 +1,109 @@ +# Copyright 1996 Acorn Computers Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Makefile for Kernel +# +# *********************************** +# *** C h a n g e L i s t *** +# *********************************** +# Date Name Description +# ---- ---- ----------- +# 25-May-94 AMcC Created. +# + +# +# Paths +# +EXP_HDR = <export$dir> + +# +# Generic options: +# +MKDIR = cdir +AS = aasm +CP = copy +RM = remove +CCFLAGS = -c -depend !Depend -IC: +ASFLAGS = -depend !Depend -Stamp -quit -To $@ -From +CPFLAGS = ~cfr~v + +TOKENISE = tokenise +TOKENS = Hdr:Tokens + +# +# Program specific options: +# +COMPONENT = Kernel +SOURCE = s.GetAll +TARGET = rm.${MACHINE}.Kernel +EXPORTS = ${EXP_HDR}.EnvNumbers \ + ${EXP_HDR}.ModHand \ + ${EXP_HDR}.PublicWS \ + ${EXP_HDR}.RISCOS \ + ${EXP_HDR}.Variables \ + ${EXP_HDR}.VduExt + +# +# Generic rules: +# +rom: ${TARGET} + @echo ${COMPONENT}: rom module built + +install_rom: ${TARGET} + ${CP} ${TARGET} ${INSTDIR}.${COMPONENT} ${CPFLAGS} + @echo ${COMPONENT}: rom module installed + +clean: + ${RM} ${TARGET} + ${RM} TMOSHelp + @echo ${COMPONENT}: cleaned + +export: ${EXPORTS} + @echo ${COMPONENT}: export complete + +resources: + ${MKDIR} ${RESDIR}.${COMPONENT} + ${CP} Resources.${LOCALE}.Messages ${RESDIR}.${COMPONENT}.Messages ${CPFLAGS} + @echo ${COMPONENT}: resource files copied + +${TARGET}: ${SOURCE} s.TMOSHelp + ${MKDIR} rm.${MACHINE} + ${AS} ${ASFLAGS} ${SOURCE} + stamp $@ + +s.TMOSHelp: ${TOKENS} HelpStrs + ${TOKENISE} ${TOKENS} HelpStrs $@ + +# +# Exported interface headers +# +${EXP_HDR}.EnvNumbers: hdr.EnvNumbers + ${CP} hdr.EnvNumbers $@ ${CPFLAGS} + +${EXP_HDR}.ModHand: hdr.ModHand + ${CP} hdr.ModHand $@ ${CPFLAGS} + +${EXP_HDR}.PublicWS: hdr.PublicWS + ${CP} hdr.PublicWS $@ ${CPFLAGS} + +${EXP_HDR}.RISCOS: hdr.RISCOS + ${CP} hdr.RISCOS $@ ${CPFLAGS} + +${EXP_HDR}.VduExt: hdr.VduExt + ${CP} hdr.VduExt $@ ${CPFLAGS} + +${EXP_HDR}.Variables: hdr.Variables + ${CP} hdr.Variables $@ ${CPFLAGS} + +# Dynamic dependencies: diff --git a/MkClean,fd7 b/MkClean,fd7 new file mode 100644 index 0000000000000000000000000000000000000000..e9d7ade7fd4d0f5126fb63aca74d820946350a83 --- /dev/null +++ b/MkClean,fd7 @@ -0,0 +1,16 @@ +| Copyright 1996 Acorn Computers Ltd +| +| Licensed under the Apache License, Version 2.0 (the "License"); +| you may not use this file except in compliance with the License. +| You may obtain a copy of the License at +| +| http://www.apache.org/licenses/LICENSE-2.0 +| +| Unless required by applicable law or agreed to in writing, software +| distributed under the License is distributed on an "AS IS" BASIS, +| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +| See the License for the specific language governing permissions and +| limitations under the License. +| +Dir <Obey$Dir> +amu_machine clean diff --git a/MkExport,fd7 b/MkExport,fd7 new file mode 100644 index 0000000000000000000000000000000000000000..9e5f66689f85c8dd747aa9baa51c30714524a7b1 --- /dev/null +++ b/MkExport,fd7 @@ -0,0 +1,16 @@ +| Copyright 1996 Acorn Computers Ltd +| +| Licensed under the Apache License, Version 2.0 (the "License"); +| you may not use this file except in compliance with the License. +| You may obtain a copy of the License at +| +| http://www.apache.org/licenses/LICENSE-2.0 +| +| Unless required by applicable law or agreed to in writing, software +| distributed under the License is distributed on an "AS IS" BASIS, +| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +| See the License for the specific language governing permissions and +| limitations under the License. +| +Dir <Obey$Dir> +amu_machine export diff --git a/MkRom,fd7 b/MkRom,fd7 new file mode 100644 index 0000000000000000000000000000000000000000..42cd1103e1a784e03f2ad8dff2bf4b4435fee5ce --- /dev/null +++ b/MkRom,fd7 @@ -0,0 +1,16 @@ +| Copyright 1996 Acorn Computers Ltd +| +| Licensed under the Apache License, Version 2.0 (the "License"); +| you may not use this file except in compliance with the License. +| You may obtain a copy of the License at +| +| http://www.apache.org/licenses/LICENSE-2.0 +| +| Unless required by applicable law or agreed to in writing, software +| distributed under the License is distributed on an "AS IS" BASIS, +| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +| See the License for the specific language governing permissions and +| limitations under the License. +| +Dir <Obey$Dir> +amu_machine rom diff --git a/NewModes/Make,feb b/NewModes/Make,feb new file mode 100644 index 0000000000000000000000000000000000000000..50fa3365299802aa617dcfa4765b7affb0507af1 --- /dev/null +++ b/NewModes/Make,feb @@ -0,0 +1,17 @@ +| Copyright 1996 Acorn Computers Ltd +| +| Licensed under the Apache License, Version 2.0 (the "License"); +| you may not use this file except in compliance with the License. +| You may obtain a copy of the License at +| +| http://www.apache.org/licenses/LICENSE-2.0 +| +| Unless required by applicable law or agreed to in writing, software +| distributed under the License is distributed on an "AS IS" BASIS, +| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +| See the License for the specific language governing permissions and +| limitations under the License. +| +| > NewModes.Make +WimpSlot -min 1024k -max 1024k +AASM <Obey$Dir>.PSSrc <Obey$Dir>.PSModule -module -quit diff --git a/NewModes/NEWF2 b/NewModes/NEWF2 new file mode 100644 index 0000000000000000000000000000000000000000..cf992a1d6ddca7325db060c9c538f7fefa7dd299 --- /dev/null +++ b/NewModes/NEWF2 @@ -0,0 +1,144 @@ +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; general purpose mode macros + +ClockShift * 9 +SyncShift * 11 + +; pixel rate specifiers + +CRPix_24000 * 3 :OR: (0 :SHL: ClockShift) +CRPix_16000 * 2 :OR: (0 :SHL: ClockShift) +CRPix_12000 * 1 :OR: (0 :SHL: ClockShift) +CRPix_8000 * 0 :OR: (0 :SHL: ClockShift) +CRPix_25175 * 3 :OR: (1 :SHL: ClockShift) +CRPix_36000 * 3 :OR: (2 :SHL: ClockShift) + + MACRO + VIDC_List $lbpp,$hsync,$hbpch,$hlbdr,$hdisp,$hrbdr,$hfpch, $vsync,$vbpch,$vlbdr,$vdisp,$vrbdr,$vfpch,$pixrate,$sp + LCLA sub + LCLA syncpol + [ $lbpp = 3 +sub SETA 5 + ] + [ $lbpp = 2 +sub SETA 7 + ] + [ $lbpp = 1 +sub SETA 11 + ] + [ $lbpp = 0 +sub SETA 19 + ] + [ "$sp"="" +syncpol SETA 0 :SHL: SyncShift ; normal sync polarity + | + ASSERT $sp<=3 +syncpol SETA $sp :SHL: SyncShift + ] + ASSERT ($hsync :AND: 1)=0 + ASSERT ($hbpch :AND: 1)=1 + ASSERT ($hlbdr :AND: 1)=0 + ASSERT ($hdisp :AND: 1)=0 + ASSERT ($hrbdr :AND: 1)=0 + ASSERT ($hfpch :AND: 1)=1 + [ (($hsync+$hbpch+$hlbdr+$hdisp+$hrbdr+$hfpch) :AND: 3)<>0 + ! 0, "Warning: mode unsuitable for interlaced use" + ] +; Horizontal + & (&80:SHL:24) :OR: ((($hsync+$hbpch+$hlbdr+$hdisp+$hrbdr+$hfpch -2 )/2) :SHL: 14) ; HCR + & (&84:SHL:24) :OR: ((($hsync -2 )/2) :SHL: 14) ; HSWR + & (&88:SHL:24) :OR: ((($hsync+$hbpch -1 )/2) :SHL: 14) ; HBSR + & (&8C:SHL:24) :OR: ((($hsync+$hbpch+$hlbdr -sub)/2) :SHL: 14) ; HDSR + & (&90:SHL:24) :OR: ((($hsync+$hbpch+$hlbdr+$hdisp -sub)/2) :SHL: 14) ; HDER + & (&94:SHL:24) :OR: ((($hsync+$hbpch+$hlbdr+$hdisp+$hrbdr -1 )/2) :SHL: 14) ; HBER + & (&9C:SHL:24) :OR: (((($hsync+$hbpch+$hlbdr+$hdisp+$hrbdr+$hfpch-2)/2+1)/2):SHL:14); HIR +; Vertical + & (&A0:SHL:24) :OR: (($vsync+$vbpch+$vlbdr+$vdisp+$vrbdr+$vfpch -1) :SHL: 14) ; VCR + & (&A4:SHL:24) :OR: (($vsync -1) :SHL: 14) ; VSWR + & (&A8:SHL:24) :OR: (($vsync+$vbpch -1) :SHL: 14) ; VBSR + & (&AC:SHL:24) :OR: (($vsync+$vbpch+$vlbdr -1) :SHL: 14) ; VDSR + & (&B0:SHL:24) :OR: (($vsync+$vbpch+$vlbdr+$vdisp -1) :SHL: 14) ; VDER + & (&B4:SHL:24) :OR: (($vsync+$vbpch+$vlbdr+$vdisp+$vrbdr -1) :SHL: 14) ; VBER +; Control Register + & (&E0:SHL:24) :OR: (CRPix_$pixrate) :OR: ($lbpp :SHL: 2) :OR: syncpol + & -1 + MEND + + MACRO + VIDC_WS $bpp,$hpix,$vpix,$multx,$multy, $dht + + & VduExt_XWindLimit, $hpix-1 + & VduExt_ScrRCol, ($hpix/8)-1 + & VduExt_LineLength, $hpix*$bpp/8 + [ "$dht" <> "" + & VduExt_ModeFlags, Flag_DoubleVertical + & VduExt_ScrBRow, ($vpix/16)-1 + | + & VduExt_ScrBRow, ($vpix/8)-1 + ] + & VduExt_YWindLimit, $vpix-1 + & VduExt_ScreenSize, $hpix*$vpix*$bpp/8 + + & VduExt_XEigFactor, $multx + & VduExt_YEigFactor, $multy + MEND + + + + +VLN_0 VIDC_List 0, 72,145, 48, 640, 48, 71, 3,18,18,256,17, 0,16000,0 ; MODE 0 +VLN_1 VIDC_List 1, 36, 73, 24, 320, 24, 35, 3,18,18,256,17, 0, 8000,0 ; MODE 1 +VLN_2 VIDC_List 2, 36, 73, 24, 320, 24, 35, 3,18,18,256,17, 0, 8000,0 ; MODE 2 +VLN_3 VIDC_List 1, 72,145, 48, 640, 48, 71, 3,18,22,250,19, 0,16000,0 ; MODE 3 +VLN_4 VIDC_List 0, 72,145, 48, 640, 48, 71, 3,18,18,256,17, 0,16000,0 ; MODE 4 +VLN_5 VIDC_List 1, 36, 73, 24, 320, 24, 35, 3,18,18,256,17, 0, 8000,0 ; MODE 5 +VLN_6 VIDC_List 1, 36, 73, 24, 320, 24, 35, 3,18,22,250,19, 0, 8000,0 ; MODE 6 +VLN_7 VIDC_List 2, 36, 73, 24, 320, 24, 35, 3,18,22,250,19, 0, 8000,0 ; MODE 7 +VLN_8 VIDC_List 1, 72,145, 48, 640, 48, 71, 3,18,18,256,17, 0,16000,0 ; MODE 8 +VLN_9 VIDC_List 2, 36, 73, 24, 320, 24, 35, 3,18,18,256,17, 0, 8000,0 ; MODE 9 +VLN_10 VIDC_List 3, 36, 73, 24, 320, 24, 35, 3,18,18,256,17, 0, 8000,0 ; MODE 10 +VLN_11 VIDC_List 1, 72,145, 48, 640, 48, 71, 3,18,22,250,19, 0,16000,0 ; MODE 11 +VLN_12 VIDC_List 2, 72,145, 48, 640, 48, 71, 3,18,18,256,17, 0,16000,0 ; MODE 12 +VLN_13 VIDC_List 3, 36, 73, 24, 320, 24, 35, 3,18,18,256,17, 0, 8000,0 ; MODE 13 +VLN_14 VIDC_List 2, 72,145, 48, 640, 48, 71, 3,18,22,250,19, 0,16000,0 ; MODE 14 +VLN_15 VIDC_List 3, 72,145, 48, 640, 48, 71, 3,18,18,256,17, 0,16000,0 ; MODE 15 +VLN_16 VIDC_List 2, 72,215, 46,1056, 46,101, 3,18,18,256,17, 0,24000,0 ; MODE 16 +VLN_17 VIDC_List 2, 72,215, 46,1056, 46,101, 3,18,22,250,19, 0,24000,0 ; MODE 17 +;VLN_18 VIDC_List 0, 56,183, 2, 640, 2, 13, 3,17, 1,512, 1, 0,24000,0 ; MODE 18 +;VLN_19 VIDC_List 1, 56,183, 2, 640, 2, 13, 3,17, 1,512, 1, 0,24000,0 ; MODE 19 +;VLN_20 VIDC_List 2, 56,183, 2, 640, 2, 13, 3,17, 1,512, 1, 0,24000,0 ; MODE 20 +;VLN_21 VIDC_List 3, 56,183, 2, 640, 2, 13, 3,17, 1,512, 1, 0,24000,0 ; MODE 21 +VLN_24 VIDC_List 3, 72,215, 46,1056, 46,101, 3,18,18,256,17, 0,24000,0 ; MODE 24 +VLN_33 VIDC_List 3, 74,127, 0, 768, 0, 55, 3,18, 0,288, 0, 3,16000,0 ; MODE 33 +VLN_34 VIDC_List 3, 74, 87, 0, 832, 0, 31, 3,18, 0,288, 0, 3,16000,0 ; MODE 34 + +VLM_0 VIDC_List 0, 72, 63, 88, 640, 88, 73, 3,16,17,256,17, 3,16000,0 ; MODE 0 +VLM_1 VIDC_List 1, 36, 33, 44, 320, 44, 35, 3,16,17,256,17, 3, 8000,0 ; MODE 1 +VLM_2 VIDC_List 2, 36, 33, 44, 320, 44, 35, 3,16,17,256,17, 3, 8000,0 ; MODE 2 +VLM_3 VIDC_List 1, 72, 63, 88, 640, 88, 73, 3,16,20,250,20, 3,16000,0 ; MODE 3 +VLM_4 VIDC_List 0, 72, 63, 88, 640, 88, 73, 3,16,17,256,17, 3,16000,0 ; MODE 4 +VLM_5 VIDC_List 1, 36, 51, 24, 320, 24, 57, 3,16,17,256,17, 3, 8000,0 ; MODE 5 +VLM_6 VIDC_List 1, 36, 33, 44, 320, 44, 35, 3,16,20,250,20, 3, 8000,0 ; MODE 6 +VLM_7 VIDC_List 2, 36, 31, 44, 320, 44, 37, 3,18,22,250,16, 3, 8000,0 ; MODE 7 +VLM_8 VIDC_List 1, 72, 63, 88, 640, 88, 73, 3,16,17,256,17, 3,16000,0 ; MODE 8 +VLM_9 VIDC_List 2, 36, 33, 44, 320, 44, 35, 3,16,17,256,17, 3, 8000,0 ; MODE 9 +VLM_10 VIDC_List 3, 36, 33, 44, 320, 44, 35, 3,16,17,256,17, 3, 8000,0 ; MODE 10 +VLM_11 VIDC_List 1, 72, 63, 88, 640, 88, 73, 3,16,20,250,20, 3,16000,0 ; MODE 11 +VLM_12 VIDC_List 2, 72, 63, 88, 640, 88, 73, 3,16,17,256,17, 3,16000,0 ; MODE 12 +VLM_13 VIDC_List 3, 36, 33, 44, 320, 44, 35, 3,16,17,256,17, 3, 8000,0 ; MODE 13 +VLM_14 VIDC_List 2, 72, 63, 88, 640, 88, 73, 3,16,20,250,20, 3,16000,0 ; MODE 14 +VLM_15 VIDC_List 3, 72, 63, 88, 640, 88, 73, 3,16,17,256,17, 3,16000,0 ; MODE 15 +VLM_16 VIDC_List 2,112, 47,132,1056,132, 57, 3,16,17,256,17, 3,24000,0 ; MODE 16 +VLM_17 VIDC_List 2,112, 47,132,1056,132, 57, 3,16,20,250,20, 3,24000,0 ; MODE 17 +VLM_18 VIDC_List 0, 56,111, 2, 640, 2, 85, 3,17, 1,512, 1, 0,24000,0 ; MODE 18 +VLM_19 VIDC_List 1, 56,111, 2, 640, 2, 85, 3,17, 1,512, 1, 0,24000,0 ; MODE 19 +VLM_20 VIDC_List 2, 56,111, 2, 640, 2, 85, 3,17, 1,512, 1, 0,24000,0 ; MODE 20 +VLM_21 VIDC_List 3, 56,111, 2, 640, 2, 85, 3,17, 1,512, 1, 0,24000,0 ; MODE 21 +VLM_24 VIDC_List 3,112, 47,132,1056,132, 57, 3,16,17,256,17, 3,24000,0 ; MODE 24 +VLM_25 VIDC_List 0, 96, 47, 0, 640, 0, 15, 2,32, 0,480, 0,11,25175,3 ; MODE 25 +VLM_26 VIDC_List 1, 96, 47, 0, 640, 0, 15, 2,32, 0,480, 0,11,25175,3 ; MODE 26 +VLM_27 VIDC_List 2, 96, 47, 0, 640, 0, 15, 2,32, 0,480, 0,11,25175,3 ; MODE 27 +VLM_28 VIDC_List 3, 96, 47, 0, 640, 0, 15, 2,32, 0,480, 0,11,25175,3 ; MODE 28 +VLM_31 VIDC_List 2, 72,129, 0, 800, 0, 23, 2,22, 0,600, 0, 1,36000,0 ; MODE 31 + +VLH_23 VIDC_List 2, 52, 47, 2, 288, 2, 1, 3,43, 4,896, 4, 0,24000,0 ; MODE 23 diff --git a/NewModes/NEWFORMAT b/NewModes/NEWFORMAT new file mode 100644 index 0000000000000000000000000000000000000000..d0734fed9585bd87c462bfeb06175a6b00b4da86 --- /dev/null +++ b/NewModes/NEWFORMAT @@ -0,0 +1,89 @@ + [ {FALSE} ; This mode not supported by VIDC, so not used +V32tab1 + VIDC_List 0,36,73,24,320,24,35, 3,18,18,256,17,0,8000,0 + ] + +V32tab2 ; MODES 1,5 + VIDC_List 1,36,73,24,320,24,35, 3,18,18,256,17,0,8000,0 + +V32tab2T ; MODE 6 + VIDC_List 1,36,73,24,320,24,35, 3,18,22,250,19,0,8000,0 + +V32tab4 ; MODES 2,9 + VIDC_List 2,36,73,24,320,24,35, 3,18,18,256,17,0,8000,0 + +V32tab4T ; MODE 7 + VIDC_List 2,36,73,24,320,24,35, 3,18,22,250,19,0,8000,0 + +V32tab8 ; MODES 10,13 + VIDC_List 3,36,73,24,320,24,35, 3,18,18,256,17,0,8000,0 + + +V64tab1 ; MODES 0,4 + VIDC_List 0,72,145,48,640,48,71, 3,18,18,256,17,0,16000,0 + +V64tab2 ; MODE 8 + VIDC_List 1,72,145,48,640,48,71, 3,18,18,256,17,0,16000,0 + +V64tab2T ; MODES 3,11 + VIDC_List 1,72,145,48,640,48,71, 3,18,22,250,19,0,16000,0 + +V64tab4 ; MODE 12 + VIDC_List 2,72,145,48,640,48,71, 3,18,18,256,17,0,16000,0 + +V64tab4T ; MODE 14 + VIDC_List 2,72,145,48,640,48,71, 3,18,22,250,19,0,16000,0 + +V64tab8 ; MODE 15 + VIDC_List 3,72,145,48,640,48,71, 3,18,18,256,17,0,16000,0 + +V132tab4 ; MODE 16 + VIDC_List 2,72,215,46,1056,46,101, 3,18,18,256,17,0,24000,0 + +V132tab4T ; MODE 17 + VIDC_List 2,72,215,46,1056,46,101, 3,18,22,250,19,0,24000,0 + + [ {TRUE} +V64tab1D ; MODE 18 + VIDC_List 0,56,183,2,640,2,13, 3,17,1,512,1,0,24000,0 + +V64tab2D ; MODE 19 + VIDC_List 1,56,183,2,640,2,13, 3,17,1,512,1,0,24000,0 + +V64tab4D ; MODE 20 + VIDC_List 2,56,183,2,640,2,13, 3,17,1,512,1,0,24000,0 + +V64tab8D ; MODE 21 (NEW) + VIDC_List 3,56,183,2,640,2,13, 3,17,1,512,1,0,24000,0 + + [ {FALSE} ; not used any more +V128tab1 ; MODE 22 + VIDC_List 2,54,39,2,320,2,7, 2,44,1,976,1,0,24000,0 + ] + +V115tab1 ; MODE 23 new Unoid monitor style, 1152x896 + ; changed again 29-Jul-88 to give 64.4Hz + VIDC_List 2,52,47,2,288,2,1, 3,43,4,896,4,0,24000,0 + + | + +V64tab1D ; MODE 18 (old) + VIDC_List 0,56,199,2,640,2,1, 3,17,1,512,1,0,24000,0 + +V64tab2D ; MODE 19 (old) + VIDC_List 1,56,199,2,640,2,1, 3,17,1,512,1,0,24000,0 + +V64tab4D ; MODE 20 (old) + VIDC_List 2,56,199,2,640,2,1, 3,17,1,512,1,0,24000,0 + +V128tab1 ; MODE 22 (old) + VIDC_List 2,60,41,0,320,0,3, 2,44,1,976,1,0,24000,0 + +V115tab1 ; MODE 23 + VIDC_List 2,60,41,16,288,16,3, 2,44,57,864,57,0,24000,0 + + ] + +V132tab8 ; MODE 24 (NEW) + VIDC_List 3,72,215,46,1056,46,101, 3,18,18,256,17,0,24000,0 + diff --git a/NewModes/OldFormat b/NewModes/OldFormat new file mode 100644 index 0000000000000000000000000000000000000000..278a8a6c718dff9177970f1d45d0ec1482a919d6 --- /dev/null +++ b/NewModes/OldFormat @@ -0,0 +1,453 @@ + [ {FALSE} ; This mode not supported by VIDC, so not used +V32tab1 + & &803FC000 + & &84044000 + & &880D8000 + & &8C0E4000 + & &90364000 + & &943B8000 + & &9C200000 + & &A04DC000 + & &A4008000 + & &A8050000 + & &AC098000 + & &B0498000 + & &B44DC000 + & &E0000030 + & -1 + ] + +V32tab2 ; MODES 1,5 + & &803FC000 + & &84044000 + & &880D8000 + & &8C0F4000 + & &90374000 + & &943B8000 + & &9C200000 + & &A04DC000 + & &A4008000 + & &A8050000 + & &AC098000 + & &B0498000 + & &B44DC000 + & &E0000034 + & -1 + +V32tab2T ; MODE 6 + & &803FC000 + & &84044000 + & &880D8000 + & &8C0F4000 + & &90374000 + & &943B8000 + & &9C200000 + & &A04DC000 + & &A4008000 + & &A8050000 + & &AC0A8000 ; start 4 pixels down + & &B0490000 ; end 2 pixels up + & &B44DC000 + & &E0000034 + & -1 + +V32tab4 ; MODES 2,9 + & &803FC000 + & &84044000 + & &880D8000 + & &8C0FC000 + & &9037C000 + & &943B8000 + & &9C200000 + & &A04DC000 + & &A4008000 + & &A8050000 + & &AC098000 + & &B0498000 + & &B44DC000 + & &E0000038 + & -1 + +V32tab4T ; MODE 7 + & &803FC000 + & &84044000 + & &880D8000 + & &8C0FC000 + & &9037C000 + & &943B8000 + & &9C200000 + & &A04DC000 + & &A4008000 + & &A8050000 + & &AC0A8000 ; start 4 pixels down + & &B0490000 ; end 2 pixels up + & &B44DC000 + & &E0000038 + & -1 + +V32tab8 ; MODES 10,13 + & &803FC000 + & &84044000 + & &880D8000 + & &8C100000 + & &90380000 + & &943B8000 + & &9C200000 + & &A04DC000 + & &A4008000 + & &A8050000 + & &AC098000 + & &B0498000 + & &B44DC000 + & &E000002C + & -1 + + +V64tab1 ; MODES 0,4 + & &807FC000 + & &8408C000 + & &881B0000 + & &8C1EC000 + & &906EC000 + & &94770000 + & &9C400000 + & &A04DC000 + & &A4008000 + & &A8050000 + & &AC098000 + & &B0498000 + & &B44DC000 + & &E0000032 + & -1 + +V64tab2 ; MODE 8 + & &807FC000 + & &8408C000 + & &881B0000 + & &8C1FC000 + & &906FC000 + & &94770000 + & &9C400000 + & &A04DC000 + & &A4008000 + & &A8050000 + & &AC098000 + & &B0498000 + & &B44DC000 + & &E0000036 + & -1 + +V64tab2T ; MODES 3,11 + & &807FC000 + & &8408C000 + & &881B0000 + & &8C1FC000 + & &906FC000 + & &94770000 + & &9C400000 + & &A04DC000 + & &A4008000 + & &A8050000 + & &AC0A8000 ; Start 4 pixels down + & &B0490000 ; End 2 pixels up + & &B44DC000 + & &E0000036 + & -1 + +V64tab4 ; MODE 12 + & &807FC000 + & &8408C000 + & &881B0000 + & &8C204000 + & &90704000 + & &94770000 + & &9C400000 + & &A04DC000 + & &A4008000 + & &A8050000 + & &AC098000 + & &B0498000 + & &B44DC000 + & &E000002A + & -1 + +V64tab4T ; MODE 14 + & &807FC000 + & &8408C000 + & &881B0000 + & &8C204000 + & &90704000 + & &94770000 + & &9C400000 + & &A04DC000 + & &A4008000 + & &A8050000 + & &AC0A8000 ; Start 4 pixels down + & &B0490000 ; End 2 pixels up + & &B44DC000 + & &E000002A + & -1 + +V64tab8 ; MODE 15 + & &807FC000 + & &8408C000 + & &881B0000 + & &8C208000 + & &90708000 + & &94770000 + & &9C400000 + & &A04DC000 + & &A4008000 + & &A8050000 + & &AC098000 + & &B0498000 + & &B44DC000 + & &E000001E + & -1 + +V132tab4 ; MODE 16 + & &80BFC000 + & &8408C000 + & &8823C000 ; 1B0000 + & &8C28C000 + & &90ACC000 + & &94B34000 ; B20000 + & &9C600000 + & &A04DC000 + & &A4008000 + & &A8050000 + & &AC098000 + & &B0498000 + & &B44DC000 + & &E000002B + & -1 + +V132tab4T ; MODE 17 + & &80BFC000 + & &8408C000 + & &8823C000 ; 1B0000 + & &8C28C000 + & &90ACC000 + & &94B34000 ; B34000 + & &9C600000 + & &A04DC000 + & &A4008000 + & &A8050000 + & &AC0A8000 ; start 4 pixels down + & &B0490000 ; end 2 pixels up + & &B44DC000 + & &E000002B + & -1 + + [ {TRUE} +V64tab1D ; MODE 18 + & &806FC000 + & &8406C000 + & &881DC000 + & &8C1BC000 + & &906BC000 + & &946E4000 + & &9C380000 + & &A0854000 + & &A4008000 + & &A804C000 + & &AC050000 + & &B0850000 + & &B4854000 + & &E0000033 + & -1 + +V64tab2D ; MODE 19 + & &806FC000 + & &8406C000 + & &881DC000 + & &8C1CC000 + & &906CC000 + & &946E4000 + & &9C380000 + & &A0854000 + & &A4008000 + & &A804C000 + & &AC050000 + & &B0850000 + & &B4854000 + & &E0000037 + & -1 + +V64tab4D ; MODE 20 + & &806FC000 + & &8406C000 + & &881DC000 + & &8C1D4000 + & &906D4000 + & &946E4000 + & &9C380000 + & &A0854000 + & &A4008000 + & &A804C000 + & &AC050000 + & &B0850000 + & &B4854000 + & &E000002B + & -1 + +V64tab8D ; MODE 21 (NEW) + & &806FC000 + & &8406C000 + & &881DC000 + & &8C1D8000 + & &906D8000 + & &946E4000 + & &9C380000 + & &A0854000 + & &A4008000 + & &A804C000 + & &AC050000 + & &B0850000 + & &B4854000 + & &E000000F + & -1 + + [ {FALSE} ; not used any more +V128tab1 ; MODE 22 + & &8034C000 + & &84068000 + & &880B8000 + & &8C0B0000 + & &90330000 + & &94340000 + & &9C1A8000 + & &A0FFC000 + & &A4004000 + & &A80B4000 + & &AC0B8000 + & &B0FF8000 + & &B4FFC000 + & &E000002B + & -1 + ] + +V115tab1 ; MODE 23 new Unoid monitor style, 1152x896 + ; changed again 29-Jul-88 to give 64.4Hz + & &8030C000 + & &84064000 + & &880C4000 + & &8C0BC000 + & &902FC000 + & &9430C000 + & &9C188000 ; changed 16-Aug-88, was 1A8 + & &A0ED4000 + & &A4008000 + & &A80B4000 + & &AC0C4000 + & &B0EC4000 + & &B4ED4000 + & &E000002B + & -1 + + | + +V64tab1D ; MODE 18 (old) + & &80704000 + & &8406C000 + & &881FC000 + & &8C1DC000 + & &906DC000 + & &94704000 + & &9C384000 + & &A0854000 + & &A4008000 + & &A804C000 + & &AC050000 + & &B0850000 + & &B4854000 + & &E0000033 + & -1 + +V64tab2D ; MODE 19 (old) + & &80704000 + & &8406C000 + & &881FC000 + & &8C1EC000 + & &906EC000 + & &94704000 + & &9C384000 + & &A0854000 + & &A4008000 + & &A804C000 + & &AC050000 + & &B0850000 + & &B4854000 + & &E0000037 + & -1 + +V64tab4D ; MODE 20 (old) + & &80704000 + & &8406C000 + & &881FC000 + & &8C1F4000 + & &906F4000 + & &94704000 + & &9C384000 + & &A0854000 + & &A4008000 + & &A804C000 + & &AC050000 + & &B0850000 + & &B4854000 + & &E000002B + & -1 + +V128tab1 ; MODE 22 (old) + & &8034C000 + & &84074000 + & &880C8000 + & &8C0BC000 + & &9033C000 + & &94348000 + & &9C1A8000 ; was wrong + & &A0FFC000 + & &A4004000 + & &A80B4000 + & &AC0B8000 + & &B0FF8000 + & &B4FFC000 + & &E000002B + & -1 + +V115tab1 ; MODE 23 + & &8034C000 + & &84074000 + & &880C8000 + & &8C0DC000 + & &9031C000 + & &94348000 + & &9C1A8000 ; was wrong + & &A0FFC000 + & &A4004000 + & &A80B4000 + & &AC198000 + & &B0F18000 + & &B4FFC000 + & &E000002B + & -1 + + ] + +V132tab8 ; MODE 24 (NEW) + & &80BFC000 + & &8408C000 + & &8823C000 + & &8C290000 + & &90AD0000 + & &94B34000 + & &9C600000 + & &A04DC000 + & &A4008000 + & &A8050000 + & &AC098000 + & &B0498000 + & &B44DC000 + & &E000000F + & -1 + diff --git a/NewModes/OldPSSrc b/NewModes/OldPSSrc new file mode 100644 index 0000000000000000000000000000000000000000..c8ebe682fa2b7914e9362c8e1740a1240c5e1e41 --- /dev/null +++ b/NewModes/OldPSSrc @@ -0,0 +1,1002 @@ +; > NewModes.PSSrc +; 08-Nov-89 + + GET &.Hdr.ListOpts + GET &.Hdr.Macros + GET &.Hdr.System + GET &.Hdr.NewSpace + GET &.Hdr.ModHand + GET &.Hdr.Services + GET &.Hdr.Proc + GET &.Hdr.File + GET &.Hdr.NewErrors + GET &.Hdr.VduExt + GET &.Hdr.Debug + GET &.Hdr.CMOS + + LEADR Module_LoadAddr + + GBLL Debug +Debug SETL {FALSE} + + GBLL Module +Module SETL {TRUE} ; Really ! + +TAB * 9 +LF * 10 +FF * 12 +CR * 13 + +MonitorType_Normal * 0 +MonitorType_MultiSync * 1 +MonitorType_HiResMono * 2 +MonitorType_VGA * 3 +MonitorType_DontCare * -1 + +Normal * 1 :SHL: MonitorType_Normal +MultiSync * 1 :SHL: MonitorType_MultiSync +HiResMono * 1 :SHL: MonitorType_HiResMono +VGA * 1 :SHL: MonitorType_VGA + +ScreenEndAdr * &02000000 +Vinit * &03600000 +Interlace * &40 + + MACRO + NewMode $modeno, $monitors, $vidclist, $wslist + & $modeno + & $monitors +99 + & ($vidclist)-%BT99 + & ($wslist)-%BT99 + MEND + +; Module workspace allocation + + ^ 0, R12 + +ModeExt_WorkspaceSize * :INDEX: @ + +; **************** Module code starts here ********************** + +Module_BaseAddr + + DCD 0 + DCD ModeExt_Init -Module_BaseAddr + DCD ModeExt_Die -Module_BaseAddr + DCD ModeExt_Service -Module_BaseAddr + DCD ModeExt_Title -Module_BaseAddr + DCD ModeExt_HelpStr -Module_BaseAddr + DCD ModeExt_HC_Table-Module_BaseAddr + +ModeExt_Title + = "NewModes", 0 + +ModeExt_HelpStr + = "NewModes" + = TAB + = "1.3 (08 Nov 1989) test Multisync Modes", 0 + ALIGN + +; ***************************************************************************** + +ModeExt_HC_Table * Module_BaseAddr + +; ***************************************************************************** +; +; ModeExt_Init - Initialisation entry point +; + +ModeExt_Init ENTRY + + MOV R0, #EventV + ADRL R1, EventRoutine + MOV R2, R12 + SWI XOS_Claim + MOVVC R0, #14 + MOVVC R1, #Event_VSync + SWIVC XOS_Byte + EXIT + +; ***************************************************************************** +; +; ModeExt_Die - Die entry +; + +ModeExt_Die ENTRY + + MOV R0, #13 + MOV R1, #Event_VSync + SWI XOS_Byte + MOV R0, #EventV + ADRL R1, EventRoutine + MOV R2, R12 + SWI XOS_Release + EXITS + +; ***************************************************************************** +; +; ModeExt_Service - Main entry point for services +; +; in: R1 = service reason code +; + +ModeExt_Service ENTRY + TEQ R1, #Service_ModeExtension + TEQNE R1, #Service_PreModeChange + TEQNE R1, #Service_ModeChange + TEQNE R1, #Service_Reset + TEQNE R1, #Service_ModeTranslation + EXIT NE + + TEQ R1, #Service_PreModeChange + MOVEQ R14, #0 ; zero the word + STREQ R14, [R12] + EXIT EQ + + TEQ R1, #Service_ModeChange + BEQ ModeChangeService + + TEQ R1, #Service_Reset + BEQ ResetCode + + TEQ R1, #Service_ModeTranslation + BEQ ModeTranslation + + [ Debug + DREG R2, "Mode = " + DREG R3, "Monitor type = " + ] + + Push "R5-R8" + + ADR R5, NewModesList-8 + MOV R8, #1 +10 + ADD R5, R5, #8 ; skip VidC, WS + LDMIA R5!, {R6, R7} ; R6 = mode, R7 = OK monitor types + CMP R6, #-1 + Pull "R5-R8, PC", EQ ; mode not in list, exit + TEQ R2, R6 ; if not this mode + BNE %BT10 ; then loop + CMP R3, #MonitorType_DontCare ; if any monitor type + BEQ %FT20 ; then found one + TST R7, R8, LSL R3 ; else if not appropriate monitor + BEQ %BT10 ; then loop +20 + LDMIA R5, {R3, R4} ; load offsets to VidCList, WSList + ADD R3, R3, R5 ; convert to addresses + ADD R4, R4, R5 ; convert to addresses + MOV R1, #0 ; claim service + Pull "R5-R8, PC" + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +NewModesList + + NewMode 0, MultiSync, Multi100VIDCList, Multi100WSList ; rshifted Mode 0 + NewMode 1, MultiSync, Multi101VIDCList, Multi101WSList ; rshifted Mode 1 + NewMode 2, MultiSync, Multi102VIDCList, Multi102WSList ; rshifted Mode 2 + NewMode 3, MultiSync, Multi103VIDCList, Multi103WSList ; rshifted Mode 3 + NewMode 4, MultiSync, Multi104VIDCList, Multi104WSList ; rshifted Mode 4 + NewMode 5, MultiSync, Multi105VIDCList, Multi105WSList ; rshifted Mode 5 + NewMode 6, MultiSync, Multi106VIDCList, Multi106WSList ; rshifted Mode 6 + NewMode 7, MultiSync, Multi107VIDCList, Multi107WSList ; rshifted Mode 7 + NewMode 8, MultiSync, Multi108VIDCList, Multi108WSList ; rshifted Mode 8 + NewMode 9, MultiSync, Multi109VIDCList, Multi109WSList ; rshifted Mode 9 + NewMode 10, MultiSync, Multi110VIDCList, Multi110WSList ; rshifted Mode 10 + NewMode 11, MultiSync, Multi111VIDCList, Multi111WSList ; rshifted Mode 11 + NewMode 12, MultiSync, Multi112VIDCList, Multi112WSList ; rshifted Mode 12 + NewMode 13, MultiSync, Multi113VIDCList, Multi113WSList ; rshifted Mode 13 + NewMode 14, MultiSync, Multi114VIDCList, Multi114WSList ; rshifted Mode 14 + NewMode 15, MultiSync, Multi115VIDCList, Multi115WSList ; rshifted Mode 15 + NewMode 16, MultiSync, Multi116VIDCList, Multi116WSList ; rshifted Mode 16 + NewMode 17, MultiSync, Multi117VIDCList, Multi117WSList ; rshifted Mode 17 + NewMode 18, MultiSync, Multi118VIDCList, Multi118WSList ; rshifted Mode 18 + NewMode 19, MultiSync, Multi119VIDCList, Multi119WSList ; rshifted Mode 19 + NewMode 20, MultiSync, Multi120VIDCList, Multi120WSList ; rshifted Mode 20 + NewMode 21, MultiSync, Multi121VIDCList, Multi121WSList ; rshifted Mode 21 + + NewMode 24, MultiSync, Multi124VIDCList, Multi124WSList ; rshifted Mode 24 + + NewMode 25, VGA :OR: MultiSync, VGA1VIDCList, VGA1WSList2 ; VGA 1bp 640x480 + NewMode 26, VGA :OR: MultiSync, VGA2VIDCList, VGA2WSList2 ; VGA 2bp 640x480 + NewMode 27, VGA :OR: MultiSync, VGA4VIDCList, VGA4WSList2 ; VGA 4bp 640x480 + NewMode 28, VGA :OR: MultiSync, VGA8VIDCList, VGA8WSList2 ; VGA 8bp 640x480 + + NewMode 31, MultiSync, sVGA4_VIDCList, sVGA4_WSList ; super VGA 4bp 800x600 + NewMode 32, MultiSync, sVGA8_VIDCList, sVGA8_WSList ; super VGA 8bp 800x600 + + NewMode 33, Normal :OR: MultiSync, Mode33VIDCList, Mode33WSList ; overscan 768x288 + NewMode 34, Normal :OR: MultiSync, Mode34VIDCList, Mode34WSList ; overscan 832x288 + +; NewMode 45, VGA :OR: MultiSync, VGA11VIDCList, VGA11WSList2 ; VGA 1bp 640x350 +; NewMode 46, VGA :OR: MultiSync, VGA12VIDCList, VGA12WSList2 ; VGA 2bp 640x350 +; NewMode 47, VGA :OR: MultiSync, VGA14VIDCList, VGA14WSList2 ; VGA 4bp 640x350 +; NewMode 48, VGA :OR: MultiSync, VGA18VIDCList, VGA18WSList2 ; VGA 8bp 640x350 + +; NewMode 55, VGA :OR: MultiSync, VGA21VIDCList, VGA21WSList2 ; VGA 1bp 720x400 +; NewMode 56, VGA :OR: MultiSync, VGA22VIDCList, VGA22WSList2 ; VGA 2bp 720x400 +; NewMode 57, VGA :OR: MultiSync, VGA24VIDCList, VGA24WSList2 ; VGA 4bp 720x400 +; NewMode 58, VGA :OR: MultiSync, VGA28VIDCList, VGA28WSList2 ; VGA 8bp 720x400 + +; NewMode 60, MultiSync, Multi350VIDCList, Multi350WSList ; MDA 640x350 +; NewMode 61, MultiSync, Multi200VIDCList, Multi200WSList ; CGA 640x200 +; NewMode 62, MultiSync, Multi351VIDCList, Multi351WSList ; EGA 640x350 + +; NewMode 66, MultiSync, Multi66VIDCList, Multi66WSList ; DTP 960x384 4bpp +; NewMode 67, MultiSync, Multi67VIDCList, Multi67WSList ; DTP 960x384 8bpp + +; NewMode 76, MultiSync, Multi76VIDCList, Multi76WSList ; DTP 1280x384 4bpp +; NewMode 77, MultiSync, Multi77VIDCList, Multi77WSList ; DTP 1280x384 8bpp + + & -1, 0 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; general purpose mode macros + +ClockShift * 9 +SyncShift * 11 + +; pixel rate specifiers + +CRPix_24000 * 3 :OR: (0 :SHL: ClockShift) +CRPix_16000 * 2 :OR: (0 :SHL: ClockShift) +CRPix_12000 * 1 :OR: (0 :SHL: ClockShift) +CRPix_8000 * 0 :OR: (0 :SHL: ClockShift) +CRPix_25175 * 3 :OR: (1 :SHL: ClockShift) +CRPix_36000 * 3 :OR: (2 :SHL: ClockShift) + + MACRO + VIDC_List $bpp,$hsync,$hbpch,$hlbdr,$hdisp,$hrbdr,$hfpch, $vsync,$vbpch,$vlbdr,$vdisp,$vrbdr,$vfpch,$pixrate,$sp + LCLA sub + LCLA lbpp + LCLA syncpol + [ $bpp = 8 +sub SETA 5 +lbpp SETA 3 + ] + [ $bpp = 4 +sub SETA 7 +lbpp SETA 2 + ] + [ $bpp = 2 +sub SETA 11 +lbpp SETA 1 + ] + [ $bpp = 1 +sub SETA 19 +lbpp SETA 0 + ] + [ "$sp"="" :LOR: "$sp"="0" +syncpol SETA 0 :SHL: SyncShift ; normal sync polarity + | + [ "$sp"="1" +syncpol SETA 3 :SHL: SyncShift ; inverted H and V sync + | + ! 1,"Sync polarity must be null string or 0 (for normal syncs) or 1 (for inverted H and V syncs)" + ] + ] + ASSERT ($hsync :AND: 1)=0 + ASSERT ($hbpch :AND: 1)=1 + ASSERT ($hlbdr :AND: 1)=0 + ASSERT ($hdisp :AND: 1)=0 + ASSERT ($hrbdr :AND: 1)=0 + ASSERT ($hfpch :AND: 1)=1 +; Horizontal + & (&80:SHL:24) :OR: ((($hsync+$hbpch+$hlbdr+$hdisp+$hrbdr+$hfpch -2 )/2) :SHL: 14) ; HCR + & (&84:SHL:24) :OR: ((($hsync -2 )/2) :SHL: 14) ; HSWR + & (&88:SHL:24) :OR: ((($hsync+$hbpch -1 )/2) :SHL: 14) ; HBSR + & (&8C:SHL:24) :OR: ((($hsync+$hbpch+$hlbdr -sub)/2) :SHL: 14) ; HDSR + & (&90:SHL:24) :OR: ((($hsync+$hbpch+$hlbdr+$hdisp -sub)/2) :SHL: 14) ; HDER + & (&94:SHL:24) :OR: ((($hsync+$hbpch+$hlbdr+$hdisp+$hrbdr -1 )/2) :SHL: 14) ; HBER +; Vertical + & (&A0:SHL:24) :OR: (($vsync+$vbpch+$vlbdr+$vdisp+$vrbdr+$vfpch -1) :SHL: 14) ; VCR + & (&A4:SHL:24) :OR: (($vsync -1) :SHL: 14) ; VSWR + & (&A8:SHL:24) :OR: (($vsync+$vbpch -1) :SHL: 14) ; VBSR + & (&AC:SHL:24) :OR: (($vsync+$vbpch+$vlbdr -1) :SHL: 14) ; VDSR + & (&B0:SHL:24) :OR: (($vsync+$vbpch+$vlbdr+$vdisp -1) :SHL: 14) ; VDER + & (&B4:SHL:24) :OR: (($vsync+$vbpch+$vlbdr+$vdisp+$vrbdr -1) :SHL: 14) ; VBER +; Control Register + & (&E0:SHL:24) :OR: (CRPix_$pixrate) :OR: (lbpp :SHL: 2) :OR: syncpol + MEND + + MACRO + VIDC_WS $bpp,$hpix,$vpix,$multx,$multy, $dht + + & VduExt_XWindLimit, $hpix-1 + & VduExt_ScrRCol, ($hpix/8)-1 + & VduExt_LineLength, $hpix*$bpp/8 + [ "$dht" <> "" + & VduExt_ModeFlags, Flag_DoubleVertical + & VduExt_ScrBRow, ($vpix/16)-1 + | + & VduExt_ScrBRow, ($vpix/8)-1 + ] + & VduExt_YWindLimit, $vpix-1 + & VduExt_ScreenSize, $hpix*$vpix*$bpp/8 + + & VduExt_XEigFactor, $multx + & VduExt_YEigFactor, $multy + MEND + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +; Start of multi sync archy modes + +; Mode 0, multiscan mode 0 +Multi100VIDCList + & 0 + & 0 + VIDC_List 1,72,63,88,640,88,73, 3,16,17,256,17,3,16000 + & -1 +Multi100WSList + & 0 + & 0 + & -1 + +; Mode 1, multiscan mode 1 +Multi101VIDCList + & 0 + & 1 + VIDC_List 2,36,33,44,320,44,35, 3,16,17,256,17,3,8000 + & -1 +Multi101WSList + & 0 + & 1 + & -1 + +; Mode 2, multiscan mode 2 +Multi102VIDCList + & 0 + & 2 + VIDC_List 4,36,33,44,320,44,35, 3,16,17,256,17,3,8000 + & -1 +Multi102WSList + & 0 + & 2 + & -1 + +; Mode 3, multiscan mode 3 +Multi103VIDCList + & 0 + & 3 + VIDC_List 2,72,63,88,640,88,73, 3,16,20,250,20,3,16000 + & -1 +Multi103WSList + & 0 + & 3 + & -1 + +; Mode 4, multiscan mode 4 +Multi104VIDCList + & 0 + & 4 + VIDC_List 1,72,63,88,640,88,73, 3,16,17,256,17,3,16000 + & -1 +Multi104WSList + & 0 + & 4 + & -1 + +; Mode 5, multiscan mode 5 +Multi105VIDCList + & 0 + & 5 + VIDC_List 2,36,51,24,320,24,57, 3,16,17,256,17,3,8000 + & -1 +Multi105WSList + & 0 + & 5 + & -1 + +; Mode 6, multiscan mode 6 +Multi106VIDCList + & 0 + & 6 + VIDC_List 2,36,33,44,320,44,35, 3,16,20,250,20,3,8000 + & -1 +Multi106WSList + & 0 + & 6 + & -1 + +; Mode 7, multiscan mode 7 +Multi107VIDCList + & 0 + & 7 + VIDC_List 4,36,31,44,320,44,37, 3,18,22,250,16,3,8000 + & -1 +Multi107WSList + & 0 + & 7 + & -1 + +; Mode 8, multiscan mode 8 +Multi108VIDCList + & 0 + & 8 + VIDC_List 2,72,63,88,640,88,73, 3,16,17,256,17,3,16000 + & -1 +Multi108WSList + & 0 + & 8 + & -1 + +; Mode 9, multiscan mode 9 +Multi109VIDCList + & 0 + & 9 + VIDC_List 4,36,33,44,320,44,35, 3,16,17,256,17,3,8000 + & -1 +Multi109WSList + & 0 + & 9 + & -1 + +; Mode 10, multiscan mode 10 +Multi110VIDCList + & 0 + & 10 + VIDC_List 8,36,33,44,320,44,35, 3,16,17,256,17,3,8000 + & -1 +Multi110WSList + & 0 + & 10 + & -1 + +; Mode 11, multiscan mode 11 +Multi111VIDCList + & 0 + & 11 + VIDC_List 2,72,63,88,640,88,73, 3,16,20,250,20,3,16000 + & -1 +Multi111WSList + & 0 + & 11 + & -1 + +; Mode 12, multiscan mode 12 +Multi112VIDCList + & 0 + & 12 + VIDC_List 4,72,63,88,640,88,73, 3,16,17,256,17,3,16000 + & -1 +Multi112WSList + & 0 + & 12 + & -1 + +; Mode 13, multiscan mode 13 +Multi113VIDCList + & 0 + & 13 + VIDC_List 8,36,33,44,320,44,35, 3,16,17,256,17,3,8000 + & -1 +Multi113WSList + & 0 + & 13 + & -1 + +; Mode 14, multiscan mode 14 +Multi114VIDCList + & 0 + & 14 + VIDC_List 4,72,63,88,640,88,73, 3,16,20,250,20,3,16000 + & -1 +Multi114WSList + & 0 + & 14 + & -1 + +; Mode 15, multiscan mode 15 +Multi115VIDCList + & 0 + & 15 + VIDC_List 8,72,63,88,640,88,73, 3,16,17,256,17,3,16000 + & -1 +Multi115WSList + & 0 + & 15 + & -1 + +; Mode 16, multiscan mode 16 +Multi116VIDCList + & 0 + & 16 + VIDC_List 4,112,47,132,1056,132,57, 3,16,17,256,17,3,24000 +; +; tv blanking! 112,139, 76,1056,114, 39, ,3,18,16,256,16,3 +; 4u67,5u79,3u2,44u,4u7,1u62, 21r 3r +; should be =10u4 =1u65 22r 3r(2r5) +;philips needs bprch > 57 or goes dark (sync at 112) +; can inc sync to 10u0, more and screen starts to wobble + & -1 +Multi116WSList + & 0 + & 16 + & -1 + +; Mode 17, multiscan mode 17 +Multi117VIDCList + & 0 + & 17 + VIDC_List 4,112,47,132,1056,132,57, 3,16,20,250,20,3,24000 + & -1 +Multi117WSList + & 0 + & 17 + & -1 + +; Mode 18, multiscan mode 18 +Multi118VIDCList + & 0 + & 18 + VIDC_List 1,56,111,2,640,2,85, 3,17,1,512,1,0,24000 + & -1 +Multi118WSList + & 0 + & 18 + & -1 + +; Mode 19, multiscan mode 19 +Multi119VIDCList + & 0 + & 19 + VIDC_List 2,56,111,2,640,2,85, 3,17,1,512,1,0,24000 + & -1 +Multi119WSList + & 0 + & 19 + & -1 + +; Mode 20, multiscan mode 20 +Multi120VIDCList + & 0 + & 20 + VIDC_List 4,56,111,2,640,2,85, 3,17,1,512,1,0,24000 + & -1 +Multi120WSList + & 0 + & 20 + & -1 + +; Mode 21, multiscan mode 21 +Multi121VIDCList + & 0 + & 21 + VIDC_List 8,56,111,2,640,2,85, 3,17,1,512,1,0,24000 + & -1 +Multi121WSList + & 0 + & 21 + & -1 + +; Mode 24, multiscan mode 24 +Multi124VIDCList + & 0 + & 24 + VIDC_List 8,112,47,132,1056,132,57, 3,16,17,256,17,3,24000 + & -1 +Multi124WSList + & 0 + & 24 + & -1 + + +; MODE 25 (VGA or multisync monitors, 640x480) +VGA1VIDCList + & 0 + & 18 + VIDC_List 1,96,47,0,640,0,15, 2,32,0,480,0,11,25175,1 + & -1 +VGA1WSList2 + & 0 + & 18 + & -1 + +; MODE 26 (VGA or multisync monitors, 640x480) +VGA2VIDCList + & 0 + & 19 + VIDC_List 2,96,47,0,640,0,15, 2,32,0,480,0,11,25175,1 + & -1 +VGA2WSList2 + & 0 + & 19 + & -1 + +; MODE 27 (VGA or multisync monitors, 640x480) +VGA4VIDCList + & 0 + & 20 + VIDC_List 4,96,47,0,640,0,15, 2,32,0,480,0,11,25175,1 + & -1 +VGA4WSList2 + & 0 + & 20 + & -1 + +; MODE 28 (VGA or multisync monitors, 640x480) +VGA8VIDCList + & 0 + & 21 + VIDC_List 8,96,47,0,640,0,15, 2,32,0,480,0,11,25175,1 + & -1 +VGA8WSList2 + & 0 + & 21 + & -1 + +; MODE 31 (800x600 by 4 bits per pixel) +sVGA4_VIDCList + & 0 + & 20 + VIDC_List 4,72,129,0,800,0,23, 2,22,0,600,0,1,36000 + & &E000042B + & -1 +sVGA4_WSList + & 0 + & 20 + VIDC_WS 4,800,600,1,1 + & -1 + +; MODE 32 (800x600 by 8 bits per pixel) +sVGA8_VIDCList + & 0 + & 24 + VIDC_List 8,72,129,0,800,0,23, 2,22,0,600,0,1,36000 + & &E000040F + & -1 +sVGA8_WSList + & 0 + & 24 + VIDC_WS 8,800,600,1,1 + & -1 + +; MODE 33 (768x288 by 8 bits per pixel) +Mode33VIDCList + + & 0 + & 15 + VIDC_List 8,74,127,0,768,0,55, 3,18,0,288,0,3,16000 + & -1 +Mode33WSList + & 0 + & 15 + VIDC_WS 8,768,288,1,2 + & -1 + +; MODE 34 (832x288 by 8 bits per pixel) +Mode34VIDCList + & 0 + & 15 + VIDC_List 8,74,87,0,832,0,31, 3,18,0,288,0,3,16000 + & -1 +Mode34WSList + & 0 + & 15 + VIDC_WS 8,832,288,1,2 + & -1 + +;; MODE 45 (VGA or multisync monitors, 640x350) +;VGA11VIDCList +; & 0 +; & 18 +; VIDC_List 1,96,47,0,640,0,15, 2,59,0,350,0,38 +; & -1 +;VGA11WSList2 +; & 0 +; & 18 +; VIDC_WS 1,640,350,1,2 +; & -1 + +;; MODE 46 (VGA or multisync monitors, 640x350) +;VGA12VIDCList +; & 0 +; & 19 +; VIDC_List 2,96,47,0,640,0,15, 2,59,0,350,0,38 +; & -1 +;VGA12WSList2 +; & 0 +; & 19 +; VIDC_WS 2,640,350,1,2 +; & -1 + +;; MODE 47 (VGA or multisync monitors, 640x350) +;VGA14VIDCList +; & 0 +; & 20 +; VIDC_List 4,96,47,0,640,0,15, 2,59,0,350,0,38 +; & -1 +;VGA14WSList2 +; & 0 +; & 20 +; VIDC_WS 4,640,350,1,2 +; & -1 + +;; MODE 48 (VGA or multisync monitors, 640x350) +;VGA18VIDCList +; & 0 +; & 21 +; VIDC_List 8,96,47,0,640,0,15, 2,59,0,350,0,38 +; & &E000020F +; & -1 +;VGA18WSList2 +; & 0 +; & 21 +; VIDC_WS 8,640,350,1,2 +; & -1 + +;; MODE 55 (VGA or multisync monitors, 720x400) +;VGA21VIDCList +; & 0 +; & 18 +; VIDC_List 1,108,55,0,720,0,17, 2,34,0,400,0,13 +; & -1 +;VGA21WSList2 +; & 0 +; & 18 +; VIDC_WS 1,720,400,1,2 +; & -1 + +;; MODE 56 (VGA or multisync monitors, 720x400) +;VGA22VIDCList +; & 0 +; & 19 +; VIDC_List 2,108,55,0,720,0,17, 2,34,0,400,0,13 +; & -1 +;VGA22WSList2 +; & 0 +; & 19 +; VIDC_WS 2,720,400,1,2 +; & -1 + +;; MODE 57 (VGA or multisync monitors, 720x400) +;VGA24VIDCList +; & 0 +; & 20 +; VIDC_List 4,108,55,0,720,0,17, 2,34,0,400,0,13 +; & -1 +;VGA24WSList2 +; & 0 +; & 20 +; VIDC_WS 4,720,400,1,2 +; & -1 + +;; MODE 58 (VGA or multisync monitors, 720x400) +;VGA28VIDCList +; & 0 +; & 21 +; VIDC_List 8,108,55,0,720,0,17, 2,34,0,400,0,13 +; & &E000020F +; & -1 +;VGA28WSList2 +; & 0 +; & 21 +; VIDC_WS 8,720,400,1,2 +; & -1 + +;; IBM standard form modes + +;; Mode 60 MDA, multiscan +;Multi350VIDCList +; & 0 +; & 12 +; VIDC_List 4,132,17,2,704,2,9, 17,4,0,350,0,0 +; & -1 +;Multi350WSList +; & 0 +; & 12 +; VIDC_WS 4,704,350,1,2 +; & -1 + +;; Mode 61 CGA, multiscan +;Multi200VIDCList +; & 0 +; & 12 +; VIDC_List 4,68,115,0,720,0,105, 3,34,0,200,0,25 +; & -1 +;Multi200WSList +; & 0 +; & 12 +; VIDC_WS 4,720,200,1,2 +; & -1 + +;; Mode 62 EGA, multiscan +;Multi351VIDCList +; & 0 +; & 12 +; VIDC_List 4,78,25,0,624,0,1, 13,2,0,350,0,1 +; & -1 +;Multi351WSList +; & 0 +; & 12 +; VIDC_WS 4,624,350,1,2 +; & -1 + + +;; Mode 66 , DTP multiscan 960x384 4bpp +;Multi66VIDCList +; & 0 +; & 20 +; VIDC_List 4,72,101,0,960,0,39, 3,18,0,384,0,2 +; & -1 +;Multi66WSList +; & 0 +; & 20 +; VIDC_WS 4,960,384,1,2 +; & -1 + +;; Mode 67 , DTP multiscan 960x384 8bpp +;Multi67VIDCList +; & 0 +; & 21 +; VIDC_List 8,72,101,0,960,0,39, 3,18,0,384,0,2 +; & -1 +;Multi67WSList +; & 0 +; & 21 +; VIDC_WS 8,960,384,1,2 +; & -1 + +;; Mode 76 , DTP multiscan 1280x296 4bpp +;Multi76VIDCList +; & 0 +; & 16 +; VIDC_List 4,48,111,0,1280,0,53, 3,14,0,296,0,4 +; & -1 +;Multi76WSList +; & 0 +; & 16 +; VIDC_WS 4,1280,296,1,2 +; & -1 + +;; Mode 77 , DTP multiscan 1280x296 8bpp +;Multi77VIDCList +; & 0 +; & 24 +; VIDC_List 8,48,111,0,1280,0,53, 3,14,0,296,0,4 +; & -1 +;Multi77WSList +; & 0 +; & 24 +; VIDC_WS 8,1280,296,1,2 +; & -1 + + [ Debug + InsertDebugRoutines + ] + +; ***************************************************************************** +; +; Code to execute on reset +; +; in: R14 already stacked +; + +ResetCode ROUT + Push "R0-R6" + BL ModeExt_Init + Pull "R0-R6,PC" + +; ***************************************************************************** +; +; EventRoutine - Routine called on Vsync +; + +EventRoutine ROUT + TEQ R0, #Event_VSync + MOVNE PC, R14 + ENTRY "R0-R6" + LDR R1, [R12] ; load state flag, 0 => disabled + RSBS R1, R1, #0 ; change sign + EXIT EQ ; if zero then do nowt + + STR R1, [R12] ; store back + VDWS WsPtr + LDR R2, [WsPtr, #TotalScreenSize] ; needed later as well + ADDMI R1, R1, R2 ; if -ve then add TotalScreenSize + + STR R1, [WsPtr, #TeletextOffset] + +; now set VInit to this + + LDR R0, [WsPtr, #DisplayStart] + SUB R0, R0, #ScreenEndAdr + ADD R0, R0, R2 ; make start of screen 0 + ADD R0, R0, R1 ; add on teletext bank offset + CMP R0, R2 ; if out of range + SUBCS R0, R0, R2 ; then subtract total size +SetVinitPhys + MOV R1, #Vinit + STR R0, [WsPtr, #VinitCopy] + MOV R0, R0, LSR #4 ; bottom 4 bits not valid + ORR R0, R1, R0, LSL #2 ; OR in at correct place + STR R0, [R0] ; any old data will do + + LDR R0, [WsPtr, #VIDCControlCopy] + ORR R0, R0, #Interlace ; turn interlace on + STR R0, [WsPtr, #VIDCControlCopy] + MOV R1, #VIDC + STR R0, [R1] + + EXIT + +; ***************************************************************************** + +ModeChangeService + Push "R0-R6" + MOV R5, R12 ; our workspace pointer + VDWS WsPtr + MOV R6, #0 + LDR R0, [WsPtr, #DisplayModeNo] + TEQ R0, #18 + TEQNE R0, #19 + TEQNE R0, #20 + TEQNE R0, #21 + TEQNE R0, #26 + TEQNE R0, #27 + BNE %FT10 + MOV R0, #&A1 + MOV R1, #VduCMOS + SWI XOS_Byte + ANDS R2, R2, #MonitorTypeBits + BNE %FT10 + + MOV R0, #255 + STR R0, [WsPtr, #DisplayYWindLimit] + LDR R0, [WsPtr, #YEigFactor] + ADD R0, R0, #1 + STR R0, [WsPtr, #DisplayYEigFactor] + LDR R0, =541-6 + STR R0, [WsPtr, #CursorFudgeFactor] + + LDR R6, [WsPtr, #LineLength] + MOV R6, R6, LSR #1 + RSB R6, R6, #0 +10 + STR R6, [R5] + Pull "R0-R6, PC" + +; ***************************************************************************** +; +; ModeTranslation - Code to perform VGA mode number translation +; +; in: R1 = Service_ModeTranslation +; R2 = mode number +; R3 = monitor type +; return address stacked +; +; out: R1 = 0 if claimed +; R2 = substitute +; R3 preserved + +ModeTranslation ROUT + TEQ R3, #MonitorType_VGA + Pull PC, NE + BIC R1, R2, #&80 ; get rid of shadow bit + CMP R1, #32 ; if in range 32..39 + RSBCSS R1, R1, #39 + BCS %FT10 ; then don't modify + + [ {TRUE} + MOV R2, #0 + | + Push R0 + MOV R0, R2 + MOV R1, #9 ; log2bpp + SWI XOS_ReadModeVariable + Pull R0 + MOVVS R2, #0 ; if error or invalid then use mode 32 + MOVCS R2, #0 + CMP R2, #4 + MOVCS R2, #3 + ADD R2, R2, #32 + ] +10 + MOV R1, #0 ; claim service + Pull PC + + END + diff --git a/NewModes/OldToNew,ffb b/NewModes/OldToNew,ffb new file mode 100644 index 0000000000000000000000000000000000000000..982d10c2346510cefd9691867c6d7f539f57082e Binary files /dev/null and b/NewModes/OldToNew,ffb differ diff --git a/NewModes/PSSrc b/NewModes/PSSrc new file mode 100644 index 0000000000000000000000000000000000000000..a9b05b5f3a3c6f9e764b70318345a4e2d2a1057a --- /dev/null +++ b/NewModes/PSSrc @@ -0,0 +1,791 @@ +; > NewModes.PSSrc +; 08-Nov-89 + + GET &.Hdr.ListOpts + GET &.Hdr.Macros + GET &.Hdr.System + GET &.Hdr.NewSpace + GET &.Hdr.ModHand + GET &.Hdr.Services + GET &.Hdr.Proc + GET &.Hdr.File + GET &.Hdr.NewErrors + GET &.Hdr.VduExt + GET &.Hdr.Debug + GET &.Hdr.CMOS + + LEADR Module_LoadAddr + + GBLL Debug +Debug SETL {FALSE} + + GBLL Module +Module SETL {TRUE} ; Really ! + +TAB * 9 +LF * 10 +FF * 12 +CR * 13 + +MonitorType_Normal * 0 +MonitorType_MultiSync * 1 +MonitorType_HiResMono * 2 +MonitorType_VGA * 3 +MonitorType_DontCare * -1 + +Normal * 1 :SHL: MonitorType_Normal +MultiSync * 1 :SHL: MonitorType_MultiSync +HiResMono * 1 :SHL: MonitorType_HiResMono +VGA * 1 :SHL: MonitorType_VGA + +ScreenEndAdr * &02000000 +Vinit * &03600000 +Interlace * &40 + + MACRO + NewMode $modeno, $monitors, $vidclist, $wslist + & $modeno + & $monitors +99 + & ($vidclist)-%BT99 + & ($wslist)-%BT99 + MEND + +; Module workspace allocation + + ^ 0, R12 + +ModeExt_WorkspaceSize * :INDEX: @ + +; **************** Module code starts here ********************** + +Module_BaseAddr + + DCD 0 + DCD ModeExt_Init -Module_BaseAddr + DCD ModeExt_Die -Module_BaseAddr + DCD ModeExt_Service -Module_BaseAddr + DCD ModeExt_Title -Module_BaseAddr + DCD ModeExt_HelpStr -Module_BaseAddr + DCD ModeExt_HC_Table-Module_BaseAddr + +ModeExt_Title + = "NewModes", 0 + +ModeExt_HelpStr + = "NewModes" + = TAB + = "1.3 (08 Nov 1989) test Multisync Modes", 0 + ALIGN + +; ***************************************************************************** + +ModeExt_HC_Table * Module_BaseAddr + +; ***************************************************************************** +; +; ModeExt_Init - Initialisation entry point +; + +ModeExt_Init ENTRY + + MOV R0, #EventV + ADRL R1, EventRoutine + MOV R2, R12 + SWI XOS_Claim + MOVVC R0, #14 + MOVVC R1, #Event_VSync + SWIVC XOS_Byte + EXIT + +; ***************************************************************************** +; +; ModeExt_Die - Die entry +; + +ModeExt_Die ENTRY + + MOV R0, #13 + MOV R1, #Event_VSync + SWI XOS_Byte + MOV R0, #EventV + ADRL R1, EventRoutine + MOV R2, R12 + SWI XOS_Release + EXITS + +; ***************************************************************************** +; +; ModeExt_Service - Main entry point for services +; +; in: R1 = service reason code +; + +ModeExt_Service ENTRY + TEQ R1, #Service_ModeExtension + TEQNE R1, #Service_PreModeChange + TEQNE R1, #Service_ModeChange + TEQNE R1, #Service_Reset + TEQNE R1, #Service_ModeTranslation + EXIT NE + + TEQ R1, #Service_PreModeChange + MOVEQ R14, #0 ; zero the word + STREQ R14, [R12] + EXIT EQ + + TEQ R1, #Service_ModeChange + BEQ ModeChangeService + + TEQ R1, #Service_Reset + BEQ ResetCode + + TEQ R1, #Service_ModeTranslation + BEQ ModeTranslation + + [ Debug + DREG R2, "Mode = " + DREG R3, "Monitor type = " + ] + + Push "R5-R8" + + ADR R5, NewModesList-8 + MOV R8, #1 +10 + ADD R5, R5, #8 ; skip VidC, WS + LDMIA R5!, {R6, R7} ; R6 = mode, R7 = OK monitor types + CMP R6, #-1 + Pull "R5-R8, PC", EQ ; mode not in list, exit + TEQ R2, R6 ; if not this mode + BNE %BT10 ; then loop + CMP R3, #MonitorType_DontCare ; if any monitor type + BEQ %FT20 ; then found one + TST R7, R8, LSL R3 ; else if not appropriate monitor + BEQ %BT10 ; then loop +20 + LDMIA R5, {R3, R4} ; load offsets to VidCList, WSList + ADD R3, R3, R5 ; convert to addresses + ADD R4, R4, R5 ; convert to addresses + MOV R1, #0 ; claim service + Pull "R5-R8, PC" + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +NewModesList + + NewMode 0, MultiSync, Multi100VIDCList, Multi100WSList ; rshifted Mode 0 + NewMode 1, MultiSync, Multi101VIDCList, Multi101WSList ; rshifted Mode 1 + NewMode 2, MultiSync, Multi102VIDCList, Multi102WSList ; rshifted Mode 2 + NewMode 3, MultiSync, Multi103VIDCList, Multi103WSList ; rshifted Mode 3 + NewMode 4, MultiSync, Multi104VIDCList, Multi104WSList ; rshifted Mode 4 + NewMode 5, MultiSync, Multi105VIDCList, Multi105WSList ; rshifted Mode 5 + NewMode 6, MultiSync, Multi106VIDCList, Multi106WSList ; rshifted Mode 6 + NewMode 7, MultiSync, Multi107VIDCList, Multi107WSList ; rshifted Mode 7 + NewMode 8, MultiSync, Multi108VIDCList, Multi108WSList ; rshifted Mode 8 + NewMode 9, MultiSync, Multi109VIDCList, Multi109WSList ; rshifted Mode 9 + NewMode 10, MultiSync, Multi110VIDCList, Multi110WSList ; rshifted Mode 10 + NewMode 11, MultiSync, Multi111VIDCList, Multi111WSList ; rshifted Mode 11 + NewMode 12, MultiSync, Multi112VIDCList, Multi112WSList ; rshifted Mode 12 + NewMode 13, MultiSync, Multi113VIDCList, Multi113WSList ; rshifted Mode 13 + NewMode 14, MultiSync, Multi114VIDCList, Multi114WSList ; rshifted Mode 14 + NewMode 15, MultiSync, Multi115VIDCList, Multi115WSList ; rshifted Mode 15 + NewMode 16, MultiSync, Multi116VIDCList, Multi116WSList ; rshifted Mode 16 + NewMode 17, MultiSync, Multi117VIDCList, Multi117WSList ; rshifted Mode 17 + NewMode 18, MultiSync, Multi118VIDCList, Multi118WSList ; rshifted Mode 18 + NewMode 19, MultiSync, Multi119VIDCList, Multi119WSList ; rshifted Mode 19 + NewMode 20, MultiSync, Multi120VIDCList, Multi120WSList ; rshifted Mode 20 + NewMode 21, MultiSync, Multi121VIDCList, Multi121WSList ; rshifted Mode 21 + + NewMode 24, MultiSync, Multi124VIDCList, Multi124WSList ; rshifted Mode 24 + + NewMode 25, VGA :OR: MultiSync, VGA1VIDCList, VGA1WSList2 ; VGA 1bp 640x480 + NewMode 26, VGA :OR: MultiSync, VGA2VIDCList, VGA2WSList2 ; VGA 2bp 640x480 + NewMode 27, VGA :OR: MultiSync, VGA4VIDCList, VGA4WSList2 ; VGA 4bp 640x480 + NewMode 28, VGA :OR: MultiSync, VGA8VIDCList, VGA8WSList2 ; VGA 8bp 640x480 + + NewMode 31, MultiSync, sVGA4_VIDCList, sVGA4_WSList ; super VGA 4bp 800x600 + NewMode 32, MultiSync, sVGA8_VIDCList, sVGA8_WSList ; super VGA 8bp 800x600 + + NewMode 33, Normal :OR: MultiSync, Mode33VIDCList, Mode33WSList ; overscan 768x288 + NewMode 34, Normal :OR: MultiSync, Mode34VIDCList, Mode34WSList ; overscan 832x288 + + & -1, 0 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; general purpose mode macros + +ClockShift * 9 +SyncShift * 11 + +; pixel rate specifiers + +CRPix_24000 * 3 :OR: (0 :SHL: ClockShift) +CRPix_16000 * 2 :OR: (0 :SHL: ClockShift) +CRPix_12000 * 1 :OR: (0 :SHL: ClockShift) +CRPix_8000 * 0 :OR: (0 :SHL: ClockShift) +CRPix_25175 * 3 :OR: (1 :SHL: ClockShift) +CRPix_36000 * 3 :OR: (2 :SHL: ClockShift) + + MACRO + VIDC_List $lbpp,$hsync,$hbpch,$hlbdr,$hdisp,$hrbdr,$hfpch, $vsync,$vbpch,$vlbdr,$vdisp,$vrbdr,$vfpch,$pixrate,$sp + LCLA sub + LCLA syncpol + [ $lbpp = 3 +sub SETA 5 + ] + [ $lbpp = 2 +sub SETA 7 + ] + [ $lbpp = 1 +sub SETA 11 + ] + [ $lbpp = 0 +sub SETA 19 + ] + [ "$sp"="" +syncpol SETA 0 :SHL: SyncShift ; normal sync polarity + | + ASSERT $sp<=3 +syncpol SETA $sp :SHL: SyncShift + ] + ASSERT ($hsync :AND: 1)=0 + ASSERT ($hbpch :AND: 1)=1 + ASSERT ($hlbdr :AND: 1)=0 + ASSERT ($hdisp :AND: 1)=0 + ASSERT ($hrbdr :AND: 1)=0 + ASSERT ($hfpch :AND: 1)=1 + [ (($hsync+$hbpch+$hlbdr+$hdisp+$hrbdr+$hfpch) :AND: 3)<>0 + ! 0, "Warning: mode unsuitable for interlaced use" + ] +; Horizontal + & (&80:SHL:24) :OR: ((($hsync+$hbpch+$hlbdr+$hdisp+$hrbdr+$hfpch -2 )/2) :SHL: 14) ; HCR + & (&84:SHL:24) :OR: ((($hsync -2 )/2) :SHL: 14) ; HSWR + & (&88:SHL:24) :OR: ((($hsync+$hbpch -1 )/2) :SHL: 14) ; HBSR + & (&8C:SHL:24) :OR: ((($hsync+$hbpch+$hlbdr -sub)/2) :SHL: 14) ; HDSR + & (&90:SHL:24) :OR: ((($hsync+$hbpch+$hlbdr+$hdisp -sub)/2) :SHL: 14) ; HDER + & (&94:SHL:24) :OR: ((($hsync+$hbpch+$hlbdr+$hdisp+$hrbdr -1 )/2) :SHL: 14) ; HBER + & (&9C:SHL:24) :OR: (((($hsync+$hbpch+$hlbdr+$hdisp+$hrbdr+$hfpch-2)/2+1)/2):SHL:14); HIR +; Vertical + & (&A0:SHL:24) :OR: (($vsync+$vbpch+$vlbdr+$vdisp+$vrbdr+$vfpch -1) :SHL: 14) ; VCR + & (&A4:SHL:24) :OR: (($vsync -1) :SHL: 14) ; VSWR + & (&A8:SHL:24) :OR: (($vsync+$vbpch -1) :SHL: 14) ; VBSR + & (&AC:SHL:24) :OR: (($vsync+$vbpch+$vlbdr -1) :SHL: 14) ; VDSR + & (&B0:SHL:24) :OR: (($vsync+$vbpch+$vlbdr+$vdisp -1) :SHL: 14) ; VDER + & (&B4:SHL:24) :OR: (($vsync+$vbpch+$vlbdr+$vdisp+$vrbdr -1) :SHL: 14) ; VBER +; Control Register + & (&E0:SHL:24) :OR: (CRPix_$pixrate) :OR: ($lbpp :SHL: 2) :OR: syncpol + MEND + + MACRO + VIDC_WS $bpp,$hpix,$vpix,$multx,$multy, $dht + + & VduExt_XWindLimit, $hpix-1 + & VduExt_ScrRCol, ($hpix/8)-1 + & VduExt_LineLength, $hpix*$bpp/8 + [ "$dht" <> "" + & VduExt_ModeFlags, Flag_DoubleVertical + & VduExt_ScrBRow, ($vpix/16)-1 + | + & VduExt_ScrBRow, ($vpix/8)-1 + ] + & VduExt_YWindLimit, $vpix-1 + & VduExt_ScreenSize, $hpix*$vpix*$bpp/8 + + & VduExt_XEigFactor, $multx + & VduExt_YEigFactor, $multy + MEND + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +; Start of multi sync archy modes + +; Mode 0, multiscan mode 0 +Multi100VIDCList + & 0 + & 0 + VIDC_List 0,72,63,88,640,88,73, 3,16,17,256,17,3,16000,0 + & -1 +Multi100WSList + & 0 + & 0 + & -1 + +; Mode 1, multiscan mode 1 +Multi101VIDCList + & 0 + & 1 + VIDC_List 1,36,33,44,320,44,35, 3,16,17,256,17,3,8000,0 + & -1 +Multi101WSList + & 0 + & 1 + & -1 + +; Mode 2, multiscan mode 2 +Multi102VIDCList + & 0 + & 2 + VIDC_List 2,36,33,44,320,44,35, 3,16,17,256,17,3,8000,0 + & -1 +Multi102WSList + & 0 + & 2 + & -1 + +; Mode 3, multiscan mode 3 +Multi103VIDCList + & 0 + & 3 + VIDC_List 1,72,63,88,640,88,73, 3,16,20,250,20,3,16000,0 + & -1 +Multi103WSList + & 0 + & 3 + & -1 + +; Mode 4, multiscan mode 4 +Multi104VIDCList + & 0 + & 4 + VIDC_List 0,72,63,88,640,88,73, 3,16,17,256,17,3,16000,0 + & -1 +Multi104WSList + & 0 + & 4 + & -1 + +; Mode 5, multiscan mode 5 +Multi105VIDCList + & 0 + & 5 + VIDC_List 1,36,51,24,320,24,57, 3,16,17,256,17,3,8000,0 + & -1 +Multi105WSList + & 0 + & 5 + & -1 + +; Mode 6, multiscan mode 6 +Multi106VIDCList + & 0 + & 6 + VIDC_List 1,36,33,44,320,44,35, 3,16,20,250,20,3,8000,0 + & -1 +Multi106WSList + & 0 + & 6 + & -1 + +; Mode 7, multiscan mode 7 +Multi107VIDCList + & 0 + & 7 + VIDC_List 2,36,31,44,320,44,37, 3,18,22,250,16,3,8000,0 + & -1 +Multi107WSList + & 0 + & 7 + & -1 + +; Mode 8, multiscan mode 8 +Multi108VIDCList + & 0 + & 8 + VIDC_List 1,72,63,88,640,88,73, 3,16,17,256,17,3,16000,0 + & -1 +Multi108WSList + & 0 + & 8 + & -1 + +; Mode 9, multiscan mode 9 +Multi109VIDCList + & 0 + & 9 + VIDC_List 2,36,33,44,320,44,35, 3,16,17,256,17,3,8000,0 + & -1 +Multi109WSList + & 0 + & 9 + & -1 + +; Mode 10, multiscan mode 10 +Multi110VIDCList + & 0 + & 10 + VIDC_List 3,36,33,44,320,44,35, 3,16,17,256,17,3,8000,0 + & -1 +Multi110WSList + & 0 + & 10 + & -1 + +; Mode 11, multiscan mode 11 +Multi111VIDCList + & 0 + & 11 + VIDC_List 1,72,63,88,640,88,73, 3,16,20,250,20,3,16000,0 + & -1 +Multi111WSList + & 0 + & 11 + & -1 + +; Mode 12, multiscan mode 12 +Multi112VIDCList + & 0 + & 12 + VIDC_List 2,72,63,88,640,88,73, 3,16,17,256,17,3,16000,0 + & -1 +Multi112WSList + & 0 + & 12 + & -1 + +; Mode 13, multiscan mode 13 +Multi113VIDCList + & 0 + & 13 + VIDC_List 3,36,33,44,320,44,35, 3,16,17,256,17,3,8000,0 + & -1 +Multi113WSList + & 0 + & 13 + & -1 + +; Mode 14, multiscan mode 14 +Multi114VIDCList + & 0 + & 14 + VIDC_List 2,72,63,88,640,88,73, 3,16,20,250,20,3,16000,0 + & -1 +Multi114WSList + & 0 + & 14 + & -1 + +; Mode 15, multiscan mode 15 +Multi115VIDCList + & 0 + & 15 + VIDC_List 3,72,63,88,640,88,73, 3,16,17,256,17,3,16000,0 + & -1 +Multi115WSList + & 0 + & 15 + & -1 + +; Mode 16, multiscan mode 16 +Multi116VIDCList + & 0 + & 16 + VIDC_List 2,112,47,132,1056,132,57, 3,16,17,256,17,3,24000,0 +; +; tv blanking! 112,139, 76,1056,114, 39, ,3,18,16,256,16,3 +; 4u67,5u79,3u2,44u,4u7,1u62, 21r 3r +; should be =10u4 =1u65 22r 3r(2r5) +;philips needs bprch > 57 or goes dark (sync at 112) +; can inc sync to 10u0, more and screen starts to wobble + & -1 +Multi116WSList + & 0 + & 16 + & -1 + +; Mode 17, multiscan mode 17 +Multi117VIDCList + & 0 + & 17 + VIDC_List 2,112,47,132,1056,132,57, 3,16,20,250,20,3,24000,0 + & -1 +Multi117WSList + & 0 + & 17 + & -1 + +; Mode 18, multiscan mode 18 +Multi118VIDCList + & 0 + & 18 + VIDC_List 0,56,111,2,640,2,85, 3,17,1,512,1,0,24000,0 + & -1 +Multi118WSList + & 0 + & 18 + & -1 + +; Mode 19, multiscan mode 19 +Multi119VIDCList + & 0 + & 19 + VIDC_List 1,56,111,2,640,2,85, 3,17,1,512,1,0,24000,0 + & -1 +Multi119WSList + & 0 + & 19 + & -1 + +; Mode 20, multiscan mode 20 +Multi120VIDCList + & 0 + & 20 + VIDC_List 2,56,111,2,640,2,85, 3,17,1,512,1,0,24000,0 + & -1 +Multi120WSList + & 0 + & 20 + & -1 + +; Mode 21, multiscan mode 21 +Multi121VIDCList + & 0 + & 21 + VIDC_List 3,56,111,2,640,2,85, 3,17,1,512,1,0,24000,0 + & -1 +Multi121WSList + & 0 + & 21 + & -1 + +; Mode 24, multiscan mode 24 +Multi124VIDCList + & 0 + & 24 + VIDC_List 3,112,47,132,1056,132,57, 3,16,17,256,17,3,24000,0 + & -1 +Multi124WSList + & 0 + & 24 + & -1 + + +; MODE 25 (VGA or multisync monitors, 640x480) +VGA1VIDCList + & 0 + & 18 + VIDC_List 0,96,47,0,640,0,15, 2,32,0,480,0,11,25175,3 + & -1 +VGA1WSList2 + & 0 + & 18 + & -1 + +; MODE 26 (VGA or multisync monitors, 640x480) +VGA2VIDCList + & 0 + & 19 + VIDC_List 1,96,47,0,640,0,15, 2,32,0,480,0,11,25175,3 + & -1 +VGA2WSList2 + & 0 + & 19 + & -1 + +; MODE 27 (VGA or multisync monitors, 640x480) +VGA4VIDCList + & 0 + & 20 + VIDC_List 2,96,47,0,640,0,15, 2,32,0,480,0,11,25175,3 + & -1 +VGA4WSList2 + & 0 + & 20 + & -1 + +; MODE 28 (VGA or multisync monitors, 640x480) +VGA8VIDCList + & 0 + & 21 + VIDC_List 3,96,47,0,640,0,15, 2,32,0,480,0,11,25175,3 + & -1 +VGA8WSList2 + & 0 + & 21 + & -1 + +; MODE 31 (800x600 by 4 bits per pixel) +sVGA4_VIDCList + & 0 + & 20 + VIDC_List 2,72,129,0,800,0,23, 2,22,0,600,0,1,36000,0 + & -1 +sVGA4_WSList + & 0 + & 20 + VIDC_WS 4,800,600,1,1 + & -1 + +; MODE 32 (800x600 by 8 bits per pixel) +sVGA8_VIDCList + & 0 + & 24 + VIDC_List 3,72,129,0,800,0,23, 2,22,0,600,0,1,36000,0 + & -1 +sVGA8_WSList + & 0 + & 24 + VIDC_WS 8,800,600,1,1 + & -1 + +; MODE 33 (768x288 by 8 bits per pixel) +Mode33VIDCList + + & 0 + & 15 + VIDC_List 3,74,127,0,768,0,55, 3,18,0,288,0,3,16000,0 + & -1 +Mode33WSList + & 0 + & 15 + VIDC_WS 8,768,288,1,2 + & -1 + +; MODE 34 (832x288 by 8 bits per pixel) +Mode34VIDCList + & 0 + & 15 + VIDC_List 3,74,87,0,832,0,31, 3,18,0,288,0,3,16000,0 + & -1 +Mode34WSList + & 0 + & 15 + VIDC_WS 8,832,288,1,2 + & -1 + + [ Debug + InsertDebugRoutines + ] + +; ***************************************************************************** +; +; Code to execute on reset +; +; in: R14 already stacked +; + +ResetCode ROUT + Push "R0-R6" + BL ModeExt_Init + Pull "R0-R6,PC" + +; ***************************************************************************** +; +; EventRoutine - Routine called on Vsync +; + +EventRoutine ROUT + TEQ R0, #Event_VSync + MOVNE PC, R14 + ENTRY "R0-R6" + LDR R1, [R12] ; load state flag, 0 => disabled + RSBS R1, R1, #0 ; change sign + EXIT EQ ; if zero then do nowt + + STR R1, [R12] ; store back + VDWS WsPtr + LDR R2, [WsPtr, #TotalScreenSize] ; needed later as well + ADDMI R1, R1, R2 ; if -ve then add TotalScreenSize + + STR R1, [WsPtr, #TeletextOffset] + +; now set VInit to this + + LDR R0, [WsPtr, #DisplayStart] + SUB R0, R0, #ScreenEndAdr + ADD R0, R0, R2 ; make start of screen 0 + ADD R0, R0, R1 ; add on teletext bank offset + CMP R0, R2 ; if out of range + SUBCS R0, R0, R2 ; then subtract total size +SetVinitPhys + MOV R1, #Vinit + STR R0, [WsPtr, #VinitCopy] + MOV R0, R0, LSR #4 ; bottom 4 bits not valid + ORR R0, R1, R0, LSL #2 ; OR in at correct place + STR R0, [R0] ; any old data will do + + LDR R0, [WsPtr, #VIDCControlCopy] + ORR R0, R0, #Interlace ; turn interlace on + STR R0, [WsPtr, #VIDCControlCopy] + MOV R1, #VIDC + STR R0, [R1] + + EXIT + +; ***************************************************************************** + +ModeChangeService + Push "R0-R6" + MOV R5, R12 ; our workspace pointer + VDWS WsPtr + MOV R6, #0 + LDR R0, [WsPtr, #DisplayModeNo] + TEQ R0, #18 + TEQNE R0, #19 + TEQNE R0, #20 + TEQNE R0, #21 + TEQNE R0, #26 + TEQNE R0, #27 + BNE %FT10 + MOV R0, #&A1 + MOV R1, #VduCMOS + SWI XOS_Byte + ANDS R2, R2, #MonitorTypeBits + BNE %FT10 + + MOV R0, #255 + STR R0, [WsPtr, #DisplayYWindLimit] + LDR R0, [WsPtr, #YEigFactor] + ADD R0, R0, #1 + STR R0, [WsPtr, #DisplayYEigFactor] + LDR R0, =541-6 + STR R0, [WsPtr, #CursorFudgeFactor] + + LDR R6, [WsPtr, #LineLength] + MOV R6, R6, LSR #1 + RSB R6, R6, #0 +10 + STR R6, [R5] + Pull "R0-R6, PC" + +; ***************************************************************************** +; +; ModeTranslation - Code to perform VGA mode number translation +; +; in: R1 = Service_ModeTranslation +; R2 = mode number +; R3 = monitor type +; return address stacked +; +; out: R1 = 0 if claimed +; R2 = substitute +; R3 preserved + +ModeTranslation ROUT + TEQ R3, #MonitorType_VGA + Pull PC, NE + BIC R1, R2, #&80 ; get rid of shadow bit + CMP R1, #32 ; if in range 32..39 + RSBCSS R1, R1, #39 + BCS %FT10 ; then don't modify + + [ {TRUE} + MOV R2, #0 + | + Push R0 + MOV R0, R2 + MOV R1, #9 ; log2bpp + SWI XOS_ReadModeVariable + Pull R0 + MOVVS R2, #0 ; if error or invalid then use mode 32 + MOVCS R2, #0 + CMP R2, #4 + MOVCS R2, #3 + ADD R2, R2, #32 + ] +10 + MOV R1, #0 ; claim service + Pull PC + + END + diff --git a/OldTestSrc/A600tlb b/OldTestSrc/A600tlb new file mode 100644 index 0000000000000000000000000000000000000000..6481c8b3ae56a34333abc2a617bc3efe58a6a586 --- /dev/null +++ b/OldTestSrc/A600tlb @@ -0,0 +1,61 @@ +; +; A600tlb +; +; POST procedure for checking the TLB in A600 MMU. +; +; for each of level 1, level 2 small-page, level 2 large-page +; construct page table +; flush cache +; start timer +; for 32 addresses (with different mappings) +; check address mapping +; save timer +; for same 32 addresses +; check address mapping +; compare test times (did 2nd test require table walk ?) + + + + + +Use a list of addresses that cover a good mixture of virtual addresses +Build a page table that maps these to physical RAM addresses in various ways +Access the addresses in such an order that the cache rotates, scrapping +one entry each time through the list, and loading another. So each cache +entry gets used 31 times, then is lost. +Choice of physical mapping should ensure that the cache entries contain +lots of different values of page and section base addresses. +Choice of virtual test address should ensure that cache tag varies as +widely as posible, too. PRBS ? +Very widely varying values of cache tag require that a large number +of mappings exist .. if these are 2-level mappings, that requires +a lot of RAM. Page tables should be multiply-mapped. +RISC OS puts lots of stuff below the 4M mark. Limits App space to 16M +for backwards compatibility. Probably worth testing outside these +limits to ensure Gold doesn't fall over, but failure rates would be +very low. + + + + +; +; POST procedure for checking access faults (was PPL test) +; +; for each of level 1, level 2 small-page, level 2 large-page +; construct page table +; for user, supervisor mode +; check address alignment fault +; check section translation fault +; check +; check page translation fault +; for 3 domain types +; for 16 domains +; check access permissions +; + + + +; +; POST procedure for checking IDC +; +; diff --git a/OldTestSrc/Arm3 b/OldTestSrc/Arm3 new file mode 100644 index 0000000000000000000000000000000000000000..a385f75f4cbbd089f79c6ac394810fa1b4dd0109 --- /dev/null +++ b/OldTestSrc/Arm3 @@ -0,0 +1,71 @@ +; > TestSrc.ARM3 + + TTL RISC OS 2+ POST ARM version determination +; +; Reads ARM3 version register, returns 0 if ARM 2 fitted. +; +;------------------------------------------------------------------------ +; History +; +; Date Name Comment +; ---- ---- ------- +; 20-Apr-89 ArtG Initial version +; +; +;------------------------------------------------------------------------ + +A3Cid CN 0 +A3Cfls CN 1 +A3Cmod CN 2 +A3Ccac CN 3 +A3Cupd CN 4 +A3Cdis CN 5 + +A3CON CP 15 + + + +ts_ARM_type + MOV r13,lr +; +; First, set up an undefined instruction vector to catch an ARM 2 +; (or a faulty ARM 3 ??) when the copro instruction is run. +; Only applies on systems where ROM isn't mapped at zero. + + [ CPU_Type = "ARM2" :LOR: CPU_Type = "ARM3" + MOV r0,#0 ; set a page at logical 0 + MOV r1,r0 + BL ts_set_cam + ADR r0,ts_ARM_undefined + LDMIA r0,{r2,r3} + MOV r1,#4 + STMIA r1,{r2,r3} ; set the undefined instruction trap + ] +; +; Read ARM3C0 version I.D. +; + MOV r0, #(-1) ; should always be altered + MRC A3CON,0,r0,A3Cid,A3Cid ; Read control register 0 + MOV r12, r0 + [ CPU_Type = "ARM2" :LOR: CPU_Type = "ARM3" + MOV r1,#0 + BL ts_set_cam_idle ; remove the vector page again + ] + MOVS r0, r12 ; return the ID (0 for ARM 2) + MOV pc,r13 + +; +; Trap to be taken when ARM 2 is fitted +; + +ts_ARM_undefined + MOV r0,#0 + MOVS pc,r14_svc +10 + ASSERT ((%10 - ts_ARM_undefined) / 4 = 2) + + + + + END + diff --git a/OldTestSrc/Begin b/OldTestSrc/Begin new file mode 100644 index 0000000000000000000000000000000000000000..b4b65b2d128da4c53e8184152d27393c5259a372 --- /dev/null +++ b/OldTestSrc/Begin @@ -0,0 +1,1428 @@ +; > TestSrc.Begin + + TTL RISC OS 2+ Power-On Self-Test +; +; Startup code for RISC OS ROM Self-Test. +; +; Performs ROM test patterns, determines test strategy and enters +; external or internal test code. +; +; A minimal set of opcodes should be used (ideally, only B, LDR and ADDS) +; so that a processor test may be validly included in the internal test +; sequence. +; +;------------------------------------------------------------------------ +; History +; +; Date Name Rel Comment +; ---- ---- --- ------- +; 23-Feb-93 ArtG 2.00 Experimental ARM 600 / Jordan mods +; 20-Oct-93 ARTG 2.02 Changed to new conditional assembly scheme +; +;------------------------------------------------------------------------ + +; TS_STATUS should be one of : +; +; 'R' RISC OS POST +; 'S' Standalone version (with a2 memory test instead of RISCOS) +; 'T' Test build - development only +; + +TS_STATUS * "R" ; Medusa POST version 2.0x +; +TS_RELEASE * 20 +TS_CHANGES * 4 + + + GBLL POSTenabled +POSTenabled SETL {TRUE} ; don't permit POST for ordinary startup + +ts_Rom_bits * 21 ; Widest ROM address +ts_Rom_length * 1 :SHL: ts_Rom_bits ; Longest ROM +ts_highaddr_bit * 1 :SHL: 25 ; ARM address width +ts_Alias_bits * (1 :SHL: 23) ; I/F output bits +ts_recover_time * (1 :SHL: 8) ; inter-twiddle delay +ts_pause_time * 200 ; Display pause time +ts_S5_base * &3350000 ; IO register base address +ts_IOEB_ID * (ts_S5_base + &50) ; IOE_B ASIC identification +ts_IOEB_ident * &5 ; the value found there +ts_PCaddress * &3010000 ; PC IO world base address +ts_ReadyByte_00 * &90 ; signal 'Here I am' to ExtIO +ts_BBRAM * &A0 ; IIC address of clock/ram chip +ts_RamChunk * &2000 ; gap between data line tests +ts_MaxRamTest * 4*1024*1024 ; Max. DRAM tested on normal reset +ts_VIDCPhys * &3400000 ; Real location of VIDC + +; +; Border colours used for self-test indicators +; + [ VIDC_Type = "VIDC1a" +C_ARMOK * &40000000+&70C ; testing ROM +C_RAMTEST * &40000000+&C70 ; testing RAM +C_FAULT * &40000000+&00F ; failed tests +C_PASSED * &40000000+&7C0 ; all passed +C_WARMSTART * &40000000+&777 ; not tested + ] + + [ VIDC_Type = "VIDC20" +C_ARMOK * &40000000+&7000C0 ; testing ROM +C_RAMTEST * &40000000+&C07000 ; testing RAM +C_FAULT * &40000000+&0000F0 ; failed tests +C_PASSED * &40000000+&70C000 ; all passed +C_WARMSTART * &40000000+&707070 ; not tested + ] + +; +; Responses to external commands +; + +ErrorCmd * &00FF + + +; +; Control bitmasks used to indicate results of test to RISCOS +; + +R_SOFT * 0 ; not a power-on reset +R_HARD * 1 ; Self-test run due to POR +R_EXTERN * 2 ; external tests performed +R_TESTED * 4 ; Self-test run due to test link +R_MEMORY * 8 ; Memory has been tested +R_ARM3 * &10 ; ARM 3 fitted +R_MEMSKIP * &20 ; long memory test disabled +R_IOEB * &40 ; PC-style IO controller +R_VRAM * &80 ; VRAM present + +R_STATUS * &1ff ; bits that aren't a fault + +R_CHKFAILBIT * &100 ; CMOS contents failed checksum +R_ROMFAILBIT * &200 ; ROM failed checksum +R_CAMFAILBIT * &400 ; CAM failed +R_PROFAILBIT * &800 ; MEMC protection failed +R_IOCFAILBIT * &1000 ; IOC register test failed +R_INTFAILBIT * &2000 ; Cannot clear interrupts +R_VIDFAILBIT * &4000 ; VIDC flyback failure +R_SNDFAILBIT * &8000 ; Sound DMA failure +R_CMSFAILBIT * &10000 ; CMOS unreadable +R_LINFAILBIT * &20000 ; Page zero RAM failure +R_MEMFAILBIT * &40000 ; Main RAM test failure +R_CACFAILBIT * &80000 ; ARM 3 Cache test failure +; + [ MorrisSupport +Kludge * 96 + | +Kludge * 0 + ] + SUBT Exception vectors +; +; These vectors are available for use while the Rom is mapped into +; low memory addresses. The Reset vector will be copied to low RAM +; as part of a software reset sequence : therefore it must perform +; a fixed operation to ensure compatibility with future versions +; of RISC-OS. +; + +Reset +ts_start + $DoMorrisROMHeader + + [ :LNOT: MorrisSupport + [ ResetIndirected + LDR pc,.+ResetIndirection ; load pc from vector at &118 + | + B ts_RomPatt + PhysROM ; Jump to normal ROM space + ] + ] +01 + & ts_Rom_length ; gets patched by ROM builder +02 + & (ts_ROM_cvectors - ROM) ; pointer to code vector table +03 + & (ts_ROM_dvectors - ROM) ; pointer to data vector table +04 + & (ts_ROM_bvectors - ROM) ; pointer to branch table + B Reset ; not currently used + B Reset + B Reset + + +ts_ROMSIZE * %BT01 - ts_start +ts_CVECTORS * %BT02 - ts_start +ts_DVECTORS * %BT03 - ts_start +ts_BVECTORS * %BT04 - ts_start + +; +; Selftest version ID +; + +00 + ASSERT %B00 <= (ts_start + &2c + Kludge) + % ((ts_start + &2c + Kludge) - %B00) + +ts_ID & ((TS_STATUS :SHL: 24) + (TS_RELEASE :SHL: 16) + TS_CHANGES) + +ts_ID_text +ts_himsg + = "SELFTEST" ; **DISPLAY_TEXT** + = &89 ; Cursor position + = TS_STATUS + = ("0" + (TS_RELEASE / 10)) + = "." + = ("0" + (TS_RELEASE :MOD: 10)) + = ("0" + (TS_CHANGES :MOD: 10)) + = 0 + + +; +; These vector tables permit access by the external (or downloaded) test +; software to data and code in the POST modules. +; Find the start of these tables through the 2nd and 3rd vectors at +; the start of the ROM. +; + +ts_ROM_dvectors +01 + & ts_ID ; Selftest identification number +02 + & (ts_ID_text - ROM) ; Selftest identification text + + +; +; vectors ORd with these flags to assure proper mode when +; executed by host thro' vector table. +; + +ts_runflags * (I_bit :OR: F_bit :OR: SVC_mode) + +ts_ROM_cvectors + & ts_RomPatt :OR: ts_runflags + & ts_User_startup :OR: ts_runflags + & ts_Self_test_startup :OR: ts_runflags + & ts_Dealer_startup :OR: ts_runflags + & ts_Forced_startup :OR: ts_runflags + & ts_GetCommand :OR: ts_runflags + & ts_Softstart :OR: ts_runflags + & ts_Hardstart :OR: ts_runflags + + +; +; ROM branch vectors - intended primarily so downloaded programs +; may use standard subroutines. This table should be in a fixed place. +; + +00 + ASSERT %B00 <= (ts_start + 128 + Kludge) + % ((ts_start + 128 + Kludge) - %B00) + +ts_ROM_bvectors + B ts_RomPatt + B ts_GetCommand + B ts_SendByte + B ts_SendWord + B ts_GetByte + B ts_GetWord + B ts_SendText + B ts_MoreText + B ts_SendLCDCmd + + +; +; Pad out until the location of the ResetIndirection vector +; + + ASSERT .-ROM <= ResetIndirection + % ResetIndirection-(.-ROM) + & ts_RomPatt-ROM+PhysROM + +; +; ROM test code +; +; Note : the register order in ADDS ...pc.. is often critical. +; If we want to adjust pc, use ADDS pc,rn,pc so that the PSR is +; rewritten with it's original value. +; If we want to do some pc-relative arithmetic, use ADDS rn,pc,rn +; so that the bits from PSR are NOT used in the address calculation. +; + + SUBT Macros + + MACRO + MODE $mode_bits + TEQP psr,#($mode_bits :OR: I_bit :OR: F_bit) + NOP + MEND + + MACRO + MOV_fiq $dest,$src + MODE FIQ_mode + MOV $dest,$src + MODE SVC_mode + MEND + + MACRO + FAULT $code + MODE FIQ_mode + ORR r12_fiq,r12_fiq,$code + MODE SVC_mode + MEND + + MACRO + M32_fiq $dest,$src,$tmp1,$tmp2 + SetMode FIQ32_mode,$tmp1,$tmp2 + MOV $dest,$src + msr AL,CPSR_all,$tmp2 + MEND + + MACRO + FAULT32 $code,$tmp + SetMode FIQ32_mode,$tmp + ORR r12_fiq,r12_fiq,$code + SetMode SVC32_mode,$tmp + MEND + +; +; Define an area of storage with the required set of data bus patterns +; These are used both for testing the complete width of the data bus +; during ROM pattern testing, and will provide a tidy set of patterns +; if the reset is held, while the ARM increments addresses. +; + + SUBT ROM Address and Data Patterns + +DataPatterns + + GBLA dmask +dmask SETA &80000000 + + DCD &FFFFFFFF ; first two : all set + DCD &0 ; all clear + + GBLA OldOpt ; don't list all the walking +OldOpt SETA {OPT} ; patterns + OPT OptNoList + + WHILE dmask > 0 ; then for each bit + DCD &$dmask ; set it + DCD :NOT: &$dmask ; and clear it +dmask SETA dmask :SHR: 1 + WEND + OPT OldOpt +DEnd + + + OPT OptList +; +; +; Read the ROM at a series of addresses +; such that : a) all the address lines are exercised individually +; b) all the data lines are exercised individually +; +; Data and address lines are exercised as walking-0 and walking-1. +; The test is performed as a series of LDR operations to avoid using +; a larger instruction set. +; + +ts_RomPatt ROUT + + ; Patterns which will exercise most of the data bus. + ; All are arbitrary instructions with NV execution + + DCD &F0000000 ; walking 1 + +OldOpt SETA {OPT} ; patterns + OPT OptNoList + +dmask SETA &08000000 + WHILE dmask > 0 + DCD dmask :OR: &F0000000 +dmask SETA dmask :SHR: 1 + WEND + + DCD &FFFFFFFF ; walking 0 + +dmask SETA &08000000 + WHILE dmask > 0 + DCD (:NOT: dmask) :OR: &F0000000 +dmask SETA dmask :SHR: 1 + WEND + + OPT OldOpt + + ; Now some proper code : + ; Initialise address pointer and make MemC safe + + LDR r0,%01 + ADD pc,r0,pc +01 + & 0 ; useful constant + + [ IO_Type = "IOC-A1" ;;!! unsafe if we execute ROM at zero + LDR r1,%02 + ADD pc,r0,pc +02 ;;!! This remaps MEMC's ROM + & &E000C :OR: MEMCADR ;;!! addressing if it hasn't + STR r1,[r1] ;;!! already happened. + ] + + LDR r5,%03 ; Load r5 with a constant which + ADD pc,r0,pc ; may be added to ROM plus a +03 ; walking-zero bitmask to create + & ts_Rom_length - 3 ; a valid word address in ROM. + LDR r2,%04 ; Offset from ROM start to here + ADD pc,r0,pc +04 + & ROM - pcfromstart + + ADD r2,pc,r2 ; pointer to start of ROM + ADD r3,r2,r0 ; pointer to start of ROM +pcfromstart + ADD r4,r2,r0 ; pointer to start of ROM + + ; assembly-time loop - only 32 iterations required + +OldOpt SETA {OPT} + + GBLA doffset +doffset SETA DataPatterns + WHILE doffset < DEnd + + LDR r0,doffset ; walking 1 data pattern + LDR r1,doffset+4 ; walking 0 data pattern + LDR r6,[r2] ; walking 1 address pattern + LDR r6,[r3] ; walking 0 address pattern + + [ (doffset - DataPatterns) > ((32 - ts_Rom_bits) * 8) + [ (doffset - DataPatterns) < (31 * 8) + ADD r2,r4,r0 ; r2 = ROM + walking 1 pattern + ADD r3,r4,r1 ; r3 = ROM + walking 0 pattern + ADD r3,r3,r5 ; adjust to a valid address + ] + ] + + OPT OptNoList + +doffset SETA doffset + 8 + WEND + + ASSERT (. - doffset < 4095) ; in range without barrel shift ? + + OPT OldOpt + +; +; External interface drivers - +; provides entry points to send byte- and word- and string-sized objects +; and to receive byte- and word-sized objects +; +; Continue into GetCommand, which determines adapter type (or no adapter) +; and jumps to an ExtCmd handler, ts_User_startup, ts_Forced_startup or +; ts_Dealer_startup as appropriate. +; + B ts_GetCommand + + GET TestSrc.ExtIO + +; +; External command handlers - respond to commands given through the +; external test interface. +; + + GET TestSrc.ExtCmd + + + SUBT Selftest +; +; There is no attached test interface. Is this a power-on reset ? +; Addressing IOC will make MEMC1a remap the ROM to high memory if +; it hasn't already done it, so be careful to ensure that the +; ARM is addressing normally-addressed ROM when this code runs. +; + +ts_User_startup ROUT + LDR r0,%01 + ADD pc,r0,pc +01 + & 0 +; +; IOMD will only access the ROM until a write to IOMD has been made - +; make this write also switch on refresh so the DRAM has a chance to +; get running before the memory test starts. +; + [ MEMC_Type = "IOMD" + LDR r1,%02 + ADD pc,r0,pc +02 + & (IOMD_Base+IOMD_VREFCR) + LDR r2,%03 + ADD pc,r0,pc +03 + & IOMD_VREFCR_REF_16 + STR r2, [r1,#0] + ] + + [ POSTenabled + LDR r1,%12 ; load address of IOC IRQ register + ADD pc,r0,pc +12 + & IOC+IOCIRQSTAA + + LDR r1, [r1,#0] ; Get IRQSTAA register (hence POR bit) + LDR r2, %13 + ADD pc,r0,pc ; Constant to shift por to bit 31 +13 + & por_bit :SHL: 1 +14 ADD r1,r1,r1 + ADDS r2,r2,r2 + BCC %14 ; loop until por_bit is at bit 31 + ADDS r1,r1,r1 ; then shift it into carry + BCC ts_Self_test_end ; POR bit clear - do soft reset. + +; it's a power-on reset, so assume we can't be in 32-bit mode + + MOV_fiq r12_fiq, #R_HARD + B ts_Self_test_startup + | + B CONT ; if user POST disabled + ] +; +; Perform self - tests +; +; Any distinction between test operation for Power-up, Display-only +; and Forced tests needs to be made between these three entry points. +; + + +; This is where tests start if a dumb test link is fitted +; (a diode from A21 to *ROMCS, disabling the ROMs when A21 is high) + +ts_Forced_startup ROUT + + MOV_fiq r12_fiq, #R_TESTED + B ts_Self_test_startup + +; This is where the tests start if an external display adapter is fitted + +ts_Dealer_startup ROUT + + MOV_fiq r12_fiq, #R_EXTERN + + LDR r4,%FT02 ; make a pointer to signon string +01 ADD r4,pc,r4 + ADD pc,r0,pc +02 + & (ts_himsg - %BT01 - 8) + + ADD r14,pc,r0 ; make a return address for this 'call' + ASSERT (.+4 = ts_Self_test_startup) ; PC must point there already ! + B ts_SendText + +ts_Self_test_startup ROUT + +; This is where the power-on test starts (every user gets this) + + +; +; Processor test would go here .... if there was one. +; + +; +; From this point on we assume we can safely use all the processor +; +; Initialise VIDC : Sync mode 0, border covers screen +; + +ts_InitVIDC + [ IO_Type = "IOMD" ; If POSTbox fitted, ROM may still be mapped everywhere + MOV r2,#IOMD_Base + MOV r0, #IOMD_VREFCR_REF_16 ; switch on DRAM refresh + STR r0, [r2, #IOMD_VREFCR] + + ; choose monitor settings from ID bit 0 + MOV r1,#ts_VIDCPhys + ADRL r2,TestVIDCTAB + LDR r0,=IOMD_MonitorType + LDR r0,[r0] + ANDS r0,r0,#IOMD_MonitorIDMask + ADDEQ r2,r2,#(TestVVIDCTAB-TestVIDCTAB) + + | ; not IOMD + MOV r1,#ts_VIDCPhys + ADRL r2,TestVIDCTAB + ] + +10 LDR r0, [r2],#4 + CMP r0, #-1 + STRNE r0, [r1] + BNE %BT10 + + LDR r0,=C_ARMOK ; set initial screen colour + STR r0, [r1] + + B ts_RomTest + + + LTORG + ROUT + +; +; Calculate ROM checksum : display status and calculated checksum. +; + +1 + = "ROM :",0 +2 + = "ROM bad",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +3 + = "ROM size",&8A,&ff,&ff,&ff,&ff,&ff,&ff,0 + ALIGN + +ts_RomTest + ADR r4,%BT1 + BL ts_SendText + + BL ts_ROM_checksum + BEQ %20 + ADR r4,%BT2 ; Failed message + FAULT #R_ROMFAILBIT ; set ROM bit in r12_fiq + MOV r8,r0 ; calculated checksum + BL ts_SendText + + BL ts_ROM_alias ; Checksum failed :- + ADR r4,%BT3 ; hunt for first alias + MOV r8,r0, LSL #8 + BL ts_SendText ; and report it. +20 + + [ IO_Type = "IOC-A1" ; Don't use RISC OS MemSize + ; until much later - it sets up + ; the ARM600 MMU as well. + B ts_MEMCset + +; +; Do MEMC setup and memory size determination (the first time). +; + LTORG + ROUT + +1 + = "M Size :",0 +2 + = "M Size",&89,&ff,&ff,&ff,&ff,".",&ff,&ff,0 + ALIGN + +ts_MEMCset + MOV r12,#0 + ADR r4,%BT1 + BL ts_SendText + LDR r1,=(&E000C :OR: MEMCADR) ; MemSize expects 32k page + STR r1,[r1] + BL MemSize + +; +; MemSize returns with r0 = page size (now in bytes, *NOT* in MEMC control patterns), +; r1 = memory size (in bytes) +; r2 = MEMC control value +; +; Translate these into a number that looks like : +; +; mmmm.pp +; +; where mmmm is memory size in hex Kbytes, pp is page size in hex Kbytes. +; + MODE FIQ_mode ; Save memory size and + MOV r11_fiq,r2 ; MEMC setup value for + MOV r10_fiq,r1 ; later use + MODE SVC_mode + + MOV r8, r0, LSR #2 ; MemSize now returns actual page size in r0 + ADD r8,r8,r1,LSL #6 + ADR r4,%BT2 + BL ts_SendText + + ] + +; +; Test data, address and byte strobe lines. +; On MEMC systems, this calls MemSize and tests the memory that finds. +; On IOMD systems, memory sizing is performed along with the data line +; tests, and that result is used for address line testing. +; + + B ts_LineTest + + GBLS tsGetMem1 +tsGetMem1 SETS "GET TestSrc.Mem1" :CC: MEMC_Type + $tsGetMem1 + +; +; Test IOC. +; This shuld require vector space to work (for testing interrupts), +; but the current version just reports the status register contents. +; +; Display is ccaabbff +; +; where cc is the control register +; aa is IRQ status register A +; bb is IRQ status register B +; ff is FIQ status register +; + + B ts_IOCTest + + LTORG + ROUT + + [ IO_Type = "IOMD" +1 + = "IOMD :",0 +2 + = "IOMD-F",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +3 + = "IOMD-V" +4 + = &88,&ff,&ff,&ff,&ff," V.",&ff,0 + | +1 + = "IOC :",0 +2 + = "IOC-F",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +3 + = "IOC" +4 + = &88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 + ] + ALIGN + +ts_IOCTest + ADR r4,%BT1 + BL ts_SendText + BL ts_IOCreg ; check register integrity + BEQ %FT8 + ADR r4,%BT2 + BL ts_SendText ; report if failure + + FAULT #R_IOCFAILBIT +8 + ADR r4,%BT1 + BL ts_SendText + BL ts_IOCstat + BEQ %FT10 ; fail message only printed if + ADR r4,%BT3 ; ID code unrecognised + BL ts_SendText + FAULT #R_IOCFAILBIT ; .. and set error bit if IOMD code is wrong + B %FT11 +10 + ADR r4,%BT4 ; print the status value + BL ts_MoreText +11 + + [ IO_Type = "IOMD" + B ts_CMOStest + | + B ts_IOEBtest + ] + + LTORG + ROUT + +; +; Check for presence of IOEB ASIC +; + + [ IO_Type = "IOEB" + +1 + = "IOEB :",0 +2 + = "IOEB",&88,"exists",0 + + + ALIGN + +ts_IOEBtest + ADR r4,%BT1 + BL ts_SendText + + LDR r0,=ts_IOEB_ID ; read an ID register in the IOEB ASIC + LDRB r0, [r0] + AND r0, r0, #&f + CMPS r0, #ts_IOEB_ident ; if it looks right ( == 5) .. + BNE %10 + + FAULT #R_IOEB ; set that bit in the result word + ADR r4, %BT2 + BL ts_SendText +10 B ts_CMOStest + ] ; IOEB IO world +; +; Read CMOS +; Check the checksum, read the memory test flag. +; + +1 + = "SRAM :",0 +2 + = "SRAM-F",0 +3 + = "SRAM-C",&8e,&ff,&ff,0 + ALIGN + +ts_CMOStest + ADR r4,%BT1 + BL ts_SendText + + [ ChecksumCMOS + + LDR r0,=(ts_BBRAM + &4000) + MOV r1,#&C0 ; Get first RAM area + MOV r2,#CMOSxseed + BL ts_CMOSread + BNE %20 + MOV r2, r0 + LDR r0,=(ts_BBRAM + &1000) ; Accumulate the second RAM area + MOV r1,#&2F + BL ts_CMOSread + BNE %20 + RSB r2, r0, #0 ; Subtract from the checksum byte + LDR r0,=(ts_BBRAM + &3F00) + MOV r1,#1 + BL ts_CMOSread + BNE %20 + MOV r8, r0, LSL #24 + ANDS r0, r0, #&FF ; A zero result ? + MOV r1, #R_CHKFAILBIT + ADR r4,%BT3 ; Report checksum failure + BNE %21 ; failed .. report error + ] ; end ChecksumCMOS + + LDR r0,=(ts_BBRAM + &FC00) ; Read Misc1CMOS byte + MOV r1,#1 + MOV r2,#0 + BL ts_CMOSread + BNE %20 + ANDS r0,r0,#&80 ; Test the memory-test-disable bit + BEQ %25 + FAULT #R_MEMSKIP ; If set, skip the memory test + B %25 + +20 + MOV r1,#R_CMSFAILBIT ; Real fault - set the fault bit + ADR r4,%BT2 ; Report fault accessing IIC + ; (Bitmap & POST display) +21 + FAULT r1 + BL ts_SendText ; Report one fault or another +25 + B ts_IOinit + + LTORG + ROUT +; +; Initialize various machine registers - e.g, turn off the floppy +; drive, etc, etc. +; + +1 + = "IOinit:",0 + ALIGN + +ts_IOinit + ADR r4,%BT1 + BL ts_SendText + ADRL r2,ts_IOinitab +10 + LDR r0,[r2],#4 ; Get address + LDR r1,[r2],#4 ; Get initialization data + CMPS r0,#(-1) + STRNE r1,[r0] ; write to IO port + BNE %10 + B Speedset +; +; Use the RISC OS MEMC setup code to guess the proper processor / memory +; configuration. The memory speed can then be set up correctly for +; fastest possible working, and the memory array tested in the +; configuration RISC OS expects. +; +; Display the results of the TimeCPU test as : +; +; ssss.m.r +; +; where ssss is the processor speed in hex kHz, +; m is 0 for MEMC, 1 for MEMC1a +; r is the MEMC rom speed switch setting. +; + ROUT + +1 + = "Speed :",0 +2 + = "Speed",&88,&ff,&ff,&ff,&ff,".",&ff,".",&ff,0 + + ALIGN + +Speedset + ADR r4,%BT1 + BL ts_SendText + + [ MEMC_Type = "IOMD" + MOV r9,#0 + | + MOV_fiq r0, r11_fiq ; get MEMC setup + MOV r9,r0 ; compare IOC and CPU clocks + ] + + BL TimeCPU + MOV r0,r9 + MOV_fiq r11_fiq,r0 + + MOV r8,r7,LSL #16 + TST r7, #1 :SHL: 16 ; test bit 16 of r7 : + ADDNE r8,r8,#&1000 ; MEMC1 / MEMC1a detected + AND r9,r9,#&C0 ; get High ROM access bits + ADD r8,r8,r9, LSL #2 + ADR r4,%BT2 + BL ts_SendText + B RAMtest + + +; +; Long RAM test, ideally exercising all memory. +; In order to keep boot time short, the following scheme is used : +; +; Normal power-on boot - test VRAM and up to 4M of first DRAM entry +; CMOS disable set - test nothing +; Test hardware fitted - test entire memory +; + + ROUT + + +1 + = "RAM :",0 +2 + = "RAM bad",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +3 + = &89,"skipped",0 +4 + = "RAM :",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 + + + ALIGN + +RAMtest + ADR r4,%BT1 + BL ts_SendText +; +; if (R_MEMSKIP && R_HARD) +; skip all the remaining tests +; if (!R_LINFAILBIT) +; perform the long memory test +; + MOV_fiq r0,r12_fiq ; skip this test if data line fault + AND r1,r0,#(R_MEMSKIP :OR: R_HARD) ; or the user didn't want it + TEQS r1,#(R_MEMSKIP :OR: R_HARD) + ANDNE r1,r1,#R_LINFAILBIT + TEQNE r1,#R_LINFAILBIT + BNE %12 + ADR r4,%BT3 ; skipping memory test .... + BL ts_MoreText + B ts_Report +12 + LDR r1,=C_RAMTEST ; doing at least part of the long memory test + LDR r0,=ts_VIDCPhys ; write the border colour + STR r1,[r0] + + BL MemSize ; Set MMU up, mapping (some) RAM at logical address 0 + ; Note that this returns with the MMU enabled, + ; the ROM remapped to it's ORGed address, + RSB r4,r4,#PhysROM ; and r4 the offset from physical to ORGed ROM addresses + ADD r4,r4,#PhysSpace + SetMode SVC32_mode,r0 ; Must do this, as PhysSpace is outside 26 bit addressing + ADD pc,pc,r4 ; Jump into the ROM at its image in PhysSpace + NOP ; this instruction skipped by pc adjustment + +; +; Modify the PhysRamTable so only VRAM and the first ts_MaxRamTest of DRAM gets tested +; + M32_fiq r0,r12_fiq,r1,r2 ; get the test condition flags + + ANDS r0,r0,#(R_EXTERN :OR: R_TESTED) + BNE %FT16 ; do full test if test adapter is present + MOV r9,#PhysRamTable + ADD r10,r9,#(PhysRamTableEnd-PhysRamTable) +14 + LDR r1,[r9, #4] + ADD r0,r0,r1 ; r0 = running sum of memory sizes + SUBS r2,r0,#ts_MaxRamTest ; r2 = excess over ts_MaxRamTest + SUBHI r1,r1,r2 ; r1 = current size truncated + STRHI r1,[r9, #4] + MOVHI r0,#ts_MaxRamTest ; truncate running sum to MaxRamTest + + ADD r9,r9,#(DRAMPhysAddrB-DRAMPhysAddrA) + CMPS r9,r10 + BNE %BT14 +16 + FAULT32 #R_MEMORY,r0 ; memory tests were attempted + + MOV r9,#VideoPhysAddr + LDR r8,[r9] ; report the test address + ADRL r4,%BT4 + BL ts_SendText + LDR r0,[r9] ; get VRAM start address and size + LDR r1,[r9,#4] + ADD r0,r0,#PhysSpace + BL ts_RamTest + BNE %FT20 ; failed - abort ram testing + +; +; VRAM (or 1st MB of DRAM, if no VRAM fitted) looks OK - move the translation +; table there so memory tests can proceed without smashing it. +; + MOV r9,#PhysRamTable + LDR r0,[r9,#VideoPhysAddr-PhysRamTable] ; get address of video RAM + LDR r1,[r9,#DRAMPhysAddrA-PhysRamTable] ; get address of 1st DRAM bank + LDR r3, =DRAMOffset_L2PT + ADD r1, r1, r3 ; make r1 -> L2PT + ADD r0, r0, r3 ; make r0 -> temporary L2PT + BL ts_remap_ttab ; copy ttab at r1 to r0 and change table base + +; +; Now run the RAM test at each DRAMPhysAddr until the end of the table or a zero entry +; is reached. Mark tested entries by setting the PhysSpace address, so a pointer to the +; next entry need not be kept. +; +18 + MOV r9,#DRAMPhysAddrA + ADD r10,r9,#(PhysRamTableEnd-DRAMPhysAddrA) +19 + CMPS r9,r10 ; reached end of table ? + LDRNE r0,[r9] + TSTNE r0,r0 ; reached unused entries ? + LDRNE r1,[r9,#4] ; or blanked-out entries ? + TSTNE r1,r1 + BEQ %FT21 ; .. all passed OK + TSTS r0,#PhysSpace + ADDNE r9,r9,#(DRAMPhysAddrB-DRAMPhysAddrA) + BNE %BT19 ; this entry done .. find the next + + MOV r8,r0 ; report address of this block + ADRL r4,%BT4 + BL ts_SendText + + LDR r0,[r9] ; start testing it + ADD r0,r0,#PhysSpace + LDR r1,[r9, #4] + STR r0,[r9] ; mark block so it isn't retested + MOV r2,#PhysRamTable + LDMIA r2,{r3-r14} ; save the PhysRamTable + STMIA r0,{r3-r14} + BL ts_RamTest + LDMIA r13,{r1-r11,r14} ; restore the PhysRamTable + MOV r13,#PhysRamTable + STMIA r13,{r1-r11,r14} + BEQ %BT18 ; if it passed, go look for another block + +20 + FAULT32 #R_MEMFAILBIT,r2 ; failed - report fault address + ADRL r4,%BT2 + MOV r11,r1 ; Save failed data + MOV r8,r0 ; first failing address + BL ts_SendText + MOV r4,r12 ; get fault message + MOV r8,r11 ; and fault data + BL ts_SendText +21 + + [ MEMM_Type = "MEMC1" + +; +; Test the CAMs - for each fitted MEMC, go through all the CAM entries +; remapping logical memory and testing against physical correspondence. +; Then try out the protection bits in each CAM entry and various +; processor modes. +; These tests return pointers to their own fault report strings. +; + B ts_CAMtest + ROUT +1 + = "CAMs :",0 +2 + = "PPLs :",0 +3 + = &89,"skipped",0 + ALIGN + +ts_CAMtest + LDR r4,=%BT1 + BL ts_SendText + + MOV_fiq r0,r12_fiq ; skip this test if memory fault + MOV r1,#(R_LINFAILBIT :OR: R_MEMFAILBIT) + ANDS r0,r0,r1 + BEQ %08 + LDR r4,=%BT3 + BL ts_MoreText + B %20 + +08 + BL ts_CAM + BEQ %10 + BL ts_SendText + FAULT #R_CAMFAILBIT +10 + LDR r4,=%BT2 + BL ts_SendText + + MOV_fiq r0,r12_fiq ; skip this test if memory fault + MOV r1,#(R_LINFAILBIT :OR: R_MEMFAILBIT) + ANDS r0,r0,r1 + BEQ %18 + LDR r4,=%BT3 + BL ts_MoreText + B %20 +18 + BL ts_memc_prot + BEQ %20 + BL ts_SendText + FAULT #R_PROFAILBIT +20 + + ] + +; +; After testing memory and translation, turn MMU off again before running remainder +; of tests. This simplifies finishing up (where system must be put back into 26-bit +; mode before initialising RISCOS) if memory tests were deselected. +; Take care to poke the real translation table - it's been relocated to video +; RAM during the memory tests. +; + +ts_restore_physical + MOV r5, pc ; obtain current address + SUB r5, r5,#PhysSpace ; adjust to point to unmapped version + MOV r5, r5, LSR #20 ; divide by 1MB + MOV r7, r5, LSL #20 ; r7 = physical address of base of section + ORR r7, r7, #(AP_None * L1_APMult) + ORR r7, r7, #L1_Section + MOV r3, #VideoPhysAddr ; find the copied translation table + LDR r3, [r3] + ADD r3, r3, #PhysSpace + ADD r3, r3, #DRAMOffset_L1PT + STR r7, [r3, r5, LSL #2] ; store replacement entry in L1 (not U,C or B) + + SetCop r7, CR_IDCFlush ; flush cache + TLB just in case + SetCop r7, CR_TLBFlush ; (data written is irrelevant) + +; The ROM should now be mapped at the present address less PhysSpace, which is where it +; would be if the MMU were turned off. + + MOV r4,#PhysSpace + SUB pc,pc,r4 + NOP ; this instruction is skipped + + MOV r7, #MMUC_D ; Now turn the MMU off + SetCop r7, CR_Control + + B ts_VIDCtest + + +; +; The VIDC tests check vertical blanking frequency in a fixed video +; mode and measure the time taken for sound DMA. +; + + ROUT + +1 + = "VIDC :",0 +2 + = "Virq bad",&88,' ',&ff,'.',&ff,&ff,&ff,&ff,&ff,0 +3 + = "Sirq bad",&8B,&ff,&ff,&ff,&ff,&ff,0 +4 + = &8A,"Mid0 ",&ff,0 + + ALIGN + +ts_VIDCtest + ADR r4,%BT1 + BL ts_SendText + [ IO_Type = "IOMD" + LDR r0,=IOMD_MonitorType ; Indicate monitor ID bit's value + LDR r0,[r0] + AND r0,r0,#IOMD_MonitorIDMask + MOV r8,r0,LSL #28 + ADR r4,%BT4 + BL ts_MoreText + ] + + BL ts_VIDC_period + BEQ %10 + ADR r4,%B2 + MOV r8, r0, LSL #8 + BL ts_SendText ; Display Virq fail msg + FAULT #R_VIDFAILBIT +10 + [ IO_Type = "IOMD" + MOV r3,#IOMD_Base ; skip Sirq test on version 1 IOMD + LDRB r0,[r3,#IOMD_VERSION] + CMPS r0,#1 + BEQ %FT20 + ] + BL ts_SIRQ_period + BEQ %20 + ADR r4,%B3 + MOV r8, r0, LSL #12 + BL ts_SendText ; Display Sirq fail msg + FAULT #R_SNDFAILBIT +20 + MOV r1,#ts_VIDCPhys ; Restore full-screen + ADRL r2,TestVIDCTAB ; border colour. + [ IO_Type = "IOMD" + LDR r0,=IOMD_MonitorType + LDR r0,[r0] + ANDS r0,r0,#IOMD_MonitorIDMask + ADDEQ r2,r2,#(TestVVIDCTAB-TestVIDCTAB) + ] +30 LDR r0, [r2],#4 + CMP r0, #-1 + STRNE r0, [r1] + BNE %BT30 + LDR r0,=C_ARMOK ; set initial screen colour + STR r0, [r1] + + B ts_ARMtype_test + +; +; Read the ARM3 identification register. +; If memory tests failed, this won't be performed since the vector +; page must exist for error recovery on ARM2 systems. +; + + ROUT +1 + = "ARM ID:",0 +2 + = "ARM ID",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +3 + = &89,"skipped",0 + + ALIGN + +ts_ARMtype_test + + ADR r4,%BT1 + BL ts_SendText + + MOV_fiq r0,r12_fiq ; skip this test if memory fault + LDR r1,=((R_LINFAILBIT :OR: R_MEMFAILBIT) :OR: (R_CAMFAILBIT :OR: R_PROFAILBIT)) + ANDS r0,r0,r1 + BEQ %05 + ADR r4,%BT3 + BL ts_MoreText + B %08 ; and quit + +05 + BL ts_ARM_type + MOVS r8, r0 ; ready to display ID code + ADR r4,%BT2 + + BEQ %FT07 ; ARM 2 : skip cache test + FAULT #R_ARM3 ; not really a fault, just status +07 + BL ts_SendText + +08 + B ts_Report + + + +; +; Report the test results to the user +; +; If this was a forced test (test adapter fitted) then pause even when +; test passed : otherwise, pause only on error. +; + +ts_passmsg + = "PASS :",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +ts_failmsg + = "FAIL :",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 + +ts_R00 & 00 + +ts_Report ROUT + MOV_fiq r7,r12_fiq ; check for fault bits set + LDR r0,=R_STATUS + BICS r0,r7,r0 + + ADREQ r4, ts_passmsg ; tests passed + LDREQ r9,=C_PASSED + + ADRNE r4, ts_failmsg ; tests failed + LDRNE r9,=C_FAULT + + LDR r0,=ts_VIDCPhys ; write the border colour + STR r9,[r0] + + MOV r8,r7 + BL ts_SendText ; write the message and fault code + + ; if the test adapter is present, leave green screen awhile + ; otherwise, wait only if there's a fault. + + LDR r3,=ts_recover_time +00 ADDS r3,r3,r3 ; 16-loop delay + BCC %B00 ; - let the adapter recover + ; from previous bus activity + ADR r2,ts_R00 + ORR r2,r2,#ts_Alias_bits + LDR r3,[r2] + MOV r2,#-1 + ADDS r3,r3,r2 + BCS ts_Report_wait + + MOV_fiq r0,r12_fiq + LDR r2,=R_STATUS + BICS r0,r0,r2 + BEQ ts_Hardstart + +ts_Report_wait ROUT + +; +; Indicate fault found : Set the border to the fault colour and flash +; the disk LED, using the fault bitmap in r12_fiq to modulate the flashing. + +ts_oldLED_on * &be0000 ; assert SEL0 and INUSE +ts_oldLED_off * &ff0000 ; on machines with 1772 controller +ts_oldLEDaddr * (ts_S5_base :OR: &40) + +ts_710LED_on * &100000 ; assert SEL0 and MotorEN0 +ts_710LED_off * &110000 ; on machines with 82C710 controller +ts_710LEDaddr * (ts_PCaddress :OR: (&3f2 :SHL: 2)) + +ts_665LED_on * &10 ; assert SEL0 and MotorEN0 +ts_665LED_off * &11 ; on machines with 37665 controller + ; and Medusa low-byte I/O world +ts_665LEDaddr * (ts_PCaddress :OR: (&3f2 :SHL: 2)) + + +01 MOV_fiq r6,r12_fiq + LDR r2,=&11111111 + LDR r7,=(35000 * 8) ; 1/4 second pause loop count + + [ IO_Type = "IOMD" + LDRNE r1,=ts_665LEDaddr ; set up for Medusa disc address + MOVNE r8,#ts_665LED_on + MOVNE r9,#ts_665LED_off + | + TST r6, #R_IOEB ; determine original / 710 disc controller + LDREQ r1,=ts_oldLEDaddr ; set up for Archimedes disc address + MOVEQ r8,#ts_oldLED_on + MOVEQ r9,#ts_oldLED_off + LDRNE r1,=ts_710LEDaddr ; set up for Brisbane disc address + MOVNE r8,#ts_710LED_on + MOVNE r9,#ts_710LED_off + ] + +02 MOV r0,r7 +03 SUBS r0,r0,#1 ; pause for a 1/4 second + BNE %03 + + MOV r0,r8 ; turn the LED on + STR r0,[r1] + + MOV r0,r7 +04 SUBS r0,r0,#1 ; pause for a 1/4 second + BNE %04 + ADDS r6,r6,r6 ; if a '1' is to be written, + BCC %06 + MOV r0,r7,LSL #1 ; then pause another 1/2 second +05 SUBS r0,r0,#1 + BNE %05 + +06 + MOV r0, r9 ; turn the LED off + STR r0,[r1] + +; +; Count down 32 bits. Every 4 bits, insert an extra pause to simplify +; reading the flashes. +; + ADDS r2,r2,r2 + BCC %08 + MOV r0,r7,LSL #2 ; then pause another second +05 SUBS r0,r0,#1 + BNE %05 +08 + ANDS r2,r2,r2 ; all the bits displayed now ? + BNE %02 + MOV_fiq r0,r12_fiq ; restore the faultcode bits + + ANDS r0,r0,#(R_EXTERN :OR: R_TESTED) ; If test adapter present, + BNE Reset ; repeat test forever + + B CONT ; otherwise, run RISC OS + +ts_Hardstart + MOVS r0,#R_HARD ; and report a hard start + B CONT ; to RISC OS + +; +; Tests skipped : fall into RISC-OS +; + +ts_Self_test_end + + LDR r1,=C_WARMSTART + LDR r0,=ts_VIDCPhys ; write the border colour + STR r1,[r0] + +ts_Softstart + MOVS r0,#R_SOFT ; soft reset indicator + B CONT + + + ROUT + +; +; This table consists of a series of address/data pairs for IO +; initialization. +; Note that these addresses are likely to be in the IO world, +; and hence the data written is that from the MOST significant +; 16 bits of the data bus. +; An 'address' of -1 terminates the table. +; + +ts_IOinitab + [ IO_Type = "IOMD" + | + & ts_S5_base :OR: &10, &000000 ; Printer port data + & ts_S5_base :OR: &18, &000000 ; FDC control & printer strobes + & ts_S5_base :OR: &40, &ff0000 ; FDD select lines + & ts_S5_base :OR: &48, &000000 ; VIDC clock control + ] + & (-1) + + + + + +; +; +;--------------------------------------------------------------------------- + + LTORG + + +; Include test modules executed by call, rather than inline + + GET TestSrc.Mem2 + GET TestSrc.Mem3 + GET TestSrc.Mem4 + GET TestSrc.Mem5 + GET TestSrc.Vidc + GET TestSrc.Ioc + GET TestSrc.Cmos + GET TestSrc.Arm3 + + END diff --git a/OldTestSrc/Cmos b/OldTestSrc/Cmos new file mode 100644 index 0000000000000000000000000000000000000000..610193c5070a152e06e8749a75abfbfa24d333bd --- /dev/null +++ b/OldTestSrc/Cmos @@ -0,0 +1,321 @@ +; > TestSrc.Cmos + + TTL RISC OS 2+ POST battery-backed RAM access +; +; A function to read bytes from CMOS, for use in verifying the checksum +; and reading memory test flag & video modes. +;------------------------------------------------------------------------ +; History +; +; Date Name Comment +; ---- ---- ------- +; 05-Apr-91 ArtG Initial version, based on IICMod. +; +; +;------------------------------------------------------------------------ +; +; in: +; R0 = device address (bit 8 - 15 register address ) +; R1 = length of block to read +; R2 = initial sum value +; +; out: R0 = sum of all bytes in block +; R1 - R13 trashed +; + +ts_CMOSread ROUT + + MOV R13,R14 + MOV R8,R2 ; initialise accumulator + MOV R7,R1 ; initialise byte counter + MOV R6,R0 ; stash register address + MOV R2, #IOC + MOV R0, #-1 ; ensure timer is ticking + STRB R0, [R2, #Timer0LL] ; (nonzero in input latch) + STRB R0, [R2, #Timer0LH] + STRB R0, [R2, #Timer0GO] ; load the count registers + BL ts_Start + BEQ %FT30 ; check clock line toggles OK + AND R0, R6, #&FE + BL ts_TXCheckAck ; transmit device address (write) + BVS %FT30 + MOV R0, R6, LSR #8 + BL ts_TXCheckAck ; write register address + BVS %FT30 + BL ts_Start ; Extra START bit to switch modes + AND R0, R6, #&FE + ORR R0, R0, #1 + BL ts_TXCheckAck ; transmit device address (read) + BVS %FT30 +20 + BL ts_RXByte ; read byte from bus + ADD R8, R8, R0 ; accumulate total + SUBS R7, R7, #1 ; is it last byte ? + MOVNE R0, #0 ; no, then acknowledge with 0 bit + MOVEQ R0, #1 ; yes, then don't acknowledge + BL ts_ClockData ; but always send ack clock pulse + TEQ R7, #0 ; loop, until last byte + BNE %BT20 +30 + MOVVS R7, #-1 ; pass error indicator to caller + BL ts_Stop + MOV R0, R8 + TEQ R7, #0 ; return zero flag if read OK + MOV PC,R13 + +; ***************************************************************************** +; +; TXCheckACK - transmit a byte and wait for slave to ACK +; +; out: Trashes r0,r1,r2,r3,r4,r5,r9,r10,r11,r12 +; V bit set on error. +; + +ts_TXCheckAck ROUT + MOV R12,R14 + BL ts_TXByte + BL ts_Acknowledge + MOVVC PC, R12 ; acknowledged ok, so return + ORRS PC, R12, #V_bit + +; ***************************************************************************** +; +; SetC1C0 - Set clock and data lines to values in R1 and R0 respectively +; +; out: Trashes r0,r1,r2,r11 +; + +ts_SetC1C0 ROUT + MOV R11, R14 + BIC R14, R14, #Z_bit ; indicate not checking clock +ts_SetOrCheck + ORR R14, R14, #I_bit ; disable interrupts + TEQP R14, #0 + + ADD R0, R0, R1, LSL #1 ; R0 := C0 + C1*2 + + ORR R0, R0, #&C0 ; make sure two test bits are + ; always set to 1 ! + MOV R2, #IOC + STRB R0, [R2, #IOCControl] +10 + LDREQB R1, [R2, #IOCControl] ; wait for clock + TSTEQ R1, #i2c_clock_bit ; to read high + BEQ %BT10 + + MOV R0, #10 ; delay for >= 10/2 microsecs +; +; in-line do-micro-delay to save a stack level +; + STRB R0, [R2, #Timer0LR] ; copy counter into output latch + LDRB R1, [R2, #Timer0CL] ; R1 := low output latch +20 + STRB R0, [R2, #Timer0LR] ; copy counter into output latch + LDRB R14, [R2, #Timer0CL] ; R14 := low output latch + TEQ R14, R1 ; unchanged ? + MOVNE R1, R14 ; copy anyway + BEQ %BT20 ; then loop + SUBS R0, R0, #1 ; decrement count + BNE %BT20 ; loop if not finished +; +; end do-micro-delay +; + MOV PC, R11 + +; Set clock and data lines to R1 and R0 and then wait for clock to be high + +ts_SetC1C0CheckClock ROUT + MOV R11, R14 + ORR R14, R14, #Z_bit ; indicate checking clock + B ts_SetOrCheck + + +; ***************************************************************************** +; +; ClockData - Clock a bit of data down the IIC bus +; +; in: R0 = data bit +; +; out: Trashes r0,r1,r2,r3,r10,r11 +; + +ts_ClockData ROUT + MOV R10,R14 + + MOV R3, R0 ; save data + MOV R1, #0 ; clock LO + BL ts_SetC1C0 + + MOV R1, #1 ; clock HI + MOV R0, R3 + BL ts_SetC1C0CheckClock + +; Delay here must be >= 4.0 microsecs + + MOV R1, #0 ; clock LO + MOV R0, R3 + BL ts_SetC1C0 + + MOV PC,R10 + +; ***************************************************************************** +; +; Start - Send the Start signal +; +; out: Trashes r0,r1,r2,r9,r11 +; R0 (and Z flag) indicates state of clock .. should be NZ. +; + +ts_Start ROUT + MOV R9,R14 + + MOV R0, #1 ; clock HI, data HI + MOV R1, #1 + BL ts_SetC1C0 + +; Delay here must be >= 4.0 microsecs + + MOV R0, #0 ; clock HI, data LO + MOV R1, #1 + BL ts_SetC1C0 + +; Make sure clock really is high (and not shorted to gnd) + + LDRB R3, [R2, #IOCControl] + +; Delay here must be >= 4.7 microsecs + + MOV R0, #0 ; clock LO, data LO + MOV R1, #0 + BL ts_SetC1C0 + + ANDS R0, R3, #i2c_clock_bit + MOV PC,R9 + +; ***************************************************************************** +; +; Acknowledge - Check acknowledge after transmitting a byte +; +; out: Trashes r0,r1,r2,r3,r9,r11 +; V=0 => acknowledge received +; V=1 => no acknowledge received +; + +ts_Acknowledge ROUT + MOV R9,R14 + + MOV R0, #1 ; clock LO, data HI + MOV R1, #0 + BL ts_SetC1C0 + + MOV R0, #1 ; clock HI, data HI + MOV R1, #1 + BL ts_SetC1C0CheckClock + +; Delay here must be >= 4.0 microsecs + + MOV R2, #IOC + LDRB R3, [R2, #IOCControl] ; get the data from IOC + + MOV R0, #1 ; clock LO, data HI + MOV R1, #0 + BL ts_SetC1C0 + + TST R3, #1 ; should be LO for correct acknowledge + MOV R3, PC + BICEQ R3, R3, #V_bit ; clear V if correct acknowledge + ORRNE R3, R3, #V_bit ; set V if no acknowledge + TEQP R3, #0 + + MOV PC,R9 + +; ***************************************************************************** +; +; Stop - Send the Stop signal +; +; out: Trashes r0,r1,r2,r9,r11 +; + +ts_Stop ROUT + MOV R9,R14 + + MOV R0, #0 ; clock HI, data LO + MOV R1, #1 + BL ts_SetC1C0 + +; Delay here must be >= 4.0 microsecs + + MOV R0, #1 ; clock HI, data HI + MOV R1, #1 + BL ts_SetC1C0 + + MOV PC,R9 + +; ***************************************************************************** +; +; TXByte - Transmit a byte +; +; in: R0 = byte to be transmitted +; +; out: Trashes r0,r1,r2,r3,r4,r5,r9,r10,r11 +; + +ts_TXByte ROUT + MOV R9, R14 + MOV R4, R0 ; byte goes into R4 + MOV R5, #&80 ; 2^7 the bit mask +10 + ANDS R0, R4, R5 ; zero if bit is zero + MOVNE R0, #1 + BL ts_ClockData ; send the bit + MOVS R5, R5, LSR #1 + BNE %BT10 + MOV PC, R9 + +; ***************************************************************************** +; +; RXByte - Receive a byte +; +; out: R0 = byte received +; Trashes r1,r2,r3,r4,r9,r11 +; + +ts_RXByte ROUT + MOV R9, R14 + MOV R3, #0 ; byte:=0 + MOV R2, #IOC + MOV R4, #7 + + MOV R0, #1 ; clock LO, data HI + MOV R1, #0 + BL ts_SetC1C0 +10 + MOV R0, #1 ; pulse clock HI + MOV R1, #1 + BL ts_SetC1C0CheckClock + + LDRB R1, [R2, #IOCControl] ; get the data from IOC + AND R1, R1, #1 + ADD R3, R1, R3, LSL #1 ; byte:=byte*2+(IOC?0)AND1 + + MOV R0, #1 ; return clock LO + MOV R1, #0 + BL ts_SetC1C0 + + SUBS R4, R4, #1 + BCS %BT10 + + MOV R0, R3 ; return the result in R0 + MOV PC, R9 + + LTORG + + END + + + + + + + + diff --git a/OldTestSrc/ExtCmd b/OldTestSrc/ExtCmd new file mode 100644 index 0000000000000000000000000000000000000000..963d2660804f148cac499eb1115b3119699d0fd9 --- /dev/null +++ b/OldTestSrc/ExtCmd @@ -0,0 +1,1019 @@ +; > TestSrc.ExtCmd + + TTL RISC OS 2+ POST external commands +; +; External test commands for RISC OS ROM. +; +; Provides functions to read data, write data and execute code using +; parameters from an external controlling host. +; +; A minimal set of opcodes should be used (ideally, only B, LDR and ADDS) +; so that a processor test may be validly included in the internal test +; sequence. +; +;------------------------------------------------------------------------ +; History +; +; Date Name Comment +; ---- ---- ------- +; 27-Nov-89 ArtG Initial version +; 06-Dec-89 ArtG Release 0.2 for integration +; 30-Mar-90 ArtG Added NOPs (ADDS r0,r0,r0) after ADDS pc,.. +; 19-Apr-90 ArtG Speedups for read/write commands. +; 15-May-90 ArtG Fixed multiple %13 label in ts_W_FIW +; 22-May-90 ArtG Fixed bugs in ts_B_MWW, ts_W_RIB +; 18-Jun-93 ArtG Added Arm600 control instructions +; 1-Jul-93 ArtG Replaced ADDS pc.. instructions with ADD pc.. +; for compatibility with SVC32_mode. +; +;------------------------------------------------------------------------ + + + +; +; All these routines use registers as follows : +; +; r0 - always zero +; r1 +; r2 +; r3 - undisturbed : used as constant by I/O routine +; r4 - return value from I/O routine, parameter to I/O routines +; r5 +; r6 +; r7 - saved value of command byte on entry +; r8 - operation counter +; r9 - pointer to data transfer operation +; r10 - increment value (0, 1 or 4) to add to pointer in r9 +; r11 - decrement constant (-1) to add to counter in r8 +; r12 - checksum accumulator +; r13 - pointer to operation code +; r14 - return address for calls to I/O routines +; + + SUBT External command handlers +; +; Called by vectoring through command_table. +; R4 contains command byte (including 3 option bits) +; Get operation count +; Get address +; If single-word data +; Get data +; Get checksum +; Reply with command byte or FF +; Do operation +; Else +; For each word +; Get data +; Do operation +; Get checksum +; Reply with command byte or FF +; Return by branching to GetCommand. + +ts_write_memory ROUT + + ADDS r13,r0,r4 ; save the control byte + ADDS r7,r0,r4 + ADDS r14, r0, pc ; setup return address for .. + B ts_GetWord ; .. get operation count word + ADDS r8, r0, r4 ; r8 is operation count + ADDS r12,r0,r4 ; initialise checksum + ADDS r14, r0, pc + B ts_GetWord ; r9 is initial target address + ADDS r9, r0, r4 + ADDS r12,r12,r4 ; accumulate checksum + ADDS r10,r0,r0 ; set initial constants + LDR r11,%01 + ADD pc,pc,r0 +01 + DCD (0 - 1) + +; +; Check for operations which don't involve reading a block of data. +; These are acknowledged BEFORE performing the operation. +; + ADDS r0,r0,r0 + ADDS r13,r13,r13 ; convert operation code to vector + ADDS r13,r13,r13 + LDR r4, %02 + ADD pc,pc,r0 +02 + & (ts_write_cmd_table - %03) + ADDS r4,pc,r4 + ADDS r13,r4,r13 +03 + LDR r13,[r13] ; fetch pointer to code + LDR r4,%04 + ADD pc,pc,r0 +04 + & (ts_write_cmd_table - ts_W_fetch_operations) + ADDS r0,r0,r0 + ADDS r4,r4,r13 + BCS ts_Write_getdata ; defer acknowledgement till later + + ; check the above test was valid, given code layout + ; Note - this is also required by code near ts_Write_cmd_done + + ASSERT (ts_W_RSW < ts_W_fetch_operations) + ASSERT (ts_W_RSB < ts_W_fetch_operations) + ASSERT (ts_W_RIW < ts_W_fetch_operations) + ASSERT (ts_W_RIB < ts_W_fetch_operations) + ASSERT (ts_W_FSW >= ts_W_fetch_operations) + ASSERT (ts_W_FSB >= ts_W_fetch_operations) + ASSERT (ts_W_FIW >= ts_W_fetch_operations) + ASSERT (ts_W_FIB >= ts_W_fetch_operations) + +; +; Fetch the first data word and checksum, and acknowledge +; + + ADDS r14,r0,pc ;get next data word + B ts_GetWord + ADDS r12,r12,r4 ;accumulate checksum + ADDS r10,r0,r4 + ADDS r14,r0,pc + B ts_GetWord ;read transmitted checksum + ADDS r4,r4,r12 ;tx + total should be zero + LDR r5,%05 + ADD pc,pc,r0 +05 + & (0 - 1) + ADDS r5,r5,r4 ;carry set on checksum failure + BCS ts_cmd_error + +; +; Checksum looks OK. Send the command and the checksum back. +; + LDR r4,%06 + ADD pc,pc,r0 +06 + & ts_WriteCmdByte + ADDS r4,r4,r7 ;restore the original + + ADDS r14,r0,pc + B ts_SendByte + ADDS r4,r0,r12 ;then send the calculated checksum + ADDS r14,r0,pc + B ts_SendWord + + ADDS r4,r0,r10 ;restore the data word + ADDS r10,r0,r0 ;and the zero in r10 + B ts_Write_usedata ;dive off to do the work + +; +; Enter the main loop, repeating the operation labelled in r13. +; + +ts_Write_getdata + ADDS r9,r9,r10 ;perform increment operation + ADDS r8,r8,r11 ;countdown repeat counter + BCC ts_Write_cmd_ack + ADDS r14,r0,pc ;get next data word + B ts_GetWord + ADDS r12,r12,r4 ;accumulate checksum + B %07 + +ts_Write_usedata + ADDS r9,r9,r10 ;perform increment operation +ts_Write_count + ADDS r8,r8,r11 ;countdown repeat counter + BCC ts_Write_cmd_done +07 + ADD pc,pc,r13 ;jump back to operations + & 0 + +; +; In this table, the operation after any word fetch is vectored by +; the 3 least significant bits of the command byte to perform some +; combination of writing with : +; +; bit 2 -> 0 R : repeat with same data +; 1 F : fetch more data for next operation +; +; bit 1 -> 0 S : leave address static +; 1 I : increment address after operation +; +; bit 0 -> 0 W : word operation +; 1 B : byte operation +; + + ASSERT ((ts_write_cmd_table - %07) = 8) + +ts_write_cmd_table + + DCD (ts_W_RSW - ts_write_cmd_table) + DCD (ts_W_RSB - ts_write_cmd_table) + DCD (ts_W_RIW - ts_write_cmd_table) + DCD (ts_W_RIB - ts_write_cmd_table) + DCD (ts_W_FSW - ts_write_cmd_table) + DCD (ts_W_FSB - ts_write_cmd_table) + DCD (ts_W_FIW - ts_write_cmd_table) + DCD (ts_W_FIB - ts_write_cmd_table) + +; +; And here are the trailers that perform these operations. +; Each is started with the data in r4, address in r9 and completes +; by returning to Write_getdata (to read another word) or Write_usedata +; (to repeat with the same data) with r10 = increment value (initially 0) +; + +ts_W_RSW + STR r4,[r9] ;store word, repeat address + ADDS r8,r8,r11 ;countdown repeat counter + BCS ts_W_RSW + B ts_Write_cmd_done + +ts_W_RSB + STRB r4,[r9] ;store byte, repeat address + ADDS r8,r8,r11 + BCS ts_W_RSB + B ts_Write_cmd_done + +ts_W_RIW + LDR r10,%11 + ADD pc,pc,r0 +11 + DCD 4 +12 + STR r4,[r9] ;store word, increment word address + ADDS r9,r9,r10 ;perform increment operation + ADDS r8,r8,r11 ;countdown repeat counter + BCS %B12 + B ts_Write_cmd_done + + +ts_W_RIB + LDR r10,%13 + ADD pc,pc,r0 +13 + DCD 1 +14 + STRB r4,[r9] ;store byte, increment byte address + ADDS r9,r9,r10 + ADDS r8,r8,r11 + BCS %B14 + B ts_Write_cmd_done + + + +ts_W_fetch_operations ;all past here fetch new data + ;on each loop + +ts_W_FSW + STR r4,[r9] ;store word, repeat address + B ts_Write_getdata + +ts_W_FSB + STRB r4,[r9] ;store byte, repeat address + B ts_Write_getdata + +ts_W_FIW + STR r4,[r9] ;store word, increment word address + LDR r10,%15 + B ts_Write_getdata +15 + DCD 4 + +ts_W_FIB + STRB r4,[r9] ;store byte, increment byte address + LDR r10,%16 + B ts_Write_getdata +16 + DCD 1 + + +; +; Operations completed. Operations that read multiple data words from +; the host must now checksum and acknowledge the block (even though +; it's a bit late to do anything about it) +; + +ts_Write_cmd_ack +; +; Operation involved multiple fetches - only now ready to ACK. +; + ADDS r14,r0,pc + B ts_GetWord ;read transmitted checksum + ADDS r4,r4,r12 ;tx + total should be zero + LDR r5,%25 + ADD pc,pc,r0 +25 + & (0 - 1) + ADDS r5,r5,r4 ;carry set on checksum failure + BCS ts_cmd_error + +; +; Checksum looks OK. Send the command and the checksum back. +; + LDR r4,%26 + ADD pc,pc,r0 +26 + & ts_WriteCmdByte + ADDS r4,r4,r7 ;restore the original + ADDS r14,r0,pc + B ts_SendByte + ADDS r4,r0,r12 ;then send the calculated checksum + ADDS r14,r0,pc + B ts_SendWord + +ts_Write_cmd_done + B ts_GetCommand + + + +; Called by vectoring through command_table. +; R4 contains command byte (including 3 option bits) +; Get operation count +; Get address +; Reply with command byte or FF +; Reply with checksum +; For each word +; Read data +; If Verbose option +; Send data +; If Quiet option +; Send result of read operation +; Send checksum of result packet +; Return by branching to GetCommand. + +ts_read_memory ROUT + + ADDS r13,r0,r4 ; save the control byte + ADDS r7,r0,r4 + + ADDS r14, r0, pc ; setup return address for .. + B ts_GetWord ; .. get operation count word + ADDS r8, r0, r4 ; r8 is operation count + ADDS r12,r0,r4 ; initialise checksum + + ADDS r14, r0, pc + B ts_GetWord ; r9 is initial target address + ADDS r9, r0, r4 + ADDS r12,r12,r4 ; accumulate checksum + ADDS r10,r0,r0 ; set initial constants + LDR r11,%01 + ADD pc,pc,r0 +01 + DCD (0 - 1) +; +; Convert the operation options into a code pointer +; + ADDS r0,r0,r0 + ADDS r13,r13,r13 ; convert operation code to vector + ADDS r13,r13,r13 + LDR r4, %02 + ADD pc,pc,r0 +02 + & (ts_read_cmd_table - %03) + ADDS r4,pc,r4 + ADDS r13,r4,r13 +03 + LDR r13,[r13] ; fetch pointer to code + +; +; Fetch the checksum, and acknowledge +; + + ADDS r14,r0,pc + B ts_GetWord ;read transmitted checksum + ADDS r4,r4,r12 ;tx + total should be zero + LDR r5,%05 + ADD pc,pc,r0 +05 + & (0 - 1) + ADDS r5,r5,r4 ;carry set on checksum failure + BCS ts_cmd_error + +; +; Checksum looks OK. Send the command and the checksum back. +; + LDR r4,%06 + ADD pc,pc,r0 +06 + & ts_ReadCmdByte + ADDS r4,r4,r7 ;restore the original + ADDS r14,r0,pc + B ts_SendByte + ADDS r4,r0,r12 ;then send the calculated checksum + ADDS r14,r0,pc + B ts_SendWord + + ADDS r12,r0,r0 ;initialise the upload checksum + B ts_Read_count ;enter the loop + +; +; Enter the main loop, repeating the operation labelled in r13. +; This loop is for operations that finish with all data sent + +ts_Read_Txdata ;send data to host + ADDS r12,r12,r4 ;accumulate the checksum + ADDS r14,r0,pc + B ts_SendWord ;send this word + ADDS r9,r9,r10 ;perform increment operation + ADDS r8,r8,r11 ;countdown repeat counter + BCC ts_Read_cmd_done + B %07 ;go off to the jump handler + +ts_Read_count + ADDS r8,r8,r11 ;countdown repeat counter + BCC ts_Read_cmd_read ;send data at finish +07 + ADD pc,pc,r13 ;jump back to operations + & 0 + +; +; In this table, the operation after any word fetch is vectored by +; the 2 least significant bits of the command byte to perform some +; combination of reading with : +; +; bit 2 -> 0 Q : read data without reporting it +; 1 V : Transmit the result of every read operation +; +; bit 1 -> 0 S : leave address static +; 1 I : increment address after operation +; +; bit 0 -> 0 W : word operation +; 1 B : byte operation +; + + ASSERT ((ts_read_cmd_table - %07) = 8) + +ts_read_cmd_table + + DCD (ts_R_QSW - ts_read_cmd_table) + DCD (ts_R_QSB - ts_read_cmd_table) + DCD (ts_R_QIW - ts_read_cmd_table) + DCD (ts_R_QIB - ts_read_cmd_table) + DCD (ts_R_VSW - ts_read_cmd_table) + DCD (ts_R_VSB - ts_read_cmd_table) + DCD (ts_R_VIW - ts_read_cmd_table) + DCD (ts_R_VIB - ts_read_cmd_table) + +; +; And here are the trailers that perform these operations. +; Each is started with the data in r4, address in r9 and completes +; by returning to Write_getdata (to read another word) or Write_usedata +; (to repeat with the same data) with r10 = increment value (initially 0) +; + +ts_R_QSW + LDR r4,[r9] ;read word, repeat address + ADDS r8,r8,r11 ;countdown repeat counter + BCS ts_R_QSW + B ts_Read_cmd_read ;send data at finish + + +ts_R_QSB + LDRB r4,[r9] ;read byte, repeat address + ADDS r8,r8,r11 + BCS ts_R_QSB + B ts_Read_cmd_read + +ts_R_QIW + LDR r10,%11 + ADD pc,pc,r0 +11 + DCD 4 +12 + LDR r4,[r9] ;read word, increment word address + ADDS r9,r9,r10 ;perform increment operation + ADDS r8,r8,r11 ;countdown repeat counter + BCS %B12 + B ts_Read_cmd_read ;send data at finish + + +ts_R_QIB + LDR r10,%13 + ADD pc,pc,r0 +13 + DCD 1 +14 + LDRB r4,[r9] ;read byte, increment byte address + ADDS r9,r9,r10 ;perform increment operation + ADDS r8,r8,r11 ;countdown repeat counter + BCS %B14 + B ts_Read_cmd_read ;send data at finish + + +ts_R_VSW + LDR r4,[r9] ;read and tx word, repeat address + B ts_Read_Txdata + +ts_R_VSB + LDRB r4,[r9] ;read and tx byte, repeat address + B ts_Read_Txdata + +ts_R_VIW + LDR r4,[r9] ;read and tx word, next word address + LDR r10,%15 + B ts_Read_Txdata +15 + DCD 4 + +ts_R_VIB + ADDS r0,r0,r0 + LDRB r4,[r9] ;read and tx byte, next byte address + LDR r10,%16 + B ts_Read_Txdata +16 + DCD 1 + + +; +; Operations completed. Report final result and checksum back to host. +; Quiet option only transmits read data here (this is pretty useless +; except where only one value was read) +; + +ts_Read_cmd_read + ADDS r12,r12,r4 + ADDS r14,r0,pc ;send result of 'quiet' read + B ts_SendWord +ts_Read_cmd_done + SUBS r4,r0,r12 ;get overall checksum - can't think + ADDS r14,r0,pc ;how to do this using only ADDS ! + B ts_SendWord + + B ts_GetCommand + + +; Called by vectoring through command table. +; if option 1 set, read processor mode +; Read address +; Read and check checksum +; Reply with command byte or FF +; Reply with checksum +; if option 1 set, load SPSR +; Jump to code + + +ts_execute ROUT + ADDS r12,r0,r0 ; initialise checksum adder + LDR r8,%00 ; initialise msr-jumper + ADD pc,pc,r0 +00 + & 4 + ADDS r7,r4,r4 ; get operation type + ADDS r7,r7,r7 + ADD pc,pc,r7 ; jump to pc + (r4 * 4) + & 0 + + B %FT10 + B %FT08 + B %FT10 + B %FT10 + B %FT10 + B %FT10 + B %FT10 + B %FT10 + + +08 ADDS r14,r0,pc ; get new processor mode + B ts_GetWord + ADDS r12,r0,r4 + ADDS r8,r0,r0 ; kill msr-jumper +10 + ADDS r14,r0,pc + B ts_GetWord ; get jump address + ADDS r9,r12,r4 + ADDS r14,r0,pc + B ts_GetWord ; get checksum + ADDS r4,r4,r9 + LDR r5,%11 + ADD pc,pc,r0 +11 + & (0 - 1) + ADDS r4,r5,r4 ; compare total chex with zero + BCS ts_cmd_error ; carry set on error + + LDR r4,%12 + ADD pc,pc,r0 +12 + & ts_ExecuteCmdByte + ADDS r0,r0,r0 + ADDS r14,r0,pc ; echo command byte + B ts_SendByte + ADDS r4,r0,r9 ;return checksum (actually, the + ADDS r14,r0,pc ; entire message ..) + B ts_SendWord + + +; Now jump to the location given in the message, using the given status bits + + ADD pc,pc,r8 ; jump over the msr instruction + NOP + & 2_11100001011010011111000000001100 ; + + ADDS r14,pc,r0 ; Load the address of %13 into r14 + ; to provide a return address + ADD pc,r0,r9 ; Do the jump +13 + B ts_GetCommand + + + +; Called by vectoring through command table +; Read operation count +; Read target addresses +; Read data +; Send command byte or FF +; Send checksum +; For all operation count +; write data +; if read-back option +; read data +; Return by branching to GetCommand + + +ts_bus_exercise ROUT + ADDS r7,r0,r4 ; save the control byte + + ADDS r14, r0, pc ; setup return address for .. + B ts_GetWord ; .. get operation count word + ADDS r8, r0, r4 ; r8 is operation count + ADDS r12,r0,r4 ; initialise checksum + + ADDS r14, r0, pc + B ts_GetWord ; r9 is first target address + ADDS r9, r0, r4 + ADDS r12,r12,r4 ; accumulate checksum + ADDS r14, r0, pc + B ts_GetWord ; r10 is second target address + ADDS r10, r0, r4 + ADDS r12,r12,r4 ; accumulate checksum + + ADDS r14, r0, pc + B ts_GetWord ; r11 is first data word + ADDS r11, r0, r4 + ADDS r12,r12,r4 ; accumulate checksum + ADDS r14, r0, pc + B ts_GetWord ; r13 is second data word + ADDS r13, r0, r4 + ADDS r12,r12,r4 ; accumulate checksum + +; +; Fetch the checksum, and acknowledge +; + + ADDS r14,r0,pc + B ts_GetWord ;read transmitted checksum + ADDS r4,r4,r12 ;tx + total should be zero + LDR r5,%05 + ADD pc,pc,r0 +05 + & (0 - 1) + ADDS r5,r5,r4 ;carry set on checksum failure + BCS ts_cmd_error + +; +; Checksum looks OK. Send the command and the checksum back. +; + LDR r4,%06 + ADD pc,pc,r0 +06 + & ts_BusExCmdByte + ADDS r4,r4,r7 ;restore the original + ADDS r14,r0,pc + B ts_SendByte + ADDS r4,r0,r12 ;then send the calculated checksum + ADDS r14,r0,pc + B ts_SendWord + + ADDS r12,r0,r13 ; Now addresses are in r9, r10 + ; and data in r11, r12. +; +; Convert the operation options into a code pointer +; + ADDS r13,r7,r7 ; convert operation code to vector + ADDS r13,r13,r13 + LDR r4, %02 + ADD pc,pc,r0 +02 + & (ts_busex_cmd_table - %03) + ADDS r4,pc,r4 + ADDS r13,r4,r13 +03 + LDR r13,[r13] ; fetch pointer to code + LDR r7, %04 ; set up decrementer in r8 + ADD pc,pc,r0 +04 + DCD (0 - 1) +07 + ADD pc,pc,r13 ; jump to operation + & 0 + +; +; In this table, the operation after any word fetch is vectored by +; the 3 least significant bits of the command byte to perform some +; combination of writing with : +; +; bit 2 -> 0 S : Perform separate data write ops +; 1 M : Use STM / LDM instructions +; +; bit 1 -> 0 R : Perform only read operations +; 1 W : Write before reading +; +; bit 0 -> 0 W : word operation +; 1 B : byte operation +; +; Note that byte and multiple operations are mutually +; exclusive. +; + + ASSERT ((ts_busex_cmd_table - %07) = 8) + +ts_busex_cmd_table + + DCD (ts_B_SRW - ts_busex_cmd_table) + DCD (ts_B_SRB - ts_busex_cmd_table) + DCD (ts_B_SWW - ts_busex_cmd_table) + DCD (ts_B_SWB - ts_busex_cmd_table) + DCD (ts_B_MRW - ts_busex_cmd_table) + DCD (ts_B_MRB - ts_busex_cmd_table) + DCD (ts_B_MWW - ts_busex_cmd_table) + DCD (ts_B_MWB - ts_busex_cmd_table) + +ts_B_SRW + LDR r11,[r9] ; read-only separate words + LDR r12,[r10] + ADDS r8, r8, r7 + BCS ts_B_SRW + B ts_B_done + +ts_B_SRB + LDRB r11,[r9] ; read-only separate bytes + LDRB r12,[r10] + ADDS r8, r8, r7 + BCS ts_B_SRB + B ts_B_done + +ts_B_SWW + STR r11,[r9] ; write and read separate words + STR r12,[r10] + LDR r1,[r9] + LDR r2,[r10] + ADDS r8, r8, r7 + BCS ts_B_SWW + B ts_B_done + +ts_B_SWB + STRB r11,[r9] ; write and read separate bytes + STRB r12,[r10] + LDRB r1,[r9] + LDRB r2,[r10] + ADDS r8, r8, r7 + BCS ts_B_SWB + B ts_B_done + + +ts_B_MRW + LDMIA r9,{r1,r2} ; read-only multiple words + LDMIA r10,{r1,r2} + ADDS r8, r8, r7 + BCS ts_B_MRW + B ts_B_done + +ts_B_MWW + STMIA r9,{r11,r12} ; write and read multiple words + LDMIA r9,{r1,r2} + STMIA r10,{r11,r12} + LDMIA r10,{r1,r2} + ADDS r8, r8, r7 + BCS ts_B_MWW + B ts_B_done + +; +; Orthogonally, these should be multiple byte operations - we can't do that, +; so they actually do a single/multiple mixture. +; The first address argument is used for word-aligned operations and the +; second for byte-aligned operations - so set only the second address +; to a non-word-aligned address. + +ts_B_MRB + LDMIA r9,{r1,r2} ; read-only multiple words + LDRB r1,[r10] ; then single bytes + LDR r1,[r9] ; and single words + ADDS r8, r8, r7 + BCS ts_B_MRB + B ts_B_done + +ts_B_MWB + STMIA r9,{r11,r12} ; store multiple words + STRB r11,[r10] ; write byte + STR r12,[r9] ; write words + LDMIA r9,{r1,r2} + LDRB r1,[r10] + LDR r1,[r9] ; read single and multiple words + ADDS r8, r8, r7 + BCS ts_B_MWB +; B ts_B_done + +ts_B_done + B ts_GetCommand + + + +; +; All commands fall through here to respond with FF if the received +; message block checksums fail. +; + +ts_cmd_error ROUT ; error in command + LDR r4, %01 ; return error response + ADD pc,pc,r0 +01 + DCD ErrorCmd + ADDS r0,r0,r0 + ADDS r14, r0, pc ; send response byte to host + B ts_SendByte + + B ts_GetCommand + + +; generic coprocessor register names + +cpr0 CN 0 +cpr1 CN 1 +cpr2 CN 2 +cpr3 CN 3 +cpr4 CN 4 +cpr5 CN 5 +cpr6 CN 6 +cpr7 CN 7 +cpr8 CN 8 +cpr9 CN 9 +cpr10 CN 10 +cpr11 CN 11 +cpr12 CN 12 +cpr13 CN 13 +cpr14 CN 14 +cpr15 CN 15 + + +; Called by vectoring through command table. +; Read transfer value +; Read and check checksum +; Extract copro register number +; Index suitable MRC instruction +; Perform copro write +; Reply with command byte or FF +; Reply with checksum + +ts_write_cpr15h ROUT + ADDS r4,r4,#8 ; adjust opcode for high registers +ts_write_cpr15l + ADDS r7,r0,r4 ; save opcode to r7 + ADDS r14,r0,pc + B ts_GetWord ; get value for copro + ADDS r9,r0,r4 + ADDS r14,r0,pc + B ts_GetWord ; get checksum + ADDS r4,r4,r9 + LDR r5,%01 + ADD pc,pc,r0 +01 + & (0 - 1) + ADDS r4,r5,r4 ; compare total chex with zero + BCS ts_cmd_error ; carry set on error + + ADDS r13,r7,r7 ; point into instruction table + ADDS r13,r13,r13 + ADDS r13,r13,r13 + ADD pc,pc,r13 ; jump to pc + (r7 * 8) + & 0 + + SetCop r9,cpr0 ; transfer instructions + B %02 + SetCop r9,cpr1 + B %02 + SetCop r9,cpr2 + B %02 + SetCop r9,cpr3 + B %02 + SetCop r9,cpr4 + B %02 + SetCop r9,cpr5 + B %02 + SetCop r9,cpr6 + B %02 + SetCop r9,cpr7 + B %02 + SetCop r9,cpr8 + B %02 + SetCop r9,cpr9 + B %02 + SetCop r9,cpr10 + B %02 + SetCop r9,cpr11 + B %02 + SetCop r9,cpr12 + B %02 + SetCop r9,cpr13 + B %02 + SetCop r9,cpr14 + B %02 + SetCop r9,cpr15 + +02 + LDR r4,%03 + ADD pc,pc,r0 +03 + & ts_CPWCmdByte ; build command byte + option + ADDS r4,r4,r7 + ADDS r14,r0,pc ; echo command byte + B ts_SendByte + ADDS r4,r0,r9 ; return checksum + ADDS r14,r0,pc ; + B ts_SendWord + + B ts_GetCommand + + + + +; Called by vectoring through command table. +; Read and check checksum +; Extract copro register number +; Index suitable MCR instruction +; Perform copro read +; Reply with command byte or FF +; Reply with checksum +; Send transfer results +; Send checksum + +ts_read_cpr15h ROUT + ADDS r4,r4,#8 ; adjust opcode for high registers +ts_read_cpr15l + ADDS r7,r0,r4 ; save opcode in r7 + ADDS r14,r0,pc + B ts_GetWord ; get checksum to r4 + ADDS r9,r0,r4 ; copy to r9 + LDR r5,%01 + ADD pc,pc,r0 +01 + & (0 - 1) + ADDS r4,r5,r4 ; compare total chex with zero + BCS ts_cmd_error ; carry set on error + + LDR r4,%02 + ADD pc,pc,r0 +02 + & ts_CPRCmdByte ; build command byte + option + ADDS r4,r4,r7 + ADDS r14,r0,pc ; echo command byte + B ts_SendByte + ADDS r4,r0,r9 ; return checksum + ADDS r14,r0,pc + B ts_SendWord + + ADDS r13,r7,r7 ; point into instruction table + ADDS r13,r13,r13 + ADDS r13,r13,r13 + ADD pc,pc,r13 ; jump to pc + (r7 * 8) + & 0 + + ReadCop r12,cpr0 ; transfer instructions + B %03 + ReadCop r12,cpr1 + B %03 + ReadCop r12,cpr2 + B %03 + ReadCop r12,cpr3 + B %03 + ReadCop r12,cpr4 + B %03 + ReadCop r12,cpr5 + B %03 + ReadCop r12,cpr6 + B %03 + ReadCop r12,cpr7 + B %03 + ReadCop r12,cpr8 + B %03 + ReadCop r12,cpr9 + B %03 + ReadCop r12,cpr10 + B %03 + ReadCop r12,cpr11 + B %03 + ReadCop r12,cpr12 + B %03 + ReadCop r12,cpr13 + B %03 + ReadCop r12,cpr14 + B %03 + ReadCop r12,cpr15 + +03 + ADDS r4,r0,r12 ; return result + ADDS r14,r0,pc + B ts_SendWord + SUBS r4,r0,r12 ; return checksum + ADDS r14,r0,pc + B ts_SendWord + + B ts_GetCommand + + + END + + diff --git a/OldTestSrc/ExtIO b/OldTestSrc/ExtIO new file mode 100644 index 0000000000000000000000000000000000000000..8ef956a201a997890c60749536a7896ac60b7cad --- /dev/null +++ b/OldTestSrc/ExtIO @@ -0,0 +1,1089 @@ +; > TestSrc.ExtIO + + TTL RISC OS 2+ POST external commands +; +; External interface for RISC OS ROM. +; provides entry points to send byte- and word- and string-sized objects +; and to receive byte- and word-sized objects +; +; A minimal set of opcodes should be used (ideally, only B, LDR and ADDS) +; so that a processor test may be validly included in the internal test +; sequence. +; +;------------------------------------------------------------------------ +; History +; +; Date Name Comment +; ---- ---- ------- +; 06-Dec-89 ArtG Initial version - split from `Begin` +; Release 0.2 for integration +; 31-Mar-90 ArtG Added ts_MoreText, cursor position, hex. +; 19-Apr-90 ArtG Added bus exercise commands +; 09-May-90 ArtG Changed LCD strobe to 12 pulses +; 15-May-90 ArtG Added ReadyByte : improves synchronization +; when ExtCmd execution toggles A21/A22. +; 18-Jun-90 ArtG Added CPR15 read/write functions +; +; +;------------------------------------------------------------------------ + + + SUBT Test adapter interface + +; +; The test adapter senses an access to the ROM with address line A21 high. +; Current (2M addressing space) ROMs only use address lines A2 to A20, +; so if A21 to A22 are asserted they will be ignored (the ROMS are aliased +; into 8M of space). With no test adapter, the aliased ROM location will +; be read and may be recognised. The test adapter may selectively disable +; ROMs when A21 is high, causing arbitrary data to be read. This data +; should be dependent on the previous ROM read operation, and will +; therefore be predictably not equal to the data read when the ROMs are +; aliased. +; The assumption that A21 is unused may be invalidated by a later issue +; of the PCB. A22 is therefore asserted at the same time : this will then +; be used on a PCB where A22 is tracked to a test connector and 8Mbit ROMS +; are used. Machines using larger ROMs than 8 Mbit (4M addressing space) +; will require explicit decoding or a new communication scheme. +; + + +; +; This section determines whether the test interface adapter exists, and +; what variety is fitted (dumb, display or external) +; 3 read operations are performed (a WS operation): if all of these +; find a ROM alias then no adapter is fitted. +; +; If an adapter responds, then a RD operation is performed - 4 strobes then +; clocking 8 bits into r4. These bits may be all zeros (a dumb adapter) +; or all ones (a display adapter) or some other value (an external +; adapter) +; + +ts_GetCommand ROUT + + LDR r0,%01 + ADD pc,pc,r0 +01 + & 0 + + ; delay to make a gap before reading + + LDR r3,%02 + ADD pc,pc,r0 +02 + & ts_recover_time +03 + ADDS r3,r3,r3 ; 16-loop delay + BCC %03 + + ROUT + +; +; Load up the registers for the test interface communication - +; + + LDR r0,%01 ; set zero in r0 + ADD pc,pc,r0 ;(generally useful constant - especially for skip) +01 + & 0 + LDR r1,%02 ; set FFFFFFFF in r1 + ADD pc,pc,r0 ;(test value : sets carry when added to non-zero) +02 + & (-1) + LDR r2,%03 ; set pointer to test address + ADD pc,pc,r0 ;(points to aliased copy of a zero word) +03 + & (ts_Alias_bits + (%01 - %04)) + ADDS r2,pc,r2 ; adjust r2 for ROM-relative address + ADDS r4,r0,r0 ; clear output accumulator +04 ; where pc is when added to r2 + + ; do an RD operation (four strobes) to ensure interface cleared + + LDR r3,[r2] + ADDS r3,r3,r1 + LDR r3,[r2] + ADDS r3,r3,r1 + LDR r3,[r2] + ADDS r3,r3,r1 + LDR r3,[r2] + ADDS r3,r3,r1 + + ; write a byte (initially, &90) to indicate readiness + + LDR r4,%20 + ADD pc,pc,r0 +20 + & ts_ReadyByte_00 + ADDS r14,r0,pc + B ts_SendByte + + ; delay to make a gap between WRS and RD operations + + LDR r3,%05 + ADD pc,pc,r0 +05 + & ts_recover_time +06 + ADDS r3,r3,r3 ; 16-loop delay + BCC %06 + + LDR r5,%07 ; counter for first 5 bits + ADD pc,pc,r0 +07 + & 1 :SHL: (32 - 5) + LDR r6,%08 ; counter for last 3 bits + ADD pc,pc,r0 +08 + & 1 :SHL: (32 - 3) + ADDS r4,r0,r0 ; input accumulator initialisation + +; put the test interface into input mode + + LDR r3,[r2] ; 3 bit lead-in + ADDS r3,r3,r1 ; (adapter detects WS operation) + BCC ts_User_startup ; abort if no adapter present + + LDR r3,[r2] ; two more strobes, then waitloop + ADDS r3,r3,r1 + LDR r3,[r2] + ADDS r3,r3,r1 + +; started input operation : wait for interface to be ready + +09 + LDR r3,[r2] ; read start bit repeatedly + ADDS r3,r3,r1 ; (adapter detects RD operation) + BCC %09 ; loop until interface is ready + +; read the first 5 bits into r5 and the second 3 bits into r4 + +10 LDR r3,[r2] ; read a bit of the byte + ADDS r3,r3,r1 ; .. if the test adapter is present, carry bit set + ADCS r4,r4,r4 ; .. shift left and add in carry + + ADDS r5,r5,r5 ; loop until 5 bits are read + BCC %10 + + ADDS r5,r4,r4 ; copy bits 7..3 to r5, bits 5..1 + + ADDS r4,r0,r0 ; and read the last 3 bits to r4 +11 LDR r3,[r2] ; read a bit of the byte + ADDS r3,r3,r1 + ADCS r4,r4,r4 + + ADDS r6,r6,r6 ; loop until last 3 bits are read + BCC %11 + +; +; Command byte read in (split between r4 and r5) +; Pass the option bits (r4) to the function identified by r5. +; + + ADDS r5,r5,r5 ; index * 2 -> index * 4 + LDR r3,%12 ; pc-relative ptr to command_table + ADD pc,pc,r0 +12 + & ts_command_table - %13 + ADDS r3,pc,r3 ; absolute pointer to command table + ADDS r3,r3,r5 + +13 LDR r3,[r3] ; get table entry +14 ADD pc,pc,r3 ; (offset from command_table) + + & 0 ; necessary padding : pc must point + ; to command table when r3 is added. + +; +; This is the table of offsets to all the built-in functions. +; The top 5 bits of the command are used to index, so there are +; 32 possible entries, mostly illegal. +; Decoding of the function modifier bits is performed by multiple +; entries in this table. +; + +; pc must point here when ADDS pc,r3,pc is executed + + ASSERT ((ts_command_table - %14) = 8) + +ts_command_table + + DCD (ts_Dealer_startup - ts_command_table) ; display interface +ts_Windex + DCD (ts_write_memory - ts_command_table) ; external tests +ts_Rindex + DCD (ts_read_memory - ts_command_table) +ts_Eindex + DCD (ts_execute - ts_command_table) +ts_Bindex + DCD (ts_bus_exercise - ts_command_table) + + DCD (ts_GetCommand - ts_command_table) ; dummy entry aligns CPR instructions + ; to allow 4-bit option field +ts_CWindex + DCD (ts_write_cpr15l - ts_command_table) + DCD (ts_write_cpr15h - ts_command_table) +ts_CRindex + DCD (ts_read_cpr15l - ts_command_table) + DCD (ts_read_cpr15h - ts_command_table) + + ; pad the table out to 31 entries + ; (leave space for display vector) + +OldOpt SETA {OPT} + OPT OptNoList +doffset SETA . + WHILE doffset < (ts_command_table + (31 * 4)) ; illegal entries + DCD (ts_GetCommand - ts_command_table) +doffset SETA doffset + 4 + WEND + OPT OldOpt + + DCD (ts_Forced_startup - ts_command_table) ; dumb interface + +; +; The indexes into the above table are needed in ExtCmd ... +; +ts_WriteCmdByte * ((ts_Windex - ts_command_table) :SHL: 1) +ts_ReadCmdByte * ((ts_Rindex - ts_command_table) :SHL: 1) +ts_ExecuteCmdByte * ((ts_Eindex - ts_command_table) :SHL: 1) +ts_BusExCmdByte * ((ts_Bindex - ts_command_table) :SHL: 1) +ts_CPWCmdByte * ((ts_CWindex - ts_command_table) :SHL: 1) +ts_CPRCmdByte * ((ts_CRindex - ts_command_table) :SHL: 1) + + +; +; Primitives for reading data from the external interface +; +; - Get a byte from the interface (into r4) +; - Get a (4 byte) word from the interface (into r4) +; +; Required register setup is presumed done by a recent ts_GetCommand. +; r0, r1 and r2 have critical values +; r14 is the link address +; + +ts_GetWord ROUT + + LDR r6,%01 ; counter for 4 bytes per word + ADD pc,pc,r0 ; (bit set 4 left shifts from Carry) +01 + & 1 :SHL: (32 - 4) + B ts_Getdata + +ts_GetByte ROUT + LDR r6,%01 ; counter for single byte + ADD pc,pc,r0 +01 + & 1 :SHL: (32 - 1) + +ts_Getdata ROUT + ADDS r4,r0,r0 ; input accumulator initialisation + + LDR r3,[r2] ; 3 bit lead-in + ADDS r3,r3,r1 ; (adapter detects RD operation) + LDR r3,[r2] + ADDS r3,r3,r1 + LDR r3,[r2] + ADDS r3,r3,r1 + +; started input operation : now loop until r6 shifts into Carry + +02 + LDR r5,%03 ; counter for 8 bits per byte + ADD pc,pc,r0 +03 + & 2_00000001000000010000000100000001 +04 + LDR r3,[r2] ; read start bit repeatedly + ADDS r3,r3,r1 + BCC %04 ; loop until interface is ready +05 + LDR r3,[r2] ; read a bit of the byte + ADDS r3,r3,r1 + ADCS r4,r4,r4 ; SHL r4, add carry bit. + + ADDS r5,r5,r5 ; loop until byte is read + BCC %05 + + ADDS r6,r6,r6 ; loop until word is read + BCC %04 + + ADD pc,r0,r14 ; back to the caller + + +; +; Primitives for sending data to the interface +; +; - Send a byte to the interface (from r4 lsb) +; - Send a (4 byte) word to the interface (from r4) +; +; Required register setup is presumed done by a recent ts_GetCommand. +; r0, r1 and r2 have critical values +; r14 is the link address +; + +ts_SendWord ROUT + LDR r6,%01 ; counter for 4 bytes per word + ADD pc,pc,r0 ; (bit set 4 left shifts from Carry) +01 + & 1 :SHL: (32 - 4) + B ts_Putdata + +ts_SendByte ROUT + LDR r6,%01 ; counter for single byte + ADD pc,pc,r0 +01 + & (3 :SHL: 7) +02 ADDS r4,r4,r4 ;shift byte into highest 8 bits + ADDS r6,r6,r6 + BCC %02 ;stop when byte shifted, + ;leaving bit 31 set in r6 + +ts_Putdata ROUT + +; Wait - gap between successive WS attempts or successive bytes + +01 LDR r3,%02 + ADD pc,pc,r0 +02 + & ts_recover_time +03 ADDS r3,r3,r3 ; 16-loop delay + BCC %03 + + LDR r3,[r2] ; Test for adapter ready for data + ADDS r3,r3,r1 ; (adapter detects WS operation) + LDR r3,[r2] + ADDS r3,r3,r1 + BCC %10 ; skip out if adapter not present + LDR r3,[r2] + ADDS r3,r3,r1 + BCC %01 ; loop back until adapter is ready + +; Adapter ready - loop around all the bits in the byte + + LDR r5,%04 ; load bits-per-byte counter + ADD pc,pc,r0 +04 + & (1 :SHL: (32-8)) + +05 LDR r3,%06 ; delay before sending bit + ADD pc,pc,r0 +06 + & ts_recover_time +07 ADDS r3,r3,r3 ; 16-loop delay + BCC %07 + + ; Send a single bit : 1 pulse for 1, 2 pulses for 0 + + LDR r3,[r2] + ADDS r4,r4,r4 ; shift current bit into Carry + LDRCC r3,[r2] ; second pulse if bit is 0 + + ; repeat until 8 bits are sent + + ADDS r5,r5,r5 + BCC %05 + +; Repeat for all the bytes to be sent (1 or 4) + + ADDS r6,r6,r6 + BCC %01 + +; Go to TXRDY to ensure the host sees the transmit request + + LDR r3,%08 ; delay before sending pattern + ADD pc,pc,r0 +08 + & ts_recover_time +09 ADDS r3,r3,r3 ; 16-loop delay + BCC %09 + + LDR r3,[r2] + ADDS r3,r3,r1 ; dummy - space between pulses + LDR r3,[r2] + ADDS r3,r3,r1 + LDR r3,[r2] + +; All sent - r14 holds the caller's return address +10 + ADD pc,r0,r14 + + + +; +; Reporting primitive +; +; - Send the text (nul-terminated, at r4) to the display +; +; Interface registers need to be set up : this function is called from test +; code rather than external interface code. +; +; The display is assumed to be a standard 16 character LCD module using +; the Hitachi HD44780 display controller. +; The 16-digit module uses a single 44780. This is an abnormal use of the +; controller, and requires it to be set to two-line mode, with the first +; 8 displayed characters on the first 'line', and the second 8 on the +; second 'line'. Characters sent to the second line must be written at +; character position 40 +. In order to permit different modules to be +; fitted to later adapters, it is suggested that the first 7 characters +; be treated as a 'title' line, and the second 8 as a 'comment' line. +; A space should always be placed at the end of the title line to +; split the display fields, unless there is no 'comment' line. +; Do not display characters across the two areas as though they adjoined +; (even though they do :-) ). +; +; The controller is operated in its 4-bit mode, which allows the interface +; to drive 4 bits of alpha information and 4 bits of control information. +; The bits in a transmitted byte are assigned as : +; +; bit 0 - D4 } 4-bit mode data bus +; 1 - D5 } +; 2 - D6 } +; 3 - D7 } +; +; 4 - RS Register Select : 0 for control, 1 for data +; +; 5 - } Unassigned +; 6 - } +; +; 7 - CPEN Interface control : 0 for enable, +; 1 for disable +; +; For each message sent, the display is first initialised, using the +; following sequence (each byte is sent as 2 bytes, high nibble first, +; with RS clear in bit 4 of each byte) +; After each byte, an RD operation is performed : this is used by the +; interface hardware to strobe the data into the display. +; +; +; The message addressed by r4 is then sent (data mode : RS set in each byte) +; until a 0 byte is encountered. +; + +; +; This is the command sequence sent to initialise the display +; + +ts_initialise + = &30,&30,&30,&20 ; power-up initialisation + = &20,&80 ; 4 bit mode, two line, Font 0 + = &00,&C0 ; Display on, no cursor visible + = &00,&60 ; Incrementing display position, no shift + = &80,&00 ; Set DD RAM address 0 + = &00,&20 ; Cursor home + = &00,&10 ; Display clear +ts_initialise_end + + ASSERT ((ts_initialise_end - ts_initialise) / 2) < 32 + + +; +; This is the command sequence sent when continuation text is sent +; + +ts_extend + = &00,&C0 ; Display on, cursor invisible + = &00,&60 ; Incrementing display position, no shift +ts_extend_end + + ASSERT ((ts_extend_end - ts_extend) / 2) < 32 + +; +; One of these commands are sent when offset text is required +; + +ts_offset_table + = &80,&00 ; Set DD RAM address 0 +ts_offset_table_1 + = &80,&10 ; Set DD RAM address 1 + = &80,&20 ; Set DD RAM address 2 + = &80,&30 ; Set DD RAM address 3 + = &80,&40 ; Set DD RAM address 4 + = &80,&50 ; Set DD RAM address 5 + = &80,&60 ; Set DD RAM address 6 + = &80,&70 ; Set DD RAM address 7 + = &C0,&00 ; Set DD RAM address 40 + = &C0,&10 ; Set DD RAM address 41 + = &C0,&20 ; Set DD RAM address 42 + = &C0,&30 ; Set DD RAM address 43 + = &C0,&40 ; Set DD RAM address 44 + = &C0,&50 ; Set DD RAM address 45 + = &C0,&60 ; Set DD RAM address 46 + = &C0,&70 ; Set DD RAM address 47 + + +; This assertion is forced by the code : each sequence assumed 2 bytes. + + ASSERT ((ts_offset_table_1 - ts_offset_table) = 2) + + + + ALIGN + +; +; Here starts the code ... +; + +ts_SendQuit ROUT ; put this code BEFORE %16 + ADD pc,r0,r14 ; + + + +; +; Entry point for initialising the display and sending r4 text. +; + + +ts_SendText ROUT + +; +; Point to the command sequence to setup and clear the display +; + + LDR r0,%10 ; set zero in r0 + ADD pc,pc,r0 +10 + & 0 + LDR r7,%11 ; pointer to init sequence + ADDS r7,pc,r7 + ADD pc,pc,r0 +11 + & (ts_initialise - .) + LDR r6,%12 ; length of init sequence + ADD pc,pc,r0 +12 + & (1 :SHL: (32 - (ts_initialise_end - ts_initialise))) + B ts_SendLCDCmd + + +; +; Entry point for adding text to current cursor position +; + +ts_MoreText ROUT + + LDR r0,%10 ; set zero in r0 + ADD pc,pc,r0 +10 + & 0 + LDR r7,%11 ; pointer to command sequence + ADDS r7,pc,r7 + ADD pc,pc,r0 +11 + & (ts_extend - .) + LDR r6,%12 ; length of command sequence + ADD pc,pc,r0 +12 + & (1 :SHL: (32 - (ts_extend_end - ts_extend))) + B ts_SendLCDCmd + + +ts_PosText ROUT + +; +; Entry point for adding text at a specific cursor position +; Used iteratively by SendText, etc if cursor position command found. +; Offset into display is given in r6. +; + + LDR r0,%10 ; set zero in r0 + ADD pc,pc,r0 +10 + & 0 + LDR r7,%11 ; pointer to command sequence + ADDS r7,pc,r7 + ADD pc,pc,r0 +11 + & (ts_offset_table - .) ; offset * 2 into table of + ADDS r6,r6,r6 ; offset command sequences + ADDS r7,r7,r6 + + LDR r6,%12 ; length of command sequence + ADD pc,pc,r0 +12 + & (1 :SHL: (32 - 2)) + + +; +; Entry point for writing arbitrary command strings. +; Set r7 to point to command string, r6 length (as tables above), +; Set r4 to point to following Data string (null-terminated). +; + +ts_SendLCDCmd + + LDR r0,%01 ; set zero in r0 + ADD pc,pc,r0 +01 + & 0 + LDR r1,%02 ; set FFFFFFFF in r1 + ADD pc,pc,r0 ;(test value : sets carry when added to non-zero) +02 + & (-1) + LDR r2,%03 ; set pointer to test address + ADD pc,pc,r0 ;(points to aliased copy of a zero word) +03 + & (ts_Alias_bits + (%01 - %04)) + ADDS r2,pc,r2 ; adjust r2 for ROM-relative address + ADDS r0,r0,r0 ; dummy (to keep labels nearby !) +04 ; where pc points when added to r2 + + +; Wait - gap between successive WS attempts or successive bytes + +ts_send_command_byte ROUT + + LDR r3,%14 + ADD pc,pc,r0 +14 + & ts_recover_time +15 ADDS r3,r3,r3 ; 16-loop delay + BCC %15 + LDR r1,%16 ; reload test register + ADD pc,pc,r0 +16 + & (-1) + + LDR r3,[r2] ; Test for adapter ready for data + ADDS r3,r3,r1 ; (adapter detects WS operation) + BCC ts_SendQuit ; skip output : adapter not present + ; (backward jump helps ensure LDR r3,[r2] + ; only reads zero when adapter absent + LDR r3,[r2] ; since previous bus data is nonzero) + ADDS r3,r3,r1 + LDR r3,[r2] + ADDS r3,r3,r1 + BCC ts_send_command_byte ; loop back until adapter is ready + +; Adapter ready - loop around all the bits in the byte + + + LDR r5,%21 ; load byte-shift counter ... + ADD pc,pc,r0 ; ... and bits-per-byte counter +21 + & (1 :SHL: 8) + 1 ; 24 shifts + 8 shifts + LDRB r1,[r7] +22 ADDS r1,r1,r1 ; shift byte up into m.s.d. + ADDS r5,r5,r5 + BCC %22 + + ; Send a single bit : 1 pulse for 1, 2 pulses for 0 + +23 LDR r3,[r2] + ADDS r1,r1,r1 ; shift current bit into Carry + LDRCC r3,[r2] ; second pulse if bit is 0 + + ; and wait for the inter-bit time + + LDR r3,%24 + ADD pc,pc,r0 +24 + & ts_recover_time +25 ADDS r3,r3,r3 ; 16-loop delay + BCC %25 + + ; repeat until 8 bits are sent + + ADDS r5,r5,r5 + BCC %23 + + ; do a RD operation to strobe the data out + + LDR r5,%26 + ADD pc,pc,r0 +26 + & (1 :SHL: (32 - 12)) +27 + LDR r3,[r2] + ADDS r5,r5,r5 + BCC %27 + +; Repeat for all the bytes to be sent (ts_initialise_end - ts_initialise) + + LDR r3,%33 + ADD pc,pc,r0 +33 + & 1 + ADDS r7,r7,r3 ; bump the pointer + ADDS r6,r6,r6 ; bump the counter (shift left) + BCC ts_send_command_byte + + +; +; Then send all the display bytes (in 4-bit mode) until a nul-terminator +; is reached. +; + +; +; Send a single character (as two separate 4-bit fields) +; First, look to see if it's one of : +; +; NUL - end of text string +; 0x80 - 0xfe - cursor positioning +; 0xff - introduce a hex digit +; + +ts_send_text_byte ROUT + + LDR r1,%40 ; reload test register + ADD pc,pc,r0 +40 + & (-1) + + LDRB r7,[r4] + ADDS r3,r7,r1 ; test for nul terminator + BCC ts_SendEnd + +; +; Byte isn't null. Check for >= 0x80. +; + + LDR r6,%42 ; test for cursor control + ADD pc,pc,r0 +42 + & (-&80) ; &8x means column x. + ADDS r6,r7,r6 + BCC ts_printable_char ; < &80 : write a character + +; +; Carry set : r6 now holds (value - 0x80). Check for numeric escape (&ff). +; + LDR r3,%43 + ADD pc,pc,r0 +43 + & (-&7f) + ADDS r3,r6,r3 + BCC %47 + +; +; Carry set : fetch a nybble from the top of r8 and display that. +; + + ADDS r8,r8,r8 + ADCS r6,r0,r0 + ADDS r8,r8,r8 + ADCS r6,r6,r6 + ADDS r8,r8,r8 + ADCS r6,r6,r6 + ADDS r8,r8,r8 + ADCS r6,r6,r6 + + LDRB r7,[pc,r6] + B ts_printable_char +45 + = "0123456789ABCDEF" + +; +; Not &ff : r6 holds cursor positioning offset (< &80). Skip over +; the cursor control byte and iterate thro' PosText to move +; typing position. +; + +47 + LDR r3, %48 + ADD pc,pc,r0 +48 + & 1 + ADDS r4,r3,r4 + B ts_PosText + +; +; Character is normal text : write it to the LCD. +; The shift loop is used to generate the inter-byte delay normally +; provided by ts_recover_time. Always make sure this is long enough. +; + +ts_printable_char + + ADDS r6,r0,r7 ; take a copy of character + LDR r5,%51 ; load byte-shift counter ... + ADD pc,pc,r0 ; ... and bits-per-byte counter +51 ; as a bitmask of the shift pattern + & (1:SHL:8)+(1:SHL:4)+1 ; 24 shifts + 4 shifts + 4 shifts +52 ADDS r6,r6,r6 ; shift byte up into m.s.d. + ADDS r0,r0,r0 ; slow this loop down - ensure it's + ADDS r0,r0,r0 ; always slower than ts_recover_time + ADDS r5,r5,r5 + BCC %52 + + LDR r3,[r2] ; Test for adapter ready for data + ADDS r3,r3,r1 ; (adapter detects WS operation) + LDR r3,[r2] + ADDS r3,r3,r1 + LDR r3,[r2] + ADDS r3,r3,r1 + BCC ts_printable_char ; loop back until adapter is ready + +; Adapter ready - loop around all the bits in the byte + +ts_send_tbit_upper + + ; wait for the inter-bit time + + LDR r3,%55 + ADD pc,pc,r0 +55 + & ts_recover_time +56 ADDS r3,r3,r3 ; 16-loop delay + BCC %56 + + ; Send a single bit : 1 pulse for 1, 2 pulses for 0 + + LDR r3,[r2] + ADDS r6,r6,r6 ; shift current bit into Carry + LDRCC r3,[r2] ; second pulse if bit is 0 + + ; repeat until upper 4 bits are sent + + ADDS r5,r5,r5 + BCC ts_send_tbit_upper + + ; then send the interface control bits + + LDR r1,%57 + ADD pc,pc,r0 +57 + & (8 :SHL: 28) ; assert RS control pin + +ts_send_cbit_upper + + ; wait for the inter-bit time + + LDR r3,%58 + ADD pc,pc,r0 +58 + & ts_recover_time +59 ADDS r3,r3,r3 ; 16-loop delay + BCC %59 + + ; Send a single bit : 1 pulse for 1, 2 pulses for 0 + + LDR r3,[r2] + ADDS r1,r1,r1 ; shift current bit into Carry + LDRCC r3,[r2] ; second pulse if bit is 0 + ADDS r5,r5,r5 + BCC ts_send_cbit_upper + +; +; do a RD operation to strobe the data out +; + + LDR r3,%61 + ADD pc,pc,r0 +61 + & ts_recover_time +62 ADDS r3,r3,r3 ; 16-loop delay + BCC %62 + + LDR r5,%63 + ADD pc,pc,r0 +63 + & (1 :SHL: (32 - 12)) +64 + LDR r3,[r2] + ADDS r5,r5,r5 + BCC %64 + + ; prepare to send the lower 4 bits out + + LDR r5,%70 ; bitcount mask for 4 data bits + ADD pc,pc,r0 ; and 4 interface control bits +70 + & (((1 :SHL: 4) + 1) :SHL: 24) + +ts_send_text_lower + LDR r3,%71 + ADD pc,pc,r0 +71 + & ts_recover_time +72 ADDS r3,r3,r3 ; 16-loop delay + BCC %72 + + LDR r1,%73 + ADD pc,pc,r0 +73 + & (-1) + + LDR r3,[r2] ; Test for adapter ready for data + ADDS r3,r3,r1 ; (adapter detects WS operation) + LDR r3,[r2] + ADDS r3,r3,r1 + LDR r3,[r2] + ADDS r3,r3,r1 + BCC ts_send_text_lower ; loop back until adapter is ready + +ts_send_tbit_lower + + ; wait for the inter-bit time + + LDR r3,%76 + ADD pc,pc,r0 +76 + & ts_recover_time +77 ADDS r3,r3,r3 ; 16-loop delay + BCC %77 + + ; Send a single bit : 1 pulse for 1, 2 pulses for 0 + + LDR r3,[r2] + ADDS r6,r6,r6 ; shift current bit into Carry + LDRCC r3,[r2] ; second pulse if bit is 0 + + ; repeat until lower 4 bits are sent + + ADDS r5,r5,r5 + BCC ts_send_tbit_lower + + + ; then send the interface control bits + + LDR r1,%78 + ADD pc,pc,r0 +78 + & (8 :SHL: 28) ; assert RS control pin + +ts_send_cbit_lower + + ; wait for the inter-bit time + + LDR r3,%80 + ADD pc,pc,r0 +80 + & ts_recover_time +81 ADDS r3,r3,r3 ; 16-loop delay + BCC %81 + + ; Send a single bit : 1 pulse for 1, 2 pulses for 0 + + LDR r3,[r2] + ADDS r1,r1,r1 ; shift current bit into Carry + LDRCC r3,[r2] ; second pulse if bit is 0 + + ADDS r5,r5,r5 + BCC ts_send_cbit_lower + +; +; do a RD operation to strobe the data out +; + + ; wait for the inter-bit time + + LDR r3,%82 + ADD pc,pc,r0 +82 + & ts_recover_time +83 ADDS r3,r3,r3 ; 16-loop delay + BCC %83 + + LDR r5,%84 + ADD pc,pc,r0 +84 + & 1 :SHL: (32 - 12) +85 + LDR r3,[r2] + ADDS r5,r5,r5 + BCC %85 + +; Repeat for all the bytes to be sent (until nul terminator is found) + + LDR r3,%86 + ADD pc,pc,r0 +86 + & 1 + ADDS r4,r3,r4 ; bump text pointer + B ts_send_text_byte + +; +; Wait for about 1 seconds worth of LCD operation delays to +; permit the operator to read the text. +; Use of the interface's monitor allows this delay to be increased +; or decreased externally. +; + +ts_SendEnd ROUT + + LDR r7, %01 + ADD pc,pc,r0 +01 + & (ts_pause_time + 1) ; must be an odd number + ; to ensure pairs of zeros + ASSERT ((ts_pause_time :AND: 1) = 0) + +02 + LDR r3,%03 + ADD pc,pc,r0 +03 + & ts_recover_time +04 ADDS r3,r3,r3 ; 16-loop delay + BCC %04 + LDR r1,%05 ; reload test register + ADD pc,pc,r0 +05 + & (-1) + + LDR r3,[r2] ; Test for adapter ready for data + ADDS r3,r3,r1 ; (adapter detects WS operation) + BCC ts_SendQuit ; skip output : adapter not present + LDR r3,[r2] + ADDS r3,r3,r1 + LDR r3,[r2] + ADDS r3,r3,r1 + BCC %02 ; loop back until adapter is ready + +; Adapter ready - loop around all the bits in the byte +; Note that each byte is actually 4 bits to the LCD module, +; so a even number must be sent or the display will get out +; of sync until the next display reset sequence. + + LDR r5,%10 ; bits-per-byte counter + ADD pc,pc,r0 +10 + & (1 :SHL: 24) + LDR r3,%11 + ADD pc,pc,r0 +11 + & ts_recover_time ; wait before sending data bits +12 ADDS r3,r3,r3 ; for byte timing. + BCC %12 + + ; Send a single bit : always 2 pulses for 0 + +13 LDR r3,[r2] + LDR r3,[r2] + + ; and wait for the inter-bit time + + LDR r3,%14 + ADD pc,pc,r0 +14 + & ts_recover_time +15 ADDS r3,r3,r3 ; 16-loop delay + BCC %15 + + ; repeat until 8 bits are sent + + ADDS r5,r5,r5 + BCC %13 + + ; do a RD operation to strobe the data out + + LDR r5,%16 + ADD pc,pc,r0 +16 + & 1 :SHL: (32 - 12) +17 + LDR r3,[r2] + ADDS r5,r5,r5 + BCC %17 + + ; repeat until a sufficient number of nuls are done + + ADDS r7,r7,r1 ; count down loop counter + BCS %02 + + ADD pc,r0,r14 ; back to caller + + + END diff --git a/OldTestSrc/Ioc b/OldTestSrc/Ioc new file mode 100644 index 0000000000000000000000000000000000000000..5ec8b152fdf554b2189b3c4302c3bfcde1514918 --- /dev/null +++ b/OldTestSrc/Ioc @@ -0,0 +1,92 @@ +; > TestSrc.IOC + + TTL RISC OS 2+ POST IO controller +; +; This initial IOC test simply reports the content of the IRQ and FIRQ +; registers, to show any unexpected pending IRQs. +; Certain of these should really be cleared, and the effect of an +; interrupt tested. +; +;------------------------------------------------------------------------ +; History +; +; Date Name Comment +; ---- ---- ------- +; 18-Dec-89 ArtG Initial version +; 29-Nov-91 ArtG Added IOC bus test using mask registers +; 20-Jun-93 ArtG Modified for 29-bit IOMD test +; +; +;------------------------------------------------------------------------ + + [ IO_Type = "IOMD" +ts_IObase * IOMD_Base +ts_IOmask * &1fffffff +ts_IOreg1 * IOMD_VIDCUR +ts_IOreg2 * IOMD_VIDSTART +ts_IObswap * 32 +ts_IOMD_ID * &D4E7 + | +ts_IObase * IOC +ts_IOmask * &ff0000 +ts_IOreg1 * IOCIRQMSKA +ts_IOreg2 * IOCIRQMSKB +ts_IObswap * 16 + ] + +ts_IOCreg + MOV r0,#0 ; zero error accumulator + LDR r3, =ts_IObase + MOV r1,#(1 :SHL: 31) ; initialise bit-set test mask +0 + MVN r2,r1 ; make bit-clear test mask + ANDS r4,r1,#ts_IOmask + BEQ %FT1 ; skip if this bit isn't tested + STR r1,[r3,#ts_IOreg1] + STR r2,[r3,#ts_IOreg2] + LDR r4,[r3,#ts_IOreg1] +; EOR r4, r4, r1, LSR #ts_IObswap ; check bit-set test was OK + EOR r4, r4, r1 ; check bit-set test was OK + ORR r0, r0, r4 ; accumulate errors in r0 + LDR r4,[r3,#ts_IOreg2] +; EOR r4, r4, r2, LSR #ts_IObswap ; check bit-clear test was OK + EOR r4, r4, r2 ; check bit-clear test was OK + ORR r0, r0, r4 ; accumulate errors in r0 +1 + MOV r1, r1, LSR #1 ; shift mask downwards + TEQ r1,#0 + BNE %BT0 ; and loop until all bits tested + + ANDS r8, r0, #ts_IOmask + MOV pc,r14 ; return error if any bit failed + +ts_IOCstat + LDR r3, =ts_IObase + MOV r0,#0 + [ IO_Type = "IOMD" + LDRB r1,[r3,#IOMD_ID1] + ORR r0,r0,r1, LSL #(32-24) + LDRB r1,[r3,#IOMD_ID0] + ORR r0,r0,r1 + LDR r1,=ts_IOMD_ID + CMPS r0,r1 ; check IOMD identity + MOV r0,r0,LSL #16 + LDRB r1,[r3,#IOMD_VERSION] + ORR r8,r0,r1, LSL #12 + MOV pc,r14 + | + LDRB r1,[r3,#IOCControl] + ORR r0,r0,r1, LSL #(32 - 8) + LDRB r1,[r3,#IOCIRQSTAA] + ORR r0,r0,r1, LSL #(32 - 16) + LDRB r1,[r3,#IOCIRQSTAB] + ORR r0,r0,r1, LSL #(32 - 24) + LDRB r1,[r3,#IOCFIQSTA] + ORR r8,r0,r1 + ANDS r1,r1,#0 ; return zero flag (OK) + + MOV pc,r14 + ] + + END + diff --git a/OldTestSrc/MEMC1 b/OldTestSrc/MEMC1 new file mode 100644 index 0000000000000000000000000000000000000000..847df36843534aee6f4bee0f4244300f5e4bff17 --- /dev/null +++ b/OldTestSrc/MEMC1 @@ -0,0 +1,552 @@ +; > MEMC1 + +; MEMC interface file - MEMC1 version + +; Created by TMD 10-Aug-90 + +VInit * &03600000 +VStart * &03620000 +VEnd * &03640000 +CInit * &03660000 +; SStart * &03680000 +; SEnd * &036A0000 +; SPtr * &036C0000 + +; ***************************************************************************** +; +; SetDAG - Program DMA address generator R1 with physical address R0 +; +; in: r0 = physical address +; r1 = index of DMA address generator to program, as defined in vdudecl +; +; out: All registers preserved, operation ignored if illegal +; + + [ {FALSE} +SetDAG ENTRY "r0" + CMP r1, #MEMCDAG_MaxReason + EXIT HI + ADR r14, DAGAddressTable + LDR r14, [r14, r1, LSL #2] ; load base address in MEMC1 + MOV r0, r0, LSR #4 ; bottom 4 bits irrelevant + CMP r0, #(1 :SHL: 15) ; ensure in range + ORRCC r14, r14, r0, LSL #2 + STRCC r14, [r14] ; any old data will do + EXIT + + GBLA DAGIndex +DAGIndex SETA 0 + + MACRO + DAGTab $reason, $address + ASSERT ($reason)=DAGIndex + & $address +DAGIndex SETA DAGIndex + 1 + MEND + +DAGAddressTable + DAGTab MEMCDAG_VInit, VInit + DAGTab MEMCDAG_VStart, VStart + DAGTab MEMCDAG_VEnd, VEnd + DAGTab MEMCDAG_CInit, CInit + ] +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; CAM manipulation utility routines + +BangCamUpdate ROUT + +; R2 = CAM entry no +; R3 = logaddr +; R9 = current MEMC value +; R11 = PPL +; set and update tables + + MOV R4, #0 + LDR R4, [R4, #CamEntriesPointer] + ORR r0, r3, r11, LSL #28 ; top nibble is PPL + STR r0, [R4, R2, LSL #2] + +BangCam + +; r0 corrupted +; r1 corrupted +; R2 = CAM entry no +; R3 = logaddr +; r4 corrupted +; r5 spare! +; r6 corrupted +; r7, r8 spare +; R9 = current MEMC value +; r10 spare +; R11 = PPL +; r12 spare + + AND R4, R9, #&C ; pagesize + ADR R0, PageMangleTable + LDR R0, [R0, R4] ; load data table pointer + MOV R4, #0 +01 LDR R1, [R0], #4 + CMP R1, #-1 + BEQ %FT02 + AND R6, R2, R1 + LDR R1, [R0], #4 + CMP R1, #0 + RSBMI R1, R1, #0 + ORRPL R4, R4, R6, LSL R1 + ORRMI R4, R4, R6, LSR R1 + B %BT01 + +02 LDR R1, [R0], #4 + CMP R1, #-1 + BEQ %FT03 + AND R6, R3, R1 + LDR R1, [R0], #4 + CMP R1, #0 + RSBMI R1, R1, #0 + ORRPL R4, R4, R6, LSL R1 + ORRMI R4, R4, R6, LSR R1 + B %BT02 + +03 ORR R4, R4, #CAM + ORR R4, R4, R11, LSL #8 ; stuff in PPL + STR R4, [R4] ; and write it + MOV PC, LR + +; Data to drive CAM setting + +PageMangleTable + & PageMangle4K + & PageMangle8K + & PageMangle16K + & PageMangle32K + +; For each page size, pairs of masks and shift factors to put the bits in the +; right place. Two sets: operations on Physical Page Number, operations on +; Logical Page Number. + +; Shifts are Shift Left values (<<). Each section terminated by -1 + +PageMangle4K +; PPN: + & 2_011111111 + & 0 ; bits in right place + & -1 +; LPN: + & 2_1100000000000:SHL:12 + & (11-12)-12 ; LPN[12:11] -> A[11:10] + & 2_0011111111111:SHL:12 + & (22-10)-12 ; LPN[10:0 ] -> A[22:12] + & -1 + +PageMangle8K +; PPN: + & 2_010000000 + & 7-7 ; PPN[7] -> A[7] + & 2_001000000 + & 0-6 ; PPN[6] -> A[0] + & 2_000111111 + & 6-5 ; PPN[5:0] -> A[6:1] + & -1 +; LPN: + & 2_110000000000:SHL:13 + & (11-11)-13 ; LPN[11:10] -> A[11:10] + & 2_001111111111:SHL:13 + & (22-9)-13 ; LPN[9:0] -> A[22:13] + & -1 + +PageMangle16K +; PPN: + & 2_010000000 + & 7-7 ; PPN[7] -> A[7] + & 2_001100000 + & 1-6 ; PPN[6:5] -> A[1:0] + & 2_000011111 + & 6-4 ; PPN[4:0] -> A[6:2] + & -1 +; LPN: + & 2_11000000000:SHL:14 + & (11-10)-14 ; LPN[10:9] -> A[11:10] + & 2_00111111111:SHL:14 + & (22-8)-14 ; LPN[8:0] -> A[22:14] + & -1 + +PageMangle32K +; PPN: + & 2_100000000 + & 12-8 ; PPN[8] -> A[12] + & 2_010000000 + & 7-7 ; PPN[7] -> A[7] + & 2_001000000 + & 1-6 ; PPN[6] -> A[1] + & 2_000100000 + & 2-5 ; PPN[5] -> A[2] + & 2_000010000 + & 0-4 ; PPN[4] -> A[0] + & 2_000001111 + & 6-3 ; PPN[3:0] -> A[6:3] + & -1 +; LPN: + & 2_1100000000:SHL:15 + & (11-9)-15 ; LPN[9:8] -> A[11:10] + & 2_0011111111:SHL:15 + & (22-7)-15 ; LPN[7:0] -> A[22:15] + & -1 + +PageSizes + & 4*1024 ; 0 is 4K + & 8*1024 ; 4 is 8K + & 16*1024 ; 8 is 16 + & 32*1024 ; C is 32 + +PageShifts + = 12, 13, 0, 14 ; 1 2 3 4 + = 0, 0, 0, 15 ; 5 6 7 8 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_UpdateMEMC: Read/write MEMC1 control register + +SSETMEMC ROUT + + AND r10, r0, r1 + MOV r12, #0 + TEQP pc, #SVC_mode+I_bit+F_bit + LDR r0, [r12, #MEMC_CR_SoftCopy] ; return old value + BIC r11, r0, r1 + ORR r11, r11, R10 + BIC r11, r11, #&FF000000 + BIC r11, r11, #&00F00000 + ORR r11, r11, #MEMCADR + STR r11, [r12, #MEMC_CR_SoftCopy] + STR r11, [r11] + TEQP pc, #SVC_mode+I_bit + ExitSWIHandler + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; ClearPhysRAM - Routine to clear "all" memory +; +; While this routine is running, keyboard IRQs may happen. For this reason +; it avoids LogRAM 0..31 (where hardware IRQ vector is) and PhysRAM +; 0..31 where the IRQ workspace is. +; + +ClearPhysRAM ROUT + MOV R0, #0 + MOV R1, #0 + MOV R2, #0 + MOV R3, #0 + MOV R4, #0 + MOV R5, #0 + MOV R6, #0 + MOV R11, #0 + MOV R8, #PhysRam + CMP R13, #512*1024 + ADDEQ R10, R8, #(512-64)*1024 ; get address that's logram 0 + ADDNE R10, R8, #512*1024 + ADD R13, R13, #PhysRam ; end of memory + ADD R8, R8, #4*8 ; skip minimal startup workspace +10 CMP R8, R10 + ADDEQ R8, R8, #4*8 ; skip physram that's logram 0 + STMNEIA R8!, {R0-R6, r11} + CMP R8, R13 + BNE %BT10 + SUB R13, R13, #PhysRam + + LDR R0, =OsbyteVars + :INDEX: LastBREAK + MOV R1, #&80 + STRB R1, [R0] ; flag the fact that RAM cleared + MOV pc, lr + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; InitMEMC - Initialise memory controller +; + +InitMEMC ROUT + LDR R0, ResetMemC_Value + STR R0, [R0] ; set ROM access times, refresh on flyback, no DMA + MOV pc, lr + +; -> MemSize + +; (non-destructive) algorithm to determine MEMC RAM configuration +; +; Dave Flynn and Alasdair Thomas +; 17-March-87 +; +; Spooling checkered by NRaine and SSwales ! +; 8MByte check bodged in by APT +; +; NOTE: Routines MemSize and TimeCPU are called by the power-on test software, +; so their specifications MUST not change. +; +; Set MEMC for 32-k page then analyse signature of possible +; external RAM configurations... +; The configurations are: +; +; Ram Size Page Size Configuration (Phys RAM) Signature +;-------------------------------------------------------------------- +; 16MByte 32k 4*32*1Mx1 A13,A20,A21,A22,A23,A23.5 distinct +; 16MByte 32k 16*8*256kx4 A13,A20,A21,A22,A23,A23.5 distinct +; +; 12MByte 32k 3*32*1Mx1 A13,A20,A21,A22,A23 OK, A23.5 fail +; 12MByte 32k 12*8*256kx4 A13,A20,A21,A22,A23 OK, A23.5 fail +; +; 8MByte 32k 2*32*1Mx1 A13,A20,A21,A22 distinct, A23 fail +; 8MByte 32k 8*8*256kx4 A13,A20,A21,A22 distinct, A23 fail +; +; 4Mbyte 32k 32*1Mx1 A13,A21,A20 distinct, A22,A23 fail +; 4Mbyte 32k 4*8*256kx4 A13,A21,A20 distinct, A22,A23 fail +; +; 2Mbyte 32k expandable 2*8*256kx4 A13,A20 distinct, A21 fails +; 2Mbyte ??? 16k fixed 2*8*256kx4 A13,A21 distinct, A20 fails +; +; 1Mbyte 8k 32*256kx1 A13,A20 fail, A19,A18,A12 distinct +; 1Mbyte 8k 8*256kx1 A13,A20 fail, A19,A18,A12 distinct +; 1Mbyte 8k 4*8*64kx4 A13,A20 fail, A19,A18,A12 distinct +; +; 512Kbyte 8k expandable 2*8*64kx4 A13,A20,A19 fail, A12,A18 distinct +; 512Kbyte 4k fixed 2*8*64kx4 A13,A20,A12 fail, A19,A18 distinct +; +; 256Kbyte 4K 8*64kx4 A13,A20,A12,A18 fail, A21,A19 ok +; 256Kbyte 4K 32*64kx1 A13,A20,A12,A18 fail, A21,A19 ok +; + +Z_Flag * &40000000 + +; MemSize routine... enter with 32K pagesize set +; R0 returns page size +; R1 returns memory size +; R2 returns value set in MEMC +; uses R3-R7 + +MemSize ROUT + MOV r7, lr + MOV r0, #PhysRam + ADD r1, r0, #A13 + BL DistinctAddresses + BNE %10 + ADD r1, r0, #A21 + BL DistinctAddresses + MOVNE r0, #Page32K + MOVNE r1, #2048*1024 + BNE MemSizeDone + + MOV r0, #PhysRam + ADD r1, r0, #4*1024*1024 + BL DistinctAddresses + MOVNE r0, #Page32K + MOVNE r1, #4*1024*1024 + BNE MemSizeDone + + MOV r0, #PhysRam + ADD r1, r0, #8*1024*1024 + BL DistinctAddresses + MOVNE r0, #Page32K + MOVNE r1, #8*1024*1024 + BNE MemSizeDone + + MOV r0, #PhysRam + ADD r1, r0, #12*1024*1024 + BL DistinctAddresses + MOV r0, #Page32K + MOVNE r1, #12*1024*1024 + MOVEQ r1, #16*1024*1024 + B MemSizeDone + +10 ADD r1, r0, #A20 + BL DistinctAddresses + BNE %20 + MOV r0, #Page16K + MOV r1, #2048*1024 + B MemSizeDone + +20 ADD r1, r0, #A19 + BL DistinctAddresses + BEQ %30 + MOV r0, #Page8K + MOV r1, #512*1024 + B MemSizeDone + +30 ADD r1, r0, #A18 + BL DistinctAddresses + BEQ %40 + MOV r0, #Page4K + MOV r1, #256*1024 + B MemSizeDone + +40 ADD r1, r0, #A12 + BL DistinctAddresses + BEQ %50 + MOV r0, #Page4K + MOV r1, #512*1024 + B MemSizeDone + +50 MOV r0, #Page8K + MOV r1, #1024*1024 + +MemSizeDone + LDR r2, ResetMemC_Value + BIC r2, r2, #&C + ORR r2, r2, r0 + STR r2, [r2] ; set MEMC to right state + MOV pc, r7 + + +; DistinctAddresses routine... +; r0,r1 are the addresses to check +; uses r2-5 +; writes interleaved patterns (to prevent dynamic storage...) +; checks writing every bit low and high... +; return Z-flag set if distinct + +DistinctAddresses ROUT + LDR r2, [r0] ; preserve + LDR r3, [r1] + LDR r4, Pattern + STR r4, [r0] ; mark first + MOV r5, r4, ROR #16 + STR r5, [r1] ; mark second + LDR r5, [r0] + CMP r5, r4 ; check first + BNE %10 ; exit with Z clear + LDR r5, [r1] ; check second + CMP r5, r4, ROR #16 ; clear Z if not same + BNE %10 +; now check inverse bit writes + STR r4, [r1] ; mark second + MOV r5, r4, ROR #16 + STR r5, [r0] ; mark first + LDR r5, [r1] + CMP r5, r4 ; check second + BNE %10 ; exit with Z clear + LDR r5, [r0] ; check first + CMP r5, r4, ROR #16 ; clear Z if not same +10 STR r3, [r1] ; restore + STR r2, [r0] + ORREQ lr, lr, #Z_Flag + BICNE lr, lr, #Z_Flag + MOVS pc, lr + +Pattern + & &AAFF5500 ; shiftable bit check pattern + +; init state with masked out page size + +ResetMemC_Value + & &E010C :OR: MEMCADR ; slugged ROMs + flyback refresh only + 32K page + +; Constants +; +A21 * 1:SHL:21 +A20 * 1:SHL:20 +A19 * 1:SHL:19 +A18 * 1:SHL:18 +A13 * 1:SHL:13 +A12 * 1:SHL:12 + +Page32K * &C ; in MEMC control reg patterns... +Page16K * &8 +Page8K * &4 +Page4K * &0 + + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r0-r6 trashable +; r9 = Current MEMC CR + +; Out r9 MEMC value with slowest ROM speed, correct pagesize +; r7 processor speed in kHz, tbs -> MEMC1a + +ncpuloops * 1024 ; don't go longer than 4ms without refresh ! +nmulloops * 128 + +TimeCPU ROUT + + BIC r9, r9, #3 :SHL: 8 + STR r9, [r9] ; turn off refresh for a bit + +; Time CPU/Memory speed + + LDR r1, =&7FFE ; 32K @ 2MHz = ~16ms limit + MOV r3, #IOC + + MOV r0, r1, LSR #8 + STRB r1, [r3, #Timer1LL] + STRB r0, [r3, #Timer1LH] + LDR r0, =ncpuloops + STRB r0, [r3, #Timer1GO] ; start the timer NOW + B %FT10 ; Looks superfluous, but is required + ; to get ncpuloops pipeline breaks + +10 SUBS r0, r0, #1 ; 1S + BNE %BT10 ; 1N + 2S + + STRB r0, [r3, #Timer1LR] ; latch count NOW + LDRB r2, [r3, #Timer1CL] + LDRB r0, [r3, #Timer1CH] + ADD r2, r2, r0, LSL #8 ; count after looping is ... + + SUB r2, r1, r2 ; decrements ! + MOV r2, r2, LSR #1 ; IOC clock decrements at 2MHz + +; Time CPU/MEMC Multiply time + + MOV r4, #-1 ; Gives worst case MUL + + MOV r0, r1, LSR #8 + STRB r1, [r3, #Timer1LL] + STRB r0, [r3, #Timer1LH] + LDR r0, =nmulloops + STRB r0, [r3, #Timer1GO] ; start the timer NOW + B %FT20 ; Looks superfluous, but is required + ; to get nmulloops pipeline breaks + +20 MUL r5, r4, r4 ; 1S + 16I + MUL r5, r4, r4 ; 1S + 16I + SUBS r0, r0, #1 ; 1S + BNE %BT20 ; 1N + 2S + + STRB r0, [r3, #Timer1LR] ; latch count NOW + LDRB r4, [r3, #Timer1CL] + LDRB r0, [r3, #Timer1CH] + ADD r4, r4, r0, LSL #8 ; count after looping is ... + + SUB r4, r1, r4 ; decrements ! + MOV r4, r4, LSR #1 ; IOC clock decrements at 2MHz + + ORR r9, r9, #1 :SHL: 8 ; set refresh on flyback + STR r9, [r9] ; restore MEMC state a.s.a.p. + +; In ROM - each cpu loop took 4R cycles @ 8/f*500ns/cycle + + LDR r0, =4*(8*500/1000)*ncpuloops*1000 + DivRem r7, r0, r2, r1 ; r2 preserved + MOV r0, #&80 ; At 8 MHz and below, run fast ROMs + LDR r1, =8050 ; Over 8 MHz, need medium ROMs + CMP r7, r1 + MOVHI r0, #&40 + LDR r1, =13000 ; Over 13 MHz, need slowest ROMs + CMP r7, r1 + MOVHI r0, #&00 + ORR r9, r9, r0 + STR r9, [r9] ; Set ROM speed appropriately + + ASSERT ncpuloops = 8*nmulloops ; for given ratio cutoff <------------ + + MOV r4, r4, LSL #10 ; *1024 to get resolution on divide + DivRem r0, r4, r2, r1 + LDR r1, =1100 ; Cutoff point; MEMC1 longer than this + CMP r0, r1 + ORRLO r7, r7, #1 :SHL: 16 ; Note MEMC1a prescence + + MOV pc, lr + +; Typical figures give (in ROM at 8MHz): + +; MEMC1 2048 CPU, 2432 MEMC -> MUL ratio 1216 +; MEMC1a 2048 864 432 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + END diff --git a/OldTestSrc/Mem1IOMD b/OldTestSrc/Mem1IOMD new file mode 100644 index 0000000000000000000000000000000000000000..f1b6a14ea10f568c6dc3079989535a0db79daa94 --- /dev/null +++ b/OldTestSrc/Mem1IOMD @@ -0,0 +1,481 @@ +; > TestSrc.Mem1IOMD + + TTL RISC OS 2+ POST memory linetest +; +; This test code is used to perform basic integrity tests on DRAM. +; It doesn't test all locations - just walks patterns through data +; and address lines. +; +;------------------------------------------------------------------------ +; History +; +; Date Name Comment +; ---- ---- ------- +; 1-Jun-93 ArtG Derived from Mem1 for use on Medusa +; +; +;------------------------------------------------------------------------ + +; +; Test the data and address and byte strobe lines for uniqueness. +; + + LTORG + ROUT + +1 + = "VRAM :",0 +2 + = "VRAM-F",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +3 + = "DRAM ",&ff,":",0 +4 + = "Data :",0 +5 + = &88,&ff,&ff," MByte",0 + + ALIGN + +ts_LineTest + + ADR r4,%BT1 + BL ts_SendText ; Start data line tests on VRAM + + MOV r0,#0 + MOV_fiq r9,r0 ; r9-fiq records VRAM or low DRAM address + + MOV r12, #IOMD_Base + MOV r2, #IOMD_VREFCR_VRAM_256Kx64 :OR: IOMD_VREFCR_REF_16 ; assume 2 banks of VRAM by default + STRB r2, [r12, #IOMD_VREFCR] + +; Find the size, using MemSize's method + + MOV r0, #VideoPhysRam ; point at VRAM + ADD r1, r0, #A2 ; test A2 + BL DistinctAddresses + MOVEQ r9, #2 ; we've got 2M of VRAM + BEQ %FT21 + + MOV r2, #IOMD_VREFCR_VRAM_256Kx32 :OR: IOMD_VREFCR_REF_16 + STRB r2, [r12, #IOMD_VREFCR] + ADD r1, r0, #A2 ; check for any VRAM at all + BL DistinctAddresses + MOVEQ r9, #1 ; we've got 1M of VRAM + MOVNE r9, #0 ; no VRAM +21 + BNE %FT22 + MOV_fiq r9,r0 ; record VRAM address + FAULT #R_VRAM ; indicate VRAM present + +; Report size .. if this is non-zero and the data line test fails, +; RISC OS will have problems. + +22 + ADR r4,%BT5 ; Add size (in hex Mbyte) + MOV r8,r9, LSL #24 ; to "VRam : " message + BL ts_MoreText + +; Worked out what size VRAM is, and set up IOMD register. +; Do a data line test on the resulting array, repeated at oddword address to +; ensure both banks get tested with walking 0 and walking 1 + + ADR r4,%BT4 + BL ts_SendText + MOV r1, #VideoPhysRam + BL ts_Dataline + ADDEQ r1,r1,#4 + BLEQ ts_Dataline + BEQ %FT25 ; looks OK - carry on with VRAM test +; +; Data line test failed. Report the bitmap that failed, then carry on. +; + ADR r4,%BT2 + MOV r8,r0 ; report data fault mask + BL ts_SendText + B %FT30 + +; +; If there was some VRAM found here, and it passed the dataline test, +; do the address and bytestrobe tests on it too. +; + +25 + ADRL r4,%FT75 ; announce start of address line test + BL ts_SendText + MOV r1,#VideoPhysRam + MOV r0,r9,LSL #20 ; size in MB determined before dataline test + BL ts_Addrline + BEQ %FT26 + ADRL r4,%FT76 ; failed - report error mask + MOV r8,r0 + BL ts_SendText + FAULT #R_LINFAILBIT ; and record failure + B %FT30 +26 + ADRL r4,%FT77 ; announce start of byte test + BL ts_SendText + MOV r1,#VideoPhysRam + BL ts_Byteword + ADDEQ r1,r1,#4 ; retest at an oddword boundary + BLEQ ts_Byteword + BEQ %FT27 + ADRL r4,%FT78 ; failed - report error mask + MOV r8,r0,LSL #16 + BL ts_SendText + FAULT #R_LINFAILBIT ; and record failure +27 + + +; Similarly, test each DRAM bank in turn, reporting failures or sizes for each + +30 + MOV r11, #IOMD_DRAMCR_DRAM_Large * &55 ; set all banks to be large initially + MOV r14, #IOMD_Base + STRB r11, [r14, #IOMD_DRAMCR] + MOV r0,#MMUC_D ; enable 32-bit addressing of data + SetCop r0,CR_Control + + MOV r10, #0 ; indicate no RAM found yet + MOV r9, #IOMD_DRAMCR_DRAM_Small ; bit to OR into DRAMCR + MOV r12, #DRAM0PhysRam +35 + MOV r8,r12,LSL #2 ; indicate bank under test + AND r8,r8,#(3 :SHL: 28) + ADR r4,%BT3 + BL ts_SendText + + MOV r8,#0 ; r8 indicates RAM found in this bank + MOV r0, r12 + ADD r1, r12, #A10 ; this should be OK for both configurations + BL DistinctAddresses + BNE %FT50 ; [no RAM in this bank at all] + + MOV_fiq r2,r9 ; if this is the first bank of DRAM or VRAM, + TEQS r2,#0 ; put it's address in r9_fiq + BNE %FT36 + MOV_fiq r9,r0 + +36 ADD r1, r12, #A11 ; test for 256K DRAM + BL DistinctAddresses + ORRNE r11, r11, r9 ; it is, so select small multiplexing + MOVNE r14, #IOMD_Base + STRNEB r11, [r14, #IOMD_DRAMCR] ; store new value of DRAMCR, so we can use memory immediately + MOVNE r8, #1024*1024 ; must be 1Mbyte at this address + BNE %FT50 + +; it's bigger than 256K words, so test address lines A21-A25 in sequence +; we assume that the size of each bank is a power of 2 + + MOV r8, #A21 ; now go through address lines A21-A25 +40 + ADD r1, r12, r8 ; see if this address line is unique + BL DistinctAddresses + BNE %FT50 ; if we've failed then r8 is true size, so exit + MOV r8, r8, LSL #1 ; else shift up to next + TEQ r8, #A26 ; only test up to A25 + BNE %BT40 + +50 + MOV r13,r8 ; remember size of this bank in bytes + MOV r8,r13,LSL #(24 - 20) ; and display it in 2 digits, in MBytes. + ADR r4,%BT5 + BL ts_MoreText + + ADRL r4,%FT73 ; announce data line test + BL ts_SendText + MOV r1,r12 ; do walking bit test + BL ts_Dataline + BEQ %FT55 ; looks OK, carry on to next bank + + ADRL r4,%FT74 ; bit test failed, so report it + MOV r8,r0 + BL ts_SendText ; and bit fault mask + + CMPS r13,#0 ; was any RAM thought to be here ? + BEQ %FT55 + FAULT #R_LINFAILBIT ; if so, it's faulty. + MOV r13,#0 ; so ignore it +55 + +; +; If there was some RAM found here, and it passed the dataline test, +; do the address and bytestrobe tests on it too. +; + CMPS r13,#0 + BEQ %FT60 + + ADR r4,%FT75 ; announce start of address line test + BL ts_SendText + MOV r1,r12 ; test address lines in this block + MOV r0,r13 + BL ts_Addrline + BEQ %FT56 + ADR r4,%FT76 ; failed - report error mask + MOV r8,r0 + BL ts_SendText + FAULT #R_LINFAILBIT ; and record failure + MOV r13,#0 ; then forget this memory block + +56 + ADR r4,%FT77 ; announce start of byte test + BL ts_SendText + MOV r1,r12 + BL ts_Byteword + BEQ %FT60 + ADR r4,%FT78 ; failed - report error mask + MOV r8,r0,LSL #16 + BL ts_SendText + FAULT #R_LINFAILBIT ; and record failure + MOV r13,#0 ; then forget this memory block +60 + + +; If the RAM found still seems OK, add it's size into the r10 accumulator +; Working or not, carry on to check the next bank. + + ADD r10,r10,r13 ; accumulate DRAM if any found + ADD r12, r12, #DRAM1PhysRam-DRAM0PhysRam ; move onto next bank + MOV r9, r9, LSL #2 ; shunt up position in DRAMCR + CMP r9, #&100 ; if more banks to do + BCC %BT35 ; then loop + + ADR r4,%FT70 + BL ts_SendText ; None found .. print message + + MOVS r8,r10,LSL #(24 - 20) ; all finished .. + ADREQ r4,%FT71 ; did we find any DRAM? + ADRNE r4,%FT72 + BNE %FT65 + FAULT #R_LINFAILBIT ; fault if we didn't +65 + BL ts_MoreText + B ts_endline + + +70 + = "DRAM",0 +71 + = &88,"Failed",0 +72 + = &88,&ff,&ff," MByte",0 +73 + = "Data :",0 +74 + = "Data-F",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +75 + = "Addrs :",0 +76 + = "Addrs-F",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +77 + = "Byte :",0 +78 + = "Byte-F",&88,&ff,&ff,&ff,&ff,0 + + +; +; Data line test. +; +; In : r1 - start address for test +; +; Out : r0 - failing data pattern +; r1 - address of failure +; +; +; This exercises data lines in attempt to find shorts/opens. +; It goes something like : +; +; for (ptr = address, pattern = 1; pattern != 0; pattern <<= 1) +; *ptr++ = pattern; +; *ptr++ = ~pattern; +; for (ptr = address, pattern = 1; pattern != 0; pattern <<= 1) +; result |= pattern ^ *ptr++; +; result |= ~pattern ^ *ptr++; +; return result and address +; + +ts_Dataline ROUT + +; +; Write all walking-zero, walking-one patterns +; +10 MOV r6,r1 ; set pointer for a write loop + MOV r5,#1 ; set initial test pattern + MVN r4,r5 ; and it's inverse +11 + STMIA r6!,{r4-r5} ; write the patterns + + ADDS r5,r5,r5 ; shift the pattern (into Carry) + MVN r4,r5 + BCC %BT11 ; repeat until all bits done +; +; Read back and accumulate in r0 any incorrect bits +; + MOV r6,r1 ; set pointer for a read loop + MOV r5,#1 ; set initial test pattern + MVN r4,r5 ; and it's inverse + MOV r0,#0 ; accumulate result +21 + LDMIA r6!,{r2-r3} ; read the patterns + EOR r2,r2,r4 + ORR r0,r0,r2 ; OR any failed bits into r0 + EOR r3,r3,r5 + ORR r0,r0,r2 + + ADDS r5,r5,r5 ; shift the pattern (into Carry) + MVN r4,r5 + BCC %BT21 ; repeat until all bits done +; +; After all checks at this address group, report back errors +; + MOVS r0,r0 ; check for any result bits set + MOV pc,r14 ; return r0 with error map (or 0) + + + +; +; Address line test +; +; In : r0 - size of memory block +; r1 - start address of memory block +; +; Out : r0 - failing address bit mask +; +; This exercises address lines in an attempt to find any which don't +; work (i.e., don't select unique addresses). +; +; It works something like : +; +; MaxRam = PhysRam | (Memory size - 4); +; for (pattern = 4; pattern < memsize; pattern <<= 1 ) +; *(PhysRam ^ pattern) = pattern; +; *(MaxRam ^ pattern) = ~pattern; +; for (pattern = 4; pattern < memsize; pattern <<= 1 ) +; if (*PhysRam == *(PhysRam ^ pattern)) +; result |= pattern; +; if (*MaxRam == *(MaxRam + pattern)) +; result |= pattern; +; return result +; + + +ts_Addrline ROUT + + MOVS r7,r0 ; Save memory size + SUB r6,r0,#4 ; Calculate MaxRam + ADD r6,r6,r1 ; (all-bits-set memory address) +; +; Mark (walking one, walking 0) addresses with unique patterns +; + LDR r5,=&5A5AA5A5 ; initialize end markers + STR r5,[r6] + MVN r4,r5 + MOV r3,r1 + STR r4,[r3] + + MOV r5,#4 ; initialize pattern +02 + MVN r4,r5 + EOR r3,r5,r1 ; point to (start ^ pattern) + STR r4,[r3] + EOR r3,r5,r6 ; point to (end ^ pattern) + STR r5,[r3] + + MOV r5,r5,LSL #1 ; shift test pattern up + CMPS r5,r7 ; test bit still inside memory ? + BCC %02 ; reached top bit - end this loop +; +; Check (walking one, walking 0) addresses for effectivity +; + MOV r5,#4 ; initialize pattern + MOV r3,r1 + MOV r0,#0 +04 + MVN r4,r5 + EOR r2,r5,r3 ; point to (start ^ pattern) + LDR r2,[r2] + LDR r1,[r3] + CMPS r1,r2 ; do contents differ ? + ORREQ r0,r0,r5 ; no - record ineffective bit + + EOR r2,r5,r6 ; point to (end ^ pattern) + LDR r2,[r2] + LDR r1,[r6] + CMPS r1,r2 ; do contents differ ? + ORREQ r0,r0,r5 ; no - record ineffective bit + + MOV r5,r5,LSL #1 ; shift test pattern up + CMPS r5,r7 ; test bit still inside memory ? + BCC %04 ; reached top bit - end this loop + + MOVS r0,r0 ; any result bits set - return error + MOV pc,r14 + + +; +; Byte / word test +; +; In : r1 - memory start +; +; Out : r0 - Failure indication +; +; This test ensures that individual bytes may be written to each part of a word +; without affecting the other bytes in the word. +; +; for (byte = 0; byte < 4; byte ++) +; address[0] = word_signature +; address[1] = ~word_signature +; address + byte = byte_signature +; if (address[0] != +; (word_signature & (~ff << byte * 8)) +; | (byte_signature << byte * 8) ) +; result |= (1 << byte) +; if (result != 0 +; result |= address; /* fail at address, byte(s) */ +; return result; /* pass */ +; + +ts_Byteword ROUT + + LDR r3,=&AABBCCDD ; word signature + MOV r0,#0 + MOV r2,r0 +; +; byte test loop ( for bytes 0 to 4 ...) +; +02 + MVN r4,r3 + STMIA r1,{r3,r4} ; write word signature + STRB r2,[r1,r2] ; write byte (0, 1, 2 or 3) + + MOV r4,r2,LSL #3 ; calculate expected result + MOV r5,#&ff + MVN r5,r5,LSL r4 + AND r5,r5,r3 ; word signature, byte removed + ORR r5,r5,r2,LSL r4 ; byte signature inserted + + LDR r4,[r1,#4] ; read (probable) inverse data to precharge bus + LDR r4,[r1] ; read modified word + CMPS r4,r5 + MOV r5,#1 + MOV r4,r2,LSL #2 + ORRNE r0,r0,r5,LSL r4 ; fault : set bit in result mask +; +; Loop for next byte +; + ADD r2,r2,#1 ; Bump byte counter + CMPS r2,#4 ; ... until 4 byte strobes tested + BLO %BT02 +; +; byte strobes all tested : check for errors +; + CMPS r0,#0 + MOV pc,r14 ; Result : return address and fault mask. + +; +; End of RAM line tests +; + +ts_endline + + END + \ No newline at end of file diff --git a/OldTestSrc/Mem1MEMC1 b/OldTestSrc/Mem1MEMC1 new file mode 100644 index 0000000000000000000000000000000000000000..632c9bf2b8e5b33faf87dc5ac37826a43174df3d --- /dev/null +++ b/OldTestSrc/Mem1MEMC1 @@ -0,0 +1,390 @@ +; > TestSrc.Mem1 + + TTL RISC OS 2+ POST memory linetest +; +; This test code is used to perform basic integrity tests on DRAM. +; It doesn't test all locations - just walks patterns through data +; and address lines. +; +;------------------------------------------------------------------------ +; History +; +; Date Name Comment +; ---- ---- ------- +; 18-Dec-89 ArtG Initial version +; 1-Jun-93 ArtG Reorganised to allow separate module for Medusa +; +; +;------------------------------------------------------------------------ + +; +; Test the data and address and byte strobe lines for uniqueness. +; + + LTORG + ROUT + +1 + = "Data :",0 +2 + = "Data @",&89,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +3 + = "Data-F",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +4 + = "Data-P",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 + + + + ALIGN + +ts_LineTest + + ADR r4,%BT1 + BL ts_SendText ; Start data line tests + + MOV_fiq r0,r10_fiq + MOV r1, #PhysRam + BL ts_Dataline + BEQ ts_address ; OK : continue to next test +; +; Data line test failed. This probably also means that RISCOS got the +; configuration wrong, so set it to 32K pages and repeat - otherwise +; the data line test result may be garbage. +; + ADR r4,%BT2 + MOV r11,r0 ; save data & report fault address + MOV r8,r1,LSL #4 + BL ts_SendText + + MOV r8,r11 + ADR r4,%BT3 ; report data fault mask + BL ts_SendText + + LDR r0,=(&E000C :OR: MEMCADR) ; set 32K page size + STR r0,[r0] + MOV_fiq r11_fiq,r0 + + MOV r0,#ts_RamChunk ; limit test to 1 block + MOV r1,#PhysRam + BL ts_Dataline + + MOV r8,r0 + ADR r4,%BT4 ; ready to report data fault mask + B ts_linefault + +; +; Start the address line tests +; + ROUT + +4 + = "Addrs :",0 +5 + = "Addrs",&89,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +6 + = "Byte :",0 +7 + = "Byte",&89,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 + + + +ts_address + ADR r4,%BT4 + BL ts_SendText ; Start address line tests + + MOV_fiq r0,r10_fiq + BL ts_Addrline + + ADR r4,%BT5 + MOV r8,r0,LSL #4 + BEQ %30 ; Failed : report address fault + +ts_linefault + FAULT #R_LINFAILBIT + B %31 + +30 ADR r4,%BT6 ; Start Byte/Word test + BL ts_SendText + + MOV_fiq r0,r10_fiq ; get memory size + BL ts_Byteword + + MOV r8,r0,LSL #4 ; Get result to top of r8 + BEQ %40 + FAULT #R_LINFAILBIT + + ADR r4,%BT7 + +31 BL ts_SendText + B %42 +; +; Line tests passed. Do a short test on memory that isn't there, +; in case it's supposed to be and we want to know why it's not .. + +40 + MOV_fiq r0, r10_fiq ; if there's less than 16Mbytes .. + CMP r0, #(16 * 1024 * 1024) + BCS %F42 + ADR r4, %FT44 ; briefly test the next bit of ram + BL ts_SendText ; in case it's a duff expansion + + MOV_fiq r1,r10_fiq + ADD r1,r1,#PhysRam + MOV r0,#ts_RamChunk + BL ts_Dataline + ADR r4, %FT45 + MOV r11, r0 ; report the result even if OK + MOV r8,r1,LSL #4 + BL ts_SendText ; report address + + MOV r8,r11 + ADR r4,%FT46 ; report data fault mask + BL ts_SendText +; +; End of line tests +; + +42 + B ts_IOCTest + +44 + = "Exp? :",0 +45 + = "Exp? @",&89,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +46 + = "Exp?",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 + + + +; +; Data line test. +; +; In : r0 - size of memory +; r1 - start address for test +; +; Out : r0 - failing data pattern +; r1 - address of failure +; +; +; This exercises data lines in attempt to find shorts/opens. +; It goes something like : +; +; for (address = start; address < end of ram; address += ts_RamChunk) +; for (ptr = address, pattern = 1; pattern != 0; pattern <<= 1) +; *ptr++ = pattern; +; *ptr++ = ~pattern; +; for (ptr = address, pattern = 1; pattern != 0; pattern <<= 1) +; result |= pattern ^ *ptr++; +; result |= ~pattern ^ *ptr++; +; if (result |= 0) +; return result and address +; + +ts_Dataline ROUT + + ADD r7,r1,r0 ; end address +; +; Write all walking-zero, walking-one patterns +; +10 MOV r6,r1 ; set pointer for a write loop + MOV r5,#1 ; set initial test pattern + MVN r4,r5 ; and it's inverse +11 + STMIA r6!,{r4-r5} ; write the patterns + + ADDS r5,r5,r5 ; shift the pattern (into Carry) + MVN r4,r5 + BCC %BT11 ; repeat until all bits done +; +; Read back and accumulate in r0 any incorrect bits +; + MOV r6,r1 ; set pointer for a read loop + MOV r5,#1 ; set initial test pattern + MVN r4,r5 ; and it's inverse + MOV r0,#0 ; accumulate result +21 + LDMIA r6!,{r2-r3} ; read the patterns + EOR r2,r2,r4 + ORR r0,r0,r2 ; OR any failed bits into r0 + EOR r3,r3,r5 + ORR r0,r0,r2 + + ADDS r5,r5,r5 ; shift the pattern (into Carry) + MVN r4,r5 + BCC %BT21 ; repeat until all bits done +; +; After all checks at this address group, report back errors +; + MOVS r0,r0 ; check for any result bits set + MOVNE pc,r14 ; return on error +; +; Bump to another address group +; + ADD r1,r1,#ts_RamChunk + CMPS r1,r7 ; test for loop end + BLO %10 + + SUBS r1,r1,#ts_RamChunk ; no fault - last tested address + MOVS r0,r0 + MOV pc,r14 ; test complete - no failures. + + +; +; Address line test +; +; In : r0 - size of memeory +; +; Out : r0 - failing address bit mask +; +; This exercises address lines in an attempt to find any which don't +; work (i.e., don't select unique addresses). +; +; It works something like : +; +; MaxRam = PhysRam | (Memory size - 4); +; for (pattern = 4; pattern < memsize; pattern <<= 1 ) +; *(PhysRam ^ pattern) = pattern; +; *(MaxRam ^ pattern) = ~pattern; +; for (pattern = 4; pattern < memsize; pattern <<= 1 ) +; if (*PhysRam == *(PhysRam ^ pattern)) +; result |= pattern; +; if (*MaxRam == *(MaxRam + pattern)) +; result |= pattern; +; return result +; + + +ts_Addrline ROUT + + MOVS r7,r0 ; Save memory size + SUB r6,r0,#4 ; Calculate MaxRam + ADD r6,r6,#PhysRam ; (all-bits-set memory address) +; +; Mark (walking one, walking 0) addresses with unique patterns +; + LDR r5,=&5A5AA5A5 ; initialize end markers + STR r5,[r6] + MVN r4,r5 + MOV r3,#PhysRam + STR r4,[r3] + + MOV r5,#4 ; initialize pattern +02 + MVN r4,r5 + EOR r3,r5,#PhysRam ; point to (start ^ pattern) + STR r4,[r3] + EOR r3,r5,r6 ; point to (end ^ pattern) + STR r5,[r3] + + MOV r5,r5,LSL #1 ; shift test pattern up + CMPS r5,r7 ; test bit still inside memory ? + BCC %02 ; reached top bit - end this loop +; +; Check (walking one, walking 0) addresses for effectivity +; + MOV r5,#4 ; initialize pattern + MOV r3,#PhysRam + MOV r0,#0 +04 + MVN r4,r5 + EOR r2,r5,r3 ; point to (start ^ pattern) + LDR r2,[r2] + LDR r1,[r3] + CMPS r1,r2 ; do contents differ ? + ORREQ r0,r0,r5 ; no - record ineffective bit + + EOR r2,r5,r6 ; point to (end ^ pattern) + LDR r2,[r2] + LDR r1,[r6] + CMPS r1,r2 ; do contents differ ? + ORREQ r0,r0,r5 ; no - record ineffective bit + + MOV r5,r5,LSL #1 ; shift test pattern up + CMPS r5,r7 ; test bit still inside memory ? + BCC %04 ; reached top bit - end this loop + + MOVS r0,r0 ; any result bits set - return error + MOV pc,r14 + + +; +; Byte / word test +; +; In : r0 - memory size +; +; Out : r0 - address of physical ram where failure occured +; +; This test ensures (for each of four possible MEMCs fitted) +; that individual bytes may be written to each part of a word +; without affecting the other bytes in the word. +; +; for (address = PhysRam; address < PhysRam + Memsize; address += 4Mbyte) +; for (byte = 0; byte < 4; byte ++) +; address[0] = word_signature +; address[1] = ~word_signature +; address + byte = byte_signature +; if (address[0] != +; (word_signature & (~ff << byte * 8)) +; | (byte_signature << byte * 8) ) +; result |= (1 << byte) +; if (result != 0 +; result |= address; /* fail at address, byte(s) */ +; return result; +; return result; /* pass */ +; + +ts_Byteword ROUT + + ADD r7,r0,#PhysRam ; Set test limit address + MOV r1,#PhysRam ; Initial test address + LDR r3,=&AABBCCDD ; word signature +; +; MEMC test loop (for addresses 4M, 8M, ...) +; +01 + MOV r0,#0 ; clear result register + MOV r2,#0 ; clear byte count +; +; byte test loop ( for bytes 0 to 4 ...) +; +02 + MVN r4,r3 + STMIA r1,{r3,r4} ; write word signature + STRB r2,[r1,r2] ; write byte + + MOV r4,r2,LSL #3 ; calculate expected result + MOV r5,#&ff + MVN r5,r5,LSL r4 + AND r5,r5,r3 ; word signature, byte removed + ORR r5,r5,r2,LSL r4 ; byte signature inserted + + LDR r4,[r1,#4] + LDR r4,[r1] ; read modified word + CMPS r4,r5 + MOV r5,#1 + ORRNE r0,r0,r5,LSL r2 ; fault : set bit in result mask +; +; Loop for next byte +; + ADD r2,r2,#1 ; Bump byte counter + CMPS r2,#4 ; ... until 4 byte strobes tested + BLO %BT02 +; +; byte strobes all tested : check for errors +; + CMPS r0,#0 + ORRNE r0,r0,r1 + MOVNE pc,r14 ; Error : return address and fault. +; +; Loop for next MEMC +; + ADD r1,r1,#&400000 ; Bump to next MEMC + CMPS r1,r7 + BLO %01 + + MOVS r0,#0 ; Passed - return OK + MOV pc,r14 + + + END + \ No newline at end of file diff --git a/OldTestSrc/Mem2 b/OldTestSrc/Mem2 new file mode 100644 index 0000000000000000000000000000000000000000..89f5bc2d3a13a7acf9b701c7cdf5a16209c3fec9 --- /dev/null +++ b/OldTestSrc/Mem2 @@ -0,0 +1,278 @@ +;> MEM2C +; +; RISC OS 2+ BOOT TEST SOFTWARE +; MEMORY TEST 2 VERSION A. +; BRIAN RICE 30-10-89 +; 06-Apr-90 ArtG 0.1 Test variable memory size +; +; This file will perform a simple test on all DRAM. +; The test code for this test was taken from thhe A680 Quick memory +; test software. The software was copied straight but the number of times +; the test looped arround was cut down to two loops, because of time +; constraints when testing the memory. + +Test_wks_msize * &40 ; Space for test block size +Test_wks_return1 * &44 ; Space for return addresses +Test_wks_return2 * &48 +Test_code_off * &4C ; Where testing starts + +test_size * 13 * 4 ; Size of test group +test_mem_rsvd * Test_code_off+test_mem_template_end-test_mem_template + +; +; Quick test the RAM (pre boot style) +; + +ts_RamTest ROUT + MOV r13,r0 + STR r14,[r13,#Test_wks_return1] + STR r1,[r13,#Test_wks_msize] + + LDR r0, test_quick_pattern + BL test_mem_code + ORRS r0,r0,r0 + BNE test_mem_quit +; + LDR r0, test_quick_pattern + MVN r0, r0 ; inverse pattern + BL test_mem_code + ORRS r0,r0,r0 + +test_mem_quit + ADR r12,%22 + BEQ %10 + +; If fault detected, exit with zero flag clear, r0 pointing to failing +; location, r1 containing faulty data and r2 pointing a suitable error +; message indicating whether all-0 or all-1 data was expected. + + LDR r2,[r14] ; fetch failing instructiom + ANDS r2,r2,#1 ; calculate expected data + ADREQ r12,%20 ; and load suitable message + ADRNE r12,%21 + MOVS r0,r0 ; with zero flag set for PASS. +10 + LDR pc,[r13,#Test_wks_return1] + +; Fail messages indicate incorrect data read after WRote 0 or Wrote 1 +; to all bits at that location. + +20 + = "WR-0 RD",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +21 + = "WR-1 RD",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +22 + = "??",0 + + ALIGN + +test_quick_pattern & &0f76 + +; Large Memory test. Generates the write + test routines in memory +; then calls them. The routine tests patterns as defined by the bottom +; 13 bits of r0. +; +; N.B. The test start address must be calculated to ensure that +; the loops finish exactly with r0 equal to End_memory +; +; The routine returns with eq true if the memory is OK. + + +test_mem_code + ROUT + + STR r14, [r13, #Test_wks_return2] +; +; Copy the ram test code into low ram, modifying MOV instructions +; to MVN in accordance with the test pattern. +; + ADR r1, test_mem_template + ADD r2, r13, #Test_code_off + LDMIA r1!, {r3-r4} ; copy initial 2 instrucions + STMIA r2!, {r3-r4} + MOV r4, #1 +0 MOVS r0, r0, ROR #1 + LDR r3, [r1], #4 + ORRCS r3, r3, #&00400000 ; Convert MOV => MVN + STR r3, [r2], #4 + ADD r4, r4, #1 + CMP r4, #13 + BLE %B0 +; +; Copy the load loop control and verify start instructions +; + LDMIA r1!, {r5-r9} + STMIA r2!, {r5-r9} +; +; Copy and modify the CMP instructions +; + MOV r0, r0, ROR #32-13 + MOV r4, #1 +1 MOVS r0, r0, ROR #1 + LDR r3, [r1], #4 + ORRCS r3, r3, #&00200000 ; Convert CMP => cmn + ORRCS r3, r3, #&00000001 ; Convert #0 => #1 + STR r3, [r2], #4 + ADD r4, r4, #1 + CMP r4, #13 + BLE %B1 +; +; Copy the verify loop control and finishing-up instructions +; + LDMIA r1!, {r5-r12} + STMIA r2!, {r5-r12} + LDMIA r1!, {r5-r12} + STMIA r2!, {r5-r12} + LDMIA r1!, {r5-r12} + STMIA r2!, {r5-r12} + +; check we've copied enough + ASSERT ((test_mem_stadd - test_mem_chk) = (24 * 4)) +; +; Calculate the test start and end addresses +; + LDR r0, [r13, #Test_wks_msize] ; size of test area + ADD r14, r13, r0 ; end of test area + SUB r1, r0, #test_mem_rsvd ; testable size + + MOV r2, #test_size ; adjust r1 to (r1 / 13*4) * (13*4) + DivRem r3, r1, r2, r4 + MUL r1, r3, r2 + SUB r0, r14, r1 ; rounded test start address + +; Do it. + MOV r1, #Test_code_off + ADD r1, r1, r13 ; pointer to copied code + MOV pc, r1 + +; +; The following code is copied (and modified) into RAM for execution +; + +test_mem_template + ROUT + STR r0, test_mem_stadd ; save initial RAM address + STR r13, test_mem_base ; save test area base address + MOV r1, #0 ; Converted to MVN if bit = 1 + MOV r2, #0 ; Converted to MVN if bit = 1 + MOV r3, #0 ; Converted to MVN if bit = 1 + MOV r4, #0 ; Converted to MVN if bit = 1 + MOV r5, #0 ; Converted to MVN if bit = 1 + MOV r6, #0 ; Converted to MVN if bit = 1 + MOV r7, #0 ; Converted to MVN if bit = 1 + MOV r8, #0 ; Converted to MVN if bit = 1 + MOV r9, #0 ; Converted to MVN if bit = 1 + MOV r10, #0 ; Converted to MVN if bit = 1 + MOV r11, #0 ; Converted to MVN if bit = 1 + MOV r12, #0 ; Converted to MVN if bit = 1 + MOV r13, #0 ; Converted to MVN if bit = 1 +0 + STMIA r0!, {r1-r13} + CMP r0, r14 + BLO %B0 + + LDR r0, test_mem_stadd +1 + LDMIA r0!, {r1-r13} +2 + CMP r1, #0 ; Converted to cmn if bit = 1 + CMPEQ r2, #0 ; Converted to cmneq if bit = 1 + CMPEQ r3, #0 ; Converted to cmneq if bit = 1 + CMPEQ r4, #0 ; Converted to cmneq if bit = 1 + CMPEQ r5, #0 ; Converted to cmneq if bit = 1 + CMPEQ r6, #0 ; Converted to cmneq if bit = 1 + CMPEQ r7, #0 ; Converted to cmneq if bit = 1 + CMPEQ r8, #0 ; Converted to cmneq if bit = 1 + CMPEQ r9, #0 ; Converted to cmneq if bit = 1 + CMPEQ r10, #0 ; Converted to cmneq if bit = 1 + CMPEQ r11, #0 ; Converted to cmneq if bit = 1 + CMPEQ r12, #0 ; Converted to cmneq if bit = 1 + CMPEQ r13, #0 ; Converted to cmneq if bit = 1 +test_mem_chk + BNE %F5 ; go report fault data + CMP r0, r14 + BLO %B1 ; else loop for next batch + MOVS r0, #0 ; All OK : return with NULL r0 +4 + LDR r13,test_mem_base + LDR pc, [r13, #Test_wks_return2] + +; Failed : repeat the last batch of tests one at a time, to determine +; the first failing address and data. +; Note that the test instructions are copied to %8 to permit individual +; execution, and %7 is overwritten with an instruction used to copy +; the failing data into r1. Change this code very carefully ! + +5 + LDR r14,%2 ; Obtain first test in the set + STR r14,%8 ; and re-execute it + SUB r0,r0,#(13*4) ; adjust pointer to bad data + ADR r14,%2 ; point to first test. +7 + B %8 ; make sure %8 is refetched +8 + & 0 ; redo the test here : + BNE %4 ; if it failed, exit with + ; r0 = ptr to memory + ; r1 = wrongly read data + ; r14 => failing instruction + + LDR r1,[r14,#4]! ;fetch next instruction + AND r1,r1,#&f0000 ;make an instruction + MOV r1,r1,LSR #16 ;to copy the next register + ORR r1,r1,#&E1000000 ;down to r1 + ORR r1,r1,#&00A00000 ;e.g. CMPEQ r10,#0 + ORR r1,r1,#&00001000 + STR r1,%7 ;and put it at %7 + LDR r1,[r14] ;then copy the next test + STR r1,%8 ;to %8 + ADD r0,r0,#4 ;bump the fault pointer + B %7 ;and execute %7 and %8. + +test_mem_stadd ; address of first test location + & 0 +test_mem_base + & 0 ; address of test block + +test_mem_template_end + +; +; Copy the L2 page table from r1 to r0, then remap the translation table's +; base address in the MMU to point to an L1 page table within it. +; + ROUT + +ts_remap_ttab + MOV r2,#FixedAreasL2Size + ADD r0,r0,r2 ; point to locations in PhysSpace + ADD r0,r0,#PhysSpace + ADD r1,r1,r2 + ADD r1,r1,#PhysSpace +10 + ASSERT ((FixedAreasL2Size :AND: ((8*4)-1)) = 0) + LDMDB r1!,{r3-r10} ; copy the page & section tables + STMDB r0!,{r3-r10} + SUBS r2,r2,#(8*4) + BNE %BT10 + + SUB r9,r1,r0 ; r9 = offset from original to copy + ADD r0, r0, #DRAMOffset_L1PT-DRAMOffset_L2PT ; r0 -> copy of L1Phys + SUB r10, r0, #PhysSpace ; keep real address of L1PT for MMU + ADD r2,r0,#((1 :SHL: (32-20))*4) ; size of L1PT - 1 word per meg of memory +11 LDR r3,[r0],#4 ; check each L1 table entry + ANDS r4,r3,#3 + CMPS r4,#L1_Page ; if it's page mapped .. + SUBEQ r3,r3,r9 ; adjust the page table base address + STREQ r3,[r0,#-4] + CMPS r0,r2 ; repeat for all the level 1 table + BNE %BT11 + + SetCop r10, CR_TTabBase ; set up MMU pointer to L1 + SetCop r0, CR_IDCFlush ; flush cache + TLB just in case + SetCop r0, CR_TLBFlush ; (data written is irrelevant) + + MOV pc,r14 + + + END + diff --git a/OldTestSrc/Mem3 b/OldTestSrc/Mem3 new file mode 100644 index 0000000000000000000000000000000000000000..1313275f4a55e6f7eb344e50900cdd97407b5f33 --- /dev/null +++ b/OldTestSrc/Mem3 @@ -0,0 +1,119 @@ + ;> RomCheck +; +; RISC OS 2+ BOOT TEST SOFTWARE +; MEMORY TEST 3 VERSION A. +; BRIAN RICE 01-11-89 +; 24.04.90 0.10 ArtG Added ROM size test +; 15.05.90 1.00 ArtG Changed to put checksum at (end - 2 words) +; 17.05.90 1.01 ArtG Changed to get ROM length from vectot table +; +; +; This file will perform quick checksum test on the OS ROMS. +; +; +; The test code for this test is a simple additive checksum routine. +; The software will read eight words from ROM then add the contents from ROM +; to a register. When the test is complete the contents of the checksum +; register is checked by adding the final word in ROM - this should give +; zero. +; The program will be run from ROM, at slowest speed. +; +; All except the last two words are checksummed : these hold the numbers +; that cause each individual ROM to CRC to zero, so they can't simultaneously +; be included in an all-zero additive checksum. + +ts_CRCsize * (2 * 4) + +; +; +;r0 IS A POINTER TO THE LOCATIONS IN MEMORY. +;r1 HAS THE CALCULATED CHECKSUM. +;r2 HOLDS A COUNTER INDICATION HOW MANY WORDS ARE LEFT TO GET +;r3 is a temporary variable +;r4 TO r11 ARE USED TO LOAD THE CONTENTS OF 8 LOCATIONS FROM THE ROM. +; + ROUT + +ts_ROM_checksum + + MOV r1, #&00 ; initialise accumulator + LDR r0, =PhysROM ; initialise pointer + LDR r2, [r0, #ts_ROMSIZE] ; initialise endstop + ADD r2, r2, r0 ; - must be at least 8 words + SUB r2, r2, #(10 * 4) ; below the real endpoint + +loop1 LDMIA r0!, {r4 - r11} ;LOAD r4 TO r11 WITH THE CONTENTS + ;OF LOCATIONS POINTED TO BY r0 + ;WHICH IS INCREMEMTED AUTOMATICALLY + ;TO POINT TO THE NEXT LOCATION +01 + ADD r1, r1, r4 ;ADD r4 TO CHECKSUM + ADD r1, r1, r5 ;ADD r5 TO CHECKSUM + ADD r1, r1, r6 ;ADD r6 TO CHECKSUM + ADD r1, r1, r7 ;ADD r7 TO CHECKSUM + ADD r1, r1, r8 ;ADD r8 TO CHECKSUM + ADD r1, r1, r9 ;ADD r9 TO CHECKSUM + ADD r1, r1, r10 ;ADD r10 TO CHECKSUM + ADD r1, r1, r11 ;ADD r11 TO CHECKSUM +02 + ASSERT ((%02 - %01) = 32) ; else r2 won't count down correctly + + CMPS r0, r2 + BCC loop1 ;loop until pointer reaches endstop + + LDMIA r0!, {r4 - r9} ; get last 6 words (miss last 2 in ROM) +03 + ADD r1, r1, r4 ;ADD r4 TO CHECKSUM + ADD r1, r1, r5 ;ADD r5 TO CHECKSUM + ADD r1, r1, r6 ;ADD r6 TO CHECKSUM + ADD r1, r1, r7 ;ADD r7 TO CHECKSUM + ADD r1, r1, r8 ;ADD r8 TO CHECKSUM + ADD r1, r1, r9 ;ADD r9 TO CHECKSUM +04 + ASSERT (((%04 - %03) + (2*4)) = 32) ; Change this if you like - + ; but be careful to count nearly + ; to the top in eights, then add + ; add in the last few words. + + MOVS r0,r1 ; should be zero if all OK + + MOV pc,r14 ;return with zero flag set on OK + ;and the calculated sum in r0. + + +; +; ROM alias check. +; This test looks for an aliased copy of the vector table at varying +; distances from the start of ROM space. +; 16K is fairly arbitrary but corresponds approximately with the size of +; the POST. If there's an alias below that, we've probably already crashed ! +; +; This test is only called if the checksum fails, in order to indicate a +; possible high ROM address line failure. + +ts_ROM_alias ROUT + + MOV r0,#PhysROM ; get some words from ROM start + LDR r3,[r0, #ts_ROMSIZE] ; get the ROM length word + LDMIA r0,{r4,r5,r6,r7} + MOV r1,#(16 * 1024) + +01 ADD r2,r0,r1 ; get some words from possible alias + LDMIA r2,{r8,r9,r10,r11} + CMPS r4,r8 + CMPNE r5,r9 + CMPNE r6,r10 + CMPNE r7,r11 + BEQ %10 ; aliased : found MS ROM address bit + + MOVS r1, r1, LSL #1 ; test the next (more significant) bit + CMPS r1, r3 ; reached the limit yet ? + BLT %01 ; no - try again. + +10 MOV r0,r1 ; reached the end, or an alias. + MOV pc,lr + + + LTORG + + END diff --git a/OldTestSrc/Mem4 b/OldTestSrc/Mem4 new file mode 100644 index 0000000000000000000000000000000000000000..8d73e78c45242b07452cbc64e675df452f4b3f7a --- /dev/null +++ b/OldTestSrc/Mem4 @@ -0,0 +1,630 @@ +;> MEM4H_SCR +; +; RISC OS 2+ BOOT TEST SOFTWARE. +; MEMORY TEST 4 VERSION H. BRIAN RICE 12-01-90. +; 04-Apr-90 ArtG 0.1 Added ts_count_cams, improved reporting +; 11-Apr-90 ArtG 0.2 Use RISC OS routine BangCams for +; alternate MEMC configurations. +; 17-Apr-90 ArtG 0.3 rationalise page-counting code +; +; This file will be called by MEM6x_SCR for the purposes of assembly. +; This file will perform quick walking bit test on the CAM Entry points. +; The test code for this test was taken from the A680 test code. +; +; The module requires the running of the memory sizing routine used by +; the OS to set up the page size for this module. +; +; This test module was designed to operate on all current and future +; machines. The module is designed to handle up to 512 physical pages +; which is the maximum number of pages in a 16 MByte FOX. +; +; A 16 MB FOX has 4 MEMCs in use, each MEMC is addressed by Bits 7 and +; 12 of the logical to physical address translator. The use of bit 12 +; does have a problem in that on machines with 0.5MB of memory this is +; used to define the logical page number. Machine with 1MB or greater bit +; 12 is not used, therefore this test may hit problems on A305's. The +; intention is that A305 owners will upgrade to A310's when upgrading to +; RISC OS 2+. +; +; Because FOX can have up to 4 MEMCs fitted the following addressing is +; used to determine the MEMC accessed, bit 12, bit 7 +; 0 0 = Master MEMC = MEMC 0 +; 0 1 = Slave MEMC 1 = MEMC 1 +; 1 0 = Slave MEMC 2 = MEMC 2 +; 1 1 = Slave MEMC 3 = MEMC 3 +; +; +; This test will initialise the CAM entries for up to 512 physical pages. +; The physical pages will be mapped to logical page 5. Each page will have +; a copy of test routine vectors and a page marker. The page marker consists +; of the page number and a code to indicate which MEMC was used. The code for +; the MEMC used is as follows :- MEMC 0 0001 1110 = &1E +; MEMC 1 0010 1101 = &2D +; MEMC 2 0100 1011 = &4B +; MEMC 3 1000 0111 = &87 +; +; The page marker is arranged as follows &mm5Apppp +; | | +; | \-- Page Number &0000 ‰ &01FF. +; \--------MEMC Code as above. +; +; The patterns are chosen so that if two or more MEMCs are accessed +; together and both RAM outputs get enabled onto the data bus simultaneously, +; then there is a reasonable chance that the data returned will show the +; presence of a fault. +; +; When the CAM entries have been initialised the module will then check that +; all the pages are mapped correctly. A simple walking one pattern is used +; to check that the page is not present anywhere else in the memory area. +; This isn't really sufficient, but keeps the test time low. +; +; The tests are performed with the memory protection level set to 0. +; +; This version uses the "my abort" routine in MEM5x_SCR instead of the +; ts_dab_exp0 .. 5 method as taken from the A680 code. +; + +ts_rst_msg = "RST",0 +ts_uni_msg = "UDF",0 +ts_swi_msg = "SWI",0 +ts_pab_msg = "PAB",0 +ts_dab_msg = "DAB",0 +ts_aex_msg = "ADX",0 +ts_irq_msg = "IRQ",0 +ts_fiq_msg = "FIQ",0 +ts_bxc_msg = &85,"@",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 + ALIGN + + +ts_rst ; Unused exception vectors + ADR r4, ts_rst_msg + B ts_bad_exception +ts_uni + ADR r4, ts_uni_msg + B ts_bad_exception +ts_swi + ADR r4, ts_swi_msg + B ts_bad_exception +ts_pab + ADR r4, ts_pab_msg + B ts_bad_exception +ts_dab_unexp + ADR r4, ts_dab_msg + B ts_bad_exception +ts_aex + ADR r4, ts_aex_msg + B ts_bad_exception +ts_irq + ADR r4, ts_irq_msg + B ts_bad_exception +ts_fiq + ADR r4, ts_fiq_msg + B ts_bad_exception + + +ts_bad_exception + SUBS r8, r14, #8 ; remember aborted instruction + BL ts_SendText + ADR r4, ts_bxc_msg ; display aborted address + BL ts_MoreText + B Reset + + +; +ts_rom_base * ROM ; Base address of the OS ROMS. +ts_phys_mem * (32*1024*1024) ; Physical Memory area. +ts_pagemark * &005A0000 ; + phys page number + MEMC code. +ts_pmark_pos * 32 ; Position of page mark (avoiding vectors). +ts_cam_base * &3800000 ; Base address of the CAM table in MEMC. +ts_vrest * &5 ; Unused page which all pages are mapped to. +ts_MAX_CAMS * 512 ; Most CAMs ever expected +ts_memc_codes = &1E, &2D, &4B, &87 ; List of the memc_codes to be used. +; +ts_logpages ; List of Logical pages. + & &0001 + & &0002 + & &0004 + & &0008 + & &0010 + & &0020 + & &0040 + & &0080 + & &0100 + & &0200 + & &03FF + & &03FE + & &03FD + & &03FB + & &03F7 + & &03EF + & &03DF + & &03BF + & &037F + & &02FF + & &01FF + & &0000 ; Terminator for the list. +ts_logpagesend ; End of the list. +; +; +; Exception vectors : copied to start of each page to ensure that they will always +; exist on page zero when arbitrary pages are mapped there. +; +ts_vectors + B (ts_vectors-ts_start)+ts_rom_base+ts_rst + B (ts_vectors-ts_start)+ts_rom_base+ts_uni + B (ts_vectors-ts_start)+ts_rom_base+ts_swi + B (ts_vectors-ts_start)+ts_rom_base+ts_pab +ts_dab_vector + B (ts_vectors-ts_start)+ts_rom_base+ts_dab + B (ts_vectors-ts_start)+ts_rom_base+ts_aex + B (ts_vectors-ts_start)+ts_rom_base+ts_irq + B (ts_vectors-ts_start)+ts_rom_base+ts_fiq + + +; *************************************************************************** +; +ts_CAM +; +; CAM test (full or partial) +; Start of the CAM test, all physical pages have a copy of the vectors +; so they may be mapped as page 0. Then each page is mapped at a series +; of (walking 1, walking 0) logical pages and tested to be correctly +; mapped. Other pages are set to an unused logical page by set_cam_idle +; to prevent any CAM clashes. +; +; Copy the test vectors and page marker into all the pages. +; + ROUT ; Local Branches. + MOV r13, lr ; Preserve link register in r13. + BL ts_count_CAMs ; get log2 pagesize + MOV r0, #ts_MAX_CAMS ; r0 = last page to test + SUB r0, r0, #1 +0 BL ts_copy_vectors ; Gosub ts_vectors. + SUBS r0, r0, #&01 ; bump down to next page + BGE %B0 ; repeatuntil all pages set. +; +; 'C' pseudocode for the test routine. +; +; for (i = &1ff; i >= 0; i--) +; set_cam_idle(i); +; +; find maximum page number. +; if (max_page != ts_count_CAMS) +; report CAM number error +; +; for (phys = &max_page; phys >= 0; phys--) { +; for (logp = &logpages[0]; logp < &logpages[sizof(logpages)]; logp++) { +; if (*logp == 0) { +; set_cam(*logp, phys); +; check_mapped(*logp, phys); +; } else { +; int zphys = (phys + 1) % num_pages; +; set_cam(0, zphys); +; set_cam(*logp, phys); +; check_mapped(*logp, phys); +; set_cam_idle(zphys); +; } +; } +; set_cam_idle(phys); +; } +; +; Idle the pages. +; + ROUT ; Local Branches. + MOV r12, #ts_MAX_CAMS ; always clear all 512 - just in case 4 MEMCs. + SUB r12, r12, #&01 ; Subtract 1 to make max page #. +0 MOV r1, r12 ; r1 = page number. + BL ts_set_cam_idle + SUBS r12, r12, #&01 ; bump to next page downwards + BGE %B0 ; repeatuntil page 0 done +; +; We need to find out what the maximum number of pages is, after running the above routine +; all the pages will have the pagemark programed in to each page. As stated in the intro +; programing the pages from the top down will ensure that, irrespective of the number of +; MEMCs available, that the bottom pages are programed correctly. Therefore if we start +; at the top, read in a page, check it's page number & memc code are correct, if so then +; that is possibly the maximum page number. If not then subtract 1 from the page number and +; try again until a possible good page is found. +; + ROUT ; Local Branches. + + BL ts_count_CAMs ; get log2 pagesize to r1 + MOV r8, #ts_MAX_CAMS ; r8= max. number of physical pages. +0 SUBS r8, r8, #&01 ; Subtract 1 to make it r8 - 1 Pages. + BEQ ts_bad_CAM_count ; no pages ? - shouldn't hit this! +; +; Calculate the expected page marker, in r4, for the current page, in r8. +; + ADR r4, ts_memc_codes ; r4 = address of table with the memc codes. + LDRB r4, [r4, r8, LSR#7] ; r4 = Loc pointed to by r4 + (r1 >> 7). + ORR r4, r8, r4, LSL #24 ; r4 = page number OR (MEMC code << 24). + ORR r4, r4, #ts_pagemark ; r4 = page id OR magic number +; +; The calculated page marker is now in r4, ref_p_mark. +; Current page in r8 - convert to physical address in r9. +; the pagesize power-of-2 is in r1 (from ts_count_CAMs) +; + MOV r9, r8, LSL r1 ; convert PPN to phys offset + ORR r9, r9, #ts_phys_mem ; add offset to start of phys mem +; +; r9 now has the address of the current page - read the page marker for that page. +; + LDR r9, [r9, #ts_pmark_pos] ; r9 = contents of loc pointed to by + ; r9 + ts_pmark_pos. +; +; Check that read_p_mark is valid. +; +; Either the value read is the expected pagemark, junk (no memory) or an +; aliased pagemark - if it's aliased, then either the memory or the MEMC +; isn't decoded that far. +; Bump down and try a bit lower, until it's OK. +; + CMP r4, r9 ; Is page-mark expected value ? + BNE %B0 + +; +; Found a pagemarker in the proper place. Check that the number of pages that +; appear to be present are the same as the number found by ts_count_CAMs +; (i.e. the memory size / page size). +; + SUB r0, r0, #1 ; convert count -> max page number + CMPS r0, r8 + BNE ts_bad_CAM_count +; +; If all is well, we should have the maximum usable page number in r8. +; +; Need to reset page 0 in the CAM entries, currently all pages are mapped to page 5. +; We need to have logical page 0 mapped to physical page 0. +; + MOV r0, #&00 ; r0 = &00, the page to map. + MOV r1, #&00 ; r1 = &00, the page to map to. + MOV r2, #&00 ; r2 = &00, set the protection level. + BL ts_set_camp +; +; Check we can still see the data abort vector at physical page zero +; - no good continuing if we can't. +; + MOV r0, #ts_phys_mem + LDR r0, [r0, #(ts_dab_vector - ts_vectors)] + LDR r1, ts_dab_vector + CMPS r0, r1 + BNE ts_bad_dab_vector + +; +; Now lets get on with the testing. +; + +2 ADRL r10, ts_logpages ; logp = &logpages[0] + +3 LDR r0, [r10] ; r0 = page to test + CMP r0, #&00 ; last entry ? + BNE %F4 + MOV r1, r8 ; r1 = r8, page under test + BL ts_set_cam ; Gosub ts_set_cam. + LDR r0, [r10] ; r0 current logical test page + MOV r1, r8 ; r1 = current test page + BL ts_check_mapped ; Gosub ts_check_mapped. + B %F5 + +4 ADD r12, r8, #&01 + BL ts_count_CAMs ; get total number of pages + SUB r0,r0,#1 ; make a mask for useable page + AND r0,r0,#&7f ; numbers - min(128, num_pages) + AND r12, r12, r0 ; r12 -> (r12 + 1) masked + MOV r0, #&00 ; to useable page numbers. + MOV r1, r12 + BL ts_set_cam ; Setup a page for vectors + LDR r0, [r10] ; r0 = current logical test page. + MOV r1, r8 ; r1 = current physical test page. + BL ts_set_cam ; Setup a page to test + + LDR r0, [r10] ; look up logical page again. + MOV r1, r8 ; recall physical page. + BL ts_check_mapped ; check the ts_set_cam worked. + MOV r1, r12 ; unmap the vector page + BL ts_set_cam_idle + +5 ADD r10, r10, #&04 ; next entry in test list. + ADRL r0, ts_logpagesend ; r0 = ts_logpagesend. + CMP r10, r0 ; repeat until list of logical + BLO %B3 ; pages all done. + + MOV r1, r8 ; unmap the page we just tested + BL ts_set_cam_idle + + SUBS r8, r8, #1 ; bump phys page counter down. + ANDS r8,r8,r8 + BGE %B2 ; If r8 >= 0 Then branch back to 2. + + ANDS r0,r0,#0 + MOV pc,r13 ; all done and passed + +; +; **************************************************************************** +; +ts_copy_vectors +; +; Copies the vectors to the physical page in r0 (preserved) also copies +; pagemark + phypage. +; Expects r1 (preserved) to hold log2 of pagesize +; + ROUT ; Local Branches. + + ADR r2, ts_vectors ; r2 = source address + LDMIA r2, {r4-r11} ; r4 - r11 = loc pointed to by r2, post inc. + + MOV r3, r0, LSL r1 ; r3 = r0 * 2**r1 . + ORR r3, r3, #ts_phys_mem ; r3 = r3 OR ts_phys_mem. + STMIA r3, {r4-r11} ; loc pointed to by r3, post inc = r4 to r11. +; +; find out which memc is handling the page (r0), then assign the appropiate memc_code. +; Add in the page number and pagemark, then store into the required position in the +; page in question. +; + ADR r2, ts_memc_codes ; r2 = address of table with the memc codes. + LDRB r2, [r2, r0, LSR#7] ; r2 = memc code for this phys page. + ORR r2, r0, r2, LSL #24 ; OR in phys page number. + ORR r2, r2, #ts_pagemark ; OR in pagemark. + STR r2, [r3, #ts_pmark_pos] ; loc pointed to by r1 + ts_pmark_pos = pagemark. + MOV pc, lr ; Return to caller. +; +; **************************************************************************** +; +ts_set_cam_idle +; +; This module will program the physical page (r1) to the logical page 5, ts_vrest and +; continue onto the next section ts_set_cam. +; + ROUT ; Local Branches. + MOV r0, #ts_vrest ; r0 = ts_vrest, = unused logical page. +; +; **************************************************************************** +; +ts_set_cam +; +; This module will program the physical page (r1) to the logical page (r0) at +; protection mode 0 and continue onto the next section ts_set_camp. +; + MOV r2, #&00 ; r2 = &00, memory prot level 0. +; +; **************************************************************************** +; +ts_set_camp +; +; This module will map a range the physical pages (r1) to the logical page (r0) and +; set the protection mode (r2). This module will return to the location from where +; either itself or ts_set_cam or ts_set_cam_idle were called from. +; +; Corrupts r0,r1,r2,r3,r4,r6,r9,r11 +; +; Calls the RISC OS routine BangCam to do the PPNO, LPNO bit switching. +; First, jumble the registers to suit BangCam .. +; +; r2 = CAM entry (PPNO) +; r3 = logical address +; r9 = current MEMC setting (for pagesize) +; r11 = PPL +; + MOV r3,r0 ; logical page number + MOV r11,r2 ; protection level + MOV r2,r1 ; physical page number + MOV_fiq r0, r11_fiq ; MEMC configuration + MOV r9, r0 ; keep a copy in r9 + MOV r1, r9, LSR #2 + AND r1, r1, #3 ; calculate pagesize shift + ADD r1, r1, #12 + MOV r3, r3, LSL r1 ; convert LPN to logaddr + B BangCam ; return thro' BangCam + +; +; **************************************************************************** +; +ts_check_mapped +; +; This routine will check that the CAM has been programed correctly and that the required +; page is responding when asked. A quick test is made to check that other pages are not +; responding as well. +; +; logical page in r0, +; physical page in r1, +; test that they are the same. +; +; No return value : reports faults directly and returns thro' r13 +; +; Uses (corrupts) r0,r1,r2,r3,r4,r5,r6,r7 +; +; Find out which memc is handling the page (r1), then assign the appropiate memc_code. +; Add in the page number and pagemark, then compare that pagemark with those found +; in memory at the expected logical and physical addresses. +; +; This code assumes that any system with multiple MEMCs will always have 32K pages. +; + ROUT ; Local Branches. + + MOV r3, r0 ; save the current logical pagenumber. + MOV r5, lr ; Preserve link register in case of Abort. + ADR r2, ts_memc_codes ; r2 = address of table with the memc codes. + LDRB r2, [r2, r1, LSR#7] ; fetch the memc code for this page. + ORR r2, r1, r2, LSL #24 ; build the page number into the pagemark + ORR r2, r2, #ts_pagemark ; build in the pagemark magic number +; +; r2 should now have the page_mark for the current page (r1). +; calculate the shift to convert page number to memory offset. +; + MODE FIQ_mode + MOV r4, r11_fiq, LSR #2 ; pagesize / 4K + MODE SVC_mode + AND r4, r4, #3 + ADD r4, r4, #12 +; +; if the mapping failed completely, the test might abort +; + MOV r6, #&00 ; r6 = &00, clear expected abort flag. + MOV r7, #&94 ; r7 = &94, set abort expected flag. +; +; make the pointers and test the contents +; + MOV r0, r0, LSL r4 ; r0 = LPN * pagesize. + LDR r0, [r0, #ts_pmark_pos] ; r0 = contents of loc in r0 + ts_pmark_pos. + CMP r6, #94 ; did that fetch abort ? + ADREQ r4, %F14 ; mapping totally failed + BEQ ts_CAM_fail + MOV r1, r1, LSL r4 ; r1 = PPN * pagesize. + ORR r1, r1, #ts_phys_mem ; r1 = r1 ORed with ts_phys_mem. + LDR r1, [r1, #ts_pmark_pos] ; r1 = contents of loc in r1 + ts_pmark_pos. + CMP r0, r1 ; Are the read pagemarks equal ?? + ADRNE r4, %F10 + BNE ts_CAM_fail ; Failed : mapping not equal. + CMP r0, r2 ; + ADRNE r4, %F11 + BNE ts_CAM_fail ; Failed : map equal, but corrupt +; +; test that the page doesn't exist anywhere else +; + MOV r2, #1 +0 EOR r0, r2, r3 ; Flip a (walking) bit in the LPN. + CMP r0, #ts_vrest ; Is r0 = ts_vrest ?? Where all the pages are + ; mapped to. + BEQ %F1 ; If r0 = ts_vrest then branch forward to 1. +; +; The following instruction should abort. +; + MOV r0, r0, LSL r4 ; r0 = LPN * pagesize. + MOV r6, #&00 ; r6 = &00, clear abort handled flag. + MOV r7, #&94 ; r7 = &94, set abort expected flag. + LDR r0, [r0, #ts_pmark_pos] ; get a possible pagemark from this page. + CMP r6, #&94 ; Did we go thro' the abort handler ? + BEQ %F1 ; If equal then an abort happened, good ! +; +; Not aborted - is it page zero, where the vectors live ? +; + TEQS r2, r3 + BEQ %F1 ; yes - that SHOULDN'T abort +; +; Fault - is the page mapped there the same as our test page ? +; + CMP r0, r1 + ADREQ r4, %F12 ; Failed : phys page also mapped here + ADRNE r4, %F13 ; Failed : page not unmapped + EOR r3, r2, r3 ; remake the duff LPN for the error display + B ts_CAM_fail + ; If equal then no abort happened, not good !! + +1 MOV r2, r2, LSL#1 ; bump to next-bit-set page number + CMP r2, #(ts_MAX_CAMS :SHL: 1) ; Hit number of logical pages ? + BLT %B0 ; If r2 < maximum number then loop again. + + MOV r7, #0 ; no longer expecting aborts + MOV pc, r5 ; Return to caller. + +; +; Indicate that CAM mapping test failed (PPN is not at LPN) +; Display r8, the physical page number and r3, the logical page. +; +; ***This error exit returns to the CALLER of check_mapped, thro' r13*** +; + +10 + = "CAM map",&88,&ff,&ff,&ff,".",&ff,&ff,&ff,&ff,0 +11 + = "CAM pmk",&88,&ff,&ff,&ff,".",&ff,&ff,&ff,&ff,0 +12 + = "CAM als",&88,&ff,&ff,&ff,".",&ff,&ff,&ff,&ff,0 +13 + = "CAM unm",&88,&ff,&ff,&ff,".",&ff,&ff,&ff,&ff,0 +14 + = "CAM abo",&88,&ff,&ff,&ff,".",&ff,&ff,&ff,&ff,0 + + ALIGN + + +ts_CAM_fail + MOV r0, r8, LSL #16 ; physical page # + LDR r1, =&ffff + AND r1, r1, r3 + ORR r0, r0, r1 ; add logical page # + MOV r8, r0, LSL #4 + MOV r6, #0 ; no longer expecting aborts + ORRS r0, r0, #1 + MOV pc, r13 + +; +; ************************************************************************** +; + +; Routine to return expected number of physical pages in r0. +; Uses memory size determination from r10_fiq and page mode from r11_fiq. +; Returns pagesize as power-of-two in r1, for pagenumber->address calcs. + +ts_count_CAMs + + MODE FIQ_mode + MOV r0,r10_fiq,LSR #12 ; get values determined + MOV r1,r11_fiq,LSR #2 ; by MemSize + MODE SVC_mode + + AND r1,r1,#3 ; memory / pagesize + MOV r0,r0,LSR r1 + ADD r1,r1,#12 ; page bit-shift value + + MOVS pc,lr + + +; +; ************************************************************************** +; + ROUT + +; Indicate that an unexpected number of CAM pages were found. +; +; Display as "CAM ## eee.fff" +; +; where eee is the expected maximum page number (r0), fff is the number +; of of the highest page actually found (r8). + +0 + = "CAM ##",&89,&ff,&ff,&ff,".",&ff,&ff,&ff,0 + ALIGN + +ts_bad_CAM_count + ADD r8, r8, r0, LSL #12 + MOV r8, r8, LSL #8 + ADR r4, %B0 + ORRS r0, r0 ,#1 + MOV pc, r13 +; +; ************************************************************************** +; + +; Indicate that the DAB vector wasn't visible in physmem + +0 + = "CAM vec",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 + ALIGN + +ts_bad_dab_vector + ADR r4, %B0 + EOR r8,r0,r1 ; indicate which bits are lost + ORRS r0, r0, #1 + MOV pc, r13 +; +; ************************************************************************** + +; Routine to indicate that an unexpected abort was found. + +0 + = "DAB @",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff, 0 + ALIGN + +ts_unxvect + ADR r4, %B0 + SUBS r8, r14_svc, #8 ; indicate the aborting instruction + BL ts_SendText + ORRS r0, r0, #1 + MOV pc, r13 + + + + LTORG + + END diff --git a/OldTestSrc/Mem5 b/OldTestSrc/Mem5 new file mode 100644 index 0000000000000000000000000000000000000000..607a8b8e1d1c47c9ac1c027c522a3acc14133554 --- /dev/null +++ b/OldTestSrc/Mem5 @@ -0,0 +1,316 @@ +;>MEM5D_SCR +; +; RISC OS 2+ BOOT TEST SOFTWARE. +; MEMORY TEST 5 VERSION D. BRIAN RICE 10-01-90. +; 04-Apr-90 ArtG 0.1 Use memory size to determine page count +; 11-Apr-90 ArtG 0.2 Changes to permit use of BangCam +; +; This file will be called by MEM6x_SCR for the purposes of assembly. +; This file requires the assembly of MEM4x_SCR to be perfromed at the +; same time. The program will call the cam setting routines in the cam +; test program. +; +; This file will test MEMCs ability to assert its protection over +; logical pages. +; The test code for this test was taken from the A680 test code. +; The Arm CPU has three mode of operation, Supervisor, Operating System. +; and User. Most of the time the machine will operate in user mode, in this. +; mode the designers do not want the user to have full access to the memory. +; map, therefore the MEMC(s) will check that the CPU has the appropiate +; level of authorisation to access specific area of memory. +; User mode is the lowest mode, allowing limited R/W access to the ram. +; Operating System is next up the list and is allowed some more access to +; to the ram than user mode. +; Supervisor mode this is the highest and the CPU has unlimited access to +; the entire memory map. +; +; This version has the "my abort" routine in it not the ts_dab_exp0..5 routine as +; coded from the A680 code. +; +; Set up some variables. +; +ts_wks_word * 36 ; Offset of word for workspace. +; +; **************************************************************************** +; +ts_memc_prot +; +; This module will map and assign protection mode 0 to all the pages. The +; module will then perfrom a read and write operations in supervisor and +; user modes. This is repeated for the three (four) protection modes. +; The module will check after every protection mode level that the required +; responses have been returned. +; +; Set up the memory, map and assign protection mode 0. +; + ROUT ; Local Branches. + MOV r13, lr ; Preserve the link register. + MOV r12, #&00 ; r12 = The physical page to test. + +0 ADD r8, r12, #&01 ; Get a page to use as vectors, + BL ts_count_CAMs ; get total number of pages + SUB r0,r0,#1 ; make a mask for useable page + AND r0,r0,#&7f ; numbers - min(128, num_pages) + AND r8, r8, r0 + + MOV r1, r8 ; r1 = r8, r1 = physical page 0. + MOV r0, #&00 ; r0 = &00, r0 = logical page 0. + BL ts_set_cam ; Gosub ts_set_cam, set the CAM up. +; +; Set protection mode 0 and test that page. +; + MOV r2, #&00 ; r2 = &00, r2 = protection mode 0. + BL ts_mem_prot ; Gosub ts_mem_prot. + CMP r3,#&0F ; Is r3 = &0F ? r3 = Super Read/Write ok. + ; O/S Read/Write ok. + ; User Read/Write ok. + MOV r2, #0 + BNE ts_prot_fail ; If r3 <> &0F Then branch to fail routine. +; +; Set protection mode 1 and test that page. +; + MOV r2, #&01 ; r2 = &01, r2 = protection mode 1. + BL ts_mem_prot ; Gosub ts_mem_prot. + [ CPU_Type = "ARM600" + CMP r3,#&0f ; no ABORT line to ARM600 + | + CMP r3,#&0B ; Is r3 = &0B ? r3 = Super Read/Write ok. + ] ; O/S Read/Write ok. + ; User Read only ok. + + MOV r2,#1 + BNE ts_prot_fail ; If r3 <> &0B Then branch to fail routine. +; +; Set protection mode 2 and test that page. +; + MOV r2, #&02 ; r2 = &02, r2 = protection mode 2. + BL ts_mem_prot ; Gosub ts_mem_prot. + [ CPU_Type = "ARM600" + CMP r3,#&0f ; no ABORT line to ARM600 + | + CMP r3,#&03 ; Is r3 = &03 ? r3 = Super Read/Write ok. + ] ; O/S Read only ok. + ; User No Access ok. + MOV r2,#2 + BNE ts_prot_fail ; If r3 <> &03 Then branch to fail routine. +; +; Set protection mode 3 and test that page. +; + MOV r2, #&03 ; r2 = &03, r2 = protection mode 3. + BL ts_mem_prot ; Gosub ts_mem_prot. + [ CPU_Type = "ARM600" + CMP r3,#&0f ; no ABORT line to ARM600 + | + CMP r3, #&03 ; Is r3 = &03 ? r3 = Super Read/Write ok. + ] ; O/S Read only ok. + ; User No Access ok. + MOV r2,#3 + BNE ts_prot_fail ; If r3 <> &03 Then branch to + ; fail routine. +; +; Reset the page used to idle. +; + MOV r0, r12 ; r0 = r12, idle the pages + ; being used. + BL ts_set_cam_idle ; Gosub ts_set_cam_idle. + MOV r0, r8 ; r0 = r8, idle the pages + ; being used. + BL ts_set_cam_idle ; Gosub ts_set_cam_idle. +; +; Increment the physical page counter and check that all the pages are +; done, else finish. +; + BL ts_count_CAMs + ADD r12, r12, #&01 ; do the next physical page. + CMP r12, r0 ; Done all pages ? + BLT %B0 ; If r12 <= cam_entries, + ; branch back to 0. + + ANDS r0, r0, #0 ; set zero flag : test passed + MOV pc, r13 ; Return to caller. +; +; ************************************************************************** +; +; Branch here when ts_memc_prot fails to get the proper result from +; ts_mem_prot. +; +; At this point, +; +; r3 is a map of permitted ops (user read, user write, sys read, sys write) +; r2 is the memc protection mode +; r12 is the physical page number. +; +; This is displayed as : +; +; PPL bad l.a.pppp +; +; where l is the PPL set on that page (0, 1, 2 or 3) +; a is a bitmap of the actual operations permitted (ur.uw.or.ow) +; p is the physical page number tested +; + +0 + = "PPL bad",&88,&ff,".",&ff,".",&ff,&ff,&ff,&ff,0 + ALIGN + +ts_prot_fail + AND r2, r2, #&0f + MOV r0, r2, LSL #20 ; mode bits + AND r3, r3, #&0f + ORR r0, r0, r3, LSL #16 ; permitted ops bits + BIC r12, r12, #&ff000000 + BIC r12, r12, #&ff0000 + ORR r0, r0, r12 ; current page number + + + ADR r4, %B0 ; get fail message + MOV r8, r0, LSL #8 ; shift number to suit ts_SendText + ORRS r0, r0, #1 ; fail flag + MOV pc, r13 + + +; +; +; This section will test that the physical page referenced in r12 at the set +; protection mode. During the operation of this module, aborts are expected to happen. +; The aborts are handled by the routine ts_dab. +; +; The system is running in supervisor mode and thus to check the user mode read / writes +; the address translator flag is used. The CPU has a signal called -TRANS which when used +; with MEMC forces the an address translation to be performed, this is not done whilst +; in supervisor mode because it has unlimited access to the memory map. The address +; translator falg (T) is used with STR and LDR instructions only, the effective result of +; adding the (T) to the opcode is to force the instruction to be executed as if the CPU +; was in user mode, thus unauthorised accesses will cause an abort to occur. +; +; IN: +; r12 - physical page. +; r2 - protection mode. +; OUT: +; r3 - access pattern. +; r3 = &0F, Super Read/Write ok, O/S Read/Write ok, User Read/Write ok. +; r3 = &0B, Super Read/Write ok, O/S Read/Write ok, User Read only ok. +; r3 = &03, Super Read/Write ok, O/S Read only ok, User No Access ok. +; +ts_mem_prot +; +; Set up data to write and read from memory. +; + MOV r10, lr ; Preserve link register. + MOV r1, r12 ; r1 = physical page. + MOV r0, #&01 ; r0 = logical page 1. + BL ts_set_camp + + MOV r3, #&00 ; Initialise access pattern. + MOV_fiq r5, r11_fiq ; get MEMC control + AND r5, r5, #&C + ADR r9, ts_ppl_tptrs + LDR r9, [r9, r5] ; get test address for this pagesize +; +; Test 1 system mode - write. +; + MOV r6, #&00 ; r6 = &00, clear expected abort flag. + MOV r7, #&94 ; r7 = &94, set abort expected flag. +; +; The following instruction may abort. +; + STR r1, [r9] ; Store r1 at loc pointed to by r9. + CMP r6, #&00 ; Is r6 = &00 ? If not then abort happened. + ORREQ r3, r3, #&01 ; If r6 = &00, Then update r3, access pattern. +; +; Test 2 system mode - read. +; + MOV r6, #&00 ; r6 = &00, clear expected abort flag. + MOV r7, #&94 ; r7 = &94, set abort expected flag. +; +; The following instruction may abort. +; + LDR r1, [r9] ; Load r1 from loc pointed to by r9. + CMP r6, #&00 ; Is r6 = &00 ? If not then abort happened. + ORREQ r3, r3, #&02 ; If r6 = &00 Then update r3, access pattern. +; +; Test 3 user mode - write. +; + MOV r6, #&00 ; r6 = &00, clear expected abort flag. + MOV r7, #&94 ; r7 = &94, set abort expected flag. +; +; The following instruction may abort. +; + STRT r1, [r9] ; Store r1 at loc pointed to by r9. + CMP r6, #&00 ; Is r6 = &00 ? If not then abort happened. + ORREQ r3, r3, #&04 ; If r6 = &00 Then update r3, access pattern. +; +; Test 4 user mode - read. +; + MOV r6, #&00 ; r6 = &00, clear expected abort flag. + MOV r7, #&94 ; r7 = &94, set expected expected flag. +; +; The following instruction may abort. +; + LDRT r1, [r9] ; Load r1 from loc pointed to by r9. + CMP r6, #&00 ; Is r6 = &00 ? If not then abort happened. + ORREQ r3, r3, #&08 ; If r6 = &00 Then update r3, access pattern. + MOV pc, r10 ; Return to caller. + +; +; addresses (a short way up page 1) to test PPL aborts +; + +ts_ppl_tptrs + & ( 4 * 1024) + ts_wks_word + & ( 8 * 1024) + ts_wks_word + & (16 * 1024) + ts_wks_word + & (32 * 1024) + ts_wks_word +; +; +ts_dab +; +; This routine provides the handling when a DATA ABORT occurs. +; The routine will if the abort was DATA cause the program to skip over the instruction +; that caused the abort first place. +; Data aborts could come from a variety of sources, in this module we are only concerned +; about a select group of aborts. This abort routine is called instead of the "usuall" +; abort routine. All that is required from this abort routine is to set a flag to +; indicate that an abort occured. Therefore this routine needs to be told that the +; abort that caused the routine to be called is either one of mine or not, (expected +; or unexpected). To achive this &94 is placed in r7. The abort routine will check +; for the presence of &94 in r7, if present then the abort is an expected abort. +; The abort routine will then copy r7 into r6, which is used as a flag to indicate +; that an abort occured and that it was an expected abort. Then the routine will +; return control to the program at the location after the instruction that caused to +; abort to occur. +; The return address is stored by the CPU into the link regester lr (r14), sort off. +; It must be remembered that the PC is always 2 instructions ahead. E.G. if the +; instruction that causes the abort is at &2000, then the lr will have &2008 in it, +; but we want to return to the location after the abort instruction, &2004. Therefore to +; return to the correct location &04 is removed from the lr and this is put into the pc. +; If the abort was not expected then the routine will jump to the end and another +; routine will show that an unexpected abort was generated. +; +; IN: +; r6 - Equals &00, cleared just before the instruction that could cause an abort. +; r7 - Equals &94, set just before the instruction that could cause an abort. +; +; OUT: +; r6 - Equals &94, set if an abort happened and was expected. +; r7 - Equals &94, preserved. +; + ROUT ; Local Branches. +; +; Check that it is an expected abort and not an unexpected abort. +; + CMP r7, #&94 ; Is r7 = &94, abort expected value. + BNE ts_dab_unexp ; If <> &94, Then branch to unexpected + ; abort handler. +; +; It is an expected abort, so handle it. +; + MOV r6, r7 ; r6 = r7, indicates that an abort happened. + SUB pc, lr, #&04 ; pc = link reg - &04. + ; Skip over aborting instruction. + ; By reloading the pc we return to the area + ; of code where the abort occured but 4 + ; locations further on. + + + END diff --git a/OldTestSrc/TestMain b/OldTestSrc/TestMain new file mode 100644 index 0000000000000000000000000000000000000000..22fcf0d1dada040ca950d51cadf2854ae7a70079 --- /dev/null +++ b/OldTestSrc/TestMain @@ -0,0 +1,78 @@ +; > TestMain + + +; Main assembly file for isolated assembly of machine test software + +MEMCADR * &3600000 +ROM * &3800000 + + [ MEMC_Type = "IOMD" +VideoPhysRam * &02000000 ; Amazing - it's in the same place! +DRAM0PhysRam * &10000000 ; 4 DRAM banks +DRAM1PhysRam * &14000000 +DRAM2PhysRam * &18000000 +DRAM3PhysRam * &1C000000 +DRAMBaseAddressMask * &1C000000 ; used to mask off bits after stealing video RAM +PhysSpaceSize * &20000000 ; IOMD physical map is 512M big +PhysROM * &00000000 ; and real ROM starts at 0 +SAMLength * 512*4 ; SAM length in bytes for 1 bank of VRAM +EASISpacePhys * &08000000 +EASISpace * PhysSpace + EASISpacePhys + | +VideoPhysRam * &02000000 +PhysSpaceSize * &04000000 ; MEMC1 physical map is 64M big +PhysROM * &03800000 +PhysRamPhys * &02000000 ; physical space starts here + ] + + ORG ROM + + GET TestSrc/Begin +CONT + ADRL r2,TestVIDCTAB + LDR r0,=IOMD_MonitorType + LDR r0,[r0] + ANDS r0,r0,#IOMD_MonitorIDMask + ADDEQ r2,r2,#(TestVVIDCTAB-TestVIDCTAB) + MOV r0,#ts_VIDCPhys +08 LDR r1, [r2],#4 + CMP r1, #-1 + STRNE r1, [r0] + BNE %BT08 + + MOV r9,#0 +10 + ORR r9,r9,#&40000000 + STR r9,[r0] ; write the border colour + ADD r9,r9,#&00000005 + ADD r9,r9,#&00000300 + ADD r9,r9,#&00010000 + AND r9,r9,#&00ffffff + + MOV r1,#&10000 +12 ADDS r1,r1,#(-1) + BNE %BT12 + + B %BT10 + +; +; The RISC-OS MEMC setup code is re-used to ensure similar +; detection of memory configuration. The MEMC1 code is modified only +; to remove an unnecessary function. + + GBLL Module +Module SETL {FALSE} + GBLL AssembleSAtest +AssembleSAtest SETL {FALSE} + +DynAreaFlags_DoublyMapped * 1 :SHL: 6 +DynAreaFlags_NotCacheable * 1 :SHL: 5 +DynAreaFlags_NotBufferable * 1 :SHL: 4 +DynAreaFlags_APBits * 15 :SHL: 0 ; currently onl + + + END + + + + diff --git a/OldTestSrc/Vidc b/OldTestSrc/Vidc new file mode 100644 index 0000000000000000000000000000000000000000..3aedb0b009aab7548ae66aa3a952f3154fdfa721 --- /dev/null +++ b/OldTestSrc/Vidc @@ -0,0 +1,530 @@ +; > TestSrc.VIDC + + TTL RISC OS 2+ POST video controller +; +; The video outputs cannot be tested directly, and VIDC permits only +; write operations on its registers. +; This module performs two tests to verify VIDC's operation +; +; - measure mode 0 FLBK period against IOC timer +; - check that sound DMA occurs (MEMC reports DMA complete) +; +; This code contains timing loops affected by gross changes in processor +; speed, and will re-initialise MEMC with 4K pages and continous refresh. +; +;------------------------------------------------------------------------ +; History +; +; Date Name Comment +; ---- ---- ------- +; 18-Dec-89 ArtG Initial version +; 04-Apr-90 ArtG Use saved MEMC control register setting +; 20-Jun-93 ArtG Medusa VIDC20 / IOMD changes +; +; +;------------------------------------------------------------------------ + + +VIDC_CLOCK_CONTROL * ts_S5_base :OR: &0048 ; Fox VIDC clock control +VIDC_CLOCK_NORMAL * &0 + +VIDC_VFLYWAIT * 72000 ; 200mS timeout loop +VIDC_SOUNDWAIT * 40000 ; 100mS timeout loop + +MEMC_Sstart * MEMCADR :OR: &80000 +MEMC_SendN * MEMCADR :OR: &A0000 +MEMC_Sptr * MEMCADR :OR: &C0000 +MEMC_Son * &00800 + +ts_Soundbuf * &200 ; relative to PhysRam +ts_Soundbuf_length * &400 + + [ VIDC_Type = "VIDC20" +VIDSTIM0 * &A0000000 ; base VIDC20 register values +VIDSTIM1 * &A1000000 +VIDSFR * &B0000000 +VIDSCR * &B1000005 +VIDDMAoff * &94000024 +VIDVCOWAIT * &5 +VIDVCOFREQ * &D0000404 + | +VIDSTIM0 * &60000000 ; base VIDC register values +VIDSTIM1 * &64000000 +VIDSFR * &C0000100 + ] + + SUBT FLBK period test +; +; This test attempts to validate the video timing system by checking for +; the proper period from the vertical flyback pulse. To make life easier, +; the test is performed only in mode 0 - i.e a 20mS period. +; +; This test contains a processor-clock timed loop as an outer limit : +; it assumes that the processor will never run more than a factor of ten +; faster than an 8Mhz ARM2. +; This is valid provided that this code isn't run with an ARM3 cache enabled. +; + +; Initialise video clock control (for FOX) +; Initialise VIDC +; Clear IR interrupt request in IOC +; Poll IOC until IR appears (if ever) +; Set IOC timer 0 to 32 mS +; Clear IR interrupt request in IOC +; Poll IOC until IR appears (if ever) +; Check timer 0 has counted down 20 mS (19.8 - 20.2 mS) +; Return zero flag set on OK, clear on test failure. + + +ts_VIDC_period ROUT + + ; Initialise VIDC clock and VIDC + + [ VIDC_Type = "VIDC1a" + LDR r3, =VIDC_CLOCK_CONTROL ; + MOV r1, #VIDC_CLOCK_NORMAL + STRB r1, [r3] + ] + + MOV r7, #0 + MOV r1, #ts_VIDCPhys + ADRL r6, TestVIDCTAB +00 LDR r0, [r6],#4 ; setup using main table + CMP r0, #-1 + STRNE r0, [r1] + BNE %BT00 +01 LDR r0, [r6],#4 ; enable DMA using 2nd table + CMP r0, #-1 + STRNE r0, [r1] + BNE %BT01 + + ; Wait for the start of a flyback period + +04 + LDR r3, =IOC + [ MEMC_Type = "IOMD" + LDR r1, [r6] ; get FSIZE value from end of TestVIDCTAB + STR r1, [r3, #IOMD_FSIZE] + ] + MOV r1, #vsync_bit + STRB r1, [r3, #IOCIRQCLRA] + LDR r2, =VIDC_VFLYWAIT ; long timeout loop - C 200mS + +05 LDRB r1, [r3, #IOCIRQSTAA] + ANDS r1, r1, #vsync_bit + BNE %06 + SUBS r2, r2,#1 + BNE %05 + + LDR r0,=&fffff + ORRS r0, r0,r7, LSL #20 ; Failed : clear 0 flag + MOV pc, r14 ; ... and quit + + ; Set up IOC timer 0 +06 + LDR r1, =(32 * 1000 * 2) ; 32mS upper limit + STRB r1, [r3, #Timer0LL] + MOV r0, r1, LSR #8 + STRB r0, [r3, #Timer0LH] + MOV r0, #0 + STRB r0, [r3, #Timer0GO] ; start the timer + + ; clear the IR and T0 bits + + MOV r0, #(vsync_bit :OR: timer0_bit) + STRB r0, [r3,#IOCIRQCLRA] + + ; wait for what should be a complete vflyback period + +10 LDR r2, =VIDC_VFLYWAIT ; timeout loop - C 200 msec +11 LDRB r0, [r3,#IOCIRQSTAA] + TSTS r0, #vsync_bit + BNE %14 ; wait for end of vsync + + TSTS r0, #timer0_bit ; or timer underflow + BNE %13 + +12 SUBS r2, r2, #1 ; or last-ditch timeout + BNE %11 + +13 ORRS r0, r0,#1 ; Failed : clear 0 flag + MOV r0, #0 ; but return a zero + MOV pc, r14 ; ... and quit + + ; finished in reasonable time : check against margins. + +14 STRB r0, [r3, #Timer0LR] ; latch the current count + LDRB r2, [r3, #Timer0CL] + LDRB r0, [r3, #Timer0CH] + ADD r2, r2, r0, LSL #8 + + SUB r2, r1, r2 + MOV r0, r2, LSR #1 ; Vertical flyback time in uS + + LDR r1, =19800 ; inside limits ? + SUBS r2, r0, r1 + BLE %F20 + + LDR r1, =400 ; 19.8 -> 20.2 mS + CMPS r2, r1 + BGE %F20 + MOV r1,#0 ; OK - 0 indicates pass + + ; After success using the 24MHz reference clock, select the + ; VCO clock (also at 24MHz) and ensure the test is passed after + ; a few cycles to allow the VCO to settle. + +20 + [ VIDC_Type = "VIDC20" + + TEQ r7,#0 ; if this is the first loop .. + BNE %FT21 + TEQ r1,#0 ; and it passed OK .. + BNE %FT25 + MOV r2,#ts_VIDCPhys + LDR r3,=VIDVCOFREQ ; set the vco to 24MHz + LDR r4,=&E0000400 ; and use the vco clock + STMIA r2,{r3,r4} + MOV r7,#VIDVCOWAIT ; set the vco test loop count + B %BT04 ; and run around again + +21 ORR r0,r0,r7,LSL #20 + SUBS r7,r7,#1 ; if all attempts now made + BEQ %FT25 ; return final result + TEQ r1,#0 ; else repeat until passed + BNE %BT04 + ] + + ; return with zero flag set if timers were OK + ; measured time (in uS) in r0 if flyback was wrong, + ; bits 20+ show fail loop - 0 for refclk, 1 for vcoclk. + +25 + ORRS r1,r1,r1 + MOV pc, r14 + + + SUBT Sound DMA test +; +; This test runs the sound DMA system to prove the operation of VIDC and +; MEMC's sound DMA control and the operation of the SIRQ sound DMA complete +; interrupt. +; To avoid making a noise, set the sound muting bit on. +; +; Initialise MEMC sound DMA +; Initialise VIDC sound channel +; Initialise timer 0 and timer 1 to guard-band 10mS sound duration +; Poll IOC until IL1 (SIRQ interrupt) becomes active +; Check timer 0 has completed and timer 1 has not +; + +ts_SIRQ_period ROUT + + ; set up MEMC to point to a buffer near the start of physical RAM, + ; labelled in r9_fiq by the early memory size tests (not MemSize) + ; Registers are set as (address / 16) + ; Register bits are (register * 4) in VIDC address mask + ; Hence values written to MEMC + register offset + (pointer / 4) + + + [ MEMC_Type = "IOMD" + MOV r3,#IOMD_Base + MOV r0,#(IOMD_DMA_C_Bit :OR: IOMD_DMA_E_Bit :OR: 16) + STR r0,[r3,#IOMD_SD0CR] + MOV_fiq r0,r9 ; zero the DMA buffer + ADD r1,r0,#ts_Soundbuf_length + MOV r2,#0 +02 STR r2,[r0],#4 + CMPS r0,r1 + BNE %BT02 + | + MOV_fiq r0,r11_fiq + BIC r0, r0, #MEMC_Son ; ensure sound DMA disabled + + STR r0, [r0] + LDR r1, =(MEMC_SendN :OR: ((ts_Soundbuf + ts_Soundbuf_length) / 4)) + STR r1, [r1] + LDR r2, =(MEMC_Sstart :OR: (ts_Soundbuf / 4)) + STR r2, [r2] + LDR r0, =MEMC_Sptr ; initialise Sptr and set up again .. + STR r0, [r0] + STR r1, [r1] + STR r2, [r2] + ] + + ; Set up VIDC for 8 channels, 10uS (/8) per sample + + LDR r0, =ts_VIDCPhys + [ VIDC_Type = "VIDC20" + LDR r1, =VIDSCR ; VIDC10 mode, 24Mhz clock + STR r1, [r0] + LDR r1, =VIDDMAoff + STR r1, [r0] + ] + LDR r1, =(VIDSTIM0 + 1) ; channel 0 at 100% left + LDR r2, =((VIDSTIM1 - VIDSTIM0) + 1) + MOV r3, #7 +05 STR r1, [r0] ; .. up to 6 at 100% right + ADD r1, r1, r2 + SUBS r3, r3, #1 + BNE %05 + SUB r1, r1, #4 ; finally ch7 at centre again + STR r1, [r0] + + LDR r1, =(VIDSFR + 8) ; 10uS/byte + STR r1, [r0] + + ; Set up the timer to limit at 20 us (10uS/sample, 1024-16 bytes => 10.08 mS) + + LDR r3, =IOC + LDR r1, =(20 * 1000 * 2) ; 20 mS upper limit + STRB r1, [r3, #Timer1LL] + MOV r0, r1, LSR #8 + STRB r0, [r3, #Timer1LH] + + MOV r0, #-1 + STRB r0, [r3, #IOCControl] ; mute sound (on IOC system) + STRB r0, [r3, #Timer1GO] ; start the timer + + [ MEMC_Type = "IOMD" + MOV r0, #(IOMD_DMA_E_Bit :OR: 16) ; enable the IOMD DMA + STR r0, [r3,#IOMD_SD0CR] + MOV_fiq r0,r9 ; set the buffer pointers + MOV r4,#((ts_Soundbuf_length/2) - 16) + STR r0,[r3,#IOMD_SD0CURA] + STR r4,[r3,#IOMD_SD0ENDA] + LDR r2,[r3,#IOMD_SD0ST] + ORR r4,r4,#IOMD_DMA_S_Bit + STR r0,[r3,#IOMD_SD0CURB] + STR r4,[r3,#IOMD_SD0ENDB] + | + MOV_fiq r0, r11_fiq + ORR r0, r0, #MEMC_Son + STR r0, [r0] ; enable the MEMC1a DMA + ] + + ; set long timeout, clear the IL1, T0 and T1 bits + + LDR r2, =VIDC_SOUNDWAIT ; lastditch timeout loop + LDR r0, =(timer0_bit :OR: timer1_bit) + STRB r0, [r3,#IOCIRQCLRA] + + + ; Wait until sound DMA completes (or up to about 100 mS), + ; then check timers. + +10 + [ MEMC_Type = "IOMD" + LDRB r0,[r3, #IOMD_SD0ST] + AND r0, r0, #(IOMD_DMA_O_Bit :OR: IOMD_DMA_I_Bit) + CMPS r0, #(IOMD_DMA_O_Bit :OR: IOMD_DMA_I_Bit) + BEQ %12 + | + LDRB r0, [r3,#IOCIRQSTAB] + ANDS r0, r0, #sound_IRQ_bit + BNE %12 + ] + LDR r0, [r3, #IOCIRQSTAA] + ANDS r0, r0,#timer1_bit ; timeout if timer 1 expires + BNE %11 + + SUBS r2, r2, #1 ; or counter reaches zero + BNE %10 + +11 ORRS r0, r0, #1 ; Failed : clear 0 flag + MOV r2, #0 ; return a timeout value of 0 + B %15 ; ... and quit + + ; finished in reasonable time : check time remaining in t1 + ; Time for DMA should be 10.24ms (1024 bytes at 10us/byte) + ; less up to the time to use the final 16-byte transfer, 160us. + +12 STRB r0, [r3, #Timer1LR] ; latch the current count + LDRB r2, [r3, #Timer1CL] + LDRB r0, [r3, #Timer1CH] + ADD r2, r2, r0, LSL #8 + + SUB r2, r1, r2 + MOV r2, r2, LSR #1 ; Sound DMA time in uS + + LDR r1, =10030 ; inside limits ? + SUBS r0, r2, r1 + BLE %F13 + + LDR r1, =260 ; 10.03 -> 10.29 mS + CMPS r0, r1 + MOVLT r1,#0 ; inside limits : set Z flag + +13 ORRS r1,r1,r1 + + ; return with zero flag set if time (in r2) was within limits + +15 + [ MEMC_Type = "IOMD" + MOV r0, #IOMD_DMA_C_Bit + STR r0, [r3,#IOMD_SD0CR] + | + BIC r0, r0, #MEMC_Son + STR r0, [r0] + ] + MOV r0, r2 ; return the long time value + MOV pc, r14 + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; Data tables: VIDC := mode 0, all palette black + +TestVIDCTAB + + [ VIDC_Type = "VIDC1a" + + & &00000000 + & &04000000 + & &08000000 + & &0C000000 + & &10000000 + & &14000000 + & &18000000 + & &1C000000 + & &20000000 + & &24000000 + & &28000000 + & &2C000000 + & &30000000 + & &34000000 + & &38000000 + & &3C000000 + & &40000000 ; Border -> black + & &44000000 ; Cursor -> black + & &48000000 + & &4C000000 ; Palette programmed (avoid messy screen on reset) +; +; standard mode 0 setup (except display area disabled) +; + + & &807FC000 + & &8408C000 + & &881B0000 + & &8C1EC000 ; HDSR + & &906EC000 ; HDER + & &94770000 + & &9C400000 + & &A04DC000 + & &A4008000 + & &A8050000 ; VBSR + & &AC098000 ; VDSR + & &B0000000 ; VDER < VDSR to disable screen DMA B0000000 + & &B44DC000 ; VBER + & &E00000B2 +; +; Additional setup : cursor blanked, sound frequency test bit set +; + & &C0000100 ; SFR NB. TEST BIT! - also DFlynn requested value + & &98258000 ; HCSR + & &B8004000 ; VCSR + & &BC400000 ; VCER +; don't mess with the stereo image registers: sound code will set them. + & &FFFFFFFF ; That's the lot + +; +; Further registers to turn screen DMA on again (border all over) +; Must have a video start register before video end register to get +; a vertical flyback interrupt. +; + & &B0494000 ; VDER > VDSR to enable screen DMA + & &FFFFFFFF + ] + + [ VIDC_Type = "VIDC20" + +; This differs from the default RISC OS VIDCTAB in running from +; the 24MHZ video ref clock. H register contents are increased by 50%. + +; Program Control Register first, to clear power-down bit + + & &E0000402 ; CR: FIFO load 16 words, 1 bpp, ck/1, rclk + & &E0000402 ; + & &B1000001 ; SCR: sound disabled (+use 24MHz clock) + +; Don't bother programming all 256 palette entries, we'll be here all night +; Since we're setting up a 1 bit-per-pixel mode, just do colours 0 and 1 + + & &10000000 ; Palette address register = 0 + & &00000000 ; Colour 0 = black + & &00000000 ; Colour 1 = black + & &407f7f7f ; Border colour = grey + & &50000000 ; Pointer colour 1 = black + & &60000000 ; Pointer colour 2 = black + & &70000000 ; Pointer colour 3 = black + +; Get a stable display up so we get stable signals + + & &800005F8 ; HCR = 114 + 132 + 144 + 960 + 144 + 42 + & &8100006A ; HSWR = 114 + & &820000EA ; HBSR = 114 + 132 + & &83000174 ; HDSR = 114 + 132 + 144 + & &84000534 ; HDER = 114 + 132 + 144 + 960 + & &850005CA ; HBER = 114 + 132 + 144 + 960 + 144 + & &860000F3 ; HCSR = HDSR + + & &90000137 ; VCR = 3 + 19 + 16 + 256 + 16 + 2 + & &91000002 ; VSWR = 3 + & &92000015 ; VBSR = 3 + 19 + & &93000025 ; VDSR = 3 + 19 + 16 + & &94000024 ; VDER = VDSR -1 to disable sceeen DMA + & &95000135 ; VBER = 3 + 19 + 16 + 256 + 16 + & &96000025 ; VCSR = VDSR + & &97000025 ; VCER = VDSR + + & &C00F1003 ; EREG = comp sync, DACs on, ereg output ext lut + & &D000C385 ; FSYNREG, clk = (3+1)/(5+1) * 24MHz = 16MHz + & &F0013000 ; DCR: bus D[31:0], Hdisc + & &FFFFFFFF + + & &94000125 ; VDER > VDSR to enable screen DMA + & &FFFFFFFF + ; FSIZE is one less than number of rasters in Vflyback + & &00000037 ; (3 + 19 + 16 + 0 + 16 + 2) - 1 + + ; Alternate settings for VGA monitor + +TestVVIDCTAB + & &E0000402 ; CR: FIFO load 16 words, 1 bpp, ck/1, rclk + & &E0000402 ; + & &B1000001 ; SCR: sound disabled (+use 24MHz clock) + + & &10000000 ; Palette address register = 0 + & &00000000 ; Colour 0 = black + & &00000000 ; Colour 1 = black + & &407f7f7f ; Border colour = grey + & &50000000 ; Pointer colour 1 = black + & &60000000 ; Pointer colour 2 = black + & &70000000 ; Pointer colour 3 = black + + & &80000310 ; HCR = 92 + 45 + 0 + 640 + 0 + 16 + & &81000054 ; HSWR = 92 + & &82000080 ; HBSR = 92 + 45 + & &83000080 ; HDSR = 92 + 45 + 0 + & &84000300 ; HDER = 92 + 45 + 0 + 640 + & &85000300 ; HBER = 92 + 45 + 0 + 640 + 0 + & &86000080 ; HCSR = HDSR + + & &9000020B ; VCR = 2 + 32 + 0 + 480 + 0 + 11 + & &91000001 ; VSWR = 2 + & &92000021 ; VBSR = 2 + 32 + & &93000021 ; VDSR = 2 + 32 + 0 + & &94000020 ; VDER = VDSR -1 to disable sceeen DMA + & &95000201 ; VBER = 2 + 32 + 0 + 480 + 0 + & &96000021 ; VCSR = VDSR + & &97000021 ; VCER = VDSR + + & &C0051003 ; EREG = sep/inv sync, DACs on, ereg output ext lut + & &F0013000 ; DCR: bus D[31:0], Hdisc + & &FFFFFFFF + + ] + + END + + + diff --git a/Resources/UK/Messages b/Resources/UK/Messages new file mode 100644 index 0000000000000000000000000000000000000000..d72a9dd57c9b4cbe93a0aefa4e234f1189502f5b Binary files /dev/null and b/Resources/UK/Messages differ diff --git a/TestSrc/A600tlb b/TestSrc/A600tlb new file mode 100644 index 0000000000000000000000000000000000000000..6481c8b3ae56a34333abc2a617bc3efe58a6a586 --- /dev/null +++ b/TestSrc/A600tlb @@ -0,0 +1,61 @@ +; +; A600tlb +; +; POST procedure for checking the TLB in A600 MMU. +; +; for each of level 1, level 2 small-page, level 2 large-page +; construct page table +; flush cache +; start timer +; for 32 addresses (with different mappings) +; check address mapping +; save timer +; for same 32 addresses +; check address mapping +; compare test times (did 2nd test require table walk ?) + + + + + +Use a list of addresses that cover a good mixture of virtual addresses +Build a page table that maps these to physical RAM addresses in various ways +Access the addresses in such an order that the cache rotates, scrapping +one entry each time through the list, and loading another. So each cache +entry gets used 31 times, then is lost. +Choice of physical mapping should ensure that the cache entries contain +lots of different values of page and section base addresses. +Choice of virtual test address should ensure that cache tag varies as +widely as posible, too. PRBS ? +Very widely varying values of cache tag require that a large number +of mappings exist .. if these are 2-level mappings, that requires +a lot of RAM. Page tables should be multiply-mapped. +RISC OS puts lots of stuff below the 4M mark. Limits App space to 16M +for backwards compatibility. Probably worth testing outside these +limits to ensure Gold doesn't fall over, but failure rates would be +very low. + + + + +; +; POST procedure for checking access faults (was PPL test) +; +; for each of level 1, level 2 small-page, level 2 large-page +; construct page table +; for user, supervisor mode +; check address alignment fault +; check section translation fault +; check +; check page translation fault +; for 3 domain types +; for 16 domains +; check access permissions +; + + + +; +; POST procedure for checking IDC +; +; diff --git a/TestSrc/Arm3 b/TestSrc/Arm3 new file mode 100644 index 0000000000000000000000000000000000000000..a385f75f4cbbd089f79c6ac394810fa1b4dd0109 --- /dev/null +++ b/TestSrc/Arm3 @@ -0,0 +1,71 @@ +; > TestSrc.ARM3 + + TTL RISC OS 2+ POST ARM version determination +; +; Reads ARM3 version register, returns 0 if ARM 2 fitted. +; +;------------------------------------------------------------------------ +; History +; +; Date Name Comment +; ---- ---- ------- +; 20-Apr-89 ArtG Initial version +; +; +;------------------------------------------------------------------------ + +A3Cid CN 0 +A3Cfls CN 1 +A3Cmod CN 2 +A3Ccac CN 3 +A3Cupd CN 4 +A3Cdis CN 5 + +A3CON CP 15 + + + +ts_ARM_type + MOV r13,lr +; +; First, set up an undefined instruction vector to catch an ARM 2 +; (or a faulty ARM 3 ??) when the copro instruction is run. +; Only applies on systems where ROM isn't mapped at zero. + + [ CPU_Type = "ARM2" :LOR: CPU_Type = "ARM3" + MOV r0,#0 ; set a page at logical 0 + MOV r1,r0 + BL ts_set_cam + ADR r0,ts_ARM_undefined + LDMIA r0,{r2,r3} + MOV r1,#4 + STMIA r1,{r2,r3} ; set the undefined instruction trap + ] +; +; Read ARM3C0 version I.D. +; + MOV r0, #(-1) ; should always be altered + MRC A3CON,0,r0,A3Cid,A3Cid ; Read control register 0 + MOV r12, r0 + [ CPU_Type = "ARM2" :LOR: CPU_Type = "ARM3" + MOV r1,#0 + BL ts_set_cam_idle ; remove the vector page again + ] + MOVS r0, r12 ; return the ID (0 for ARM 2) + MOV pc,r13 + +; +; Trap to be taken when ARM 2 is fitted +; + +ts_ARM_undefined + MOV r0,#0 + MOVS pc,r14_svc +10 + ASSERT ((%10 - ts_ARM_undefined) / 4 = 2) + + + + + END + diff --git a/TestSrc/Begin b/TestSrc/Begin new file mode 100644 index 0000000000000000000000000000000000000000..4cc4f5bfc32c9b56c5e7b05ed5577b25ab88dc33 --- /dev/null +++ b/TestSrc/Begin @@ -0,0 +1,1490 @@ +; > TestSrc.Begin + + TTL RISC OS 2+ Power-On Self-Test +; +; Startup code for RISC OS ROM Self-Test. +; +; Performs ROM test patterns, determines test strategy and enters +; external or internal test code. +; +; A minimal set of opcodes should be used (ideally, only B, LDR and ADDS) +; so that a processor test may be validly included in the internal test +; sequence. +; +;------------------------------------------------------------------------ +; History +; +; Date Name Rel Comment +; ---- ---- --- ------- +; 23-Feb-93 ArtG 2.00 Experimental ARM 600 / Jordan mods +; 20-Oct-93 ARTG 2.02 Changed to new conditional assembly scheme +; 18-Nov-94 RCM 2.05 Morris changes +; +;------------------------------------------------------------------------ + +; TS_STATUS should be one of : +; +; 'R' RISC OS POST +; 'S' Standalone version (with a2 memory test instead of RISCOS) +; 'T' Test build - development only +; + +TS_STATUS * "R" ; Medusa POST version 2.0x +; +TS_RELEASE * 20 +TS_CHANGES * 5 + + + GBLL POSTenabled +POSTenabled SETL {TRUE} ; don't permit POST for ordinary startup + +ts_Rom_bits * 21 ; Widest ROM address +ts_Rom_length * 1 :SHL: ts_Rom_bits ; Longest ROM +ts_highaddr_bit * 1 :SHL: 25 ; ARM address width +ts_Alias_bits * (1 :SHL: 23) ; I/F output bits +ts_recover_time * (1 :SHL: 8) ; inter-twiddle delay +ts_pause_time * 200 ; Display pause time +ts_S5_base * &3350000 ; IO register base address +ts_IOEB_ID * (ts_S5_base + &50) ; IOE_B ASIC identification +ts_IOEB_ident * &5 ; the value found there +ts_PCaddress * &3010000 ; PC IO world base address +ts_ReadyByte_00 * &90 ; signal 'Here I am' to ExtIO +ts_BBRAM * &A0 ; IIC address of clock/ram chip +ts_RamChunk * &2000 ; gap between data line tests +ts_MaxRamTest * 4*1024*1024 ; Max. DRAM tested on normal reset +ts_VIDCPhys * &3400000 ; Real location of VIDC + +; +; Border colours used for self-test indicators +; + [ VIDC_Type = "VIDC1a" +C_ARMOK * &40000000+&70C ; testing ROM +C_RAMTEST * &40000000+&C70 ; testing RAM +C_FAULT * &40000000+&00F ; failed tests +C_PASSED * &40000000+&7C0 ; all passed +C_WARMSTART * &40000000+&777 ; not tested + ] + + [ VIDC_Type = "VIDC20" +C_ARMOK * &40000000+&7000C0 ; testing ROM +C_RAMTEST * &40000000+&C07000 ; testing RAM +C_FAULT * &40000000+&0000F0 ; failed tests +C_PASSED * &40000000+&70C000 ; all passed +C_WARMSTART * &40000000+&707070 ; not tested + ] + +; +; Responses to external commands +; + +ErrorCmd * &00FF + + +; +; Control bitmasks used to indicate results of test to RISCOS +; + +R_SOFT * 0 ; not a power-on reset +R_HARD * 1 ; Self-test run due to POR +R_EXTERN * 2 ; external tests performed +R_TESTED * 4 ; Self-test run due to test link +R_MEMORY * 8 ; Memory has been tested +R_ARM3 * &10 ; ARM 3 fitted +R_MEMSKIP * &20 ; long memory test disabled +R_IOEB * &40 ; PC-style IO controller +R_VRAM * &80 ; VRAM present + +R_STATUS * &1ff ; bits that aren't a fault + +R_CHKFAILBIT * &100 ; CMOS contents failed checksum +R_ROMFAILBIT * &200 ; ROM failed checksum +R_CAMFAILBIT * &400 ; CAM failed +R_PROFAILBIT * &800 ; MEMC protection failed +R_IOCFAILBIT * &1000 ; IOC register test failed +R_INTFAILBIT * &2000 ; Cannot clear interrupts +R_VIDFAILBIT * &4000 ; VIDC flyback failure +R_SNDFAILBIT * &8000 ; Sound DMA failure +R_CMSFAILBIT * &10000 ; CMOS unreadable +R_LINFAILBIT * &20000 ; Page zero RAM failure +R_MEMFAILBIT * &40000 ; Main RAM test failure +R_CACFAILBIT * &80000 ; ARM 3 Cache test failure +; + [ MorrisSupport +Kludge * 96 + | +Kludge * 0 + ] + SUBT Exception vectors +; +; These vectors are available for use while the Rom is mapped into +; low memory addresses. The Reset vector will be copied to low RAM +; as part of a software reset sequence : therefore it must perform +; a fixed operation to ensure compatibility with future versions +; of RISC-OS. +; + +Reset +ts_start + $DoMorrisROMHeader + + [ :LNOT: MorrisSupport + [ ResetIndirected + LDR pc,.+ResetIndirection ; load pc from vector at &118 + | + B ts_RomPatt + PhysROM ; Jump to normal ROM space + ] + ] +01 + & ts_Rom_length ; gets patched by ROM builder +02 + & (ts_ROM_cvectors - ROM) ; pointer to code vector table +03 + & (ts_ROM_dvectors - ROM) ; pointer to data vector table +04 + & (ts_ROM_bvectors - ROM) ; pointer to branch table + B Reset ; not currently used + B Reset + B Reset + + +ts_ROMSIZE * %BT01 - ts_start +ts_CVECTORS * %BT02 - ts_start +ts_DVECTORS * %BT03 - ts_start +ts_BVECTORS * %BT04 - ts_start + + ! 0, "ts_Rom_length held at ":CC::STR:(%BT01 - ROM) + + +; +; Selftest version ID +; + +00 + ASSERT %B00 <= (ts_start + &2c + Kludge) + % ((ts_start + &2c + Kludge) - %B00) + +ts_ID & ((TS_STATUS :SHL: 24) + (TS_RELEASE :SHL: 16) + TS_CHANGES) + +ts_ID_text +ts_himsg + = "SELFTEST" ; **DISPLAY_TEXT** + = &89 ; Cursor position + = TS_STATUS + = ("0" + (TS_RELEASE / 10)) + = "." + = ("0" + (TS_RELEASE :MOD: 10)) + = ("0" + (TS_CHANGES :MOD: 10)) + = 0 + + +; +; These vector tables permit access by the external (or downloaded) test +; software to data and code in the POST modules. +; Find the start of these tables through the 2nd and 3rd vectors at +; the start of the ROM. +; + +ts_ROM_dvectors +01 + & ts_ID ; Selftest identification number +02 + & (ts_ID_text - ROM) ; Selftest identification text + + +; +; vectors ORd with these flags to assure proper mode when +; executed by host thro' vector table. +; + +ts_runflags * (I_bit :OR: F_bit :OR: SVC_mode) + +ts_ROM_cvectors + & ts_RomPatt :OR: ts_runflags + & ts_User_startup :OR: ts_runflags + & ts_Self_test_startup :OR: ts_runflags + & ts_Dealer_startup :OR: ts_runflags + & ts_Forced_startup :OR: ts_runflags + & ts_GetCommand :OR: ts_runflags + & ts_Softstart :OR: ts_runflags + & ts_Hardstart :OR: ts_runflags + + +; +; ROM branch vectors - intended primarily so downloaded programs +; may use standard subroutines. This table should be in a fixed place. +; + +00 + ASSERT %B00 <= (ts_start + 128 + Kludge) + % ((ts_start + 128 + Kludge) - %B00) + +ts_ROM_bvectors + B ts_RomPatt + B ts_GetCommand + B ts_SendByte + B ts_SendWord + B ts_GetByte + B ts_GetWord + B ts_SendText + B ts_MoreText + B ts_SendLCDCmd + + +; +; Pad out until the location of the ResetIndirection vector +; + + ASSERT .-ROM <= ResetIndirection + % ResetIndirection-(.-ROM) + & ts_RomPatt-ROM+PhysROM + +; +; ROM test code +; +; Note : the register order in ADDS ...pc.. is often critical. +; If we want to adjust pc, use ADDS pc,rn,pc so that the PSR is +; rewritten with it's original value. +; If we want to do some pc-relative arithmetic, use ADDS rn,pc,rn +; so that the bits from PSR are NOT used in the address calculation. +; + + SUBT Macros + + MACRO + MODE $mode_bits + TEQP psr,#($mode_bits :OR: I_bit :OR: F_bit) + NOP + MEND + + MACRO + MOV_fiq $dest,$src + MODE FIQ_mode + MOV $dest,$src + MODE SVC_mode + MEND + + MACRO + FAULT $code + MODE FIQ_mode + ORR r12_fiq,r12_fiq,$code + MODE SVC_mode + MEND + + MACRO + M32_fiq $dest,$src,$tmp1,$tmp2 + SetMode FIQ32_mode,$tmp1,$tmp2 + MOV $dest,$src + msr AL,CPSR_all,$tmp2 + MEND + + MACRO + FAULT32 $code,$tmp + SetMode FIQ32_mode,$tmp + ORR r12_fiq,r12_fiq,$code + SetMode SVC32_mode,$tmp + MEND + +; +; Define an area of storage with the required set of data bus patterns +; These are used both for testing the complete width of the data bus +; during ROM pattern testing, and will provide a tidy set of patterns +; if the reset is held, while the ARM increments addresses. +; + + SUBT ROM Address and Data Patterns + +DataPatterns + + GBLA dmask +dmask SETA &80000000 + + DCD &FFFFFFFF ; first two : all set + DCD &0 ; all clear + + GBLA OldOpt ; don't list all the walking +OldOpt SETA {OPT} ; patterns + OPT OptNoList + + WHILE dmask > 0 ; then for each bit + DCD &$dmask ; set it + DCD :NOT: &$dmask ; and clear it +dmask SETA dmask :SHR: 1 + WEND + OPT OldOpt +DEnd + + + OPT OptList +; +; +; Read the ROM at a series of addresses +; such that : a) all the address lines are exercised individually +; b) all the data lines are exercised individually +; +; Data and address lines are exercised as walking-0 and walking-1. +; The test is performed as a series of LDR operations to avoid using +; a larger instruction set. +; + +ts_RomPatt ROUT + + ; Patterns which will exercise most of the data bus. + ; All are arbitrary instructions with NV execution + + DCD &F0000000 ; walking 1 + +OldOpt SETA {OPT} ; patterns + OPT OptNoList + +dmask SETA &08000000 + WHILE dmask > 0 + DCD dmask :OR: &F0000000 +dmask SETA dmask :SHR: 1 + WEND + + DCD &FFFFFFFF ; walking 0 + +dmask SETA &08000000 + WHILE dmask > 0 + DCD (:NOT: dmask) :OR: &F0000000 +dmask SETA dmask :SHR: 1 + WEND + + OPT OldOpt + + ; Now some proper code : + ; Initialise address pointer and make MemC safe + + LDR r0,%01 + ADD pc,r0,pc +01 + & 0 ; useful constant + + [ IO_Type = "IOC-A1" ;;!! unsafe if we execute ROM at zero + LDR r1,%02 + ADD pc,r0,pc +02 ;;!! This remaps MEMC's ROM + & &E000C :OR: MEMCADR ;;!! addressing if it hasn't + STR r1,[r1] ;;!! already happened. + ] + + LDR r5,%03 ; Load r5 with a constant which + ADD pc,r0,pc ; may be added to ROM plus a +03 ; walking-zero bitmask to create + & ts_Rom_length - 3 ; a valid word address in ROM. + LDR r2,%04 ; Offset from ROM start to here + ADD pc,r0,pc +04 + & ROM - pcfromstart + + ADD r2,pc,r2 ; pointer to start of ROM + ADD r3,r2,r0 ; pointer to start of ROM +pcfromstart + ADD r4,r2,r0 ; pointer to start of ROM + + ; assembly-time loop - only 32 iterations required + +OldOpt SETA {OPT} + + GBLA doffset +doffset SETA DataPatterns + WHILE doffset < DEnd + + LDR r0,doffset ; walking 1 data pattern + LDR r1,doffset+4 ; walking 0 data pattern + LDR r6,[r2] ; walking 1 address pattern + LDR r6,[r3] ; walking 0 address pattern + + [ (doffset - DataPatterns) > ((32 - ts_Rom_bits) * 8) + [ (doffset - DataPatterns) < (31 * 8) + ADD r2,r4,r0 ; r2 = ROM + walking 1 pattern + ADD r3,r4,r1 ; r3 = ROM + walking 0 pattern + ADD r3,r3,r5 ; adjust to a valid address + ] + ] + + OPT OptNoList + +doffset SETA doffset + 8 + WEND + + ASSERT (. - doffset < 4095) ; in range without barrel shift ? + + OPT OldOpt + + +; +; External interface drivers - +; provides entry points to send byte- and word- and string-sized objects +; and to receive byte- and word-sized objects +; +; Continue into GetCommand, which determines adapter type (or no adapter) +; and jumps to an ExtCmd handler, ts_User_startup, ts_Forced_startup or +; ts_Dealer_startup as appropriate. +; + B ts_GetCommand + + GET TestSrc.ExtIO + +; +; External command handlers - respond to commands given through the +; external test interface. +; + + GET TestSrc.ExtCmd + + + SUBT Selftest +; +; There is no attached test interface. Is this a power-on reset ? +; Addressing IOC will make MEMC1a remap the ROM to high memory if +; it hasn't already done it, so be careful to ensure that the +; ARM is addressing normally-addressed ROM when this code runs. +; + +ts_User_startup ROUT + LDR r0,%01 + ADD pc,r0,pc +01 + & 0 +; +; IOMD will only access the ROM until a write to IOMD has been made - +; make this write also switch on refresh so the DRAM has a chance to +; get running before the memory test starts. +; + [ MEMC_Type = "IOMD" + LDR r1,%02 + ADD pc,r0,pc +02 + & (IOMD_Base+IOMD_VREFCR) + LDR r2,%03 + ADD pc,r0,pc +03 + & IOMD_VREFCR_REF_16 + STR r2, [r1,#0] + ] + + [ POSTenabled + LDR r1,%12 ; load address of IOC IRQ register + ADD pc,r0,pc +12 + & IOC+IOCIRQSTAA + + LDR r1, [r1,#0] ; Get IRQSTAA register (hence POR bit) + LDR r2, %13 + ADD pc,r0,pc ; Constant to shift por to bit 31 +13 + & por_bit :SHL: 1 +14 ADD r1,r1,r1 + ADDS r2,r2,r2 + BCC %14 ; loop until por_bit is at bit 31 + ADDS r1,r1,r1 ; then shift it into carry + BCC ts_Self_test_end ; POR bit clear - do soft reset. + +; it's a power-on reset, so assume we can't be in 32-bit mode + + MOV_fiq r12_fiq, #R_HARD + B ts_Self_test_startup + | + B CONT ; if user POST disabled + ] +; +; Perform self - tests +; +; Any distinction between test operation for Power-up, Display-only +; and Forced tests needs to be made between these three entry points. +; + + +; This is where tests start if a dumb test link is fitted +; (a diode from A21 to *ROMCS, disabling the ROMs when A21 is high) + +ts_Forced_startup ROUT + + MOV_fiq r12_fiq, #R_TESTED + B ts_Self_test_startup + +; This is where the tests start if an external display adapter is fitted + +ts_Dealer_startup ROUT + + MOV_fiq r12_fiq, #R_EXTERN + + LDR r4,%FT02 ; make a pointer to signon string +01 ADD r4,pc,r4 + ADD pc,r0,pc +02 + & (ts_himsg - %BT01 - 8) + + ADD r14,pc,r0 ; make a return address for this 'call' + ASSERT (.+4 = ts_Self_test_startup) ; PC must point there already ! + B ts_SendText + +ts_Self_test_startup ROUT + +; This is where the power-on test starts (every user gets this) + + +; +; Processor test would go here .... if there was one. +; + + [ MorrisSupport +; +; On startup Morris defaults to dividing all its clocks by two and +; accessing ROM at the slowest possible access speed. So check for +; Morris and set to sensible values. +; + MOV r2, #IOMD_Base + + LDRB r0, [r2, #IOMD_ID0] + CMP r0, #&98 + LDRB r0, [r2, #IOMD_ID1] + CMPEQ r0, #&5B + BNE %FT10 + +; +; PSwindell wants all prescalers set to divide by 1 +; + MOV r0, #IOMD_CLKCTL_CpuclkNormal + IOMD_CLKCTL_MemclkNormal + IOMD_CLKCTL_IOclkNormal + STRB r0, [r2, #IOMD_CLKCTL] ; initialise all prescalers to div1 +; +; Set ROM speed, take care to preserve 16-bit mode bit... +; +; According to RJKing on 6/5/94, Kryten will use burst mode roms: use 93nS burst, 156nS initial. +; +; We assume that the extension ROMs are the same access time and width as the main OS ROMS. +; + LDRB r0, [r2, #IOMD_ROMCR0] + AND r0, r0, #&40 ; clear all but 16-bit mode bit + [ NormalSpeedROMS + ;Normal code + ORR r0, r0, #IOMD_ROMCR_Normal + IOMD_ROMCR_156 + IOMD_ROMCR_Burst93 + ; initialise ROM speed to 156.25nS, 93.75nS burst + ; the fast EPROMS used for Kryten testing should be able to cope even though they aren't + ; burst devices + | + ;Slow ROM access for PSwindells test EPROMS. Paul requested 156nS (or slower), burst off. + ORR r0, r0, #IOMD_ROMCR_Normal + IOMD_ROMCR_187 + IOMD_ROMCR_BurstOff + + ! 0, "*** WARNING *** Slow ROM version ment for PSwindell" + ] + STRB r0, [r2, #IOMD_ROMCR0] + STRB r0, [r2, #IOMD_ROMCR1] ; and do the same for extension ROMs (just in case) +; +10 + ] +; +; From this point on we assume we can safely use all the processor +; +; Initialise VIDC : Sync mode 0, border covers screen +; + +ts_InitVIDC + [ IO_Type = "IOMD" ; If POSTbox fitted, ROM may still be mapped everywhere + MOV r2,#IOMD_Base + MOV r0, #IOMD_VREFCR_REF_16 ; switch on DRAM refresh + STR r0, [r2, #IOMD_VREFCR] + + ; choose monitor settings from ID bit 0 + MOV r1,#ts_VIDCPhys + ADRL r2,TestVIDCTAB + LDR r0,=IOMD_MonitorType + LDR r0,[r0] + ANDS r0,r0,#IOMD_MonitorIDMask + ADDEQ r2,r2,#(TestVVIDCTAB-TestVIDCTAB) + + | ; not IOMD + MOV r1,#ts_VIDCPhys + ADRL r2,TestVIDCTAB + ] + +10 LDR r0, [r2],#4 + CMP r0, #-1 + STRNE r0, [r1] + BNE %BT10 + + LDR r0,=C_ARMOK ; set initial screen colour + STR r0, [r1] + + B ts_RomTest + + + LTORG + ROUT + +; +; Calculate ROM checksum : display status and calculated checksum. +; + +1 + = "ROM :",0 +2 + = "ROM bad",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +3 + = "ROM size",&8A,&ff,&ff,&ff,&ff,&ff,&ff,0 + ALIGN + +ts_RomTest + ADR r4,%BT1 + BL ts_SendText + + BL ts_ROM_checksum + BEQ %20 + ADR r4,%BT2 ; Failed message + FAULT #R_ROMFAILBIT ; set ROM bit in r12_fiq + MOV r8,r0 ; calculated checksum + BL ts_SendText + + BL ts_ROM_alias ; Checksum failed :- + ADR r4,%BT3 ; hunt for first alias + MOV r8,r0, LSL #8 + BL ts_SendText ; and report it. +20 + + [ IO_Type = "IOC-A1" ; Don't use RISC OS MemSize + ; until much later - it sets up + ; the ARM600 MMU as well. + B ts_MEMCset + +; +; Do MEMC setup and memory size determination (the first time). +; + LTORG + ROUT + +1 + = "M Size :",0 +2 + = "M Size",&89,&ff,&ff,&ff,&ff,".",&ff,&ff,0 + ALIGN + +ts_MEMCset + MOV r12,#0 + ADR r4,%BT1 + BL ts_SendText + LDR r1,=(&E000C :OR: MEMCADR) ; MemSize expects 32k page + STR r1,[r1] + BL MemSize + +; +; MemSize returns with r0 = page size (now in bytes, *NOT* in MEMC control patterns), +; r1 = memory size (in bytes) +; r2 = MEMC control value +; +; Translate these into a number that looks like : +; +; mmmm.pp +; +; where mmmm is memory size in hex Kbytes, pp is page size in hex Kbytes. +; + MODE FIQ_mode ; Save memory size and + MOV r11_fiq,r2 ; MEMC setup value for + MOV r10_fiq,r1 ; later use + MODE SVC_mode + + MOV r8, r0, LSR #2 ; MemSize now returns actual page size in r0 + ADD r8,r8,r1,LSL #6 + ADR r4,%BT2 + BL ts_SendText + + ] + +; +; Test data, address and byte strobe lines. +; On MEMC systems, this calls MemSize and tests the memory that finds. +; On IOMD systems, memory sizing is performed along with the data line +; tests, and that result is used for address line testing. +; + + B ts_LineTest + + GBLS tsGetMem1 +tsGetMem1 SETS "GET TestSrc.Mem1" :CC: MEMC_Type + $tsGetMem1 + +; +; Test IOC. +; This shuld require vector space to work (for testing interrupts), +; but the current version just reports the status register contents. +; +; Display is ccaabbff +; +; where cc is the control register +; aa is IRQ status register A +; bb is IRQ status register B +; ff is FIQ status register +; + + B ts_IOCTest + + LTORG + ROUT + + [ IO_Type = "IOMD" +1 + = "IOMD :",0 +2 + = "IOMD-F",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +3 + = "IOMD-V" +4 + = &88,&ff,&ff,&ff,&ff," V.",&ff,0 + | +1 + = "IOC :",0 +2 + = "IOC-F",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +3 + = "IOC" +4 + = &88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 + ] + ALIGN + +ts_IOCTest + ADR r4,%BT1 + BL ts_SendText + BL ts_IOCreg ; check register integrity + BEQ %FT8 + ADR r4,%BT2 + BL ts_SendText ; report if failure + + FAULT #R_IOCFAILBIT +8 + ADR r4,%BT1 + BL ts_SendText + BL ts_IOCstat + BEQ %FT10 ; fail message only printed if + ADR r4,%BT3 ; ID code unrecognised + BL ts_SendText + FAULT #R_IOCFAILBIT ; .. and set error bit if IOMD code is wrong + B %FT11 +10 + ADR r4,%BT4 ; print the status value + BL ts_MoreText +11 + + [ IO_Type = "IOMD" + B ts_CMOStest + | + B ts_IOEBtest + ] + + LTORG + ROUT + +; +; Check for presence of IOEB ASIC +; + + [ IO_Type = "IOEB" + +1 + = "IOEB :",0 +2 + = "IOEB",&88,"exists",0 + + + ALIGN + +ts_IOEBtest + ADR r4,%BT1 + BL ts_SendText + + LDR r0,=ts_IOEB_ID ; read an ID register in the IOEB ASIC + LDRB r0, [r0] + AND r0, r0, #&f + CMPS r0, #ts_IOEB_ident ; if it looks right ( == 5) .. + BNE %10 + + FAULT #R_IOEB ; set that bit in the result word + ADR r4, %BT2 + BL ts_SendText +10 B ts_CMOStest + ] ; IOEB IO world +; +; Read CMOS +; Check the checksum, read the memory test flag. +; + +1 + = "SRAM :",0 +2 + = "SRAM-F",0 +3 + = "SRAM-C",&8e,&ff,&ff,0 + ALIGN + +ts_CMOStest + ADR r4,%BT1 + BL ts_SendText + + [ ChecksumCMOS + + LDR r0,=(ts_BBRAM + &4000) + MOV r1,#&C0 ; Get first RAM area + MOV r2,#CMOSxseed + BL ts_CMOSread + BNE %20 + MOV r2, r0 + LDR r0,=(ts_BBRAM + &1000) ; Accumulate the second RAM area + MOV r1,#&2F + BL ts_CMOSread + BNE %20 + RSB r2, r0, #0 ; Subtract from the checksum byte + LDR r0,=(ts_BBRAM + &3F00) + MOV r1,#1 + BL ts_CMOSread + BNE %20 + MOV r8, r0, LSL #24 + ANDS r0, r0, #&FF ; A zero result ? + MOV r1, #R_CHKFAILBIT + ADR r4,%BT3 ; Report checksum failure + BNE %21 ; failed .. report error + ] ; end ChecksumCMOS + + LDR r0,=(ts_BBRAM + &FC00) ; Read Misc1CMOS byte + MOV r1,#1 + MOV r2,#0 + BL ts_CMOSread + BNE %20 + ANDS r0,r0,#&80 ; Test the memory-test-disable bit + BEQ %25 + FAULT #R_MEMSKIP ; If set, skip the memory test + B %25 + +20 + MOV r1,#R_CMSFAILBIT ; Real fault - set the fault bit + ADR r4,%BT2 ; Report fault accessing IIC + ; (Bitmap & POST display) +21 + FAULT r1 + BL ts_SendText ; Report one fault or another +25 + B ts_IOinit + + LTORG + ROUT +; +; Initialize various machine registers - e.g, turn off the floppy +; drive, etc, etc. +; + +1 + = "IOinit:",0 + ALIGN + +ts_IOinit + ADR r4,%BT1 + BL ts_SendText + ADRL r2,ts_IOinitab +10 + LDR r0,[r2],#4 ; Get address + LDR r1,[r2],#4 ; Get initialization data + CMPS r0,#(-1) + STRNE r1,[r0] ; write to IO port + BNE %10 + B Speedset +; +; Use the RISC OS MEMC setup code to guess the proper processor / memory +; configuration. The memory speed can then be set up correctly for +; fastest possible working, and the memory array tested in the +; configuration RISC OS expects. +; +; Display the results of the TimeCPU test as : +; +; ssss.m.r +; +; where ssss is the processor speed in hex kHz, +; m is 0 for MEMC, 1 for MEMC1a +; r is the MEMC rom speed switch setting. +; + ROUT + +1 + = "Speed :",0 +2 + = "Speed",&88,&ff,&ff,&ff,&ff,".",&ff,".",&ff,0 + + ALIGN + +Speedset + ADR r4,%BT1 + BL ts_SendText + + [ MEMC_Type = "IOMD" + MOV r9,#0 + | + MOV_fiq r0, r11_fiq ; get MEMC setup + MOV r9,r0 ; compare IOC and CPU clocks + ] + + BL TimeCPU + MOV r0,r9 + MOV_fiq r11_fiq,r0 + + MOV r8,r7,LSL #16 + TST r7, #1 :SHL: 16 ; test bit 16 of r7 : + ADDNE r8,r8,#&1000 ; MEMC1 / MEMC1a detected + AND r9,r9,#&C0 ; get High ROM access bits + ADD r8,r8,r9, LSL #2 + ADR r4,%BT2 + BL ts_SendText + B RAMtest + + +; +; Long RAM test, ideally exercising all memory. +; In order to keep boot time short, the following scheme is used : +; +; Normal power-on boot - test VRAM and up to 4M of first DRAM entry +; CMOS disable set - test nothing +; Test hardware fitted - test entire memory +; + + ROUT + + +1 + = "RAM :",0 +2 + = "RAM bad",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +3 + = &89,"skipped",0 +4 + = "RAM :",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 + + + ALIGN + +RAMtest + ADR r4,%BT1 + BL ts_SendText +; +; if (R_MEMSKIP && R_HARD) +; skip all the remaining tests +; if (!R_LINFAILBIT) +; perform the long memory test +; + MOV_fiq r0,r12_fiq ; skip this test if data line fault + AND r1,r0,#(R_MEMSKIP :OR: R_HARD) ; or the user didn't want it + TEQS r1,#(R_MEMSKIP :OR: R_HARD) + ANDNE r1,r1,#R_LINFAILBIT + TEQNE r1,#R_LINFAILBIT + BNE %12 + ADR r4,%BT3 ; skipping memory test .... + BL ts_MoreText + B ts_Report +12 + LDR r1,=C_RAMTEST ; doing at least part of the long memory test + LDR r0,=ts_VIDCPhys ; write the border colour + STR r1,[r0] + + BL MemSize ; Set MMU up, mapping (some) RAM at logical address 0 + ; Note that this returns with the MMU enabled, + ; the ROM remapped to it's ORGed address, + RSB r4,r4,#PhysROM ; and r4 the offset from physical to ORGed ROM addresses + ADD r4,r4,#PhysSpace + SetMode SVC32_mode,r0 ; Must do this, as PhysSpace is outside 26 bit addressing + ADD pc,pc,r4 ; Jump into the ROM at its image in PhysSpace + NOP ; this instruction skipped by pc adjustment + +; +; Modify the PhysRamTable so only VRAM and the first ts_MaxRamTest of DRAM gets tested +; + M32_fiq r0,r12_fiq,r1,r2 ; get the test condition flags + + ANDS r0,r0,#(R_EXTERN :OR: R_TESTED) + BNE %FT16 ; do full test if test adapter is present + MOV r9,#PhysRamTable + ADD r10,r9,#(PhysRamTableEnd-PhysRamTable) +14 + LDR r1,[r9, #4] + ADD r0,r0,r1 ; r0 = running sum of memory sizes + SUBS r2,r0,#ts_MaxRamTest ; r2 = excess over ts_MaxRamTest + SUBHI r1,r1,r2 ; r1 = current size truncated + STRHI r1,[r9, #4] + MOVHI r0,#ts_MaxRamTest ; truncate running sum to MaxRamTest + + ADD r9,r9,#(DRAMPhysAddrB-DRAMPhysAddrA) + CMPS r9,r10 + BNE %BT14 +16 + FAULT32 #R_MEMORY,r0 ; memory tests were attempted + + MOV r9,#VideoPhysAddr + LDR r8,[r9] ; report the test address + ADRL r4,%BT4 + BL ts_SendText + LDR r0,[r9] ; get VRAM start address and size + LDR r1,[r9,#4] + ADD r0,r0,#PhysSpace + BL ts_RamTest + BNE %FT20 ; failed - abort ram testing + +; +; VRAM (or 1st MB of DRAM, if no VRAM fitted) looks OK - move the translation +; table there so memory tests can proceed without smashing it. +; + MOV r9,#PhysRamTable + LDR r0,[r9,#VideoPhysAddr-PhysRamTable] ; get address of video RAM + LDR r1,[r9,#DRAMPhysAddrA-PhysRamTable] ; get address of 1st DRAM bank + LDR r3, =DRAMOffset_L2PT + ADD r1, r1, r3 ; make r1 -> L2PT + ADD r0, r0, r3 ; make r0 -> temporary L2PT + BL ts_remap_ttab ; copy ttab at r1 to r0 and change table base + +; +; Now run the RAM test at each DRAMPhysAddr until the end of the table or a zero entry +; is reached. Mark tested entries by setting the PhysSpace address, so a pointer to the +; next entry need not be kept. +; +18 + MOV r9,#DRAMPhysAddrA + ADD r10,r9,#(PhysRamTableEnd-DRAMPhysAddrA) +19 + CMPS r9,r10 ; reached end of table ? + LDRNE r0,[r9] + TSTNE r0,r0 ; reached unused entries ? + LDRNE r1,[r9,#4] ; or blanked-out entries ? + TSTNE r1,r1 + BEQ %FT21 ; .. all passed OK + TSTS r0,#PhysSpace + ADDNE r9,r9,#(DRAMPhysAddrB-DRAMPhysAddrA) + BNE %BT19 ; this entry done .. find the next + + MOV r8,r0 ; report address of this block + ADRL r4,%BT4 + BL ts_SendText + + LDR r0,[r9] ; start testing it + ADD r0,r0,#PhysSpace + LDR r1,[r9, #4] + STR r0,[r9] ; mark block so it isn't retested + MOV r2,#PhysRamTable + LDMIA r2,{r3-r14} ; save the PhysRamTable + STMIA r0,{r3-r14} + BL ts_RamTest + LDMIA r13,{r1-r11,r14} ; restore the PhysRamTable + MOV r13,#PhysRamTable + STMIA r13,{r1-r11,r14} + BEQ %BT18 ; if it passed, go look for another block + +20 + FAULT32 #R_MEMFAILBIT,r2 ; failed - report fault address + ADRL r4,%BT2 + MOV r11,r1 ; Save failed data + MOV r8,r0 ; first failing address + BL ts_SendText + MOV r4,r12 ; get fault message + MOV r8,r11 ; and fault data + BL ts_SendText +21 + + [ MEMM_Type = "MEMC1" + +; +; Test the CAMs - for each fitted MEMC, go through all the CAM entries +; remapping logical memory and testing against physical correspondence. +; Then try out the protection bits in each CAM entry and various +; processor modes. +; These tests return pointers to their own fault report strings. +; + B ts_CAMtest + ROUT +1 + = "CAMs :",0 +2 + = "PPLs :",0 +3 + = &89,"skipped",0 + ALIGN + +ts_CAMtest + LDR r4,=%BT1 + BL ts_SendText + + MOV_fiq r0,r12_fiq ; skip this test if memory fault + MOV r1,#(R_LINFAILBIT :OR: R_MEMFAILBIT) + ANDS r0,r0,r1 + BEQ %08 + LDR r4,=%BT3 + BL ts_MoreText + B %20 + +08 + BL ts_CAM + BEQ %10 + BL ts_SendText + FAULT #R_CAMFAILBIT +10 + LDR r4,=%BT2 + BL ts_SendText + + MOV_fiq r0,r12_fiq ; skip this test if memory fault + MOV r1,#(R_LINFAILBIT :OR: R_MEMFAILBIT) + ANDS r0,r0,r1 + BEQ %18 + LDR r4,=%BT3 + BL ts_MoreText + B %20 +18 + BL ts_memc_prot + BEQ %20 + BL ts_SendText + FAULT #R_PROFAILBIT +20 + + ] + +; +; After testing memory and translation, turn MMU off again before running remainder +; of tests. This simplifies finishing up (where system must be put back into 26-bit +; mode before initialising RISCOS) if memory tests were deselected. +; Take care to poke the real translation table - it's been relocated to video +; RAM during the memory tests. +; + +ts_restore_physical + MOV r5, pc ; obtain current address + SUB r5, r5,#PhysSpace ; adjust to point to unmapped version + MOV r5, r5, LSR #20 ; divide by 1MB + MOV r7, r5, LSL #20 ; r7 = physical address of base of section + ORR r7, r7, #(AP_None * L1_APMult) + ORR r7, r7, #L1_Section + MOV r3, #VideoPhysAddr ; find the copied translation table + LDR r3, [r3] + ADD r3, r3, #PhysSpace + ADD r3, r3, #DRAMOffset_L1PT + STR r7, [r3, r5, LSL #2] ; store replacement entry in L1 (not U,C or B) + + SetCop r7, CR_IDCFlush ; flush cache + TLB just in case + SetCop r7, CR_TLBFlush ; (data written is irrelevant) + +; The ROM should now be mapped at the present address less PhysSpace, which is where it +; would be if the MMU were turned off. + + MOV r4,#PhysSpace + SUB pc,pc,r4 + NOP ; this instruction is skipped + + MOV r7, #MMUC_D ; Now turn the MMU off + SetCop r7, CR_Control + + B ts_VIDCtest + + +; +; The VIDC tests check vertical blanking frequency in a fixed video +; mode and measure the time taken for sound DMA. +; + + ROUT + +1 + = "VIDC :",0 +2 + = "Virq bad",&88,' ',&ff,'.',&ff,&ff,&ff,&ff,&ff,0 +3 + = "Sirq bad",&8B,&ff,&ff,&ff,&ff,&ff,0 +4 + = &8A,"Mid0 ",&ff,0 + + ALIGN + +ts_VIDCtest + ADR r4,%BT1 + BL ts_SendText + [ IO_Type = "IOMD" + LDR r0,=IOMD_MonitorType ; Indicate monitor ID bit's value + LDR r0,[r0] + AND r0,r0,#IOMD_MonitorIDMask + MOV r8,r0,LSL #28 + ADR r4,%BT4 + BL ts_MoreText + ] + + [ MorrisSupport + MOV r3, #IOMD_Base + + LDRB r0, [r3, #IOMD_ID0] + CMP r0, #&98 + LDRB r0, [r3, #IOMD_ID1] + CMPEQ r0, #&5B ; skip Virq test on Morris + BEQ %FT10 + ] + + BL ts_VIDC_period + BEQ %10 + ADR r4,%B2 + MOV r8, r0, LSL #8 + BL ts_SendText ; Display Virq fail msg + FAULT #R_VIDFAILBIT +10 + [ IO_Type = "IOMD" + ; RCM thinks this is no longer needed - all IOMD's are issue two + ; besides, the test takes no account of Morris reusing the number space! + ; MOV r3,#IOMD_Base ; skip Sirq test on version 1 IOMD + ; LDRB r0,[r3,#IOMD_VERSION] + ; CMPS r0,#1 + ; BEQ %FT20 + ] + BL ts_SIRQ_period + BEQ %20 + ADR r4,%B3 + MOV r8, r0, LSL #12 + BL ts_SendText ; Display Sirq fail msg + FAULT #R_SNDFAILBIT +20 + MOV r1,#ts_VIDCPhys ; Restore full-screen + ADRL r2,TestVIDCTAB ; border colour. + [ IO_Type = "IOMD" + LDR r0,=IOMD_MonitorType + LDR r0,[r0] + ANDS r0,r0,#IOMD_MonitorIDMask + ADDEQ r2,r2,#(TestVVIDCTAB-TestVIDCTAB) + ] +30 LDR r0, [r2],#4 + CMP r0, #-1 + STRNE r0, [r1] + BNE %BT30 + LDR r0,=C_ARMOK ; set initial screen colour + STR r0, [r1] + + B ts_ARMtype_test + +; +; Read the ARM3 identification register. +; If memory tests failed, this won't be performed since the vector +; page must exist for error recovery on ARM2 systems. +; + + ROUT +1 + = "ARM ID:",0 +2 + = "ARM ID",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +3 + = &89,"skipped",0 + + ALIGN + +ts_ARMtype_test + + ADR r4,%BT1 + BL ts_SendText + + MOV_fiq r0,r12_fiq ; skip this test if memory fault + LDR r1,=((R_LINFAILBIT :OR: R_MEMFAILBIT) :OR: (R_CAMFAILBIT :OR: R_PROFAILBIT)) + ANDS r0,r0,r1 + BEQ %05 + ADR r4,%BT3 + BL ts_MoreText + B %08 ; and quit + +05 + BL ts_ARM_type + MOVS r8, r0 ; ready to display ID code + ADR r4,%BT2 + + BEQ %FT07 ; ARM 2 : skip cache test + FAULT #R_ARM3 ; not really a fault, just status +07 + BL ts_SendText + +08 + B ts_Report + + + +; +; Report the test results to the user +; +; If this was a forced test (test adapter fitted) then pause even when +; test passed : otherwise, pause only on error. +; + +ts_passmsg + = "PASS :",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +ts_failmsg + = "FAIL :",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 + +ts_R00 & 00 + +ts_Report ROUT + MOV_fiq r7,r12_fiq ; check for fault bits set + LDR r0,=R_STATUS + BICS r0,r7,r0 + + ADREQ r4, ts_passmsg ; tests passed + LDREQ r9,=C_PASSED + + ADRNE r4, ts_failmsg ; tests failed + LDRNE r9,=C_FAULT + + LDR r0,=ts_VIDCPhys ; write the border colour + STR r9,[r0] + + MOV r8,r7 + BL ts_SendText ; write the message and fault code + + ; if the test adapter is present, leave green screen awhile + ; otherwise, wait only if there's a fault. + + LDR r3,=ts_recover_time +00 ADDS r3,r3,r3 ; 16-loop delay + BCC %B00 ; - let the adapter recover + ; from previous bus activity + ADR r2,ts_R00 + ORR r2,r2,#ts_Alias_bits + LDR r3,[r2] + MOV r2,#-1 + ADDS r3,r3,r2 + BCS ts_Report_wait + + MOV_fiq r0,r12_fiq + LDR r2,=R_STATUS + BICS r0,r0,r2 + BEQ ts_Hardstart + +ts_Report_wait ROUT + +; +; Indicate fault found : Set the border to the fault colour and flash +; the disk LED, using the fault bitmap in r12_fiq to modulate the flashing. + +ts_oldLED_on * &be0000 ; assert SEL0 and INUSE +ts_oldLED_off * &ff0000 ; on machines with 1772 controller +ts_oldLEDaddr * (ts_S5_base :OR: &40) + +ts_710LED_on * &100000 ; assert SEL0 and MotorEN0 +ts_710LED_off * &110000 ; on machines with 82C710 controller +ts_710LEDaddr * (ts_PCaddress :OR: (&3f2 :SHL: 2)) + +ts_665LED_on * &10 ; assert SEL0 and MotorEN0 +ts_665LED_off * &11 ; on machines with 37665 controller + ; and Medusa low-byte I/O world +ts_665LEDaddr * (ts_PCaddress :OR: (&3f2 :SHL: 2)) + + +01 MOV_fiq r6,r12_fiq + LDR r2,=&11111111 + LDR r7,=(35000 * 8) ; 1/4 second pause loop count + + [ IO_Type = "IOMD" + LDRNE r1,=ts_665LEDaddr ; set up for Medusa disc address + MOVNE r8,#ts_665LED_on + MOVNE r9,#ts_665LED_off + | + TST r6, #R_IOEB ; determine original / 710 disc controller + LDREQ r1,=ts_oldLEDaddr ; set up for Archimedes disc address + MOVEQ r8,#ts_oldLED_on + MOVEQ r9,#ts_oldLED_off + LDRNE r1,=ts_710LEDaddr ; set up for Brisbane disc address + MOVNE r8,#ts_710LED_on + MOVNE r9,#ts_710LED_off + ] + +02 MOV r0,r7 +03 SUBS r0,r0,#1 ; pause for a 1/4 second + BNE %03 + + MOV r0,r8 ; turn the LED on + STR r0,[r1] + + MOV r0,r7 +04 SUBS r0,r0,#1 ; pause for a 1/4 second + BNE %04 + ADDS r6,r6,r6 ; if a '1' is to be written, + BCC %06 + MOV r0,r7,LSL #1 ; then pause another 1/2 second +05 SUBS r0,r0,#1 + BNE %05 + +06 + MOV r0, r9 ; turn the LED off + STR r0,[r1] + +; +; Count down 32 bits. Every 4 bits, insert an extra pause to simplify +; reading the flashes. +; + ADDS r2,r2,r2 + BCC %08 + MOV r0,r7,LSL #2 ; then pause another second +05 SUBS r0,r0,#1 + BNE %05 +08 + ANDS r2,r2,r2 ; all the bits displayed now ? + BNE %02 + MOV_fiq r0,r12_fiq ; restore the faultcode bits + + ANDS r0,r0,#(R_EXTERN :OR: R_TESTED) ; If test adapter present, + BNE Reset ; repeat test forever + + B CONT ; otherwise, run RISC OS + +ts_Hardstart + MOVS r0,#R_HARD ; and report a hard start + B CONT ; to RISC OS + +; +; Tests skipped : fall into RISC-OS +; + +ts_Self_test_end + + LDR r1,=C_WARMSTART + LDR r0,=ts_VIDCPhys ; write the border colour + STR r1,[r0] + +ts_Softstart + MOVS r0,#R_SOFT ; soft reset indicator + B CONT + + + ROUT + +; +; This table consists of a series of address/data pairs for IO +; initialization. +; Note that these addresses are likely to be in the IO world, +; and hence the data written is that from the MOST significant +; 16 bits of the data bus. +; An 'address' of -1 terminates the table. +; + +ts_IOinitab + [ IO_Type = "IOMD" + | + & ts_S5_base :OR: &10, &000000 ; Printer port data + & ts_S5_base :OR: &18, &000000 ; FDC control & printer strobes + & ts_S5_base :OR: &40, &ff0000 ; FDD select lines + & ts_S5_base :OR: &48, &000000 ; VIDC clock control + ] + & (-1) + + + + + +; +; +;--------------------------------------------------------------------------- + + LTORG + + +; Include test modules executed by call, rather than inline + + GET TestSrc.Mem2 + GET TestSrc.Mem3 + GET TestSrc.Mem4 + GET TestSrc.Mem5 + GET TestSrc.Vidc + GET TestSrc.Ioc + GET TestSrc.Cmos + GET TestSrc.Arm3 + + END diff --git a/TestSrc/Cmos b/TestSrc/Cmos new file mode 100644 index 0000000000000000000000000000000000000000..610193c5070a152e06e8749a75abfbfa24d333bd --- /dev/null +++ b/TestSrc/Cmos @@ -0,0 +1,321 @@ +; > TestSrc.Cmos + + TTL RISC OS 2+ POST battery-backed RAM access +; +; A function to read bytes from CMOS, for use in verifying the checksum +; and reading memory test flag & video modes. +;------------------------------------------------------------------------ +; History +; +; Date Name Comment +; ---- ---- ------- +; 05-Apr-91 ArtG Initial version, based on IICMod. +; +; +;------------------------------------------------------------------------ +; +; in: +; R0 = device address (bit 8 - 15 register address ) +; R1 = length of block to read +; R2 = initial sum value +; +; out: R0 = sum of all bytes in block +; R1 - R13 trashed +; + +ts_CMOSread ROUT + + MOV R13,R14 + MOV R8,R2 ; initialise accumulator + MOV R7,R1 ; initialise byte counter + MOV R6,R0 ; stash register address + MOV R2, #IOC + MOV R0, #-1 ; ensure timer is ticking + STRB R0, [R2, #Timer0LL] ; (nonzero in input latch) + STRB R0, [R2, #Timer0LH] + STRB R0, [R2, #Timer0GO] ; load the count registers + BL ts_Start + BEQ %FT30 ; check clock line toggles OK + AND R0, R6, #&FE + BL ts_TXCheckAck ; transmit device address (write) + BVS %FT30 + MOV R0, R6, LSR #8 + BL ts_TXCheckAck ; write register address + BVS %FT30 + BL ts_Start ; Extra START bit to switch modes + AND R0, R6, #&FE + ORR R0, R0, #1 + BL ts_TXCheckAck ; transmit device address (read) + BVS %FT30 +20 + BL ts_RXByte ; read byte from bus + ADD R8, R8, R0 ; accumulate total + SUBS R7, R7, #1 ; is it last byte ? + MOVNE R0, #0 ; no, then acknowledge with 0 bit + MOVEQ R0, #1 ; yes, then don't acknowledge + BL ts_ClockData ; but always send ack clock pulse + TEQ R7, #0 ; loop, until last byte + BNE %BT20 +30 + MOVVS R7, #-1 ; pass error indicator to caller + BL ts_Stop + MOV R0, R8 + TEQ R7, #0 ; return zero flag if read OK + MOV PC,R13 + +; ***************************************************************************** +; +; TXCheckACK - transmit a byte and wait for slave to ACK +; +; out: Trashes r0,r1,r2,r3,r4,r5,r9,r10,r11,r12 +; V bit set on error. +; + +ts_TXCheckAck ROUT + MOV R12,R14 + BL ts_TXByte + BL ts_Acknowledge + MOVVC PC, R12 ; acknowledged ok, so return + ORRS PC, R12, #V_bit + +; ***************************************************************************** +; +; SetC1C0 - Set clock and data lines to values in R1 and R0 respectively +; +; out: Trashes r0,r1,r2,r11 +; + +ts_SetC1C0 ROUT + MOV R11, R14 + BIC R14, R14, #Z_bit ; indicate not checking clock +ts_SetOrCheck + ORR R14, R14, #I_bit ; disable interrupts + TEQP R14, #0 + + ADD R0, R0, R1, LSL #1 ; R0 := C0 + C1*2 + + ORR R0, R0, #&C0 ; make sure two test bits are + ; always set to 1 ! + MOV R2, #IOC + STRB R0, [R2, #IOCControl] +10 + LDREQB R1, [R2, #IOCControl] ; wait for clock + TSTEQ R1, #i2c_clock_bit ; to read high + BEQ %BT10 + + MOV R0, #10 ; delay for >= 10/2 microsecs +; +; in-line do-micro-delay to save a stack level +; + STRB R0, [R2, #Timer0LR] ; copy counter into output latch + LDRB R1, [R2, #Timer0CL] ; R1 := low output latch +20 + STRB R0, [R2, #Timer0LR] ; copy counter into output latch + LDRB R14, [R2, #Timer0CL] ; R14 := low output latch + TEQ R14, R1 ; unchanged ? + MOVNE R1, R14 ; copy anyway + BEQ %BT20 ; then loop + SUBS R0, R0, #1 ; decrement count + BNE %BT20 ; loop if not finished +; +; end do-micro-delay +; + MOV PC, R11 + +; Set clock and data lines to R1 and R0 and then wait for clock to be high + +ts_SetC1C0CheckClock ROUT + MOV R11, R14 + ORR R14, R14, #Z_bit ; indicate checking clock + B ts_SetOrCheck + + +; ***************************************************************************** +; +; ClockData - Clock a bit of data down the IIC bus +; +; in: R0 = data bit +; +; out: Trashes r0,r1,r2,r3,r10,r11 +; + +ts_ClockData ROUT + MOV R10,R14 + + MOV R3, R0 ; save data + MOV R1, #0 ; clock LO + BL ts_SetC1C0 + + MOV R1, #1 ; clock HI + MOV R0, R3 + BL ts_SetC1C0CheckClock + +; Delay here must be >= 4.0 microsecs + + MOV R1, #0 ; clock LO + MOV R0, R3 + BL ts_SetC1C0 + + MOV PC,R10 + +; ***************************************************************************** +; +; Start - Send the Start signal +; +; out: Trashes r0,r1,r2,r9,r11 +; R0 (and Z flag) indicates state of clock .. should be NZ. +; + +ts_Start ROUT + MOV R9,R14 + + MOV R0, #1 ; clock HI, data HI + MOV R1, #1 + BL ts_SetC1C0 + +; Delay here must be >= 4.0 microsecs + + MOV R0, #0 ; clock HI, data LO + MOV R1, #1 + BL ts_SetC1C0 + +; Make sure clock really is high (and not shorted to gnd) + + LDRB R3, [R2, #IOCControl] + +; Delay here must be >= 4.7 microsecs + + MOV R0, #0 ; clock LO, data LO + MOV R1, #0 + BL ts_SetC1C0 + + ANDS R0, R3, #i2c_clock_bit + MOV PC,R9 + +; ***************************************************************************** +; +; Acknowledge - Check acknowledge after transmitting a byte +; +; out: Trashes r0,r1,r2,r3,r9,r11 +; V=0 => acknowledge received +; V=1 => no acknowledge received +; + +ts_Acknowledge ROUT + MOV R9,R14 + + MOV R0, #1 ; clock LO, data HI + MOV R1, #0 + BL ts_SetC1C0 + + MOV R0, #1 ; clock HI, data HI + MOV R1, #1 + BL ts_SetC1C0CheckClock + +; Delay here must be >= 4.0 microsecs + + MOV R2, #IOC + LDRB R3, [R2, #IOCControl] ; get the data from IOC + + MOV R0, #1 ; clock LO, data HI + MOV R1, #0 + BL ts_SetC1C0 + + TST R3, #1 ; should be LO for correct acknowledge + MOV R3, PC + BICEQ R3, R3, #V_bit ; clear V if correct acknowledge + ORRNE R3, R3, #V_bit ; set V if no acknowledge + TEQP R3, #0 + + MOV PC,R9 + +; ***************************************************************************** +; +; Stop - Send the Stop signal +; +; out: Trashes r0,r1,r2,r9,r11 +; + +ts_Stop ROUT + MOV R9,R14 + + MOV R0, #0 ; clock HI, data LO + MOV R1, #1 + BL ts_SetC1C0 + +; Delay here must be >= 4.0 microsecs + + MOV R0, #1 ; clock HI, data HI + MOV R1, #1 + BL ts_SetC1C0 + + MOV PC,R9 + +; ***************************************************************************** +; +; TXByte - Transmit a byte +; +; in: R0 = byte to be transmitted +; +; out: Trashes r0,r1,r2,r3,r4,r5,r9,r10,r11 +; + +ts_TXByte ROUT + MOV R9, R14 + MOV R4, R0 ; byte goes into R4 + MOV R5, #&80 ; 2^7 the bit mask +10 + ANDS R0, R4, R5 ; zero if bit is zero + MOVNE R0, #1 + BL ts_ClockData ; send the bit + MOVS R5, R5, LSR #1 + BNE %BT10 + MOV PC, R9 + +; ***************************************************************************** +; +; RXByte - Receive a byte +; +; out: R0 = byte received +; Trashes r1,r2,r3,r4,r9,r11 +; + +ts_RXByte ROUT + MOV R9, R14 + MOV R3, #0 ; byte:=0 + MOV R2, #IOC + MOV R4, #7 + + MOV R0, #1 ; clock LO, data HI + MOV R1, #0 + BL ts_SetC1C0 +10 + MOV R0, #1 ; pulse clock HI + MOV R1, #1 + BL ts_SetC1C0CheckClock + + LDRB R1, [R2, #IOCControl] ; get the data from IOC + AND R1, R1, #1 + ADD R3, R1, R3, LSL #1 ; byte:=byte*2+(IOC?0)AND1 + + MOV R0, #1 ; return clock LO + MOV R1, #0 + BL ts_SetC1C0 + + SUBS R4, R4, #1 + BCS %BT10 + + MOV R0, R3 ; return the result in R0 + MOV PC, R9 + + LTORG + + END + + + + + + + + diff --git a/TestSrc/ExtCmd b/TestSrc/ExtCmd new file mode 100644 index 0000000000000000000000000000000000000000..963d2660804f148cac499eb1115b3119699d0fd9 --- /dev/null +++ b/TestSrc/ExtCmd @@ -0,0 +1,1019 @@ +; > TestSrc.ExtCmd + + TTL RISC OS 2+ POST external commands +; +; External test commands for RISC OS ROM. +; +; Provides functions to read data, write data and execute code using +; parameters from an external controlling host. +; +; A minimal set of opcodes should be used (ideally, only B, LDR and ADDS) +; so that a processor test may be validly included in the internal test +; sequence. +; +;------------------------------------------------------------------------ +; History +; +; Date Name Comment +; ---- ---- ------- +; 27-Nov-89 ArtG Initial version +; 06-Dec-89 ArtG Release 0.2 for integration +; 30-Mar-90 ArtG Added NOPs (ADDS r0,r0,r0) after ADDS pc,.. +; 19-Apr-90 ArtG Speedups for read/write commands. +; 15-May-90 ArtG Fixed multiple %13 label in ts_W_FIW +; 22-May-90 ArtG Fixed bugs in ts_B_MWW, ts_W_RIB +; 18-Jun-93 ArtG Added Arm600 control instructions +; 1-Jul-93 ArtG Replaced ADDS pc.. instructions with ADD pc.. +; for compatibility with SVC32_mode. +; +;------------------------------------------------------------------------ + + + +; +; All these routines use registers as follows : +; +; r0 - always zero +; r1 +; r2 +; r3 - undisturbed : used as constant by I/O routine +; r4 - return value from I/O routine, parameter to I/O routines +; r5 +; r6 +; r7 - saved value of command byte on entry +; r8 - operation counter +; r9 - pointer to data transfer operation +; r10 - increment value (0, 1 or 4) to add to pointer in r9 +; r11 - decrement constant (-1) to add to counter in r8 +; r12 - checksum accumulator +; r13 - pointer to operation code +; r14 - return address for calls to I/O routines +; + + SUBT External command handlers +; +; Called by vectoring through command_table. +; R4 contains command byte (including 3 option bits) +; Get operation count +; Get address +; If single-word data +; Get data +; Get checksum +; Reply with command byte or FF +; Do operation +; Else +; For each word +; Get data +; Do operation +; Get checksum +; Reply with command byte or FF +; Return by branching to GetCommand. + +ts_write_memory ROUT + + ADDS r13,r0,r4 ; save the control byte + ADDS r7,r0,r4 + ADDS r14, r0, pc ; setup return address for .. + B ts_GetWord ; .. get operation count word + ADDS r8, r0, r4 ; r8 is operation count + ADDS r12,r0,r4 ; initialise checksum + ADDS r14, r0, pc + B ts_GetWord ; r9 is initial target address + ADDS r9, r0, r4 + ADDS r12,r12,r4 ; accumulate checksum + ADDS r10,r0,r0 ; set initial constants + LDR r11,%01 + ADD pc,pc,r0 +01 + DCD (0 - 1) + +; +; Check for operations which don't involve reading a block of data. +; These are acknowledged BEFORE performing the operation. +; + ADDS r0,r0,r0 + ADDS r13,r13,r13 ; convert operation code to vector + ADDS r13,r13,r13 + LDR r4, %02 + ADD pc,pc,r0 +02 + & (ts_write_cmd_table - %03) + ADDS r4,pc,r4 + ADDS r13,r4,r13 +03 + LDR r13,[r13] ; fetch pointer to code + LDR r4,%04 + ADD pc,pc,r0 +04 + & (ts_write_cmd_table - ts_W_fetch_operations) + ADDS r0,r0,r0 + ADDS r4,r4,r13 + BCS ts_Write_getdata ; defer acknowledgement till later + + ; check the above test was valid, given code layout + ; Note - this is also required by code near ts_Write_cmd_done + + ASSERT (ts_W_RSW < ts_W_fetch_operations) + ASSERT (ts_W_RSB < ts_W_fetch_operations) + ASSERT (ts_W_RIW < ts_W_fetch_operations) + ASSERT (ts_W_RIB < ts_W_fetch_operations) + ASSERT (ts_W_FSW >= ts_W_fetch_operations) + ASSERT (ts_W_FSB >= ts_W_fetch_operations) + ASSERT (ts_W_FIW >= ts_W_fetch_operations) + ASSERT (ts_W_FIB >= ts_W_fetch_operations) + +; +; Fetch the first data word and checksum, and acknowledge +; + + ADDS r14,r0,pc ;get next data word + B ts_GetWord + ADDS r12,r12,r4 ;accumulate checksum + ADDS r10,r0,r4 + ADDS r14,r0,pc + B ts_GetWord ;read transmitted checksum + ADDS r4,r4,r12 ;tx + total should be zero + LDR r5,%05 + ADD pc,pc,r0 +05 + & (0 - 1) + ADDS r5,r5,r4 ;carry set on checksum failure + BCS ts_cmd_error + +; +; Checksum looks OK. Send the command and the checksum back. +; + LDR r4,%06 + ADD pc,pc,r0 +06 + & ts_WriteCmdByte + ADDS r4,r4,r7 ;restore the original + + ADDS r14,r0,pc + B ts_SendByte + ADDS r4,r0,r12 ;then send the calculated checksum + ADDS r14,r0,pc + B ts_SendWord + + ADDS r4,r0,r10 ;restore the data word + ADDS r10,r0,r0 ;and the zero in r10 + B ts_Write_usedata ;dive off to do the work + +; +; Enter the main loop, repeating the operation labelled in r13. +; + +ts_Write_getdata + ADDS r9,r9,r10 ;perform increment operation + ADDS r8,r8,r11 ;countdown repeat counter + BCC ts_Write_cmd_ack + ADDS r14,r0,pc ;get next data word + B ts_GetWord + ADDS r12,r12,r4 ;accumulate checksum + B %07 + +ts_Write_usedata + ADDS r9,r9,r10 ;perform increment operation +ts_Write_count + ADDS r8,r8,r11 ;countdown repeat counter + BCC ts_Write_cmd_done +07 + ADD pc,pc,r13 ;jump back to operations + & 0 + +; +; In this table, the operation after any word fetch is vectored by +; the 3 least significant bits of the command byte to perform some +; combination of writing with : +; +; bit 2 -> 0 R : repeat with same data +; 1 F : fetch more data for next operation +; +; bit 1 -> 0 S : leave address static +; 1 I : increment address after operation +; +; bit 0 -> 0 W : word operation +; 1 B : byte operation +; + + ASSERT ((ts_write_cmd_table - %07) = 8) + +ts_write_cmd_table + + DCD (ts_W_RSW - ts_write_cmd_table) + DCD (ts_W_RSB - ts_write_cmd_table) + DCD (ts_W_RIW - ts_write_cmd_table) + DCD (ts_W_RIB - ts_write_cmd_table) + DCD (ts_W_FSW - ts_write_cmd_table) + DCD (ts_W_FSB - ts_write_cmd_table) + DCD (ts_W_FIW - ts_write_cmd_table) + DCD (ts_W_FIB - ts_write_cmd_table) + +; +; And here are the trailers that perform these operations. +; Each is started with the data in r4, address in r9 and completes +; by returning to Write_getdata (to read another word) or Write_usedata +; (to repeat with the same data) with r10 = increment value (initially 0) +; + +ts_W_RSW + STR r4,[r9] ;store word, repeat address + ADDS r8,r8,r11 ;countdown repeat counter + BCS ts_W_RSW + B ts_Write_cmd_done + +ts_W_RSB + STRB r4,[r9] ;store byte, repeat address + ADDS r8,r8,r11 + BCS ts_W_RSB + B ts_Write_cmd_done + +ts_W_RIW + LDR r10,%11 + ADD pc,pc,r0 +11 + DCD 4 +12 + STR r4,[r9] ;store word, increment word address + ADDS r9,r9,r10 ;perform increment operation + ADDS r8,r8,r11 ;countdown repeat counter + BCS %B12 + B ts_Write_cmd_done + + +ts_W_RIB + LDR r10,%13 + ADD pc,pc,r0 +13 + DCD 1 +14 + STRB r4,[r9] ;store byte, increment byte address + ADDS r9,r9,r10 + ADDS r8,r8,r11 + BCS %B14 + B ts_Write_cmd_done + + + +ts_W_fetch_operations ;all past here fetch new data + ;on each loop + +ts_W_FSW + STR r4,[r9] ;store word, repeat address + B ts_Write_getdata + +ts_W_FSB + STRB r4,[r9] ;store byte, repeat address + B ts_Write_getdata + +ts_W_FIW + STR r4,[r9] ;store word, increment word address + LDR r10,%15 + B ts_Write_getdata +15 + DCD 4 + +ts_W_FIB + STRB r4,[r9] ;store byte, increment byte address + LDR r10,%16 + B ts_Write_getdata +16 + DCD 1 + + +; +; Operations completed. Operations that read multiple data words from +; the host must now checksum and acknowledge the block (even though +; it's a bit late to do anything about it) +; + +ts_Write_cmd_ack +; +; Operation involved multiple fetches - only now ready to ACK. +; + ADDS r14,r0,pc + B ts_GetWord ;read transmitted checksum + ADDS r4,r4,r12 ;tx + total should be zero + LDR r5,%25 + ADD pc,pc,r0 +25 + & (0 - 1) + ADDS r5,r5,r4 ;carry set on checksum failure + BCS ts_cmd_error + +; +; Checksum looks OK. Send the command and the checksum back. +; + LDR r4,%26 + ADD pc,pc,r0 +26 + & ts_WriteCmdByte + ADDS r4,r4,r7 ;restore the original + ADDS r14,r0,pc + B ts_SendByte + ADDS r4,r0,r12 ;then send the calculated checksum + ADDS r14,r0,pc + B ts_SendWord + +ts_Write_cmd_done + B ts_GetCommand + + + +; Called by vectoring through command_table. +; R4 contains command byte (including 3 option bits) +; Get operation count +; Get address +; Reply with command byte or FF +; Reply with checksum +; For each word +; Read data +; If Verbose option +; Send data +; If Quiet option +; Send result of read operation +; Send checksum of result packet +; Return by branching to GetCommand. + +ts_read_memory ROUT + + ADDS r13,r0,r4 ; save the control byte + ADDS r7,r0,r4 + + ADDS r14, r0, pc ; setup return address for .. + B ts_GetWord ; .. get operation count word + ADDS r8, r0, r4 ; r8 is operation count + ADDS r12,r0,r4 ; initialise checksum + + ADDS r14, r0, pc + B ts_GetWord ; r9 is initial target address + ADDS r9, r0, r4 + ADDS r12,r12,r4 ; accumulate checksum + ADDS r10,r0,r0 ; set initial constants + LDR r11,%01 + ADD pc,pc,r0 +01 + DCD (0 - 1) +; +; Convert the operation options into a code pointer +; + ADDS r0,r0,r0 + ADDS r13,r13,r13 ; convert operation code to vector + ADDS r13,r13,r13 + LDR r4, %02 + ADD pc,pc,r0 +02 + & (ts_read_cmd_table - %03) + ADDS r4,pc,r4 + ADDS r13,r4,r13 +03 + LDR r13,[r13] ; fetch pointer to code + +; +; Fetch the checksum, and acknowledge +; + + ADDS r14,r0,pc + B ts_GetWord ;read transmitted checksum + ADDS r4,r4,r12 ;tx + total should be zero + LDR r5,%05 + ADD pc,pc,r0 +05 + & (0 - 1) + ADDS r5,r5,r4 ;carry set on checksum failure + BCS ts_cmd_error + +; +; Checksum looks OK. Send the command and the checksum back. +; + LDR r4,%06 + ADD pc,pc,r0 +06 + & ts_ReadCmdByte + ADDS r4,r4,r7 ;restore the original + ADDS r14,r0,pc + B ts_SendByte + ADDS r4,r0,r12 ;then send the calculated checksum + ADDS r14,r0,pc + B ts_SendWord + + ADDS r12,r0,r0 ;initialise the upload checksum + B ts_Read_count ;enter the loop + +; +; Enter the main loop, repeating the operation labelled in r13. +; This loop is for operations that finish with all data sent + +ts_Read_Txdata ;send data to host + ADDS r12,r12,r4 ;accumulate the checksum + ADDS r14,r0,pc + B ts_SendWord ;send this word + ADDS r9,r9,r10 ;perform increment operation + ADDS r8,r8,r11 ;countdown repeat counter + BCC ts_Read_cmd_done + B %07 ;go off to the jump handler + +ts_Read_count + ADDS r8,r8,r11 ;countdown repeat counter + BCC ts_Read_cmd_read ;send data at finish +07 + ADD pc,pc,r13 ;jump back to operations + & 0 + +; +; In this table, the operation after any word fetch is vectored by +; the 2 least significant bits of the command byte to perform some +; combination of reading with : +; +; bit 2 -> 0 Q : read data without reporting it +; 1 V : Transmit the result of every read operation +; +; bit 1 -> 0 S : leave address static +; 1 I : increment address after operation +; +; bit 0 -> 0 W : word operation +; 1 B : byte operation +; + + ASSERT ((ts_read_cmd_table - %07) = 8) + +ts_read_cmd_table + + DCD (ts_R_QSW - ts_read_cmd_table) + DCD (ts_R_QSB - ts_read_cmd_table) + DCD (ts_R_QIW - ts_read_cmd_table) + DCD (ts_R_QIB - ts_read_cmd_table) + DCD (ts_R_VSW - ts_read_cmd_table) + DCD (ts_R_VSB - ts_read_cmd_table) + DCD (ts_R_VIW - ts_read_cmd_table) + DCD (ts_R_VIB - ts_read_cmd_table) + +; +; And here are the trailers that perform these operations. +; Each is started with the data in r4, address in r9 and completes +; by returning to Write_getdata (to read another word) or Write_usedata +; (to repeat with the same data) with r10 = increment value (initially 0) +; + +ts_R_QSW + LDR r4,[r9] ;read word, repeat address + ADDS r8,r8,r11 ;countdown repeat counter + BCS ts_R_QSW + B ts_Read_cmd_read ;send data at finish + + +ts_R_QSB + LDRB r4,[r9] ;read byte, repeat address + ADDS r8,r8,r11 + BCS ts_R_QSB + B ts_Read_cmd_read + +ts_R_QIW + LDR r10,%11 + ADD pc,pc,r0 +11 + DCD 4 +12 + LDR r4,[r9] ;read word, increment word address + ADDS r9,r9,r10 ;perform increment operation + ADDS r8,r8,r11 ;countdown repeat counter + BCS %B12 + B ts_Read_cmd_read ;send data at finish + + +ts_R_QIB + LDR r10,%13 + ADD pc,pc,r0 +13 + DCD 1 +14 + LDRB r4,[r9] ;read byte, increment byte address + ADDS r9,r9,r10 ;perform increment operation + ADDS r8,r8,r11 ;countdown repeat counter + BCS %B14 + B ts_Read_cmd_read ;send data at finish + + +ts_R_VSW + LDR r4,[r9] ;read and tx word, repeat address + B ts_Read_Txdata + +ts_R_VSB + LDRB r4,[r9] ;read and tx byte, repeat address + B ts_Read_Txdata + +ts_R_VIW + LDR r4,[r9] ;read and tx word, next word address + LDR r10,%15 + B ts_Read_Txdata +15 + DCD 4 + +ts_R_VIB + ADDS r0,r0,r0 + LDRB r4,[r9] ;read and tx byte, next byte address + LDR r10,%16 + B ts_Read_Txdata +16 + DCD 1 + + +; +; Operations completed. Report final result and checksum back to host. +; Quiet option only transmits read data here (this is pretty useless +; except where only one value was read) +; + +ts_Read_cmd_read + ADDS r12,r12,r4 + ADDS r14,r0,pc ;send result of 'quiet' read + B ts_SendWord +ts_Read_cmd_done + SUBS r4,r0,r12 ;get overall checksum - can't think + ADDS r14,r0,pc ;how to do this using only ADDS ! + B ts_SendWord + + B ts_GetCommand + + +; Called by vectoring through command table. +; if option 1 set, read processor mode +; Read address +; Read and check checksum +; Reply with command byte or FF +; Reply with checksum +; if option 1 set, load SPSR +; Jump to code + + +ts_execute ROUT + ADDS r12,r0,r0 ; initialise checksum adder + LDR r8,%00 ; initialise msr-jumper + ADD pc,pc,r0 +00 + & 4 + ADDS r7,r4,r4 ; get operation type + ADDS r7,r7,r7 + ADD pc,pc,r7 ; jump to pc + (r4 * 4) + & 0 + + B %FT10 + B %FT08 + B %FT10 + B %FT10 + B %FT10 + B %FT10 + B %FT10 + B %FT10 + + +08 ADDS r14,r0,pc ; get new processor mode + B ts_GetWord + ADDS r12,r0,r4 + ADDS r8,r0,r0 ; kill msr-jumper +10 + ADDS r14,r0,pc + B ts_GetWord ; get jump address + ADDS r9,r12,r4 + ADDS r14,r0,pc + B ts_GetWord ; get checksum + ADDS r4,r4,r9 + LDR r5,%11 + ADD pc,pc,r0 +11 + & (0 - 1) + ADDS r4,r5,r4 ; compare total chex with zero + BCS ts_cmd_error ; carry set on error + + LDR r4,%12 + ADD pc,pc,r0 +12 + & ts_ExecuteCmdByte + ADDS r0,r0,r0 + ADDS r14,r0,pc ; echo command byte + B ts_SendByte + ADDS r4,r0,r9 ;return checksum (actually, the + ADDS r14,r0,pc ; entire message ..) + B ts_SendWord + + +; Now jump to the location given in the message, using the given status bits + + ADD pc,pc,r8 ; jump over the msr instruction + NOP + & 2_11100001011010011111000000001100 ; + + ADDS r14,pc,r0 ; Load the address of %13 into r14 + ; to provide a return address + ADD pc,r0,r9 ; Do the jump +13 + B ts_GetCommand + + + +; Called by vectoring through command table +; Read operation count +; Read target addresses +; Read data +; Send command byte or FF +; Send checksum +; For all operation count +; write data +; if read-back option +; read data +; Return by branching to GetCommand + + +ts_bus_exercise ROUT + ADDS r7,r0,r4 ; save the control byte + + ADDS r14, r0, pc ; setup return address for .. + B ts_GetWord ; .. get operation count word + ADDS r8, r0, r4 ; r8 is operation count + ADDS r12,r0,r4 ; initialise checksum + + ADDS r14, r0, pc + B ts_GetWord ; r9 is first target address + ADDS r9, r0, r4 + ADDS r12,r12,r4 ; accumulate checksum + ADDS r14, r0, pc + B ts_GetWord ; r10 is second target address + ADDS r10, r0, r4 + ADDS r12,r12,r4 ; accumulate checksum + + ADDS r14, r0, pc + B ts_GetWord ; r11 is first data word + ADDS r11, r0, r4 + ADDS r12,r12,r4 ; accumulate checksum + ADDS r14, r0, pc + B ts_GetWord ; r13 is second data word + ADDS r13, r0, r4 + ADDS r12,r12,r4 ; accumulate checksum + +; +; Fetch the checksum, and acknowledge +; + + ADDS r14,r0,pc + B ts_GetWord ;read transmitted checksum + ADDS r4,r4,r12 ;tx + total should be zero + LDR r5,%05 + ADD pc,pc,r0 +05 + & (0 - 1) + ADDS r5,r5,r4 ;carry set on checksum failure + BCS ts_cmd_error + +; +; Checksum looks OK. Send the command and the checksum back. +; + LDR r4,%06 + ADD pc,pc,r0 +06 + & ts_BusExCmdByte + ADDS r4,r4,r7 ;restore the original + ADDS r14,r0,pc + B ts_SendByte + ADDS r4,r0,r12 ;then send the calculated checksum + ADDS r14,r0,pc + B ts_SendWord + + ADDS r12,r0,r13 ; Now addresses are in r9, r10 + ; and data in r11, r12. +; +; Convert the operation options into a code pointer +; + ADDS r13,r7,r7 ; convert operation code to vector + ADDS r13,r13,r13 + LDR r4, %02 + ADD pc,pc,r0 +02 + & (ts_busex_cmd_table - %03) + ADDS r4,pc,r4 + ADDS r13,r4,r13 +03 + LDR r13,[r13] ; fetch pointer to code + LDR r7, %04 ; set up decrementer in r8 + ADD pc,pc,r0 +04 + DCD (0 - 1) +07 + ADD pc,pc,r13 ; jump to operation + & 0 + +; +; In this table, the operation after any word fetch is vectored by +; the 3 least significant bits of the command byte to perform some +; combination of writing with : +; +; bit 2 -> 0 S : Perform separate data write ops +; 1 M : Use STM / LDM instructions +; +; bit 1 -> 0 R : Perform only read operations +; 1 W : Write before reading +; +; bit 0 -> 0 W : word operation +; 1 B : byte operation +; +; Note that byte and multiple operations are mutually +; exclusive. +; + + ASSERT ((ts_busex_cmd_table - %07) = 8) + +ts_busex_cmd_table + + DCD (ts_B_SRW - ts_busex_cmd_table) + DCD (ts_B_SRB - ts_busex_cmd_table) + DCD (ts_B_SWW - ts_busex_cmd_table) + DCD (ts_B_SWB - ts_busex_cmd_table) + DCD (ts_B_MRW - ts_busex_cmd_table) + DCD (ts_B_MRB - ts_busex_cmd_table) + DCD (ts_B_MWW - ts_busex_cmd_table) + DCD (ts_B_MWB - ts_busex_cmd_table) + +ts_B_SRW + LDR r11,[r9] ; read-only separate words + LDR r12,[r10] + ADDS r8, r8, r7 + BCS ts_B_SRW + B ts_B_done + +ts_B_SRB + LDRB r11,[r9] ; read-only separate bytes + LDRB r12,[r10] + ADDS r8, r8, r7 + BCS ts_B_SRB + B ts_B_done + +ts_B_SWW + STR r11,[r9] ; write and read separate words + STR r12,[r10] + LDR r1,[r9] + LDR r2,[r10] + ADDS r8, r8, r7 + BCS ts_B_SWW + B ts_B_done + +ts_B_SWB + STRB r11,[r9] ; write and read separate bytes + STRB r12,[r10] + LDRB r1,[r9] + LDRB r2,[r10] + ADDS r8, r8, r7 + BCS ts_B_SWB + B ts_B_done + + +ts_B_MRW + LDMIA r9,{r1,r2} ; read-only multiple words + LDMIA r10,{r1,r2} + ADDS r8, r8, r7 + BCS ts_B_MRW + B ts_B_done + +ts_B_MWW + STMIA r9,{r11,r12} ; write and read multiple words + LDMIA r9,{r1,r2} + STMIA r10,{r11,r12} + LDMIA r10,{r1,r2} + ADDS r8, r8, r7 + BCS ts_B_MWW + B ts_B_done + +; +; Orthogonally, these should be multiple byte operations - we can't do that, +; so they actually do a single/multiple mixture. +; The first address argument is used for word-aligned operations and the +; second for byte-aligned operations - so set only the second address +; to a non-word-aligned address. + +ts_B_MRB + LDMIA r9,{r1,r2} ; read-only multiple words + LDRB r1,[r10] ; then single bytes + LDR r1,[r9] ; and single words + ADDS r8, r8, r7 + BCS ts_B_MRB + B ts_B_done + +ts_B_MWB + STMIA r9,{r11,r12} ; store multiple words + STRB r11,[r10] ; write byte + STR r12,[r9] ; write words + LDMIA r9,{r1,r2} + LDRB r1,[r10] + LDR r1,[r9] ; read single and multiple words + ADDS r8, r8, r7 + BCS ts_B_MWB +; B ts_B_done + +ts_B_done + B ts_GetCommand + + + +; +; All commands fall through here to respond with FF if the received +; message block checksums fail. +; + +ts_cmd_error ROUT ; error in command + LDR r4, %01 ; return error response + ADD pc,pc,r0 +01 + DCD ErrorCmd + ADDS r0,r0,r0 + ADDS r14, r0, pc ; send response byte to host + B ts_SendByte + + B ts_GetCommand + + +; generic coprocessor register names + +cpr0 CN 0 +cpr1 CN 1 +cpr2 CN 2 +cpr3 CN 3 +cpr4 CN 4 +cpr5 CN 5 +cpr6 CN 6 +cpr7 CN 7 +cpr8 CN 8 +cpr9 CN 9 +cpr10 CN 10 +cpr11 CN 11 +cpr12 CN 12 +cpr13 CN 13 +cpr14 CN 14 +cpr15 CN 15 + + +; Called by vectoring through command table. +; Read transfer value +; Read and check checksum +; Extract copro register number +; Index suitable MRC instruction +; Perform copro write +; Reply with command byte or FF +; Reply with checksum + +ts_write_cpr15h ROUT + ADDS r4,r4,#8 ; adjust opcode for high registers +ts_write_cpr15l + ADDS r7,r0,r4 ; save opcode to r7 + ADDS r14,r0,pc + B ts_GetWord ; get value for copro + ADDS r9,r0,r4 + ADDS r14,r0,pc + B ts_GetWord ; get checksum + ADDS r4,r4,r9 + LDR r5,%01 + ADD pc,pc,r0 +01 + & (0 - 1) + ADDS r4,r5,r4 ; compare total chex with zero + BCS ts_cmd_error ; carry set on error + + ADDS r13,r7,r7 ; point into instruction table + ADDS r13,r13,r13 + ADDS r13,r13,r13 + ADD pc,pc,r13 ; jump to pc + (r7 * 8) + & 0 + + SetCop r9,cpr0 ; transfer instructions + B %02 + SetCop r9,cpr1 + B %02 + SetCop r9,cpr2 + B %02 + SetCop r9,cpr3 + B %02 + SetCop r9,cpr4 + B %02 + SetCop r9,cpr5 + B %02 + SetCop r9,cpr6 + B %02 + SetCop r9,cpr7 + B %02 + SetCop r9,cpr8 + B %02 + SetCop r9,cpr9 + B %02 + SetCop r9,cpr10 + B %02 + SetCop r9,cpr11 + B %02 + SetCop r9,cpr12 + B %02 + SetCop r9,cpr13 + B %02 + SetCop r9,cpr14 + B %02 + SetCop r9,cpr15 + +02 + LDR r4,%03 + ADD pc,pc,r0 +03 + & ts_CPWCmdByte ; build command byte + option + ADDS r4,r4,r7 + ADDS r14,r0,pc ; echo command byte + B ts_SendByte + ADDS r4,r0,r9 ; return checksum + ADDS r14,r0,pc ; + B ts_SendWord + + B ts_GetCommand + + + + +; Called by vectoring through command table. +; Read and check checksum +; Extract copro register number +; Index suitable MCR instruction +; Perform copro read +; Reply with command byte or FF +; Reply with checksum +; Send transfer results +; Send checksum + +ts_read_cpr15h ROUT + ADDS r4,r4,#8 ; adjust opcode for high registers +ts_read_cpr15l + ADDS r7,r0,r4 ; save opcode in r7 + ADDS r14,r0,pc + B ts_GetWord ; get checksum to r4 + ADDS r9,r0,r4 ; copy to r9 + LDR r5,%01 + ADD pc,pc,r0 +01 + & (0 - 1) + ADDS r4,r5,r4 ; compare total chex with zero + BCS ts_cmd_error ; carry set on error + + LDR r4,%02 + ADD pc,pc,r0 +02 + & ts_CPRCmdByte ; build command byte + option + ADDS r4,r4,r7 + ADDS r14,r0,pc ; echo command byte + B ts_SendByte + ADDS r4,r0,r9 ; return checksum + ADDS r14,r0,pc + B ts_SendWord + + ADDS r13,r7,r7 ; point into instruction table + ADDS r13,r13,r13 + ADDS r13,r13,r13 + ADD pc,pc,r13 ; jump to pc + (r7 * 8) + & 0 + + ReadCop r12,cpr0 ; transfer instructions + B %03 + ReadCop r12,cpr1 + B %03 + ReadCop r12,cpr2 + B %03 + ReadCop r12,cpr3 + B %03 + ReadCop r12,cpr4 + B %03 + ReadCop r12,cpr5 + B %03 + ReadCop r12,cpr6 + B %03 + ReadCop r12,cpr7 + B %03 + ReadCop r12,cpr8 + B %03 + ReadCop r12,cpr9 + B %03 + ReadCop r12,cpr10 + B %03 + ReadCop r12,cpr11 + B %03 + ReadCop r12,cpr12 + B %03 + ReadCop r12,cpr13 + B %03 + ReadCop r12,cpr14 + B %03 + ReadCop r12,cpr15 + +03 + ADDS r4,r0,r12 ; return result + ADDS r14,r0,pc + B ts_SendWord + SUBS r4,r0,r12 ; return checksum + ADDS r14,r0,pc + B ts_SendWord + + B ts_GetCommand + + + END + + diff --git a/TestSrc/ExtIO b/TestSrc/ExtIO new file mode 100644 index 0000000000000000000000000000000000000000..8ef956a201a997890c60749536a7896ac60b7cad --- /dev/null +++ b/TestSrc/ExtIO @@ -0,0 +1,1089 @@ +; > TestSrc.ExtIO + + TTL RISC OS 2+ POST external commands +; +; External interface for RISC OS ROM. +; provides entry points to send byte- and word- and string-sized objects +; and to receive byte- and word-sized objects +; +; A minimal set of opcodes should be used (ideally, only B, LDR and ADDS) +; so that a processor test may be validly included in the internal test +; sequence. +; +;------------------------------------------------------------------------ +; History +; +; Date Name Comment +; ---- ---- ------- +; 06-Dec-89 ArtG Initial version - split from `Begin` +; Release 0.2 for integration +; 31-Mar-90 ArtG Added ts_MoreText, cursor position, hex. +; 19-Apr-90 ArtG Added bus exercise commands +; 09-May-90 ArtG Changed LCD strobe to 12 pulses +; 15-May-90 ArtG Added ReadyByte : improves synchronization +; when ExtCmd execution toggles A21/A22. +; 18-Jun-90 ArtG Added CPR15 read/write functions +; +; +;------------------------------------------------------------------------ + + + SUBT Test adapter interface + +; +; The test adapter senses an access to the ROM with address line A21 high. +; Current (2M addressing space) ROMs only use address lines A2 to A20, +; so if A21 to A22 are asserted they will be ignored (the ROMS are aliased +; into 8M of space). With no test adapter, the aliased ROM location will +; be read and may be recognised. The test adapter may selectively disable +; ROMs when A21 is high, causing arbitrary data to be read. This data +; should be dependent on the previous ROM read operation, and will +; therefore be predictably not equal to the data read when the ROMs are +; aliased. +; The assumption that A21 is unused may be invalidated by a later issue +; of the PCB. A22 is therefore asserted at the same time : this will then +; be used on a PCB where A22 is tracked to a test connector and 8Mbit ROMS +; are used. Machines using larger ROMs than 8 Mbit (4M addressing space) +; will require explicit decoding or a new communication scheme. +; + + +; +; This section determines whether the test interface adapter exists, and +; what variety is fitted (dumb, display or external) +; 3 read operations are performed (a WS operation): if all of these +; find a ROM alias then no adapter is fitted. +; +; If an adapter responds, then a RD operation is performed - 4 strobes then +; clocking 8 bits into r4. These bits may be all zeros (a dumb adapter) +; or all ones (a display adapter) or some other value (an external +; adapter) +; + +ts_GetCommand ROUT + + LDR r0,%01 + ADD pc,pc,r0 +01 + & 0 + + ; delay to make a gap before reading + + LDR r3,%02 + ADD pc,pc,r0 +02 + & ts_recover_time +03 + ADDS r3,r3,r3 ; 16-loop delay + BCC %03 + + ROUT + +; +; Load up the registers for the test interface communication - +; + + LDR r0,%01 ; set zero in r0 + ADD pc,pc,r0 ;(generally useful constant - especially for skip) +01 + & 0 + LDR r1,%02 ; set FFFFFFFF in r1 + ADD pc,pc,r0 ;(test value : sets carry when added to non-zero) +02 + & (-1) + LDR r2,%03 ; set pointer to test address + ADD pc,pc,r0 ;(points to aliased copy of a zero word) +03 + & (ts_Alias_bits + (%01 - %04)) + ADDS r2,pc,r2 ; adjust r2 for ROM-relative address + ADDS r4,r0,r0 ; clear output accumulator +04 ; where pc is when added to r2 + + ; do an RD operation (four strobes) to ensure interface cleared + + LDR r3,[r2] + ADDS r3,r3,r1 + LDR r3,[r2] + ADDS r3,r3,r1 + LDR r3,[r2] + ADDS r3,r3,r1 + LDR r3,[r2] + ADDS r3,r3,r1 + + ; write a byte (initially, &90) to indicate readiness + + LDR r4,%20 + ADD pc,pc,r0 +20 + & ts_ReadyByte_00 + ADDS r14,r0,pc + B ts_SendByte + + ; delay to make a gap between WRS and RD operations + + LDR r3,%05 + ADD pc,pc,r0 +05 + & ts_recover_time +06 + ADDS r3,r3,r3 ; 16-loop delay + BCC %06 + + LDR r5,%07 ; counter for first 5 bits + ADD pc,pc,r0 +07 + & 1 :SHL: (32 - 5) + LDR r6,%08 ; counter for last 3 bits + ADD pc,pc,r0 +08 + & 1 :SHL: (32 - 3) + ADDS r4,r0,r0 ; input accumulator initialisation + +; put the test interface into input mode + + LDR r3,[r2] ; 3 bit lead-in + ADDS r3,r3,r1 ; (adapter detects WS operation) + BCC ts_User_startup ; abort if no adapter present + + LDR r3,[r2] ; two more strobes, then waitloop + ADDS r3,r3,r1 + LDR r3,[r2] + ADDS r3,r3,r1 + +; started input operation : wait for interface to be ready + +09 + LDR r3,[r2] ; read start bit repeatedly + ADDS r3,r3,r1 ; (adapter detects RD operation) + BCC %09 ; loop until interface is ready + +; read the first 5 bits into r5 and the second 3 bits into r4 + +10 LDR r3,[r2] ; read a bit of the byte + ADDS r3,r3,r1 ; .. if the test adapter is present, carry bit set + ADCS r4,r4,r4 ; .. shift left and add in carry + + ADDS r5,r5,r5 ; loop until 5 bits are read + BCC %10 + + ADDS r5,r4,r4 ; copy bits 7..3 to r5, bits 5..1 + + ADDS r4,r0,r0 ; and read the last 3 bits to r4 +11 LDR r3,[r2] ; read a bit of the byte + ADDS r3,r3,r1 + ADCS r4,r4,r4 + + ADDS r6,r6,r6 ; loop until last 3 bits are read + BCC %11 + +; +; Command byte read in (split between r4 and r5) +; Pass the option bits (r4) to the function identified by r5. +; + + ADDS r5,r5,r5 ; index * 2 -> index * 4 + LDR r3,%12 ; pc-relative ptr to command_table + ADD pc,pc,r0 +12 + & ts_command_table - %13 + ADDS r3,pc,r3 ; absolute pointer to command table + ADDS r3,r3,r5 + +13 LDR r3,[r3] ; get table entry +14 ADD pc,pc,r3 ; (offset from command_table) + + & 0 ; necessary padding : pc must point + ; to command table when r3 is added. + +; +; This is the table of offsets to all the built-in functions. +; The top 5 bits of the command are used to index, so there are +; 32 possible entries, mostly illegal. +; Decoding of the function modifier bits is performed by multiple +; entries in this table. +; + +; pc must point here when ADDS pc,r3,pc is executed + + ASSERT ((ts_command_table - %14) = 8) + +ts_command_table + + DCD (ts_Dealer_startup - ts_command_table) ; display interface +ts_Windex + DCD (ts_write_memory - ts_command_table) ; external tests +ts_Rindex + DCD (ts_read_memory - ts_command_table) +ts_Eindex + DCD (ts_execute - ts_command_table) +ts_Bindex + DCD (ts_bus_exercise - ts_command_table) + + DCD (ts_GetCommand - ts_command_table) ; dummy entry aligns CPR instructions + ; to allow 4-bit option field +ts_CWindex + DCD (ts_write_cpr15l - ts_command_table) + DCD (ts_write_cpr15h - ts_command_table) +ts_CRindex + DCD (ts_read_cpr15l - ts_command_table) + DCD (ts_read_cpr15h - ts_command_table) + + ; pad the table out to 31 entries + ; (leave space for display vector) + +OldOpt SETA {OPT} + OPT OptNoList +doffset SETA . + WHILE doffset < (ts_command_table + (31 * 4)) ; illegal entries + DCD (ts_GetCommand - ts_command_table) +doffset SETA doffset + 4 + WEND + OPT OldOpt + + DCD (ts_Forced_startup - ts_command_table) ; dumb interface + +; +; The indexes into the above table are needed in ExtCmd ... +; +ts_WriteCmdByte * ((ts_Windex - ts_command_table) :SHL: 1) +ts_ReadCmdByte * ((ts_Rindex - ts_command_table) :SHL: 1) +ts_ExecuteCmdByte * ((ts_Eindex - ts_command_table) :SHL: 1) +ts_BusExCmdByte * ((ts_Bindex - ts_command_table) :SHL: 1) +ts_CPWCmdByte * ((ts_CWindex - ts_command_table) :SHL: 1) +ts_CPRCmdByte * ((ts_CRindex - ts_command_table) :SHL: 1) + + +; +; Primitives for reading data from the external interface +; +; - Get a byte from the interface (into r4) +; - Get a (4 byte) word from the interface (into r4) +; +; Required register setup is presumed done by a recent ts_GetCommand. +; r0, r1 and r2 have critical values +; r14 is the link address +; + +ts_GetWord ROUT + + LDR r6,%01 ; counter for 4 bytes per word + ADD pc,pc,r0 ; (bit set 4 left shifts from Carry) +01 + & 1 :SHL: (32 - 4) + B ts_Getdata + +ts_GetByte ROUT + LDR r6,%01 ; counter for single byte + ADD pc,pc,r0 +01 + & 1 :SHL: (32 - 1) + +ts_Getdata ROUT + ADDS r4,r0,r0 ; input accumulator initialisation + + LDR r3,[r2] ; 3 bit lead-in + ADDS r3,r3,r1 ; (adapter detects RD operation) + LDR r3,[r2] + ADDS r3,r3,r1 + LDR r3,[r2] + ADDS r3,r3,r1 + +; started input operation : now loop until r6 shifts into Carry + +02 + LDR r5,%03 ; counter for 8 bits per byte + ADD pc,pc,r0 +03 + & 2_00000001000000010000000100000001 +04 + LDR r3,[r2] ; read start bit repeatedly + ADDS r3,r3,r1 + BCC %04 ; loop until interface is ready +05 + LDR r3,[r2] ; read a bit of the byte + ADDS r3,r3,r1 + ADCS r4,r4,r4 ; SHL r4, add carry bit. + + ADDS r5,r5,r5 ; loop until byte is read + BCC %05 + + ADDS r6,r6,r6 ; loop until word is read + BCC %04 + + ADD pc,r0,r14 ; back to the caller + + +; +; Primitives for sending data to the interface +; +; - Send a byte to the interface (from r4 lsb) +; - Send a (4 byte) word to the interface (from r4) +; +; Required register setup is presumed done by a recent ts_GetCommand. +; r0, r1 and r2 have critical values +; r14 is the link address +; + +ts_SendWord ROUT + LDR r6,%01 ; counter for 4 bytes per word + ADD pc,pc,r0 ; (bit set 4 left shifts from Carry) +01 + & 1 :SHL: (32 - 4) + B ts_Putdata + +ts_SendByte ROUT + LDR r6,%01 ; counter for single byte + ADD pc,pc,r0 +01 + & (3 :SHL: 7) +02 ADDS r4,r4,r4 ;shift byte into highest 8 bits + ADDS r6,r6,r6 + BCC %02 ;stop when byte shifted, + ;leaving bit 31 set in r6 + +ts_Putdata ROUT + +; Wait - gap between successive WS attempts or successive bytes + +01 LDR r3,%02 + ADD pc,pc,r0 +02 + & ts_recover_time +03 ADDS r3,r3,r3 ; 16-loop delay + BCC %03 + + LDR r3,[r2] ; Test for adapter ready for data + ADDS r3,r3,r1 ; (adapter detects WS operation) + LDR r3,[r2] + ADDS r3,r3,r1 + BCC %10 ; skip out if adapter not present + LDR r3,[r2] + ADDS r3,r3,r1 + BCC %01 ; loop back until adapter is ready + +; Adapter ready - loop around all the bits in the byte + + LDR r5,%04 ; load bits-per-byte counter + ADD pc,pc,r0 +04 + & (1 :SHL: (32-8)) + +05 LDR r3,%06 ; delay before sending bit + ADD pc,pc,r0 +06 + & ts_recover_time +07 ADDS r3,r3,r3 ; 16-loop delay + BCC %07 + + ; Send a single bit : 1 pulse for 1, 2 pulses for 0 + + LDR r3,[r2] + ADDS r4,r4,r4 ; shift current bit into Carry + LDRCC r3,[r2] ; second pulse if bit is 0 + + ; repeat until 8 bits are sent + + ADDS r5,r5,r5 + BCC %05 + +; Repeat for all the bytes to be sent (1 or 4) + + ADDS r6,r6,r6 + BCC %01 + +; Go to TXRDY to ensure the host sees the transmit request + + LDR r3,%08 ; delay before sending pattern + ADD pc,pc,r0 +08 + & ts_recover_time +09 ADDS r3,r3,r3 ; 16-loop delay + BCC %09 + + LDR r3,[r2] + ADDS r3,r3,r1 ; dummy - space between pulses + LDR r3,[r2] + ADDS r3,r3,r1 + LDR r3,[r2] + +; All sent - r14 holds the caller's return address +10 + ADD pc,r0,r14 + + + +; +; Reporting primitive +; +; - Send the text (nul-terminated, at r4) to the display +; +; Interface registers need to be set up : this function is called from test +; code rather than external interface code. +; +; The display is assumed to be a standard 16 character LCD module using +; the Hitachi HD44780 display controller. +; The 16-digit module uses a single 44780. This is an abnormal use of the +; controller, and requires it to be set to two-line mode, with the first +; 8 displayed characters on the first 'line', and the second 8 on the +; second 'line'. Characters sent to the second line must be written at +; character position 40 +. In order to permit different modules to be +; fitted to later adapters, it is suggested that the first 7 characters +; be treated as a 'title' line, and the second 8 as a 'comment' line. +; A space should always be placed at the end of the title line to +; split the display fields, unless there is no 'comment' line. +; Do not display characters across the two areas as though they adjoined +; (even though they do :-) ). +; +; The controller is operated in its 4-bit mode, which allows the interface +; to drive 4 bits of alpha information and 4 bits of control information. +; The bits in a transmitted byte are assigned as : +; +; bit 0 - D4 } 4-bit mode data bus +; 1 - D5 } +; 2 - D6 } +; 3 - D7 } +; +; 4 - RS Register Select : 0 for control, 1 for data +; +; 5 - } Unassigned +; 6 - } +; +; 7 - CPEN Interface control : 0 for enable, +; 1 for disable +; +; For each message sent, the display is first initialised, using the +; following sequence (each byte is sent as 2 bytes, high nibble first, +; with RS clear in bit 4 of each byte) +; After each byte, an RD operation is performed : this is used by the +; interface hardware to strobe the data into the display. +; +; +; The message addressed by r4 is then sent (data mode : RS set in each byte) +; until a 0 byte is encountered. +; + +; +; This is the command sequence sent to initialise the display +; + +ts_initialise + = &30,&30,&30,&20 ; power-up initialisation + = &20,&80 ; 4 bit mode, two line, Font 0 + = &00,&C0 ; Display on, no cursor visible + = &00,&60 ; Incrementing display position, no shift + = &80,&00 ; Set DD RAM address 0 + = &00,&20 ; Cursor home + = &00,&10 ; Display clear +ts_initialise_end + + ASSERT ((ts_initialise_end - ts_initialise) / 2) < 32 + + +; +; This is the command sequence sent when continuation text is sent +; + +ts_extend + = &00,&C0 ; Display on, cursor invisible + = &00,&60 ; Incrementing display position, no shift +ts_extend_end + + ASSERT ((ts_extend_end - ts_extend) / 2) < 32 + +; +; One of these commands are sent when offset text is required +; + +ts_offset_table + = &80,&00 ; Set DD RAM address 0 +ts_offset_table_1 + = &80,&10 ; Set DD RAM address 1 + = &80,&20 ; Set DD RAM address 2 + = &80,&30 ; Set DD RAM address 3 + = &80,&40 ; Set DD RAM address 4 + = &80,&50 ; Set DD RAM address 5 + = &80,&60 ; Set DD RAM address 6 + = &80,&70 ; Set DD RAM address 7 + = &C0,&00 ; Set DD RAM address 40 + = &C0,&10 ; Set DD RAM address 41 + = &C0,&20 ; Set DD RAM address 42 + = &C0,&30 ; Set DD RAM address 43 + = &C0,&40 ; Set DD RAM address 44 + = &C0,&50 ; Set DD RAM address 45 + = &C0,&60 ; Set DD RAM address 46 + = &C0,&70 ; Set DD RAM address 47 + + +; This assertion is forced by the code : each sequence assumed 2 bytes. + + ASSERT ((ts_offset_table_1 - ts_offset_table) = 2) + + + + ALIGN + +; +; Here starts the code ... +; + +ts_SendQuit ROUT ; put this code BEFORE %16 + ADD pc,r0,r14 ; + + + +; +; Entry point for initialising the display and sending r4 text. +; + + +ts_SendText ROUT + +; +; Point to the command sequence to setup and clear the display +; + + LDR r0,%10 ; set zero in r0 + ADD pc,pc,r0 +10 + & 0 + LDR r7,%11 ; pointer to init sequence + ADDS r7,pc,r7 + ADD pc,pc,r0 +11 + & (ts_initialise - .) + LDR r6,%12 ; length of init sequence + ADD pc,pc,r0 +12 + & (1 :SHL: (32 - (ts_initialise_end - ts_initialise))) + B ts_SendLCDCmd + + +; +; Entry point for adding text to current cursor position +; + +ts_MoreText ROUT + + LDR r0,%10 ; set zero in r0 + ADD pc,pc,r0 +10 + & 0 + LDR r7,%11 ; pointer to command sequence + ADDS r7,pc,r7 + ADD pc,pc,r0 +11 + & (ts_extend - .) + LDR r6,%12 ; length of command sequence + ADD pc,pc,r0 +12 + & (1 :SHL: (32 - (ts_extend_end - ts_extend))) + B ts_SendLCDCmd + + +ts_PosText ROUT + +; +; Entry point for adding text at a specific cursor position +; Used iteratively by SendText, etc if cursor position command found. +; Offset into display is given in r6. +; + + LDR r0,%10 ; set zero in r0 + ADD pc,pc,r0 +10 + & 0 + LDR r7,%11 ; pointer to command sequence + ADDS r7,pc,r7 + ADD pc,pc,r0 +11 + & (ts_offset_table - .) ; offset * 2 into table of + ADDS r6,r6,r6 ; offset command sequences + ADDS r7,r7,r6 + + LDR r6,%12 ; length of command sequence + ADD pc,pc,r0 +12 + & (1 :SHL: (32 - 2)) + + +; +; Entry point for writing arbitrary command strings. +; Set r7 to point to command string, r6 length (as tables above), +; Set r4 to point to following Data string (null-terminated). +; + +ts_SendLCDCmd + + LDR r0,%01 ; set zero in r0 + ADD pc,pc,r0 +01 + & 0 + LDR r1,%02 ; set FFFFFFFF in r1 + ADD pc,pc,r0 ;(test value : sets carry when added to non-zero) +02 + & (-1) + LDR r2,%03 ; set pointer to test address + ADD pc,pc,r0 ;(points to aliased copy of a zero word) +03 + & (ts_Alias_bits + (%01 - %04)) + ADDS r2,pc,r2 ; adjust r2 for ROM-relative address + ADDS r0,r0,r0 ; dummy (to keep labels nearby !) +04 ; where pc points when added to r2 + + +; Wait - gap between successive WS attempts or successive bytes + +ts_send_command_byte ROUT + + LDR r3,%14 + ADD pc,pc,r0 +14 + & ts_recover_time +15 ADDS r3,r3,r3 ; 16-loop delay + BCC %15 + LDR r1,%16 ; reload test register + ADD pc,pc,r0 +16 + & (-1) + + LDR r3,[r2] ; Test for adapter ready for data + ADDS r3,r3,r1 ; (adapter detects WS operation) + BCC ts_SendQuit ; skip output : adapter not present + ; (backward jump helps ensure LDR r3,[r2] + ; only reads zero when adapter absent + LDR r3,[r2] ; since previous bus data is nonzero) + ADDS r3,r3,r1 + LDR r3,[r2] + ADDS r3,r3,r1 + BCC ts_send_command_byte ; loop back until adapter is ready + +; Adapter ready - loop around all the bits in the byte + + + LDR r5,%21 ; load byte-shift counter ... + ADD pc,pc,r0 ; ... and bits-per-byte counter +21 + & (1 :SHL: 8) + 1 ; 24 shifts + 8 shifts + LDRB r1,[r7] +22 ADDS r1,r1,r1 ; shift byte up into m.s.d. + ADDS r5,r5,r5 + BCC %22 + + ; Send a single bit : 1 pulse for 1, 2 pulses for 0 + +23 LDR r3,[r2] + ADDS r1,r1,r1 ; shift current bit into Carry + LDRCC r3,[r2] ; second pulse if bit is 0 + + ; and wait for the inter-bit time + + LDR r3,%24 + ADD pc,pc,r0 +24 + & ts_recover_time +25 ADDS r3,r3,r3 ; 16-loop delay + BCC %25 + + ; repeat until 8 bits are sent + + ADDS r5,r5,r5 + BCC %23 + + ; do a RD operation to strobe the data out + + LDR r5,%26 + ADD pc,pc,r0 +26 + & (1 :SHL: (32 - 12)) +27 + LDR r3,[r2] + ADDS r5,r5,r5 + BCC %27 + +; Repeat for all the bytes to be sent (ts_initialise_end - ts_initialise) + + LDR r3,%33 + ADD pc,pc,r0 +33 + & 1 + ADDS r7,r7,r3 ; bump the pointer + ADDS r6,r6,r6 ; bump the counter (shift left) + BCC ts_send_command_byte + + +; +; Then send all the display bytes (in 4-bit mode) until a nul-terminator +; is reached. +; + +; +; Send a single character (as two separate 4-bit fields) +; First, look to see if it's one of : +; +; NUL - end of text string +; 0x80 - 0xfe - cursor positioning +; 0xff - introduce a hex digit +; + +ts_send_text_byte ROUT + + LDR r1,%40 ; reload test register + ADD pc,pc,r0 +40 + & (-1) + + LDRB r7,[r4] + ADDS r3,r7,r1 ; test for nul terminator + BCC ts_SendEnd + +; +; Byte isn't null. Check for >= 0x80. +; + + LDR r6,%42 ; test for cursor control + ADD pc,pc,r0 +42 + & (-&80) ; &8x means column x. + ADDS r6,r7,r6 + BCC ts_printable_char ; < &80 : write a character + +; +; Carry set : r6 now holds (value - 0x80). Check for numeric escape (&ff). +; + LDR r3,%43 + ADD pc,pc,r0 +43 + & (-&7f) + ADDS r3,r6,r3 + BCC %47 + +; +; Carry set : fetch a nybble from the top of r8 and display that. +; + + ADDS r8,r8,r8 + ADCS r6,r0,r0 + ADDS r8,r8,r8 + ADCS r6,r6,r6 + ADDS r8,r8,r8 + ADCS r6,r6,r6 + ADDS r8,r8,r8 + ADCS r6,r6,r6 + + LDRB r7,[pc,r6] + B ts_printable_char +45 + = "0123456789ABCDEF" + +; +; Not &ff : r6 holds cursor positioning offset (< &80). Skip over +; the cursor control byte and iterate thro' PosText to move +; typing position. +; + +47 + LDR r3, %48 + ADD pc,pc,r0 +48 + & 1 + ADDS r4,r3,r4 + B ts_PosText + +; +; Character is normal text : write it to the LCD. +; The shift loop is used to generate the inter-byte delay normally +; provided by ts_recover_time. Always make sure this is long enough. +; + +ts_printable_char + + ADDS r6,r0,r7 ; take a copy of character + LDR r5,%51 ; load byte-shift counter ... + ADD pc,pc,r0 ; ... and bits-per-byte counter +51 ; as a bitmask of the shift pattern + & (1:SHL:8)+(1:SHL:4)+1 ; 24 shifts + 4 shifts + 4 shifts +52 ADDS r6,r6,r6 ; shift byte up into m.s.d. + ADDS r0,r0,r0 ; slow this loop down - ensure it's + ADDS r0,r0,r0 ; always slower than ts_recover_time + ADDS r5,r5,r5 + BCC %52 + + LDR r3,[r2] ; Test for adapter ready for data + ADDS r3,r3,r1 ; (adapter detects WS operation) + LDR r3,[r2] + ADDS r3,r3,r1 + LDR r3,[r2] + ADDS r3,r3,r1 + BCC ts_printable_char ; loop back until adapter is ready + +; Adapter ready - loop around all the bits in the byte + +ts_send_tbit_upper + + ; wait for the inter-bit time + + LDR r3,%55 + ADD pc,pc,r0 +55 + & ts_recover_time +56 ADDS r3,r3,r3 ; 16-loop delay + BCC %56 + + ; Send a single bit : 1 pulse for 1, 2 pulses for 0 + + LDR r3,[r2] + ADDS r6,r6,r6 ; shift current bit into Carry + LDRCC r3,[r2] ; second pulse if bit is 0 + + ; repeat until upper 4 bits are sent + + ADDS r5,r5,r5 + BCC ts_send_tbit_upper + + ; then send the interface control bits + + LDR r1,%57 + ADD pc,pc,r0 +57 + & (8 :SHL: 28) ; assert RS control pin + +ts_send_cbit_upper + + ; wait for the inter-bit time + + LDR r3,%58 + ADD pc,pc,r0 +58 + & ts_recover_time +59 ADDS r3,r3,r3 ; 16-loop delay + BCC %59 + + ; Send a single bit : 1 pulse for 1, 2 pulses for 0 + + LDR r3,[r2] + ADDS r1,r1,r1 ; shift current bit into Carry + LDRCC r3,[r2] ; second pulse if bit is 0 + ADDS r5,r5,r5 + BCC ts_send_cbit_upper + +; +; do a RD operation to strobe the data out +; + + LDR r3,%61 + ADD pc,pc,r0 +61 + & ts_recover_time +62 ADDS r3,r3,r3 ; 16-loop delay + BCC %62 + + LDR r5,%63 + ADD pc,pc,r0 +63 + & (1 :SHL: (32 - 12)) +64 + LDR r3,[r2] + ADDS r5,r5,r5 + BCC %64 + + ; prepare to send the lower 4 bits out + + LDR r5,%70 ; bitcount mask for 4 data bits + ADD pc,pc,r0 ; and 4 interface control bits +70 + & (((1 :SHL: 4) + 1) :SHL: 24) + +ts_send_text_lower + LDR r3,%71 + ADD pc,pc,r0 +71 + & ts_recover_time +72 ADDS r3,r3,r3 ; 16-loop delay + BCC %72 + + LDR r1,%73 + ADD pc,pc,r0 +73 + & (-1) + + LDR r3,[r2] ; Test for adapter ready for data + ADDS r3,r3,r1 ; (adapter detects WS operation) + LDR r3,[r2] + ADDS r3,r3,r1 + LDR r3,[r2] + ADDS r3,r3,r1 + BCC ts_send_text_lower ; loop back until adapter is ready + +ts_send_tbit_lower + + ; wait for the inter-bit time + + LDR r3,%76 + ADD pc,pc,r0 +76 + & ts_recover_time +77 ADDS r3,r3,r3 ; 16-loop delay + BCC %77 + + ; Send a single bit : 1 pulse for 1, 2 pulses for 0 + + LDR r3,[r2] + ADDS r6,r6,r6 ; shift current bit into Carry + LDRCC r3,[r2] ; second pulse if bit is 0 + + ; repeat until lower 4 bits are sent + + ADDS r5,r5,r5 + BCC ts_send_tbit_lower + + + ; then send the interface control bits + + LDR r1,%78 + ADD pc,pc,r0 +78 + & (8 :SHL: 28) ; assert RS control pin + +ts_send_cbit_lower + + ; wait for the inter-bit time + + LDR r3,%80 + ADD pc,pc,r0 +80 + & ts_recover_time +81 ADDS r3,r3,r3 ; 16-loop delay + BCC %81 + + ; Send a single bit : 1 pulse for 1, 2 pulses for 0 + + LDR r3,[r2] + ADDS r1,r1,r1 ; shift current bit into Carry + LDRCC r3,[r2] ; second pulse if bit is 0 + + ADDS r5,r5,r5 + BCC ts_send_cbit_lower + +; +; do a RD operation to strobe the data out +; + + ; wait for the inter-bit time + + LDR r3,%82 + ADD pc,pc,r0 +82 + & ts_recover_time +83 ADDS r3,r3,r3 ; 16-loop delay + BCC %83 + + LDR r5,%84 + ADD pc,pc,r0 +84 + & 1 :SHL: (32 - 12) +85 + LDR r3,[r2] + ADDS r5,r5,r5 + BCC %85 + +; Repeat for all the bytes to be sent (until nul terminator is found) + + LDR r3,%86 + ADD pc,pc,r0 +86 + & 1 + ADDS r4,r3,r4 ; bump text pointer + B ts_send_text_byte + +; +; Wait for about 1 seconds worth of LCD operation delays to +; permit the operator to read the text. +; Use of the interface's monitor allows this delay to be increased +; or decreased externally. +; + +ts_SendEnd ROUT + + LDR r7, %01 + ADD pc,pc,r0 +01 + & (ts_pause_time + 1) ; must be an odd number + ; to ensure pairs of zeros + ASSERT ((ts_pause_time :AND: 1) = 0) + +02 + LDR r3,%03 + ADD pc,pc,r0 +03 + & ts_recover_time +04 ADDS r3,r3,r3 ; 16-loop delay + BCC %04 + LDR r1,%05 ; reload test register + ADD pc,pc,r0 +05 + & (-1) + + LDR r3,[r2] ; Test for adapter ready for data + ADDS r3,r3,r1 ; (adapter detects WS operation) + BCC ts_SendQuit ; skip output : adapter not present + LDR r3,[r2] + ADDS r3,r3,r1 + LDR r3,[r2] + ADDS r3,r3,r1 + BCC %02 ; loop back until adapter is ready + +; Adapter ready - loop around all the bits in the byte +; Note that each byte is actually 4 bits to the LCD module, +; so a even number must be sent or the display will get out +; of sync until the next display reset sequence. + + LDR r5,%10 ; bits-per-byte counter + ADD pc,pc,r0 +10 + & (1 :SHL: 24) + LDR r3,%11 + ADD pc,pc,r0 +11 + & ts_recover_time ; wait before sending data bits +12 ADDS r3,r3,r3 ; for byte timing. + BCC %12 + + ; Send a single bit : always 2 pulses for 0 + +13 LDR r3,[r2] + LDR r3,[r2] + + ; and wait for the inter-bit time + + LDR r3,%14 + ADD pc,pc,r0 +14 + & ts_recover_time +15 ADDS r3,r3,r3 ; 16-loop delay + BCC %15 + + ; repeat until 8 bits are sent + + ADDS r5,r5,r5 + BCC %13 + + ; do a RD operation to strobe the data out + + LDR r5,%16 + ADD pc,pc,r0 +16 + & 1 :SHL: (32 - 12) +17 + LDR r3,[r2] + ADDS r5,r5,r5 + BCC %17 + + ; repeat until a sufficient number of nuls are done + + ADDS r7,r7,r1 ; count down loop counter + BCS %02 + + ADD pc,r0,r14 ; back to caller + + + END diff --git a/TestSrc/Ioc b/TestSrc/Ioc new file mode 100644 index 0000000000000000000000000000000000000000..1c37914c8beb0bb94e4ea6804cef835ca2da3370 --- /dev/null +++ b/TestSrc/Ioc @@ -0,0 +1,102 @@ +; > TestSrc.IOC + + TTL RISC OS 2+ POST IO controller +; +; This initial IOC test simply reports the content of the IRQ and FIRQ +; registers, to show any unexpected pending IRQs. +; Certain of these should really be cleared, and the effect of an +; interrupt tested. +; +;------------------------------------------------------------------------ +; History +; +; Date Name Comment +; ---- ---- ------- +; 18-Dec-89 ArtG Initial version +; 29-Nov-91 ArtG Added IOC bus test using mask registers +; 20-Jun-93 ArtG Modified for 29-bit IOMD test +; 18-Nov-94 RCM Morris changes +; +; +;------------------------------------------------------------------------ + + [ IO_Type = "IOMD" +ts_IObase * IOMD_Base +ts_IOmask * &00fffff0 ;&1fffffff +ts_IOreg1 * IOMD_VIDEND ;IOMD_VIDCUR +ts_IOreg2 * IOMD_VIDSTART +ts_IObswap * 32 +ts_IOMD_ID * &D4E7 + [ MorrisSupport +ts_IOMD_IDmorris * &5B98 + ] + | +ts_IObase * IOC +ts_IOmask * &ff0000 +ts_IOreg1 * IOCIRQMSKA +ts_IOreg2 * IOCIRQMSKB +ts_IObswap * 16 + ] + +ts_IOCreg + MOV r0,#0 ; zero error accumulator + LDR r3, =ts_IObase + MOV r1,#(1 :SHL: 31) ; initialise bit-set test mask +0 + MVN r2,r1 ; make bit-clear test mask + LDR r4, =ts_IOmask + ANDS r4,r1,r4 + BEQ %FT1 ; skip if this bit isn't tested + STR r1,[r3,#ts_IOreg1] + STR r2,[r3,#ts_IOreg2] + LDR r4,[r3,#ts_IOreg1] +; EOR r4, r4, r1, LSR #ts_IObswap ; check bit-set test was OK + EOR r4, r4, r1 ; check bit-set test was OK + ORR r0, r0, r4 ; accumulate errors in r0 + LDR r4,[r3,#ts_IOreg2] +; EOR r4, r4, r2, LSR #ts_IObswap ; check bit-clear test was OK + EOR r4, r4, r2 ; check bit-clear test was OK + ORR r0, r0, r4 ; accumulate errors in r0 +1 + MOV r1, r1, LSR #1 ; shift mask downwards + TEQ r1,#0 + BNE %BT0 ; and loop until all bits tested + + LDR r8, =ts_IOmask + ANDS r8, r0, r8 + MOV pc,r14 ; return error if any bit failed + +ts_IOCstat + LDR r3, =ts_IObase + MOV r0,#0 + [ IO_Type = "IOMD" + LDRB r1,[r3,#IOMD_ID1] + ORR r0,r0,r1, LSL #(32-24) + LDRB r1,[r3,#IOMD_ID0] + ORR r0,r0,r1 + LDR r1,=ts_IOMD_ID + CMPS r0,r1 ; check IOMD identity + [ MorrisSupport + LDRNE r1,=ts_IOMD_IDmorris ; allow for Morris variant + CMPNES r0,r1 + ] + MOV r0,r0,LSL #16 + LDRB r1,[r3,#IOMD_VERSION] + ORR r8,r0,r1, LSL #12 + MOV pc,r14 + | + LDRB r1,[r3,#IOCControl] + ORR r0,r0,r1, LSL #(32 - 8) + LDRB r1,[r3,#IOCIRQSTAA] + ORR r0,r0,r1, LSL #(32 - 16) + LDRB r1,[r3,#IOCIRQSTAB] + ORR r0,r0,r1, LSL #(32 - 24) + LDRB r1,[r3,#IOCFIQSTA] + ORR r8,r0,r1 + ANDS r1,r1,#0 ; return zero flag (OK) + + MOV pc,r14 + ] + + END + diff --git a/TestSrc/MEMC1 b/TestSrc/MEMC1 new file mode 100644 index 0000000000000000000000000000000000000000..847df36843534aee6f4bee0f4244300f5e4bff17 --- /dev/null +++ b/TestSrc/MEMC1 @@ -0,0 +1,552 @@ +; > MEMC1 + +; MEMC interface file - MEMC1 version + +; Created by TMD 10-Aug-90 + +VInit * &03600000 +VStart * &03620000 +VEnd * &03640000 +CInit * &03660000 +; SStart * &03680000 +; SEnd * &036A0000 +; SPtr * &036C0000 + +; ***************************************************************************** +; +; SetDAG - Program DMA address generator R1 with physical address R0 +; +; in: r0 = physical address +; r1 = index of DMA address generator to program, as defined in vdudecl +; +; out: All registers preserved, operation ignored if illegal +; + + [ {FALSE} +SetDAG ENTRY "r0" + CMP r1, #MEMCDAG_MaxReason + EXIT HI + ADR r14, DAGAddressTable + LDR r14, [r14, r1, LSL #2] ; load base address in MEMC1 + MOV r0, r0, LSR #4 ; bottom 4 bits irrelevant + CMP r0, #(1 :SHL: 15) ; ensure in range + ORRCC r14, r14, r0, LSL #2 + STRCC r14, [r14] ; any old data will do + EXIT + + GBLA DAGIndex +DAGIndex SETA 0 + + MACRO + DAGTab $reason, $address + ASSERT ($reason)=DAGIndex + & $address +DAGIndex SETA DAGIndex + 1 + MEND + +DAGAddressTable + DAGTab MEMCDAG_VInit, VInit + DAGTab MEMCDAG_VStart, VStart + DAGTab MEMCDAG_VEnd, VEnd + DAGTab MEMCDAG_CInit, CInit + ] +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; CAM manipulation utility routines + +BangCamUpdate ROUT + +; R2 = CAM entry no +; R3 = logaddr +; R9 = current MEMC value +; R11 = PPL +; set and update tables + + MOV R4, #0 + LDR R4, [R4, #CamEntriesPointer] + ORR r0, r3, r11, LSL #28 ; top nibble is PPL + STR r0, [R4, R2, LSL #2] + +BangCam + +; r0 corrupted +; r1 corrupted +; R2 = CAM entry no +; R3 = logaddr +; r4 corrupted +; r5 spare! +; r6 corrupted +; r7, r8 spare +; R9 = current MEMC value +; r10 spare +; R11 = PPL +; r12 spare + + AND R4, R9, #&C ; pagesize + ADR R0, PageMangleTable + LDR R0, [R0, R4] ; load data table pointer + MOV R4, #0 +01 LDR R1, [R0], #4 + CMP R1, #-1 + BEQ %FT02 + AND R6, R2, R1 + LDR R1, [R0], #4 + CMP R1, #0 + RSBMI R1, R1, #0 + ORRPL R4, R4, R6, LSL R1 + ORRMI R4, R4, R6, LSR R1 + B %BT01 + +02 LDR R1, [R0], #4 + CMP R1, #-1 + BEQ %FT03 + AND R6, R3, R1 + LDR R1, [R0], #4 + CMP R1, #0 + RSBMI R1, R1, #0 + ORRPL R4, R4, R6, LSL R1 + ORRMI R4, R4, R6, LSR R1 + B %BT02 + +03 ORR R4, R4, #CAM + ORR R4, R4, R11, LSL #8 ; stuff in PPL + STR R4, [R4] ; and write it + MOV PC, LR + +; Data to drive CAM setting + +PageMangleTable + & PageMangle4K + & PageMangle8K + & PageMangle16K + & PageMangle32K + +; For each page size, pairs of masks and shift factors to put the bits in the +; right place. Two sets: operations on Physical Page Number, operations on +; Logical Page Number. + +; Shifts are Shift Left values (<<). Each section terminated by -1 + +PageMangle4K +; PPN: + & 2_011111111 + & 0 ; bits in right place + & -1 +; LPN: + & 2_1100000000000:SHL:12 + & (11-12)-12 ; LPN[12:11] -> A[11:10] + & 2_0011111111111:SHL:12 + & (22-10)-12 ; LPN[10:0 ] -> A[22:12] + & -1 + +PageMangle8K +; PPN: + & 2_010000000 + & 7-7 ; PPN[7] -> A[7] + & 2_001000000 + & 0-6 ; PPN[6] -> A[0] + & 2_000111111 + & 6-5 ; PPN[5:0] -> A[6:1] + & -1 +; LPN: + & 2_110000000000:SHL:13 + & (11-11)-13 ; LPN[11:10] -> A[11:10] + & 2_001111111111:SHL:13 + & (22-9)-13 ; LPN[9:0] -> A[22:13] + & -1 + +PageMangle16K +; PPN: + & 2_010000000 + & 7-7 ; PPN[7] -> A[7] + & 2_001100000 + & 1-6 ; PPN[6:5] -> A[1:0] + & 2_000011111 + & 6-4 ; PPN[4:0] -> A[6:2] + & -1 +; LPN: + & 2_11000000000:SHL:14 + & (11-10)-14 ; LPN[10:9] -> A[11:10] + & 2_00111111111:SHL:14 + & (22-8)-14 ; LPN[8:0] -> A[22:14] + & -1 + +PageMangle32K +; PPN: + & 2_100000000 + & 12-8 ; PPN[8] -> A[12] + & 2_010000000 + & 7-7 ; PPN[7] -> A[7] + & 2_001000000 + & 1-6 ; PPN[6] -> A[1] + & 2_000100000 + & 2-5 ; PPN[5] -> A[2] + & 2_000010000 + & 0-4 ; PPN[4] -> A[0] + & 2_000001111 + & 6-3 ; PPN[3:0] -> A[6:3] + & -1 +; LPN: + & 2_1100000000:SHL:15 + & (11-9)-15 ; LPN[9:8] -> A[11:10] + & 2_0011111111:SHL:15 + & (22-7)-15 ; LPN[7:0] -> A[22:15] + & -1 + +PageSizes + & 4*1024 ; 0 is 4K + & 8*1024 ; 4 is 8K + & 16*1024 ; 8 is 16 + & 32*1024 ; C is 32 + +PageShifts + = 12, 13, 0, 14 ; 1 2 3 4 + = 0, 0, 0, 15 ; 5 6 7 8 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_UpdateMEMC: Read/write MEMC1 control register + +SSETMEMC ROUT + + AND r10, r0, r1 + MOV r12, #0 + TEQP pc, #SVC_mode+I_bit+F_bit + LDR r0, [r12, #MEMC_CR_SoftCopy] ; return old value + BIC r11, r0, r1 + ORR r11, r11, R10 + BIC r11, r11, #&FF000000 + BIC r11, r11, #&00F00000 + ORR r11, r11, #MEMCADR + STR r11, [r12, #MEMC_CR_SoftCopy] + STR r11, [r11] + TEQP pc, #SVC_mode+I_bit + ExitSWIHandler + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; ClearPhysRAM - Routine to clear "all" memory +; +; While this routine is running, keyboard IRQs may happen. For this reason +; it avoids LogRAM 0..31 (where hardware IRQ vector is) and PhysRAM +; 0..31 where the IRQ workspace is. +; + +ClearPhysRAM ROUT + MOV R0, #0 + MOV R1, #0 + MOV R2, #0 + MOV R3, #0 + MOV R4, #0 + MOV R5, #0 + MOV R6, #0 + MOV R11, #0 + MOV R8, #PhysRam + CMP R13, #512*1024 + ADDEQ R10, R8, #(512-64)*1024 ; get address that's logram 0 + ADDNE R10, R8, #512*1024 + ADD R13, R13, #PhysRam ; end of memory + ADD R8, R8, #4*8 ; skip minimal startup workspace +10 CMP R8, R10 + ADDEQ R8, R8, #4*8 ; skip physram that's logram 0 + STMNEIA R8!, {R0-R6, r11} + CMP R8, R13 + BNE %BT10 + SUB R13, R13, #PhysRam + + LDR R0, =OsbyteVars + :INDEX: LastBREAK + MOV R1, #&80 + STRB R1, [R0] ; flag the fact that RAM cleared + MOV pc, lr + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; InitMEMC - Initialise memory controller +; + +InitMEMC ROUT + LDR R0, ResetMemC_Value + STR R0, [R0] ; set ROM access times, refresh on flyback, no DMA + MOV pc, lr + +; -> MemSize + +; (non-destructive) algorithm to determine MEMC RAM configuration +; +; Dave Flynn and Alasdair Thomas +; 17-March-87 +; +; Spooling checkered by NRaine and SSwales ! +; 8MByte check bodged in by APT +; +; NOTE: Routines MemSize and TimeCPU are called by the power-on test software, +; so their specifications MUST not change. +; +; Set MEMC for 32-k page then analyse signature of possible +; external RAM configurations... +; The configurations are: +; +; Ram Size Page Size Configuration (Phys RAM) Signature +;-------------------------------------------------------------------- +; 16MByte 32k 4*32*1Mx1 A13,A20,A21,A22,A23,A23.5 distinct +; 16MByte 32k 16*8*256kx4 A13,A20,A21,A22,A23,A23.5 distinct +; +; 12MByte 32k 3*32*1Mx1 A13,A20,A21,A22,A23 OK, A23.5 fail +; 12MByte 32k 12*8*256kx4 A13,A20,A21,A22,A23 OK, A23.5 fail +; +; 8MByte 32k 2*32*1Mx1 A13,A20,A21,A22 distinct, A23 fail +; 8MByte 32k 8*8*256kx4 A13,A20,A21,A22 distinct, A23 fail +; +; 4Mbyte 32k 32*1Mx1 A13,A21,A20 distinct, A22,A23 fail +; 4Mbyte 32k 4*8*256kx4 A13,A21,A20 distinct, A22,A23 fail +; +; 2Mbyte 32k expandable 2*8*256kx4 A13,A20 distinct, A21 fails +; 2Mbyte ??? 16k fixed 2*8*256kx4 A13,A21 distinct, A20 fails +; +; 1Mbyte 8k 32*256kx1 A13,A20 fail, A19,A18,A12 distinct +; 1Mbyte 8k 8*256kx1 A13,A20 fail, A19,A18,A12 distinct +; 1Mbyte 8k 4*8*64kx4 A13,A20 fail, A19,A18,A12 distinct +; +; 512Kbyte 8k expandable 2*8*64kx4 A13,A20,A19 fail, A12,A18 distinct +; 512Kbyte 4k fixed 2*8*64kx4 A13,A20,A12 fail, A19,A18 distinct +; +; 256Kbyte 4K 8*64kx4 A13,A20,A12,A18 fail, A21,A19 ok +; 256Kbyte 4K 32*64kx1 A13,A20,A12,A18 fail, A21,A19 ok +; + +Z_Flag * &40000000 + +; MemSize routine... enter with 32K pagesize set +; R0 returns page size +; R1 returns memory size +; R2 returns value set in MEMC +; uses R3-R7 + +MemSize ROUT + MOV r7, lr + MOV r0, #PhysRam + ADD r1, r0, #A13 + BL DistinctAddresses + BNE %10 + ADD r1, r0, #A21 + BL DistinctAddresses + MOVNE r0, #Page32K + MOVNE r1, #2048*1024 + BNE MemSizeDone + + MOV r0, #PhysRam + ADD r1, r0, #4*1024*1024 + BL DistinctAddresses + MOVNE r0, #Page32K + MOVNE r1, #4*1024*1024 + BNE MemSizeDone + + MOV r0, #PhysRam + ADD r1, r0, #8*1024*1024 + BL DistinctAddresses + MOVNE r0, #Page32K + MOVNE r1, #8*1024*1024 + BNE MemSizeDone + + MOV r0, #PhysRam + ADD r1, r0, #12*1024*1024 + BL DistinctAddresses + MOV r0, #Page32K + MOVNE r1, #12*1024*1024 + MOVEQ r1, #16*1024*1024 + B MemSizeDone + +10 ADD r1, r0, #A20 + BL DistinctAddresses + BNE %20 + MOV r0, #Page16K + MOV r1, #2048*1024 + B MemSizeDone + +20 ADD r1, r0, #A19 + BL DistinctAddresses + BEQ %30 + MOV r0, #Page8K + MOV r1, #512*1024 + B MemSizeDone + +30 ADD r1, r0, #A18 + BL DistinctAddresses + BEQ %40 + MOV r0, #Page4K + MOV r1, #256*1024 + B MemSizeDone + +40 ADD r1, r0, #A12 + BL DistinctAddresses + BEQ %50 + MOV r0, #Page4K + MOV r1, #512*1024 + B MemSizeDone + +50 MOV r0, #Page8K + MOV r1, #1024*1024 + +MemSizeDone + LDR r2, ResetMemC_Value + BIC r2, r2, #&C + ORR r2, r2, r0 + STR r2, [r2] ; set MEMC to right state + MOV pc, r7 + + +; DistinctAddresses routine... +; r0,r1 are the addresses to check +; uses r2-5 +; writes interleaved patterns (to prevent dynamic storage...) +; checks writing every bit low and high... +; return Z-flag set if distinct + +DistinctAddresses ROUT + LDR r2, [r0] ; preserve + LDR r3, [r1] + LDR r4, Pattern + STR r4, [r0] ; mark first + MOV r5, r4, ROR #16 + STR r5, [r1] ; mark second + LDR r5, [r0] + CMP r5, r4 ; check first + BNE %10 ; exit with Z clear + LDR r5, [r1] ; check second + CMP r5, r4, ROR #16 ; clear Z if not same + BNE %10 +; now check inverse bit writes + STR r4, [r1] ; mark second + MOV r5, r4, ROR #16 + STR r5, [r0] ; mark first + LDR r5, [r1] + CMP r5, r4 ; check second + BNE %10 ; exit with Z clear + LDR r5, [r0] ; check first + CMP r5, r4, ROR #16 ; clear Z if not same +10 STR r3, [r1] ; restore + STR r2, [r0] + ORREQ lr, lr, #Z_Flag + BICNE lr, lr, #Z_Flag + MOVS pc, lr + +Pattern + & &AAFF5500 ; shiftable bit check pattern + +; init state with masked out page size + +ResetMemC_Value + & &E010C :OR: MEMCADR ; slugged ROMs + flyback refresh only + 32K page + +; Constants +; +A21 * 1:SHL:21 +A20 * 1:SHL:20 +A19 * 1:SHL:19 +A18 * 1:SHL:18 +A13 * 1:SHL:13 +A12 * 1:SHL:12 + +Page32K * &C ; in MEMC control reg patterns... +Page16K * &8 +Page8K * &4 +Page4K * &0 + + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r0-r6 trashable +; r9 = Current MEMC CR + +; Out r9 MEMC value with slowest ROM speed, correct pagesize +; r7 processor speed in kHz, tbs -> MEMC1a + +ncpuloops * 1024 ; don't go longer than 4ms without refresh ! +nmulloops * 128 + +TimeCPU ROUT + + BIC r9, r9, #3 :SHL: 8 + STR r9, [r9] ; turn off refresh for a bit + +; Time CPU/Memory speed + + LDR r1, =&7FFE ; 32K @ 2MHz = ~16ms limit + MOV r3, #IOC + + MOV r0, r1, LSR #8 + STRB r1, [r3, #Timer1LL] + STRB r0, [r3, #Timer1LH] + LDR r0, =ncpuloops + STRB r0, [r3, #Timer1GO] ; start the timer NOW + B %FT10 ; Looks superfluous, but is required + ; to get ncpuloops pipeline breaks + +10 SUBS r0, r0, #1 ; 1S + BNE %BT10 ; 1N + 2S + + STRB r0, [r3, #Timer1LR] ; latch count NOW + LDRB r2, [r3, #Timer1CL] + LDRB r0, [r3, #Timer1CH] + ADD r2, r2, r0, LSL #8 ; count after looping is ... + + SUB r2, r1, r2 ; decrements ! + MOV r2, r2, LSR #1 ; IOC clock decrements at 2MHz + +; Time CPU/MEMC Multiply time + + MOV r4, #-1 ; Gives worst case MUL + + MOV r0, r1, LSR #8 + STRB r1, [r3, #Timer1LL] + STRB r0, [r3, #Timer1LH] + LDR r0, =nmulloops + STRB r0, [r3, #Timer1GO] ; start the timer NOW + B %FT20 ; Looks superfluous, but is required + ; to get nmulloops pipeline breaks + +20 MUL r5, r4, r4 ; 1S + 16I + MUL r5, r4, r4 ; 1S + 16I + SUBS r0, r0, #1 ; 1S + BNE %BT20 ; 1N + 2S + + STRB r0, [r3, #Timer1LR] ; latch count NOW + LDRB r4, [r3, #Timer1CL] + LDRB r0, [r3, #Timer1CH] + ADD r4, r4, r0, LSL #8 ; count after looping is ... + + SUB r4, r1, r4 ; decrements ! + MOV r4, r4, LSR #1 ; IOC clock decrements at 2MHz + + ORR r9, r9, #1 :SHL: 8 ; set refresh on flyback + STR r9, [r9] ; restore MEMC state a.s.a.p. + +; In ROM - each cpu loop took 4R cycles @ 8/f*500ns/cycle + + LDR r0, =4*(8*500/1000)*ncpuloops*1000 + DivRem r7, r0, r2, r1 ; r2 preserved + MOV r0, #&80 ; At 8 MHz and below, run fast ROMs + LDR r1, =8050 ; Over 8 MHz, need medium ROMs + CMP r7, r1 + MOVHI r0, #&40 + LDR r1, =13000 ; Over 13 MHz, need slowest ROMs + CMP r7, r1 + MOVHI r0, #&00 + ORR r9, r9, r0 + STR r9, [r9] ; Set ROM speed appropriately + + ASSERT ncpuloops = 8*nmulloops ; for given ratio cutoff <------------ + + MOV r4, r4, LSL #10 ; *1024 to get resolution on divide + DivRem r0, r4, r2, r1 + LDR r1, =1100 ; Cutoff point; MEMC1 longer than this + CMP r0, r1 + ORRLO r7, r7, #1 :SHL: 16 ; Note MEMC1a prescence + + MOV pc, lr + +; Typical figures give (in ROM at 8MHz): + +; MEMC1 2048 CPU, 2432 MEMC -> MUL ratio 1216 +; MEMC1a 2048 864 432 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + END diff --git a/TestSrc/Mem1IOMD b/TestSrc/Mem1IOMD new file mode 100644 index 0000000000000000000000000000000000000000..6b966bf72fdd9193df1ab31808623b2676687a75 --- /dev/null +++ b/TestSrc/Mem1IOMD @@ -0,0 +1,691 @@ +; > TestSrc.Mem1IOMD + + TTL RISC OS 2+ POST memory linetest +; +; This test code is used to perform basic integrity tests on DRAM. +; It doesn't test all locations - just walks patterns through data +; and address lines. +; +;------------------------------------------------------------------------ +; History +; +; Date Name Comment +; ---- ---- ------- +; 1-Jun-93 ArtG Derived from Mem1 for use on Medusa +; 18-Nov-94 RCM Morris changes +; +; +;------------------------------------------------------------------------ + +; +; Test the data and address and byte strobe lines for uniqueness. +; + + LTORG + ROUT + +1 + = "VRAM :",0 +2 + = "VRAM-F",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +3 + = "DRAM ",&ff,":",0 +4 + = "Data :",0 +5 + = &88,&ff,&ff," MByte",0 + + ALIGN + +ts_LineTest + [ MorrisSupport + MOV r12, #IOMD_Base + + LDRB r0, [r12, #IOMD_ID0] + CMP r0, #&98 + LDRB r0, [r12, #IOMD_ID1] + CMPEQ r0, #&5B + BNE ts_LineTestIOMD ; NOT MORRIS assume Medusa hardware + +; +; ts_LineTest for Morris +; + MOV r11, #IOMD_DRAMWID_DRAM_32bit * &0F ;set all 4 banks to be 32bit initially + MOV r14, #IOMD_Base + STRB r11, [r14, #IOMD_DRAMWID] + MOV r0,#MMUC_D ; enable 32-bit addressing of data + SetCop r0,CR_Control + + MOV r0,#0 + MOV_fiq r9,r0 ; r9-fiq records low DRAM address for use elsewhere + + MOV r10, #0 ;indicate no RAM found yet + MOV r9, #IOMD_DRAMWID_DRAM_16bit ;bit to OR into DRAMWID to set 16bit + MOV r12, #DRAM0PhysRam +; +; r12 DRAM address +; r9 IOMD_DRAMWID_DRAM_16bit for current DRAM bank +; r11 current IOMD_DRAMWID register contents +; +;ExamineDRAMBank ;examine first/next DRAM bank +2005 +; + MOV r8,r12,LSL #2 ; indicate bank under test + AND r8,r8,#(3 :SHL: 28) + ADR r4,%BT3 + BL ts_SendText +; + MOV r8,#0 ; r8 indicates RAM found in this bank + + LDMIA r12, {r1, r2} ;Preserve the two locations that we widdle on + + ADRL r3, funnypatterns ;We write different values to two locations + LDMIA r3, {r3, r4} ; incase bus capacitance holds our value + STMIA r12, {r3, r4} + LDMIA r12, {r5, r6} ;Reread test locations + EORS r5, r5, r3 ;Both locations should read correctly + EOR r6, r6, r4 ; if memory is 32bits wide + ;TEQ r5, #0 + TEQEQ r6, #0 + BEQ %FT2010 ;32bit wide memory + + TST r5, #&00FF ;If the bottom 16bits of each location + TSTEQ r5, #&FF00 ; are correct, the memory is 16bits wide + TSTEQ r6, #&00FF + TSTEQ r6, #&FF00 + BNE %FT2050 ;No memory in this bank + + ORR r11, r11, r9 ;Bank is 16bits wide +2010 + STMIA r12, {r1, r2} ;Restore the two locations we widdled on + ;Must do BEFORE poking the DRAMWID register + MOV r14, #IOMD_Base ; + STRB r11, [r14, #IOMD_DRAMWID] ; +; +; minimum ram test +; + MOV r0, r12 + ADD r1, r12, #A18 + BL DistinctAddresses + BNE %FT2050 ;Less than 512KBytes, so ignore this bank + + MOV_fiq r2,r9 ; if this is the first bank of DRAM or VRAM, + TEQS r2,#0 ; put it's address in r9_fiq + BNE %FT2012 + MOV_fiq r9,r0 +2012 + + + MOV r6, #0 ;Fragment address + MOV r7, #0 ;Fragment address + MOV r8, #A19 ; now go through address lines A19-A25 +2015 + MOV r0, r12 + ADD r1, r12, r8 ; see if this address line is unique + BL DistinctAddresses + BNE %FT2020 ; if we've failed then r8 is true size, so exit + MOV r8, r8, LSL #1 ; else shift up to next + TEQ r8, #A26 ; only test up to A25 + BNE %BT2015 + BEQ %FT2035 ;Bank fully occupied, DON'T test for higher fragments +2020 +; +; Found some DRAM, at address r0, size r8. +; There may be one or two higher address lines connected, so scan upto A25 looking for +; extra DRAM chunks. +; + MOV r1, r8 +2025 + TEQ r1, #A25 + BEQ %FT2035 ;No higher active address lines found ie one lump of DRAM + ADD r1, r0, r1,LSL #1 + BL DistinctAddresses + SUB r1, r1, r0 ;Recover bit value + BNE %BT2025 +; +; Got a 2nd fragment, at address r1 (also of size r8) +; + MOV r6, r1 +2030 + TEQ r1, #A25 + BEQ %FT2035 ;No higher active address lines found ie two lumps of DRAM + ADD r1, r0, r1,LSL #1 + BL DistinctAddresses + SUB r1, r1, r0 ;Recover bit value + BNE %BT2030 +; +; Got another active address line (ie total four fragments) +; + MOV r7, r1 +; +2035 +; +; Found 1, 2 or 4 lumps of DRAM +; +;NoRamInBank +2050 + MOV r13, r8 + TEQ r6, #0 + MOVNE r13, r13, LSL #1 + TEQNE r7, #0 + MOVNE r13, r13, LSL #1 ; remember size of this bank in bytes + MOV r8,r13,LSL #(24 - 20) ; and display it in 2 digits, in MBytes. + ADR r4,%BT5 + BL ts_MoreText + + + ADRL r4,%FT73 ; announce data line test + BL ts_SendText + MOV r1,r12 ; do walking bit test + BL ts_Dataline + BEQ %FT2055 ; looks OK, carry on to next bank + + ADRL r4,%FT74 ; bit test failed, so report it + MOV r8,r0 + BL ts_SendText ; and bit fault mask + + CMPS r13,#0 ; was any RAM thought to be here ? + BEQ %FT2055 + FAULT #R_LINFAILBIT ; if so, it's faulty. + MOV r13,#0 ; so ignore it +2055 +2055 +; +; If there was some RAM found here, and it passed the dataline test, +; do the address and bytestrobe tests on it too. +; + CMPS r13,#0 + BEQ %FT2060 + + ADRL r4,%FT75 ; announce start of address line test + BL ts_SendText + MOV r1,r12 ; test address lines in this block + MOV r0,r13, LSR #2 ; bank may be in 4 fragments + BL ts_Addrline + BEQ %FT2056 + ADRL r4,%FT76 ; failed - report error mask + MOV r8,r0 + BL ts_SendText + FAULT #R_LINFAILBIT ; and record failure + MOV r13,#0 ; then forget this memory block + +2056 + ADR r4,%FT77 ; announce start of byte test + BL ts_SendText + MOV r1,r12 + BL ts_Byteword + BEQ %FT2060 + ADR r4,%FT78 ; failed - report error mask + MOV r8,r0,LSL #16 + BL ts_SendText + FAULT #R_LINFAILBIT ; and record failure + MOV r13,#0 ; then forget this memory block +2060 + + +; If the RAM found still seems OK, add it's size into the r10 accumulator +; Working or not, carry on to check the next bank. + + ADD r10,r10,r13 ; accumulate DRAM if any found + ADD r12, r12, #DRAM1PhysRam-DRAM0PhysRam ; move onto next bank + MOV r9, r9, LSL #1 ; shunt up position in DRAMWID + CMP r9, #&0010 ; if more banks to do + BLT %BT2005 ; then loop + + ADR r4,%FT70 + BL ts_SendText ; None found .. print message + + MOVS r8,r10,LSL #(24 - 20) ; all finished .. + ADREQL r4,%FT71 ; did we find any DRAM? + ADRNEL r4,%FT72 + BNE %FT2065 + FAULT #R_LINFAILBIT ; fault if we didn't +2065 + BL ts_MoreText + B ts_endline + + + ] + +ts_LineTestIOMD + ADR r4,%BT1 + BL ts_SendText ; Start data line tests on VRAM + + MOV r0,#0 + MOV_fiq r9,r0 ; r9-fiq records VRAM or low DRAM address + + MOV r12, #IOMD_Base + MOV r2, #IOMD_VREFCR_VRAM_256Kx64 :OR: IOMD_VREFCR_REF_16 ; assume 2 banks of VRAM by default + STRB r2, [r12, #IOMD_VREFCR] + +; Find the size, using MemSize's method + + MOV r0, #VideoPhysRam ; point at VRAM + ADD r1, r0, #A2 ; test A2 + BL DistinctAddresses + MOVEQ r9, #2 ; we've got 2M of VRAM + BEQ %FT21 + + MOV r2, #IOMD_VREFCR_VRAM_256Kx32 :OR: IOMD_VREFCR_REF_16 + STRB r2, [r12, #IOMD_VREFCR] + ADD r1, r0, #A2 ; check for any VRAM at all + BL DistinctAddresses + MOVEQ r9, #1 ; we've got 1M of VRAM + MOVNE r9, #0 ; no VRAM +21 + BNE %FT22 + MOV_fiq r9,r0 ; record VRAM address + FAULT #R_VRAM ; indicate VRAM present + +; Report size .. if this is non-zero and the data line test fails, +; RISC OS will have problems. + +22 + ADR r4,%BT5 ; Add size (in hex Mbyte) + MOV r8,r9, LSL #24 ; to "VRam : " message + BL ts_MoreText + +; Worked out what size VRAM is, and set up IOMD register. +; Do a data line test on the resulting array, repeated at oddword address to +; ensure both banks get tested with walking 0 and walking 1 + + ADR r4,%BT4 + BL ts_SendText + MOV r1, #VideoPhysRam + BL ts_Dataline + ADDEQ r1,r1,#4 + BLEQ ts_Dataline + BEQ %FT25 ; looks OK - carry on with VRAM test +; +; Data line test failed. Report the bitmap that failed, then carry on. +; + ADR r4,%BT2 + MOV r8,r0 ; report data fault mask + BL ts_SendText + B %FT30 + +; +; If there was some VRAM found here, and it passed the dataline test, +; do the address and bytestrobe tests on it too. +; + +25 + ADRL r4,%FT75 ; announce start of address line test + BL ts_SendText + MOV r1,#VideoPhysRam + MOV r0,r9,LSL #20 ; size in MB determined before dataline test + BL ts_Addrline + BEQ %FT26 + ADRL r4,%FT76 ; failed - report error mask + MOV r8,r0 + BL ts_SendText + FAULT #R_LINFAILBIT ; and record failure + B %FT30 +26 + ADRL r4,%FT77 ; announce start of byte test + BL ts_SendText + MOV r1,#VideoPhysRam + BL ts_Byteword + ADDEQ r1,r1,#4 ; retest at an oddword boundary + BLEQ ts_Byteword + BEQ %FT27 + ADRL r4,%FT78 ; failed - report error mask + MOV r8,r0,LSL #16 + BL ts_SendText + FAULT #R_LINFAILBIT ; and record failure +27 + + +; Similarly, test each DRAM bank in turn, reporting failures or sizes for each + +30 + MOV r11, #IOMD_DRAMCR_DRAM_Large * &55 ; set all banks to be large initially + MOV r14, #IOMD_Base + STRB r11, [r14, #IOMD_DRAMCR] + MOV r0,#MMUC_D ; enable 32-bit addressing of data + SetCop r0,CR_Control + + MOV r10, #0 ; indicate no RAM found yet + MOV r9, #IOMD_DRAMCR_DRAM_Small ; bit to OR into DRAMCR + MOV r12, #DRAM0PhysRam +35 + MOV r8,r12,LSL #2 ; indicate bank under test + AND r8,r8,#(3 :SHL: 28) + ADRL r4,%BT3 + BL ts_SendText + + MOV r8,#0 ; r8 indicates RAM found in this bank + MOV r0, r12 + ADD r1, r12, #A10 ; this should be OK for both configurations + BL DistinctAddresses + BNE %FT50 ; [no RAM in this bank at all] + + MOV_fiq r2,r9 ; if this is the first bank of DRAM or VRAM, + TEQS r2,#0 ; put it's address in r9_fiq + BNE %FT36 + MOV_fiq r9,r0 + +36 ADD r1, r12, #A11 ; test for 256K DRAM + BL DistinctAddresses + ORRNE r11, r11, r9 ; it is, so select small multiplexing + MOVNE r14, #IOMD_Base + STRNEB r11, [r14, #IOMD_DRAMCR] ; store new value of DRAMCR, so we can use memory immediately + MOVNE r8, #1024*1024 ; must be 1Mbyte at this address + BNE %FT50 + +; it's bigger than 256K words, so test address lines A21-A25 in sequence +; we assume that the size of each bank is a power of 2 + + MOV r8, #A21 ; now go through address lines A21-A25 +40 + ADD r1, r12, r8 ; see if this address line is unique + BL DistinctAddresses + BNE %FT50 ; if we've failed then r8 is true size, so exit + MOV r8, r8, LSL #1 ; else shift up to next + TEQ r8, #A26 ; only test up to A25 + BNE %BT40 + +50 + MOV r13,r8 ; remember size of this bank in bytes + MOV r8,r13,LSL #(24 - 20) ; and display it in 2 digits, in MBytes. + ADRL r4,%BT5 + BL ts_MoreText + + ADRL r4,%FT73 ; announce data line test + BL ts_SendText + MOV r1,r12 ; do walking bit test + BL ts_Dataline + BEQ %FT55 ; looks OK, carry on to next bank + + ADRL r4,%FT74 ; bit test failed, so report it + MOV r8,r0 + BL ts_SendText ; and bit fault mask + + CMPS r13,#0 ; was any RAM thought to be here ? + BEQ %FT55 + FAULT #R_LINFAILBIT ; if so, it's faulty. + MOV r13,#0 ; so ignore it +55 + +; +; If there was some RAM found here, and it passed the dataline test, +; do the address and bytestrobe tests on it too. +; + CMPS r13,#0 + BEQ %FT60 + + ADR r4,%FT75 ; announce start of address line test + BL ts_SendText + MOV r1,r12 ; test address lines in this block + MOV r0,r13 + BL ts_Addrline + BEQ %FT56 + ADR r4,%FT76 ; failed - report error mask + MOV r8,r0 + BL ts_SendText + FAULT #R_LINFAILBIT ; and record failure + MOV r13,#0 ; then forget this memory block + +56 + ADR r4,%FT77 ; announce start of byte test + BL ts_SendText + MOV r1,r12 + BL ts_Byteword + BEQ %FT60 + ADR r4,%FT78 ; failed - report error mask + MOV r8,r0,LSL #16 + BL ts_SendText + FAULT #R_LINFAILBIT ; and record failure + MOV r13,#0 ; then forget this memory block +60 + + +; If the RAM found still seems OK, add it's size into the r10 accumulator +; Working or not, carry on to check the next bank. + + ADD r10,r10,r13 ; accumulate DRAM if any found + ADD r12, r12, #DRAM1PhysRam-DRAM0PhysRam ; move onto next bank + MOV r9, r9, LSL #2 ; shunt up position in DRAMCR + CMP r9, #&100 ; if more banks to do + BCC %BT35 ; then loop + + ADR r4,%FT70 + BL ts_SendText ; None found .. print message + + MOVS r8,r10,LSL #(24 - 20) ; all finished .. + ADREQ r4,%FT71 ; did we find any DRAM? + ADRNE r4,%FT72 + BNE %FT65 + FAULT #R_LINFAILBIT ; fault if we didn't +65 + BL ts_MoreText + B ts_endline + + +70 + = "DRAM",0 +71 + = &88,"Failed",0 +72 + = &88,&ff,&ff," MByte",0 +73 + = "Data :",0 +74 + = "Data-F",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +75 + = "Addrs :",0 +76 + = "Addrs-F",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +77 + = "Byte :",0 +78 + = "Byte-F",&88,&ff,&ff,&ff,&ff,0 + + +; +; Data line test. +; +; In : r1 - start address for test +; +; Out : r0 - failing data pattern +; r1 - address of failure +; +; +; This exercises data lines in attempt to find shorts/opens. +; It goes something like : +; +; for (ptr = address, pattern = 1; pattern != 0; pattern <<= 1) +; *ptr++ = pattern; +; *ptr++ = ~pattern; +; for (ptr = address, pattern = 1; pattern != 0; pattern <<= 1) +; result |= pattern ^ *ptr++; +; result |= ~pattern ^ *ptr++; +; return result and address +; + +ts_Dataline ROUT + +; +; Write all walking-zero, walking-one patterns +; +10 MOV r6,r1 ; set pointer for a write loop + MOV r5,#1 ; set initial test pattern + MVN r4,r5 ; and it's inverse +11 + STMIA r6!,{r4-r5} ; write the patterns + + ADDS r5,r5,r5 ; shift the pattern (into Carry) + MVN r4,r5 + BCC %BT11 ; repeat until all bits done +; +; Read back and accumulate in r0 any incorrect bits +; + MOV r6,r1 ; set pointer for a read loop + MOV r5,#1 ; set initial test pattern + MVN r4,r5 ; and it's inverse + MOV r0,#0 ; accumulate result +21 + LDMIA r6!,{r2-r3} ; read the patterns + EOR r2,r2,r4 + ORR r0,r0,r2 ; OR any failed bits into r0 + EOR r3,r3,r5 + ORR r0,r0,r2 + + ADDS r5,r5,r5 ; shift the pattern (into Carry) + MVN r4,r5 + BCC %BT21 ; repeat until all bits done +; +; After all checks at this address group, report back errors +; + MOVS r0,r0 ; check for any result bits set + MOV pc,r14 ; return r0 with error map (or 0) + + + +; +; Address line test +; +; In : r0 - size of memory block +; r1 - start address of memory block +; +; Out : r0 - failing address bit mask +; +; This exercises address lines in an attempt to find any which don't +; work (i.e., don't select unique addresses). +; +; It works something like : +; +; MaxRam = PhysRam | (Memory size - 4); +; for (pattern = 4; pattern < memsize; pattern <<= 1 ) +; *(PhysRam ^ pattern) = pattern; +; *(MaxRam ^ pattern) = ~pattern; +; for (pattern = 4; pattern < memsize; pattern <<= 1 ) +; if (*PhysRam == *(PhysRam ^ pattern)) +; result |= pattern; +; if (*MaxRam == *(MaxRam + pattern)) +; result |= pattern; +; return result +; + + +ts_Addrline ROUT + + MOVS r7,r0 ; Save memory size + SUB r6,r0,#4 ; Calculate MaxRam + ADD r6,r6,r1 ; (all-bits-set memory address) +; +; Mark (walking one, walking 0) addresses with unique patterns +; + LDR r5,=&5A5AA5A5 ; initialize end markers + STR r5,[r6] + MVN r4,r5 + MOV r3,r1 + STR r4,[r3] + + MOV r5,#4 ; initialize pattern +02 + MVN r4,r5 + EOR r3,r5,r1 ; point to (start ^ pattern) + STR r4,[r3] + EOR r3,r5,r6 ; point to (end ^ pattern) + STR r5,[r3] + + MOV r5,r5,LSL #1 ; shift test pattern up + CMPS r5,r7 ; test bit still inside memory ? + BCC %02 ; reached top bit - end this loop +; +; Check (walking one, walking 0) addresses for effectivity +; + MOV r5,#4 ; initialize pattern + MOV r3,r1 + MOV r0,#0 +04 + MVN r4,r5 + EOR r2,r5,r3 ; point to (start ^ pattern) + LDR r2,[r2] + LDR r1,[r3] + CMPS r1,r2 ; do contents differ ? + ORREQ r0,r0,r5 ; no - record ineffective bit + + EOR r2,r5,r6 ; point to (end ^ pattern) + LDR r2,[r2] + LDR r1,[r6] + CMPS r1,r2 ; do contents differ ? + ORREQ r0,r0,r5 ; no - record ineffective bit + + MOV r5,r5,LSL #1 ; shift test pattern up + CMPS r5,r7 ; test bit still inside memory ? + BCC %04 ; reached top bit - end this loop + + MOVS r0,r0 ; any result bits set - return error + MOV pc,r14 + + +; +; Byte / word test +; +; In : r1 - memory start +; +; Out : r0 - Failure indication +; +; This test ensures that individual bytes may be written to each part of a word +; without affecting the other bytes in the word. +; +; for (byte = 0; byte < 4; byte ++) +; address[0] = word_signature +; address[1] = ~word_signature +; address + byte = byte_signature +; if (address[0] != +; (word_signature & (~ff << byte * 8)) +; | (byte_signature << byte * 8) ) +; result |= (1 << byte) +; if (result != 0 +; result |= address; /* fail at address, byte(s) */ +; return result; /* pass */ +; + +ts_Byteword ROUT + + LDR r3,=&AABBCCDD ; word signature + MOV r0,#0 + MOV r2,r0 +; +; byte test loop ( for bytes 0 to 4 ...) +; +02 + MVN r4,r3 + STMIA r1,{r3,r4} ; write word signature + STRB r2,[r1,r2] ; write byte (0, 1, 2 or 3) + + MOV r4,r2,LSL #3 ; calculate expected result + MOV r5,#&ff + MVN r5,r5,LSL r4 + AND r5,r5,r3 ; word signature, byte removed + ORR r5,r5,r2,LSL r4 ; byte signature inserted + + LDR r4,[r1,#4] ; read (probable) inverse data to precharge bus + LDR r4,[r1] ; read modified word + CMPS r4,r5 + MOV r5,#1 + MOV r4,r2,LSL #2 + ORRNE r0,r0,r5,LSL r4 ; fault : set bit in result mask +; +; Loop for next byte +; + ADD r2,r2,#1 ; Bump byte counter + CMPS r2,#4 ; ... until 4 byte strobes tested + BLO %BT02 +; +; byte strobes all tested : check for errors +; + CMPS r0,#0 + MOV pc,r14 ; Result : return address and fault mask. + +; +; End of RAM line tests +; + +ts_endline + + END + \ No newline at end of file diff --git a/TestSrc/Mem1MEMC1 b/TestSrc/Mem1MEMC1 new file mode 100644 index 0000000000000000000000000000000000000000..632c9bf2b8e5b33faf87dc5ac37826a43174df3d --- /dev/null +++ b/TestSrc/Mem1MEMC1 @@ -0,0 +1,390 @@ +; > TestSrc.Mem1 + + TTL RISC OS 2+ POST memory linetest +; +; This test code is used to perform basic integrity tests on DRAM. +; It doesn't test all locations - just walks patterns through data +; and address lines. +; +;------------------------------------------------------------------------ +; History +; +; Date Name Comment +; ---- ---- ------- +; 18-Dec-89 ArtG Initial version +; 1-Jun-93 ArtG Reorganised to allow separate module for Medusa +; +; +;------------------------------------------------------------------------ + +; +; Test the data and address and byte strobe lines for uniqueness. +; + + LTORG + ROUT + +1 + = "Data :",0 +2 + = "Data @",&89,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +3 + = "Data-F",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +4 + = "Data-P",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 + + + + ALIGN + +ts_LineTest + + ADR r4,%BT1 + BL ts_SendText ; Start data line tests + + MOV_fiq r0,r10_fiq + MOV r1, #PhysRam + BL ts_Dataline + BEQ ts_address ; OK : continue to next test +; +; Data line test failed. This probably also means that RISCOS got the +; configuration wrong, so set it to 32K pages and repeat - otherwise +; the data line test result may be garbage. +; + ADR r4,%BT2 + MOV r11,r0 ; save data & report fault address + MOV r8,r1,LSL #4 + BL ts_SendText + + MOV r8,r11 + ADR r4,%BT3 ; report data fault mask + BL ts_SendText + + LDR r0,=(&E000C :OR: MEMCADR) ; set 32K page size + STR r0,[r0] + MOV_fiq r11_fiq,r0 + + MOV r0,#ts_RamChunk ; limit test to 1 block + MOV r1,#PhysRam + BL ts_Dataline + + MOV r8,r0 + ADR r4,%BT4 ; ready to report data fault mask + B ts_linefault + +; +; Start the address line tests +; + ROUT + +4 + = "Addrs :",0 +5 + = "Addrs",&89,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +6 + = "Byte :",0 +7 + = "Byte",&89,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 + + + +ts_address + ADR r4,%BT4 + BL ts_SendText ; Start address line tests + + MOV_fiq r0,r10_fiq + BL ts_Addrline + + ADR r4,%BT5 + MOV r8,r0,LSL #4 + BEQ %30 ; Failed : report address fault + +ts_linefault + FAULT #R_LINFAILBIT + B %31 + +30 ADR r4,%BT6 ; Start Byte/Word test + BL ts_SendText + + MOV_fiq r0,r10_fiq ; get memory size + BL ts_Byteword + + MOV r8,r0,LSL #4 ; Get result to top of r8 + BEQ %40 + FAULT #R_LINFAILBIT + + ADR r4,%BT7 + +31 BL ts_SendText + B %42 +; +; Line tests passed. Do a short test on memory that isn't there, +; in case it's supposed to be and we want to know why it's not .. + +40 + MOV_fiq r0, r10_fiq ; if there's less than 16Mbytes .. + CMP r0, #(16 * 1024 * 1024) + BCS %F42 + ADR r4, %FT44 ; briefly test the next bit of ram + BL ts_SendText ; in case it's a duff expansion + + MOV_fiq r1,r10_fiq + ADD r1,r1,#PhysRam + MOV r0,#ts_RamChunk + BL ts_Dataline + ADR r4, %FT45 + MOV r11, r0 ; report the result even if OK + MOV r8,r1,LSL #4 + BL ts_SendText ; report address + + MOV r8,r11 + ADR r4,%FT46 ; report data fault mask + BL ts_SendText +; +; End of line tests +; + +42 + B ts_IOCTest + +44 + = "Exp? :",0 +45 + = "Exp? @",&89,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +46 + = "Exp?",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 + + + +; +; Data line test. +; +; In : r0 - size of memory +; r1 - start address for test +; +; Out : r0 - failing data pattern +; r1 - address of failure +; +; +; This exercises data lines in attempt to find shorts/opens. +; It goes something like : +; +; for (address = start; address < end of ram; address += ts_RamChunk) +; for (ptr = address, pattern = 1; pattern != 0; pattern <<= 1) +; *ptr++ = pattern; +; *ptr++ = ~pattern; +; for (ptr = address, pattern = 1; pattern != 0; pattern <<= 1) +; result |= pattern ^ *ptr++; +; result |= ~pattern ^ *ptr++; +; if (result |= 0) +; return result and address +; + +ts_Dataline ROUT + + ADD r7,r1,r0 ; end address +; +; Write all walking-zero, walking-one patterns +; +10 MOV r6,r1 ; set pointer for a write loop + MOV r5,#1 ; set initial test pattern + MVN r4,r5 ; and it's inverse +11 + STMIA r6!,{r4-r5} ; write the patterns + + ADDS r5,r5,r5 ; shift the pattern (into Carry) + MVN r4,r5 + BCC %BT11 ; repeat until all bits done +; +; Read back and accumulate in r0 any incorrect bits +; + MOV r6,r1 ; set pointer for a read loop + MOV r5,#1 ; set initial test pattern + MVN r4,r5 ; and it's inverse + MOV r0,#0 ; accumulate result +21 + LDMIA r6!,{r2-r3} ; read the patterns + EOR r2,r2,r4 + ORR r0,r0,r2 ; OR any failed bits into r0 + EOR r3,r3,r5 + ORR r0,r0,r2 + + ADDS r5,r5,r5 ; shift the pattern (into Carry) + MVN r4,r5 + BCC %BT21 ; repeat until all bits done +; +; After all checks at this address group, report back errors +; + MOVS r0,r0 ; check for any result bits set + MOVNE pc,r14 ; return on error +; +; Bump to another address group +; + ADD r1,r1,#ts_RamChunk + CMPS r1,r7 ; test for loop end + BLO %10 + + SUBS r1,r1,#ts_RamChunk ; no fault - last tested address + MOVS r0,r0 + MOV pc,r14 ; test complete - no failures. + + +; +; Address line test +; +; In : r0 - size of memeory +; +; Out : r0 - failing address bit mask +; +; This exercises address lines in an attempt to find any which don't +; work (i.e., don't select unique addresses). +; +; It works something like : +; +; MaxRam = PhysRam | (Memory size - 4); +; for (pattern = 4; pattern < memsize; pattern <<= 1 ) +; *(PhysRam ^ pattern) = pattern; +; *(MaxRam ^ pattern) = ~pattern; +; for (pattern = 4; pattern < memsize; pattern <<= 1 ) +; if (*PhysRam == *(PhysRam ^ pattern)) +; result |= pattern; +; if (*MaxRam == *(MaxRam + pattern)) +; result |= pattern; +; return result +; + + +ts_Addrline ROUT + + MOVS r7,r0 ; Save memory size + SUB r6,r0,#4 ; Calculate MaxRam + ADD r6,r6,#PhysRam ; (all-bits-set memory address) +; +; Mark (walking one, walking 0) addresses with unique patterns +; + LDR r5,=&5A5AA5A5 ; initialize end markers + STR r5,[r6] + MVN r4,r5 + MOV r3,#PhysRam + STR r4,[r3] + + MOV r5,#4 ; initialize pattern +02 + MVN r4,r5 + EOR r3,r5,#PhysRam ; point to (start ^ pattern) + STR r4,[r3] + EOR r3,r5,r6 ; point to (end ^ pattern) + STR r5,[r3] + + MOV r5,r5,LSL #1 ; shift test pattern up + CMPS r5,r7 ; test bit still inside memory ? + BCC %02 ; reached top bit - end this loop +; +; Check (walking one, walking 0) addresses for effectivity +; + MOV r5,#4 ; initialize pattern + MOV r3,#PhysRam + MOV r0,#0 +04 + MVN r4,r5 + EOR r2,r5,r3 ; point to (start ^ pattern) + LDR r2,[r2] + LDR r1,[r3] + CMPS r1,r2 ; do contents differ ? + ORREQ r0,r0,r5 ; no - record ineffective bit + + EOR r2,r5,r6 ; point to (end ^ pattern) + LDR r2,[r2] + LDR r1,[r6] + CMPS r1,r2 ; do contents differ ? + ORREQ r0,r0,r5 ; no - record ineffective bit + + MOV r5,r5,LSL #1 ; shift test pattern up + CMPS r5,r7 ; test bit still inside memory ? + BCC %04 ; reached top bit - end this loop + + MOVS r0,r0 ; any result bits set - return error + MOV pc,r14 + + +; +; Byte / word test +; +; In : r0 - memory size +; +; Out : r0 - address of physical ram where failure occured +; +; This test ensures (for each of four possible MEMCs fitted) +; that individual bytes may be written to each part of a word +; without affecting the other bytes in the word. +; +; for (address = PhysRam; address < PhysRam + Memsize; address += 4Mbyte) +; for (byte = 0; byte < 4; byte ++) +; address[0] = word_signature +; address[1] = ~word_signature +; address + byte = byte_signature +; if (address[0] != +; (word_signature & (~ff << byte * 8)) +; | (byte_signature << byte * 8) ) +; result |= (1 << byte) +; if (result != 0 +; result |= address; /* fail at address, byte(s) */ +; return result; +; return result; /* pass */ +; + +ts_Byteword ROUT + + ADD r7,r0,#PhysRam ; Set test limit address + MOV r1,#PhysRam ; Initial test address + LDR r3,=&AABBCCDD ; word signature +; +; MEMC test loop (for addresses 4M, 8M, ...) +; +01 + MOV r0,#0 ; clear result register + MOV r2,#0 ; clear byte count +; +; byte test loop ( for bytes 0 to 4 ...) +; +02 + MVN r4,r3 + STMIA r1,{r3,r4} ; write word signature + STRB r2,[r1,r2] ; write byte + + MOV r4,r2,LSL #3 ; calculate expected result + MOV r5,#&ff + MVN r5,r5,LSL r4 + AND r5,r5,r3 ; word signature, byte removed + ORR r5,r5,r2,LSL r4 ; byte signature inserted + + LDR r4,[r1,#4] + LDR r4,[r1] ; read modified word + CMPS r4,r5 + MOV r5,#1 + ORRNE r0,r0,r5,LSL r2 ; fault : set bit in result mask +; +; Loop for next byte +; + ADD r2,r2,#1 ; Bump byte counter + CMPS r2,#4 ; ... until 4 byte strobes tested + BLO %BT02 +; +; byte strobes all tested : check for errors +; + CMPS r0,#0 + ORRNE r0,r0,r1 + MOVNE pc,r14 ; Error : return address and fault. +; +; Loop for next MEMC +; + ADD r1,r1,#&400000 ; Bump to next MEMC + CMPS r1,r7 + BLO %01 + + MOVS r0,#0 ; Passed - return OK + MOV pc,r14 + + + END + \ No newline at end of file diff --git a/TestSrc/Mem2 b/TestSrc/Mem2 new file mode 100644 index 0000000000000000000000000000000000000000..89f5bc2d3a13a7acf9b701c7cdf5a16209c3fec9 --- /dev/null +++ b/TestSrc/Mem2 @@ -0,0 +1,278 @@ +;> MEM2C +; +; RISC OS 2+ BOOT TEST SOFTWARE +; MEMORY TEST 2 VERSION A. +; BRIAN RICE 30-10-89 +; 06-Apr-90 ArtG 0.1 Test variable memory size +; +; This file will perform a simple test on all DRAM. +; The test code for this test was taken from thhe A680 Quick memory +; test software. The software was copied straight but the number of times +; the test looped arround was cut down to two loops, because of time +; constraints when testing the memory. + +Test_wks_msize * &40 ; Space for test block size +Test_wks_return1 * &44 ; Space for return addresses +Test_wks_return2 * &48 +Test_code_off * &4C ; Where testing starts + +test_size * 13 * 4 ; Size of test group +test_mem_rsvd * Test_code_off+test_mem_template_end-test_mem_template + +; +; Quick test the RAM (pre boot style) +; + +ts_RamTest ROUT + MOV r13,r0 + STR r14,[r13,#Test_wks_return1] + STR r1,[r13,#Test_wks_msize] + + LDR r0, test_quick_pattern + BL test_mem_code + ORRS r0,r0,r0 + BNE test_mem_quit +; + LDR r0, test_quick_pattern + MVN r0, r0 ; inverse pattern + BL test_mem_code + ORRS r0,r0,r0 + +test_mem_quit + ADR r12,%22 + BEQ %10 + +; If fault detected, exit with zero flag clear, r0 pointing to failing +; location, r1 containing faulty data and r2 pointing a suitable error +; message indicating whether all-0 or all-1 data was expected. + + LDR r2,[r14] ; fetch failing instructiom + ANDS r2,r2,#1 ; calculate expected data + ADREQ r12,%20 ; and load suitable message + ADRNE r12,%21 + MOVS r0,r0 ; with zero flag set for PASS. +10 + LDR pc,[r13,#Test_wks_return1] + +; Fail messages indicate incorrect data read after WRote 0 or Wrote 1 +; to all bits at that location. + +20 + = "WR-0 RD",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +21 + = "WR-1 RD",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 +22 + = "??",0 + + ALIGN + +test_quick_pattern & &0f76 + +; Large Memory test. Generates the write + test routines in memory +; then calls them. The routine tests patterns as defined by the bottom +; 13 bits of r0. +; +; N.B. The test start address must be calculated to ensure that +; the loops finish exactly with r0 equal to End_memory +; +; The routine returns with eq true if the memory is OK. + + +test_mem_code + ROUT + + STR r14, [r13, #Test_wks_return2] +; +; Copy the ram test code into low ram, modifying MOV instructions +; to MVN in accordance with the test pattern. +; + ADR r1, test_mem_template + ADD r2, r13, #Test_code_off + LDMIA r1!, {r3-r4} ; copy initial 2 instrucions + STMIA r2!, {r3-r4} + MOV r4, #1 +0 MOVS r0, r0, ROR #1 + LDR r3, [r1], #4 + ORRCS r3, r3, #&00400000 ; Convert MOV => MVN + STR r3, [r2], #4 + ADD r4, r4, #1 + CMP r4, #13 + BLE %B0 +; +; Copy the load loop control and verify start instructions +; + LDMIA r1!, {r5-r9} + STMIA r2!, {r5-r9} +; +; Copy and modify the CMP instructions +; + MOV r0, r0, ROR #32-13 + MOV r4, #1 +1 MOVS r0, r0, ROR #1 + LDR r3, [r1], #4 + ORRCS r3, r3, #&00200000 ; Convert CMP => cmn + ORRCS r3, r3, #&00000001 ; Convert #0 => #1 + STR r3, [r2], #4 + ADD r4, r4, #1 + CMP r4, #13 + BLE %B1 +; +; Copy the verify loop control and finishing-up instructions +; + LDMIA r1!, {r5-r12} + STMIA r2!, {r5-r12} + LDMIA r1!, {r5-r12} + STMIA r2!, {r5-r12} + LDMIA r1!, {r5-r12} + STMIA r2!, {r5-r12} + +; check we've copied enough + ASSERT ((test_mem_stadd - test_mem_chk) = (24 * 4)) +; +; Calculate the test start and end addresses +; + LDR r0, [r13, #Test_wks_msize] ; size of test area + ADD r14, r13, r0 ; end of test area + SUB r1, r0, #test_mem_rsvd ; testable size + + MOV r2, #test_size ; adjust r1 to (r1 / 13*4) * (13*4) + DivRem r3, r1, r2, r4 + MUL r1, r3, r2 + SUB r0, r14, r1 ; rounded test start address + +; Do it. + MOV r1, #Test_code_off + ADD r1, r1, r13 ; pointer to copied code + MOV pc, r1 + +; +; The following code is copied (and modified) into RAM for execution +; + +test_mem_template + ROUT + STR r0, test_mem_stadd ; save initial RAM address + STR r13, test_mem_base ; save test area base address + MOV r1, #0 ; Converted to MVN if bit = 1 + MOV r2, #0 ; Converted to MVN if bit = 1 + MOV r3, #0 ; Converted to MVN if bit = 1 + MOV r4, #0 ; Converted to MVN if bit = 1 + MOV r5, #0 ; Converted to MVN if bit = 1 + MOV r6, #0 ; Converted to MVN if bit = 1 + MOV r7, #0 ; Converted to MVN if bit = 1 + MOV r8, #0 ; Converted to MVN if bit = 1 + MOV r9, #0 ; Converted to MVN if bit = 1 + MOV r10, #0 ; Converted to MVN if bit = 1 + MOV r11, #0 ; Converted to MVN if bit = 1 + MOV r12, #0 ; Converted to MVN if bit = 1 + MOV r13, #0 ; Converted to MVN if bit = 1 +0 + STMIA r0!, {r1-r13} + CMP r0, r14 + BLO %B0 + + LDR r0, test_mem_stadd +1 + LDMIA r0!, {r1-r13} +2 + CMP r1, #0 ; Converted to cmn if bit = 1 + CMPEQ r2, #0 ; Converted to cmneq if bit = 1 + CMPEQ r3, #0 ; Converted to cmneq if bit = 1 + CMPEQ r4, #0 ; Converted to cmneq if bit = 1 + CMPEQ r5, #0 ; Converted to cmneq if bit = 1 + CMPEQ r6, #0 ; Converted to cmneq if bit = 1 + CMPEQ r7, #0 ; Converted to cmneq if bit = 1 + CMPEQ r8, #0 ; Converted to cmneq if bit = 1 + CMPEQ r9, #0 ; Converted to cmneq if bit = 1 + CMPEQ r10, #0 ; Converted to cmneq if bit = 1 + CMPEQ r11, #0 ; Converted to cmneq if bit = 1 + CMPEQ r12, #0 ; Converted to cmneq if bit = 1 + CMPEQ r13, #0 ; Converted to cmneq if bit = 1 +test_mem_chk + BNE %F5 ; go report fault data + CMP r0, r14 + BLO %B1 ; else loop for next batch + MOVS r0, #0 ; All OK : return with NULL r0 +4 + LDR r13,test_mem_base + LDR pc, [r13, #Test_wks_return2] + +; Failed : repeat the last batch of tests one at a time, to determine +; the first failing address and data. +; Note that the test instructions are copied to %8 to permit individual +; execution, and %7 is overwritten with an instruction used to copy +; the failing data into r1. Change this code very carefully ! + +5 + LDR r14,%2 ; Obtain first test in the set + STR r14,%8 ; and re-execute it + SUB r0,r0,#(13*4) ; adjust pointer to bad data + ADR r14,%2 ; point to first test. +7 + B %8 ; make sure %8 is refetched +8 + & 0 ; redo the test here : + BNE %4 ; if it failed, exit with + ; r0 = ptr to memory + ; r1 = wrongly read data + ; r14 => failing instruction + + LDR r1,[r14,#4]! ;fetch next instruction + AND r1,r1,#&f0000 ;make an instruction + MOV r1,r1,LSR #16 ;to copy the next register + ORR r1,r1,#&E1000000 ;down to r1 + ORR r1,r1,#&00A00000 ;e.g. CMPEQ r10,#0 + ORR r1,r1,#&00001000 + STR r1,%7 ;and put it at %7 + LDR r1,[r14] ;then copy the next test + STR r1,%8 ;to %8 + ADD r0,r0,#4 ;bump the fault pointer + B %7 ;and execute %7 and %8. + +test_mem_stadd ; address of first test location + & 0 +test_mem_base + & 0 ; address of test block + +test_mem_template_end + +; +; Copy the L2 page table from r1 to r0, then remap the translation table's +; base address in the MMU to point to an L1 page table within it. +; + ROUT + +ts_remap_ttab + MOV r2,#FixedAreasL2Size + ADD r0,r0,r2 ; point to locations in PhysSpace + ADD r0,r0,#PhysSpace + ADD r1,r1,r2 + ADD r1,r1,#PhysSpace +10 + ASSERT ((FixedAreasL2Size :AND: ((8*4)-1)) = 0) + LDMDB r1!,{r3-r10} ; copy the page & section tables + STMDB r0!,{r3-r10} + SUBS r2,r2,#(8*4) + BNE %BT10 + + SUB r9,r1,r0 ; r9 = offset from original to copy + ADD r0, r0, #DRAMOffset_L1PT-DRAMOffset_L2PT ; r0 -> copy of L1Phys + SUB r10, r0, #PhysSpace ; keep real address of L1PT for MMU + ADD r2,r0,#((1 :SHL: (32-20))*4) ; size of L1PT - 1 word per meg of memory +11 LDR r3,[r0],#4 ; check each L1 table entry + ANDS r4,r3,#3 + CMPS r4,#L1_Page ; if it's page mapped .. + SUBEQ r3,r3,r9 ; adjust the page table base address + STREQ r3,[r0,#-4] + CMPS r0,r2 ; repeat for all the level 1 table + BNE %BT11 + + SetCop r10, CR_TTabBase ; set up MMU pointer to L1 + SetCop r0, CR_IDCFlush ; flush cache + TLB just in case + SetCop r0, CR_TLBFlush ; (data written is irrelevant) + + MOV pc,r14 + + + END + diff --git a/TestSrc/Mem3 b/TestSrc/Mem3 new file mode 100644 index 0000000000000000000000000000000000000000..1313275f4a55e6f7eb344e50900cdd97407b5f33 --- /dev/null +++ b/TestSrc/Mem3 @@ -0,0 +1,119 @@ + ;> RomCheck +; +; RISC OS 2+ BOOT TEST SOFTWARE +; MEMORY TEST 3 VERSION A. +; BRIAN RICE 01-11-89 +; 24.04.90 0.10 ArtG Added ROM size test +; 15.05.90 1.00 ArtG Changed to put checksum at (end - 2 words) +; 17.05.90 1.01 ArtG Changed to get ROM length from vectot table +; +; +; This file will perform quick checksum test on the OS ROMS. +; +; +; The test code for this test is a simple additive checksum routine. +; The software will read eight words from ROM then add the contents from ROM +; to a register. When the test is complete the contents of the checksum +; register is checked by adding the final word in ROM - this should give +; zero. +; The program will be run from ROM, at slowest speed. +; +; All except the last two words are checksummed : these hold the numbers +; that cause each individual ROM to CRC to zero, so they can't simultaneously +; be included in an all-zero additive checksum. + +ts_CRCsize * (2 * 4) + +; +; +;r0 IS A POINTER TO THE LOCATIONS IN MEMORY. +;r1 HAS THE CALCULATED CHECKSUM. +;r2 HOLDS A COUNTER INDICATION HOW MANY WORDS ARE LEFT TO GET +;r3 is a temporary variable +;r4 TO r11 ARE USED TO LOAD THE CONTENTS OF 8 LOCATIONS FROM THE ROM. +; + ROUT + +ts_ROM_checksum + + MOV r1, #&00 ; initialise accumulator + LDR r0, =PhysROM ; initialise pointer + LDR r2, [r0, #ts_ROMSIZE] ; initialise endstop + ADD r2, r2, r0 ; - must be at least 8 words + SUB r2, r2, #(10 * 4) ; below the real endpoint + +loop1 LDMIA r0!, {r4 - r11} ;LOAD r4 TO r11 WITH THE CONTENTS + ;OF LOCATIONS POINTED TO BY r0 + ;WHICH IS INCREMEMTED AUTOMATICALLY + ;TO POINT TO THE NEXT LOCATION +01 + ADD r1, r1, r4 ;ADD r4 TO CHECKSUM + ADD r1, r1, r5 ;ADD r5 TO CHECKSUM + ADD r1, r1, r6 ;ADD r6 TO CHECKSUM + ADD r1, r1, r7 ;ADD r7 TO CHECKSUM + ADD r1, r1, r8 ;ADD r8 TO CHECKSUM + ADD r1, r1, r9 ;ADD r9 TO CHECKSUM + ADD r1, r1, r10 ;ADD r10 TO CHECKSUM + ADD r1, r1, r11 ;ADD r11 TO CHECKSUM +02 + ASSERT ((%02 - %01) = 32) ; else r2 won't count down correctly + + CMPS r0, r2 + BCC loop1 ;loop until pointer reaches endstop + + LDMIA r0!, {r4 - r9} ; get last 6 words (miss last 2 in ROM) +03 + ADD r1, r1, r4 ;ADD r4 TO CHECKSUM + ADD r1, r1, r5 ;ADD r5 TO CHECKSUM + ADD r1, r1, r6 ;ADD r6 TO CHECKSUM + ADD r1, r1, r7 ;ADD r7 TO CHECKSUM + ADD r1, r1, r8 ;ADD r8 TO CHECKSUM + ADD r1, r1, r9 ;ADD r9 TO CHECKSUM +04 + ASSERT (((%04 - %03) + (2*4)) = 32) ; Change this if you like - + ; but be careful to count nearly + ; to the top in eights, then add + ; add in the last few words. + + MOVS r0,r1 ; should be zero if all OK + + MOV pc,r14 ;return with zero flag set on OK + ;and the calculated sum in r0. + + +; +; ROM alias check. +; This test looks for an aliased copy of the vector table at varying +; distances from the start of ROM space. +; 16K is fairly arbitrary but corresponds approximately with the size of +; the POST. If there's an alias below that, we've probably already crashed ! +; +; This test is only called if the checksum fails, in order to indicate a +; possible high ROM address line failure. + +ts_ROM_alias ROUT + + MOV r0,#PhysROM ; get some words from ROM start + LDR r3,[r0, #ts_ROMSIZE] ; get the ROM length word + LDMIA r0,{r4,r5,r6,r7} + MOV r1,#(16 * 1024) + +01 ADD r2,r0,r1 ; get some words from possible alias + LDMIA r2,{r8,r9,r10,r11} + CMPS r4,r8 + CMPNE r5,r9 + CMPNE r6,r10 + CMPNE r7,r11 + BEQ %10 ; aliased : found MS ROM address bit + + MOVS r1, r1, LSL #1 ; test the next (more significant) bit + CMPS r1, r3 ; reached the limit yet ? + BLT %01 ; no - try again. + +10 MOV r0,r1 ; reached the end, or an alias. + MOV pc,lr + + + LTORG + + END diff --git a/TestSrc/Mem4 b/TestSrc/Mem4 new file mode 100644 index 0000000000000000000000000000000000000000..8d73e78c45242b07452cbc64e675df452f4b3f7a --- /dev/null +++ b/TestSrc/Mem4 @@ -0,0 +1,630 @@ +;> MEM4H_SCR +; +; RISC OS 2+ BOOT TEST SOFTWARE. +; MEMORY TEST 4 VERSION H. BRIAN RICE 12-01-90. +; 04-Apr-90 ArtG 0.1 Added ts_count_cams, improved reporting +; 11-Apr-90 ArtG 0.2 Use RISC OS routine BangCams for +; alternate MEMC configurations. +; 17-Apr-90 ArtG 0.3 rationalise page-counting code +; +; This file will be called by MEM6x_SCR for the purposes of assembly. +; This file will perform quick walking bit test on the CAM Entry points. +; The test code for this test was taken from the A680 test code. +; +; The module requires the running of the memory sizing routine used by +; the OS to set up the page size for this module. +; +; This test module was designed to operate on all current and future +; machines. The module is designed to handle up to 512 physical pages +; which is the maximum number of pages in a 16 MByte FOX. +; +; A 16 MB FOX has 4 MEMCs in use, each MEMC is addressed by Bits 7 and +; 12 of the logical to physical address translator. The use of bit 12 +; does have a problem in that on machines with 0.5MB of memory this is +; used to define the logical page number. Machine with 1MB or greater bit +; 12 is not used, therefore this test may hit problems on A305's. The +; intention is that A305 owners will upgrade to A310's when upgrading to +; RISC OS 2+. +; +; Because FOX can have up to 4 MEMCs fitted the following addressing is +; used to determine the MEMC accessed, bit 12, bit 7 +; 0 0 = Master MEMC = MEMC 0 +; 0 1 = Slave MEMC 1 = MEMC 1 +; 1 0 = Slave MEMC 2 = MEMC 2 +; 1 1 = Slave MEMC 3 = MEMC 3 +; +; +; This test will initialise the CAM entries for up to 512 physical pages. +; The physical pages will be mapped to logical page 5. Each page will have +; a copy of test routine vectors and a page marker. The page marker consists +; of the page number and a code to indicate which MEMC was used. The code for +; the MEMC used is as follows :- MEMC 0 0001 1110 = &1E +; MEMC 1 0010 1101 = &2D +; MEMC 2 0100 1011 = &4B +; MEMC 3 1000 0111 = &87 +; +; The page marker is arranged as follows &mm5Apppp +; | | +; | \-- Page Number &0000 ‰ &01FF. +; \--------MEMC Code as above. +; +; The patterns are chosen so that if two or more MEMCs are accessed +; together and both RAM outputs get enabled onto the data bus simultaneously, +; then there is a reasonable chance that the data returned will show the +; presence of a fault. +; +; When the CAM entries have been initialised the module will then check that +; all the pages are mapped correctly. A simple walking one pattern is used +; to check that the page is not present anywhere else in the memory area. +; This isn't really sufficient, but keeps the test time low. +; +; The tests are performed with the memory protection level set to 0. +; +; This version uses the "my abort" routine in MEM5x_SCR instead of the +; ts_dab_exp0 .. 5 method as taken from the A680 code. +; + +ts_rst_msg = "RST",0 +ts_uni_msg = "UDF",0 +ts_swi_msg = "SWI",0 +ts_pab_msg = "PAB",0 +ts_dab_msg = "DAB",0 +ts_aex_msg = "ADX",0 +ts_irq_msg = "IRQ",0 +ts_fiq_msg = "FIQ",0 +ts_bxc_msg = &85,"@",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 + ALIGN + + +ts_rst ; Unused exception vectors + ADR r4, ts_rst_msg + B ts_bad_exception +ts_uni + ADR r4, ts_uni_msg + B ts_bad_exception +ts_swi + ADR r4, ts_swi_msg + B ts_bad_exception +ts_pab + ADR r4, ts_pab_msg + B ts_bad_exception +ts_dab_unexp + ADR r4, ts_dab_msg + B ts_bad_exception +ts_aex + ADR r4, ts_aex_msg + B ts_bad_exception +ts_irq + ADR r4, ts_irq_msg + B ts_bad_exception +ts_fiq + ADR r4, ts_fiq_msg + B ts_bad_exception + + +ts_bad_exception + SUBS r8, r14, #8 ; remember aborted instruction + BL ts_SendText + ADR r4, ts_bxc_msg ; display aborted address + BL ts_MoreText + B Reset + + +; +ts_rom_base * ROM ; Base address of the OS ROMS. +ts_phys_mem * (32*1024*1024) ; Physical Memory area. +ts_pagemark * &005A0000 ; + phys page number + MEMC code. +ts_pmark_pos * 32 ; Position of page mark (avoiding vectors). +ts_cam_base * &3800000 ; Base address of the CAM table in MEMC. +ts_vrest * &5 ; Unused page which all pages are mapped to. +ts_MAX_CAMS * 512 ; Most CAMs ever expected +ts_memc_codes = &1E, &2D, &4B, &87 ; List of the memc_codes to be used. +; +ts_logpages ; List of Logical pages. + & &0001 + & &0002 + & &0004 + & &0008 + & &0010 + & &0020 + & &0040 + & &0080 + & &0100 + & &0200 + & &03FF + & &03FE + & &03FD + & &03FB + & &03F7 + & &03EF + & &03DF + & &03BF + & &037F + & &02FF + & &01FF + & &0000 ; Terminator for the list. +ts_logpagesend ; End of the list. +; +; +; Exception vectors : copied to start of each page to ensure that they will always +; exist on page zero when arbitrary pages are mapped there. +; +ts_vectors + B (ts_vectors-ts_start)+ts_rom_base+ts_rst + B (ts_vectors-ts_start)+ts_rom_base+ts_uni + B (ts_vectors-ts_start)+ts_rom_base+ts_swi + B (ts_vectors-ts_start)+ts_rom_base+ts_pab +ts_dab_vector + B (ts_vectors-ts_start)+ts_rom_base+ts_dab + B (ts_vectors-ts_start)+ts_rom_base+ts_aex + B (ts_vectors-ts_start)+ts_rom_base+ts_irq + B (ts_vectors-ts_start)+ts_rom_base+ts_fiq + + +; *************************************************************************** +; +ts_CAM +; +; CAM test (full or partial) +; Start of the CAM test, all physical pages have a copy of the vectors +; so they may be mapped as page 0. Then each page is mapped at a series +; of (walking 1, walking 0) logical pages and tested to be correctly +; mapped. Other pages are set to an unused logical page by set_cam_idle +; to prevent any CAM clashes. +; +; Copy the test vectors and page marker into all the pages. +; + ROUT ; Local Branches. + MOV r13, lr ; Preserve link register in r13. + BL ts_count_CAMs ; get log2 pagesize + MOV r0, #ts_MAX_CAMS ; r0 = last page to test + SUB r0, r0, #1 +0 BL ts_copy_vectors ; Gosub ts_vectors. + SUBS r0, r0, #&01 ; bump down to next page + BGE %B0 ; repeatuntil all pages set. +; +; 'C' pseudocode for the test routine. +; +; for (i = &1ff; i >= 0; i--) +; set_cam_idle(i); +; +; find maximum page number. +; if (max_page != ts_count_CAMS) +; report CAM number error +; +; for (phys = &max_page; phys >= 0; phys--) { +; for (logp = &logpages[0]; logp < &logpages[sizof(logpages)]; logp++) { +; if (*logp == 0) { +; set_cam(*logp, phys); +; check_mapped(*logp, phys); +; } else { +; int zphys = (phys + 1) % num_pages; +; set_cam(0, zphys); +; set_cam(*logp, phys); +; check_mapped(*logp, phys); +; set_cam_idle(zphys); +; } +; } +; set_cam_idle(phys); +; } +; +; Idle the pages. +; + ROUT ; Local Branches. + MOV r12, #ts_MAX_CAMS ; always clear all 512 - just in case 4 MEMCs. + SUB r12, r12, #&01 ; Subtract 1 to make max page #. +0 MOV r1, r12 ; r1 = page number. + BL ts_set_cam_idle + SUBS r12, r12, #&01 ; bump to next page downwards + BGE %B0 ; repeatuntil page 0 done +; +; We need to find out what the maximum number of pages is, after running the above routine +; all the pages will have the pagemark programed in to each page. As stated in the intro +; programing the pages from the top down will ensure that, irrespective of the number of +; MEMCs available, that the bottom pages are programed correctly. Therefore if we start +; at the top, read in a page, check it's page number & memc code are correct, if so then +; that is possibly the maximum page number. If not then subtract 1 from the page number and +; try again until a possible good page is found. +; + ROUT ; Local Branches. + + BL ts_count_CAMs ; get log2 pagesize to r1 + MOV r8, #ts_MAX_CAMS ; r8= max. number of physical pages. +0 SUBS r8, r8, #&01 ; Subtract 1 to make it r8 - 1 Pages. + BEQ ts_bad_CAM_count ; no pages ? - shouldn't hit this! +; +; Calculate the expected page marker, in r4, for the current page, in r8. +; + ADR r4, ts_memc_codes ; r4 = address of table with the memc codes. + LDRB r4, [r4, r8, LSR#7] ; r4 = Loc pointed to by r4 + (r1 >> 7). + ORR r4, r8, r4, LSL #24 ; r4 = page number OR (MEMC code << 24). + ORR r4, r4, #ts_pagemark ; r4 = page id OR magic number +; +; The calculated page marker is now in r4, ref_p_mark. +; Current page in r8 - convert to physical address in r9. +; the pagesize power-of-2 is in r1 (from ts_count_CAMs) +; + MOV r9, r8, LSL r1 ; convert PPN to phys offset + ORR r9, r9, #ts_phys_mem ; add offset to start of phys mem +; +; r9 now has the address of the current page - read the page marker for that page. +; + LDR r9, [r9, #ts_pmark_pos] ; r9 = contents of loc pointed to by + ; r9 + ts_pmark_pos. +; +; Check that read_p_mark is valid. +; +; Either the value read is the expected pagemark, junk (no memory) or an +; aliased pagemark - if it's aliased, then either the memory or the MEMC +; isn't decoded that far. +; Bump down and try a bit lower, until it's OK. +; + CMP r4, r9 ; Is page-mark expected value ? + BNE %B0 + +; +; Found a pagemarker in the proper place. Check that the number of pages that +; appear to be present are the same as the number found by ts_count_CAMs +; (i.e. the memory size / page size). +; + SUB r0, r0, #1 ; convert count -> max page number + CMPS r0, r8 + BNE ts_bad_CAM_count +; +; If all is well, we should have the maximum usable page number in r8. +; +; Need to reset page 0 in the CAM entries, currently all pages are mapped to page 5. +; We need to have logical page 0 mapped to physical page 0. +; + MOV r0, #&00 ; r0 = &00, the page to map. + MOV r1, #&00 ; r1 = &00, the page to map to. + MOV r2, #&00 ; r2 = &00, set the protection level. + BL ts_set_camp +; +; Check we can still see the data abort vector at physical page zero +; - no good continuing if we can't. +; + MOV r0, #ts_phys_mem + LDR r0, [r0, #(ts_dab_vector - ts_vectors)] + LDR r1, ts_dab_vector + CMPS r0, r1 + BNE ts_bad_dab_vector + +; +; Now lets get on with the testing. +; + +2 ADRL r10, ts_logpages ; logp = &logpages[0] + +3 LDR r0, [r10] ; r0 = page to test + CMP r0, #&00 ; last entry ? + BNE %F4 + MOV r1, r8 ; r1 = r8, page under test + BL ts_set_cam ; Gosub ts_set_cam. + LDR r0, [r10] ; r0 current logical test page + MOV r1, r8 ; r1 = current test page + BL ts_check_mapped ; Gosub ts_check_mapped. + B %F5 + +4 ADD r12, r8, #&01 + BL ts_count_CAMs ; get total number of pages + SUB r0,r0,#1 ; make a mask for useable page + AND r0,r0,#&7f ; numbers - min(128, num_pages) + AND r12, r12, r0 ; r12 -> (r12 + 1) masked + MOV r0, #&00 ; to useable page numbers. + MOV r1, r12 + BL ts_set_cam ; Setup a page for vectors + LDR r0, [r10] ; r0 = current logical test page. + MOV r1, r8 ; r1 = current physical test page. + BL ts_set_cam ; Setup a page to test + + LDR r0, [r10] ; look up logical page again. + MOV r1, r8 ; recall physical page. + BL ts_check_mapped ; check the ts_set_cam worked. + MOV r1, r12 ; unmap the vector page + BL ts_set_cam_idle + +5 ADD r10, r10, #&04 ; next entry in test list. + ADRL r0, ts_logpagesend ; r0 = ts_logpagesend. + CMP r10, r0 ; repeat until list of logical + BLO %B3 ; pages all done. + + MOV r1, r8 ; unmap the page we just tested + BL ts_set_cam_idle + + SUBS r8, r8, #1 ; bump phys page counter down. + ANDS r8,r8,r8 + BGE %B2 ; If r8 >= 0 Then branch back to 2. + + ANDS r0,r0,#0 + MOV pc,r13 ; all done and passed + +; +; **************************************************************************** +; +ts_copy_vectors +; +; Copies the vectors to the physical page in r0 (preserved) also copies +; pagemark + phypage. +; Expects r1 (preserved) to hold log2 of pagesize +; + ROUT ; Local Branches. + + ADR r2, ts_vectors ; r2 = source address + LDMIA r2, {r4-r11} ; r4 - r11 = loc pointed to by r2, post inc. + + MOV r3, r0, LSL r1 ; r3 = r0 * 2**r1 . + ORR r3, r3, #ts_phys_mem ; r3 = r3 OR ts_phys_mem. + STMIA r3, {r4-r11} ; loc pointed to by r3, post inc = r4 to r11. +; +; find out which memc is handling the page (r0), then assign the appropiate memc_code. +; Add in the page number and pagemark, then store into the required position in the +; page in question. +; + ADR r2, ts_memc_codes ; r2 = address of table with the memc codes. + LDRB r2, [r2, r0, LSR#7] ; r2 = memc code for this phys page. + ORR r2, r0, r2, LSL #24 ; OR in phys page number. + ORR r2, r2, #ts_pagemark ; OR in pagemark. + STR r2, [r3, #ts_pmark_pos] ; loc pointed to by r1 + ts_pmark_pos = pagemark. + MOV pc, lr ; Return to caller. +; +; **************************************************************************** +; +ts_set_cam_idle +; +; This module will program the physical page (r1) to the logical page 5, ts_vrest and +; continue onto the next section ts_set_cam. +; + ROUT ; Local Branches. + MOV r0, #ts_vrest ; r0 = ts_vrest, = unused logical page. +; +; **************************************************************************** +; +ts_set_cam +; +; This module will program the physical page (r1) to the logical page (r0) at +; protection mode 0 and continue onto the next section ts_set_camp. +; + MOV r2, #&00 ; r2 = &00, memory prot level 0. +; +; **************************************************************************** +; +ts_set_camp +; +; This module will map a range the physical pages (r1) to the logical page (r0) and +; set the protection mode (r2). This module will return to the location from where +; either itself or ts_set_cam or ts_set_cam_idle were called from. +; +; Corrupts r0,r1,r2,r3,r4,r6,r9,r11 +; +; Calls the RISC OS routine BangCam to do the PPNO, LPNO bit switching. +; First, jumble the registers to suit BangCam .. +; +; r2 = CAM entry (PPNO) +; r3 = logical address +; r9 = current MEMC setting (for pagesize) +; r11 = PPL +; + MOV r3,r0 ; logical page number + MOV r11,r2 ; protection level + MOV r2,r1 ; physical page number + MOV_fiq r0, r11_fiq ; MEMC configuration + MOV r9, r0 ; keep a copy in r9 + MOV r1, r9, LSR #2 + AND r1, r1, #3 ; calculate pagesize shift + ADD r1, r1, #12 + MOV r3, r3, LSL r1 ; convert LPN to logaddr + B BangCam ; return thro' BangCam + +; +; **************************************************************************** +; +ts_check_mapped +; +; This routine will check that the CAM has been programed correctly and that the required +; page is responding when asked. A quick test is made to check that other pages are not +; responding as well. +; +; logical page in r0, +; physical page in r1, +; test that they are the same. +; +; No return value : reports faults directly and returns thro' r13 +; +; Uses (corrupts) r0,r1,r2,r3,r4,r5,r6,r7 +; +; Find out which memc is handling the page (r1), then assign the appropiate memc_code. +; Add in the page number and pagemark, then compare that pagemark with those found +; in memory at the expected logical and physical addresses. +; +; This code assumes that any system with multiple MEMCs will always have 32K pages. +; + ROUT ; Local Branches. + + MOV r3, r0 ; save the current logical pagenumber. + MOV r5, lr ; Preserve link register in case of Abort. + ADR r2, ts_memc_codes ; r2 = address of table with the memc codes. + LDRB r2, [r2, r1, LSR#7] ; fetch the memc code for this page. + ORR r2, r1, r2, LSL #24 ; build the page number into the pagemark + ORR r2, r2, #ts_pagemark ; build in the pagemark magic number +; +; r2 should now have the page_mark for the current page (r1). +; calculate the shift to convert page number to memory offset. +; + MODE FIQ_mode + MOV r4, r11_fiq, LSR #2 ; pagesize / 4K + MODE SVC_mode + AND r4, r4, #3 + ADD r4, r4, #12 +; +; if the mapping failed completely, the test might abort +; + MOV r6, #&00 ; r6 = &00, clear expected abort flag. + MOV r7, #&94 ; r7 = &94, set abort expected flag. +; +; make the pointers and test the contents +; + MOV r0, r0, LSL r4 ; r0 = LPN * pagesize. + LDR r0, [r0, #ts_pmark_pos] ; r0 = contents of loc in r0 + ts_pmark_pos. + CMP r6, #94 ; did that fetch abort ? + ADREQ r4, %F14 ; mapping totally failed + BEQ ts_CAM_fail + MOV r1, r1, LSL r4 ; r1 = PPN * pagesize. + ORR r1, r1, #ts_phys_mem ; r1 = r1 ORed with ts_phys_mem. + LDR r1, [r1, #ts_pmark_pos] ; r1 = contents of loc in r1 + ts_pmark_pos. + CMP r0, r1 ; Are the read pagemarks equal ?? + ADRNE r4, %F10 + BNE ts_CAM_fail ; Failed : mapping not equal. + CMP r0, r2 ; + ADRNE r4, %F11 + BNE ts_CAM_fail ; Failed : map equal, but corrupt +; +; test that the page doesn't exist anywhere else +; + MOV r2, #1 +0 EOR r0, r2, r3 ; Flip a (walking) bit in the LPN. + CMP r0, #ts_vrest ; Is r0 = ts_vrest ?? Where all the pages are + ; mapped to. + BEQ %F1 ; If r0 = ts_vrest then branch forward to 1. +; +; The following instruction should abort. +; + MOV r0, r0, LSL r4 ; r0 = LPN * pagesize. + MOV r6, #&00 ; r6 = &00, clear abort handled flag. + MOV r7, #&94 ; r7 = &94, set abort expected flag. + LDR r0, [r0, #ts_pmark_pos] ; get a possible pagemark from this page. + CMP r6, #&94 ; Did we go thro' the abort handler ? + BEQ %F1 ; If equal then an abort happened, good ! +; +; Not aborted - is it page zero, where the vectors live ? +; + TEQS r2, r3 + BEQ %F1 ; yes - that SHOULDN'T abort +; +; Fault - is the page mapped there the same as our test page ? +; + CMP r0, r1 + ADREQ r4, %F12 ; Failed : phys page also mapped here + ADRNE r4, %F13 ; Failed : page not unmapped + EOR r3, r2, r3 ; remake the duff LPN for the error display + B ts_CAM_fail + ; If equal then no abort happened, not good !! + +1 MOV r2, r2, LSL#1 ; bump to next-bit-set page number + CMP r2, #(ts_MAX_CAMS :SHL: 1) ; Hit number of logical pages ? + BLT %B0 ; If r2 < maximum number then loop again. + + MOV r7, #0 ; no longer expecting aborts + MOV pc, r5 ; Return to caller. + +; +; Indicate that CAM mapping test failed (PPN is not at LPN) +; Display r8, the physical page number and r3, the logical page. +; +; ***This error exit returns to the CALLER of check_mapped, thro' r13*** +; + +10 + = "CAM map",&88,&ff,&ff,&ff,".",&ff,&ff,&ff,&ff,0 +11 + = "CAM pmk",&88,&ff,&ff,&ff,".",&ff,&ff,&ff,&ff,0 +12 + = "CAM als",&88,&ff,&ff,&ff,".",&ff,&ff,&ff,&ff,0 +13 + = "CAM unm",&88,&ff,&ff,&ff,".",&ff,&ff,&ff,&ff,0 +14 + = "CAM abo",&88,&ff,&ff,&ff,".",&ff,&ff,&ff,&ff,0 + + ALIGN + + +ts_CAM_fail + MOV r0, r8, LSL #16 ; physical page # + LDR r1, =&ffff + AND r1, r1, r3 + ORR r0, r0, r1 ; add logical page # + MOV r8, r0, LSL #4 + MOV r6, #0 ; no longer expecting aborts + ORRS r0, r0, #1 + MOV pc, r13 + +; +; ************************************************************************** +; + +; Routine to return expected number of physical pages in r0. +; Uses memory size determination from r10_fiq and page mode from r11_fiq. +; Returns pagesize as power-of-two in r1, for pagenumber->address calcs. + +ts_count_CAMs + + MODE FIQ_mode + MOV r0,r10_fiq,LSR #12 ; get values determined + MOV r1,r11_fiq,LSR #2 ; by MemSize + MODE SVC_mode + + AND r1,r1,#3 ; memory / pagesize + MOV r0,r0,LSR r1 + ADD r1,r1,#12 ; page bit-shift value + + MOVS pc,lr + + +; +; ************************************************************************** +; + ROUT + +; Indicate that an unexpected number of CAM pages were found. +; +; Display as "CAM ## eee.fff" +; +; where eee is the expected maximum page number (r0), fff is the number +; of of the highest page actually found (r8). + +0 + = "CAM ##",&89,&ff,&ff,&ff,".",&ff,&ff,&ff,0 + ALIGN + +ts_bad_CAM_count + ADD r8, r8, r0, LSL #12 + MOV r8, r8, LSL #8 + ADR r4, %B0 + ORRS r0, r0 ,#1 + MOV pc, r13 +; +; ************************************************************************** +; + +; Indicate that the DAB vector wasn't visible in physmem + +0 + = "CAM vec",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 + ALIGN + +ts_bad_dab_vector + ADR r4, %B0 + EOR r8,r0,r1 ; indicate which bits are lost + ORRS r0, r0, #1 + MOV pc, r13 +; +; ************************************************************************** + +; Routine to indicate that an unexpected abort was found. + +0 + = "DAB @",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff, 0 + ALIGN + +ts_unxvect + ADR r4, %B0 + SUBS r8, r14_svc, #8 ; indicate the aborting instruction + BL ts_SendText + ORRS r0, r0, #1 + MOV pc, r13 + + + + LTORG + + END diff --git a/TestSrc/Mem5 b/TestSrc/Mem5 new file mode 100644 index 0000000000000000000000000000000000000000..607a8b8e1d1c47c9ac1c027c522a3acc14133554 --- /dev/null +++ b/TestSrc/Mem5 @@ -0,0 +1,316 @@ +;>MEM5D_SCR +; +; RISC OS 2+ BOOT TEST SOFTWARE. +; MEMORY TEST 5 VERSION D. BRIAN RICE 10-01-90. +; 04-Apr-90 ArtG 0.1 Use memory size to determine page count +; 11-Apr-90 ArtG 0.2 Changes to permit use of BangCam +; +; This file will be called by MEM6x_SCR for the purposes of assembly. +; This file requires the assembly of MEM4x_SCR to be perfromed at the +; same time. The program will call the cam setting routines in the cam +; test program. +; +; This file will test MEMCs ability to assert its protection over +; logical pages. +; The test code for this test was taken from the A680 test code. +; The Arm CPU has three mode of operation, Supervisor, Operating System. +; and User. Most of the time the machine will operate in user mode, in this. +; mode the designers do not want the user to have full access to the memory. +; map, therefore the MEMC(s) will check that the CPU has the appropiate +; level of authorisation to access specific area of memory. +; User mode is the lowest mode, allowing limited R/W access to the ram. +; Operating System is next up the list and is allowed some more access to +; to the ram than user mode. +; Supervisor mode this is the highest and the CPU has unlimited access to +; the entire memory map. +; +; This version has the "my abort" routine in it not the ts_dab_exp0..5 routine as +; coded from the A680 code. +; +; Set up some variables. +; +ts_wks_word * 36 ; Offset of word for workspace. +; +; **************************************************************************** +; +ts_memc_prot +; +; This module will map and assign protection mode 0 to all the pages. The +; module will then perfrom a read and write operations in supervisor and +; user modes. This is repeated for the three (four) protection modes. +; The module will check after every protection mode level that the required +; responses have been returned. +; +; Set up the memory, map and assign protection mode 0. +; + ROUT ; Local Branches. + MOV r13, lr ; Preserve the link register. + MOV r12, #&00 ; r12 = The physical page to test. + +0 ADD r8, r12, #&01 ; Get a page to use as vectors, + BL ts_count_CAMs ; get total number of pages + SUB r0,r0,#1 ; make a mask for useable page + AND r0,r0,#&7f ; numbers - min(128, num_pages) + AND r8, r8, r0 + + MOV r1, r8 ; r1 = r8, r1 = physical page 0. + MOV r0, #&00 ; r0 = &00, r0 = logical page 0. + BL ts_set_cam ; Gosub ts_set_cam, set the CAM up. +; +; Set protection mode 0 and test that page. +; + MOV r2, #&00 ; r2 = &00, r2 = protection mode 0. + BL ts_mem_prot ; Gosub ts_mem_prot. + CMP r3,#&0F ; Is r3 = &0F ? r3 = Super Read/Write ok. + ; O/S Read/Write ok. + ; User Read/Write ok. + MOV r2, #0 + BNE ts_prot_fail ; If r3 <> &0F Then branch to fail routine. +; +; Set protection mode 1 and test that page. +; + MOV r2, #&01 ; r2 = &01, r2 = protection mode 1. + BL ts_mem_prot ; Gosub ts_mem_prot. + [ CPU_Type = "ARM600" + CMP r3,#&0f ; no ABORT line to ARM600 + | + CMP r3,#&0B ; Is r3 = &0B ? r3 = Super Read/Write ok. + ] ; O/S Read/Write ok. + ; User Read only ok. + + MOV r2,#1 + BNE ts_prot_fail ; If r3 <> &0B Then branch to fail routine. +; +; Set protection mode 2 and test that page. +; + MOV r2, #&02 ; r2 = &02, r2 = protection mode 2. + BL ts_mem_prot ; Gosub ts_mem_prot. + [ CPU_Type = "ARM600" + CMP r3,#&0f ; no ABORT line to ARM600 + | + CMP r3,#&03 ; Is r3 = &03 ? r3 = Super Read/Write ok. + ] ; O/S Read only ok. + ; User No Access ok. + MOV r2,#2 + BNE ts_prot_fail ; If r3 <> &03 Then branch to fail routine. +; +; Set protection mode 3 and test that page. +; + MOV r2, #&03 ; r2 = &03, r2 = protection mode 3. + BL ts_mem_prot ; Gosub ts_mem_prot. + [ CPU_Type = "ARM600" + CMP r3,#&0f ; no ABORT line to ARM600 + | + CMP r3, #&03 ; Is r3 = &03 ? r3 = Super Read/Write ok. + ] ; O/S Read only ok. + ; User No Access ok. + MOV r2,#3 + BNE ts_prot_fail ; If r3 <> &03 Then branch to + ; fail routine. +; +; Reset the page used to idle. +; + MOV r0, r12 ; r0 = r12, idle the pages + ; being used. + BL ts_set_cam_idle ; Gosub ts_set_cam_idle. + MOV r0, r8 ; r0 = r8, idle the pages + ; being used. + BL ts_set_cam_idle ; Gosub ts_set_cam_idle. +; +; Increment the physical page counter and check that all the pages are +; done, else finish. +; + BL ts_count_CAMs + ADD r12, r12, #&01 ; do the next physical page. + CMP r12, r0 ; Done all pages ? + BLT %B0 ; If r12 <= cam_entries, + ; branch back to 0. + + ANDS r0, r0, #0 ; set zero flag : test passed + MOV pc, r13 ; Return to caller. +; +; ************************************************************************** +; +; Branch here when ts_memc_prot fails to get the proper result from +; ts_mem_prot. +; +; At this point, +; +; r3 is a map of permitted ops (user read, user write, sys read, sys write) +; r2 is the memc protection mode +; r12 is the physical page number. +; +; This is displayed as : +; +; PPL bad l.a.pppp +; +; where l is the PPL set on that page (0, 1, 2 or 3) +; a is a bitmap of the actual operations permitted (ur.uw.or.ow) +; p is the physical page number tested +; + +0 + = "PPL bad",&88,&ff,".",&ff,".",&ff,&ff,&ff,&ff,0 + ALIGN + +ts_prot_fail + AND r2, r2, #&0f + MOV r0, r2, LSL #20 ; mode bits + AND r3, r3, #&0f + ORR r0, r0, r3, LSL #16 ; permitted ops bits + BIC r12, r12, #&ff000000 + BIC r12, r12, #&ff0000 + ORR r0, r0, r12 ; current page number + + + ADR r4, %B0 ; get fail message + MOV r8, r0, LSL #8 ; shift number to suit ts_SendText + ORRS r0, r0, #1 ; fail flag + MOV pc, r13 + + +; +; +; This section will test that the physical page referenced in r12 at the set +; protection mode. During the operation of this module, aborts are expected to happen. +; The aborts are handled by the routine ts_dab. +; +; The system is running in supervisor mode and thus to check the user mode read / writes +; the address translator flag is used. The CPU has a signal called -TRANS which when used +; with MEMC forces the an address translation to be performed, this is not done whilst +; in supervisor mode because it has unlimited access to the memory map. The address +; translator falg (T) is used with STR and LDR instructions only, the effective result of +; adding the (T) to the opcode is to force the instruction to be executed as if the CPU +; was in user mode, thus unauthorised accesses will cause an abort to occur. +; +; IN: +; r12 - physical page. +; r2 - protection mode. +; OUT: +; r3 - access pattern. +; r3 = &0F, Super Read/Write ok, O/S Read/Write ok, User Read/Write ok. +; r3 = &0B, Super Read/Write ok, O/S Read/Write ok, User Read only ok. +; r3 = &03, Super Read/Write ok, O/S Read only ok, User No Access ok. +; +ts_mem_prot +; +; Set up data to write and read from memory. +; + MOV r10, lr ; Preserve link register. + MOV r1, r12 ; r1 = physical page. + MOV r0, #&01 ; r0 = logical page 1. + BL ts_set_camp + + MOV r3, #&00 ; Initialise access pattern. + MOV_fiq r5, r11_fiq ; get MEMC control + AND r5, r5, #&C + ADR r9, ts_ppl_tptrs + LDR r9, [r9, r5] ; get test address for this pagesize +; +; Test 1 system mode - write. +; + MOV r6, #&00 ; r6 = &00, clear expected abort flag. + MOV r7, #&94 ; r7 = &94, set abort expected flag. +; +; The following instruction may abort. +; + STR r1, [r9] ; Store r1 at loc pointed to by r9. + CMP r6, #&00 ; Is r6 = &00 ? If not then abort happened. + ORREQ r3, r3, #&01 ; If r6 = &00, Then update r3, access pattern. +; +; Test 2 system mode - read. +; + MOV r6, #&00 ; r6 = &00, clear expected abort flag. + MOV r7, #&94 ; r7 = &94, set abort expected flag. +; +; The following instruction may abort. +; + LDR r1, [r9] ; Load r1 from loc pointed to by r9. + CMP r6, #&00 ; Is r6 = &00 ? If not then abort happened. + ORREQ r3, r3, #&02 ; If r6 = &00 Then update r3, access pattern. +; +; Test 3 user mode - write. +; + MOV r6, #&00 ; r6 = &00, clear expected abort flag. + MOV r7, #&94 ; r7 = &94, set abort expected flag. +; +; The following instruction may abort. +; + STRT r1, [r9] ; Store r1 at loc pointed to by r9. + CMP r6, #&00 ; Is r6 = &00 ? If not then abort happened. + ORREQ r3, r3, #&04 ; If r6 = &00 Then update r3, access pattern. +; +; Test 4 user mode - read. +; + MOV r6, #&00 ; r6 = &00, clear expected abort flag. + MOV r7, #&94 ; r7 = &94, set expected expected flag. +; +; The following instruction may abort. +; + LDRT r1, [r9] ; Load r1 from loc pointed to by r9. + CMP r6, #&00 ; Is r6 = &00 ? If not then abort happened. + ORREQ r3, r3, #&08 ; If r6 = &00 Then update r3, access pattern. + MOV pc, r10 ; Return to caller. + +; +; addresses (a short way up page 1) to test PPL aborts +; + +ts_ppl_tptrs + & ( 4 * 1024) + ts_wks_word + & ( 8 * 1024) + ts_wks_word + & (16 * 1024) + ts_wks_word + & (32 * 1024) + ts_wks_word +; +; +ts_dab +; +; This routine provides the handling when a DATA ABORT occurs. +; The routine will if the abort was DATA cause the program to skip over the instruction +; that caused the abort first place. +; Data aborts could come from a variety of sources, in this module we are only concerned +; about a select group of aborts. This abort routine is called instead of the "usuall" +; abort routine. All that is required from this abort routine is to set a flag to +; indicate that an abort occured. Therefore this routine needs to be told that the +; abort that caused the routine to be called is either one of mine or not, (expected +; or unexpected). To achive this &94 is placed in r7. The abort routine will check +; for the presence of &94 in r7, if present then the abort is an expected abort. +; The abort routine will then copy r7 into r6, which is used as a flag to indicate +; that an abort occured and that it was an expected abort. Then the routine will +; return control to the program at the location after the instruction that caused to +; abort to occur. +; The return address is stored by the CPU into the link regester lr (r14), sort off. +; It must be remembered that the PC is always 2 instructions ahead. E.G. if the +; instruction that causes the abort is at &2000, then the lr will have &2008 in it, +; but we want to return to the location after the abort instruction, &2004. Therefore to +; return to the correct location &04 is removed from the lr and this is put into the pc. +; If the abort was not expected then the routine will jump to the end and another +; routine will show that an unexpected abort was generated. +; +; IN: +; r6 - Equals &00, cleared just before the instruction that could cause an abort. +; r7 - Equals &94, set just before the instruction that could cause an abort. +; +; OUT: +; r6 - Equals &94, set if an abort happened and was expected. +; r7 - Equals &94, preserved. +; + ROUT ; Local Branches. +; +; Check that it is an expected abort and not an unexpected abort. +; + CMP r7, #&94 ; Is r7 = &94, abort expected value. + BNE ts_dab_unexp ; If <> &94, Then branch to unexpected + ; abort handler. +; +; It is an expected abort, so handle it. +; + MOV r6, r7 ; r6 = r7, indicates that an abort happened. + SUB pc, lr, #&04 ; pc = link reg - &04. + ; Skip over aborting instruction. + ; By reloading the pc we return to the area + ; of code where the abort occured but 4 + ; locations further on. + + + END diff --git a/TestSrc/TestMain b/TestSrc/TestMain new file mode 100644 index 0000000000000000000000000000000000000000..22fcf0d1dada040ca950d51cadf2854ae7a70079 --- /dev/null +++ b/TestSrc/TestMain @@ -0,0 +1,78 @@ +; > TestMain + + +; Main assembly file for isolated assembly of machine test software + +MEMCADR * &3600000 +ROM * &3800000 + + [ MEMC_Type = "IOMD" +VideoPhysRam * &02000000 ; Amazing - it's in the same place! +DRAM0PhysRam * &10000000 ; 4 DRAM banks +DRAM1PhysRam * &14000000 +DRAM2PhysRam * &18000000 +DRAM3PhysRam * &1C000000 +DRAMBaseAddressMask * &1C000000 ; used to mask off bits after stealing video RAM +PhysSpaceSize * &20000000 ; IOMD physical map is 512M big +PhysROM * &00000000 ; and real ROM starts at 0 +SAMLength * 512*4 ; SAM length in bytes for 1 bank of VRAM +EASISpacePhys * &08000000 +EASISpace * PhysSpace + EASISpacePhys + | +VideoPhysRam * &02000000 +PhysSpaceSize * &04000000 ; MEMC1 physical map is 64M big +PhysROM * &03800000 +PhysRamPhys * &02000000 ; physical space starts here + ] + + ORG ROM + + GET TestSrc/Begin +CONT + ADRL r2,TestVIDCTAB + LDR r0,=IOMD_MonitorType + LDR r0,[r0] + ANDS r0,r0,#IOMD_MonitorIDMask + ADDEQ r2,r2,#(TestVVIDCTAB-TestVIDCTAB) + MOV r0,#ts_VIDCPhys +08 LDR r1, [r2],#4 + CMP r1, #-1 + STRNE r1, [r0] + BNE %BT08 + + MOV r9,#0 +10 + ORR r9,r9,#&40000000 + STR r9,[r0] ; write the border colour + ADD r9,r9,#&00000005 + ADD r9,r9,#&00000300 + ADD r9,r9,#&00010000 + AND r9,r9,#&00ffffff + + MOV r1,#&10000 +12 ADDS r1,r1,#(-1) + BNE %BT12 + + B %BT10 + +; +; The RISC-OS MEMC setup code is re-used to ensure similar +; detection of memory configuration. The MEMC1 code is modified only +; to remove an unnecessary function. + + GBLL Module +Module SETL {FALSE} + GBLL AssembleSAtest +AssembleSAtest SETL {FALSE} + +DynAreaFlags_DoublyMapped * 1 :SHL: 6 +DynAreaFlags_NotCacheable * 1 :SHL: 5 +DynAreaFlags_NotBufferable * 1 :SHL: 4 +DynAreaFlags_APBits * 15 :SHL: 0 ; currently onl + + + END + + + + diff --git a/TestSrc/Vidc b/TestSrc/Vidc new file mode 100644 index 0000000000000000000000000000000000000000..feaa74f81d8a727015ffeaa401442e6d0c03d81c --- /dev/null +++ b/TestSrc/Vidc @@ -0,0 +1,532 @@ +; > TestSrc.VIDC + + TTL RISC OS 2+ POST video controller +; +; The video outputs cannot be tested directly, and VIDC permits only +; write operations on its registers. +; This module performs two tests to verify VIDC's operation +; +; - measure mode 0 FLBK period against IOC timer +; - check that sound DMA occurs (MEMC reports DMA complete) +; +; This code contains timing loops affected by gross changes in processor +; speed, and will re-initialise MEMC with 4K pages and continous refresh. +; +;------------------------------------------------------------------------ +; History +; +; Date Name Comment +; ---- ---- ------- +; 18-Dec-89 ArtG Initial version +; 04-Apr-90 ArtG Use saved MEMC control register setting +; 20-Jun-93 ArtG Medusa VIDC20 / IOMD changes +; 18-Nov-94 RCM Morris changes +; +; +;------------------------------------------------------------------------ + + +VIDC_CLOCK_CONTROL * ts_S5_base :OR: &0048 ; Fox VIDC clock control +VIDC_CLOCK_NORMAL * &0 + +VIDC_VFLYWAIT * 72000 ; 200mS timeout loop +VIDC_SOUNDWAIT * 40000 ; 100mS timeout loop + +MEMC_Sstart * MEMCADR :OR: &80000 +MEMC_SendN * MEMCADR :OR: &A0000 +MEMC_Sptr * MEMCADR :OR: &C0000 +MEMC_Son * &00800 + +ts_Soundbuf * &200 ; relative to PhysRam +ts_Soundbuf_length * &400 + + [ VIDC_Type = "VIDC20" +VIDSTIM0 * &A0000000 ; base VIDC20 register values +VIDSTIM1 * &A1000000 +VIDSFR * &B0000000 +VIDSCR * &B1000005 +VIDDMAoff * &94000024 +VIDVCOWAIT * &5 +VIDVCOFREQ * &D0000404 + | +VIDSTIM0 * &60000000 ; base VIDC register values +VIDSTIM1 * &64000000 +VIDSFR * &C0000100 + ] + + SUBT FLBK period test +; +; This test attempts to validate the video timing system by checking for +; the proper period from the vertical flyback pulse. To make life easier, +; the test is performed only in mode 0 - i.e a 20mS period. +; +; This test contains a processor-clock timed loop as an outer limit : +; it assumes that the processor will never run more than a factor of ten +; faster than an 8Mhz ARM2. +; This is valid provided that this code isn't run with an ARM3 cache enabled. +; + +; Initialise video clock control (for FOX) +; Initialise VIDC +; Clear IR interrupt request in IOC +; Poll IOC until IR appears (if ever) +; Set IOC timer 0 to 32 mS +; Clear IR interrupt request in IOC +; Poll IOC until IR appears (if ever) +; Check timer 0 has counted down 20 mS (19.8 - 20.2 mS) +; Return zero flag set on OK, clear on test failure. + + +ts_VIDC_period ROUT + + ; Initialise VIDC clock and VIDC + + [ VIDC_Type = "VIDC1a" + LDR r3, =VIDC_CLOCK_CONTROL ; + MOV r1, #VIDC_CLOCK_NORMAL + STRB r1, [r3] + ] + + MOV r7, #0 + MOV r1, #ts_VIDCPhys + ADRL r6, TestVIDCTAB +00 LDR r0, [r6],#4 ; setup using main table + CMP r0, #-1 + STRNE r0, [r1] + BNE %BT00 +01 LDR r0, [r6],#4 ; enable DMA using 2nd table + CMP r0, #-1 + STRNE r0, [r1] + BNE %BT01 + + ; Wait for the start of a flyback period + +04 + LDR r3, =IOC + [ MEMC_Type = "IOMD" + LDR r1, [r6] ; get FSIZE value from end of TestVIDCTAB + STR r1, [r3, #IOMD_FSIZE] + ] + MOV r1, #vsync_bit + STRB r1, [r3, #IOCIRQCLRA] + LDR r2, =VIDC_VFLYWAIT ; long timeout loop - C 200mS + +05 LDRB r1, [r3, #IOCIRQSTAA] + ANDS r1, r1, #vsync_bit + BNE %06 + SUBS r2, r2,#1 + BNE %05 + + LDR r0,=&fffff + ORRS r0, r0,r7, LSL #20 ; Failed : clear 0 flag + MOV pc, r14 ; ... and quit + + ; Set up IOC timer 0 +06 + LDR r1, =(32 * 1000 * 2) ; 32mS upper limit + STRB r1, [r3, #Timer0LL] + MOV r0, r1, LSR #8 + STRB r0, [r3, #Timer0LH] + MOV r0, #0 + STRB r0, [r3, #Timer0GO] ; start the timer + + ; clear the IR and T0 bits + + MOV r0, #(vsync_bit :OR: timer0_bit) + STRB r0, [r3,#IOCIRQCLRA] + + ; wait for what should be a complete vflyback period + +10 LDR r2, =VIDC_VFLYWAIT ; timeout loop - C 200 msec +11 LDRB r0, [r3,#IOCIRQSTAA] + TSTS r0, #vsync_bit + BNE %14 ; wait for end of vsync + + TSTS r0, #timer0_bit ; or timer underflow + BNE %13 + +12 SUBS r2, r2, #1 ; or last-ditch timeout + BNE %11 + +13 ORRS r0, r0,#1 ; Failed : clear 0 flag + MOV r0, #0 ; but return a zero + MOV pc, r14 ; ... and quit + + ; finished in reasonable time : check against margins. + +14 STRB r0, [r3, #Timer0LR] ; latch the current count + LDRB r2, [r3, #Timer0CL] + LDRB r0, [r3, #Timer0CH] + ADD r2, r2, r0, LSL #8 + + SUB r2, r1, r2 + MOV r0, r2, LSR #1 ; Vertical flyback time in uS + + LDR r1, =19800 ; inside limits ? + SUBS r2, r0, r1 + BLE %F20 + + LDR r1, =400 ; 19.8 -> 20.2 mS + CMPS r2, r1 + BGE %F20 + MOV r1,#0 ; OK - 0 indicates pass + + ; After success using the 24MHz reference clock, select the + ; VCO clock (also at 24MHz) and ensure the test is passed after + ; a few cycles to allow the VCO to settle. + +20 + [ VIDC_Type = "VIDC20" + + TEQ r7,#0 ; if this is the first loop .. + BNE %FT21 + TEQ r1,#0 ; and it passed OK .. + BNE %FT25 + MOV r2,#ts_VIDCPhys + LDR r3,=VIDVCOFREQ ; set the vco to 24MHz + LDR r4,=&E0000400 ; and use the vco clock + STMIA r2,{r3,r4} + MOV r7,#VIDVCOWAIT ; set the vco test loop count + B %BT04 ; and run around again + +21 ORR r0,r0,r7,LSL #20 + SUBS r7,r7,#1 ; if all attempts now made + BEQ %FT25 ; return final result + TEQ r1,#0 ; else repeat until passed + BNE %BT04 + ] + + ; return with zero flag set if timers were OK + ; measured time (in uS) in r0 if flyback was wrong, + ; bits 20+ show fail loop - 0 for refclk, 1 for vcoclk. + +25 + ORRS r1,r1,r1 + MOV pc, r14 + + + SUBT Sound DMA test +; +; This test runs the sound DMA system to prove the operation of VIDC and +; MEMC's sound DMA control and the operation of the SIRQ sound DMA complete +; interrupt. +; To avoid making a noise, set the sound muting bit on. +; +; Initialise MEMC sound DMA +; Initialise VIDC sound channel +; Initialise timer 0 and timer 1 to guard-band 10mS sound duration +; Poll IOC until IL1 (SIRQ interrupt) becomes active +; Check timer 0 has completed and timer 1 has not +; + +ts_SIRQ_period ROUT + + ; set up MEMC to point to a buffer near the start of physical RAM, + ; labelled in r9_fiq by the early memory size tests (not MemSize) + ; Registers are set as (address / 16) + ; Register bits are (register * 4) in VIDC address mask + ; Hence values written to MEMC + register offset + (pointer / 4) + + + [ MEMC_Type = "IOMD" + MOV r3,#IOMD_Base + MOV r0,#(IOMD_DMA_C_Bit :OR: IOMD_DMA_E_Bit :OR: 16) + STR r0,[r3,#IOMD_SD0CR] + MOV_fiq r0,r9 ; zero the DMA buffer + ADD r1,r0,#ts_Soundbuf_length + MOV r2,#0 +02 STR r2,[r0],#4 + CMPS r0,r1 + BNE %BT02 + | + MOV_fiq r0,r11_fiq + BIC r0, r0, #MEMC_Son ; ensure sound DMA disabled + + STR r0, [r0] + LDR r1, =(MEMC_SendN :OR: ((ts_Soundbuf + ts_Soundbuf_length) / 4)) + STR r1, [r1] + LDR r2, =(MEMC_Sstart :OR: (ts_Soundbuf / 4)) + STR r2, [r2] + LDR r0, =MEMC_Sptr ; initialise Sptr and set up again .. + STR r0, [r0] + STR r1, [r1] + STR r2, [r2] + ] + + ; Set up VIDC for 8 channels, 10uS (/8) per sample + + LDR r0, =ts_VIDCPhys + [ VIDC_Type = "VIDC20" + LDR r1, =VIDSCR ; VIDC10 mode, 24Mhz clock + STR r1, [r0] + LDR r1, =VIDDMAoff + STR r1, [r0] + ] + LDR r1, =(VIDSTIM0 + 1) ; channel 0 at 100% left + LDR r2, =((VIDSTIM1 - VIDSTIM0) + 1) + MOV r3, #7 +05 STR r1, [r0] ; .. up to 6 at 100% right + ADD r1, r1, r2 + SUBS r3, r3, #1 + BNE %05 + SUB r1, r1, #4 ; finally ch7 at centre again + STR r1, [r0] + + LDR r1, =(VIDSFR + 8) ; 10uS/byte + STR r1, [r0] + + ; Set up the timer to limit at 20 us (10uS/sample, 1024-16 bytes => 10.08 mS) + + LDR r3, =IOC + LDR r1, =(20 * 1000 * 2) ; 20 mS upper limit + STRB r1, [r3, #Timer1LL] + MOV r0, r1, LSR #8 + STRB r0, [r3, #Timer1LH] + + MOV r0, #-1 + STRB r0, [r3, #IOCControl] ; mute sound (on IOC system) + STRB r0, [r3, #Timer1GO] ; start the timer + + [ MEMC_Type = "IOMD" + MOV r0, #(IOMD_DMA_E_Bit :OR: 16) ; enable the IOMD DMA + STR r0, [r3,#IOMD_SD0CR] + MOV_fiq r0,r9 ; set the buffer pointers + MOV r4,#((ts_Soundbuf_length/2) - 16) + STR r0,[r3,#IOMD_SD0CURA] + STR r4,[r3,#IOMD_SD0ENDA] + LDR r2,[r3,#IOMD_SD0ST] + ORR r4,r4,#IOMD_DMA_S_Bit + STR r0,[r3,#IOMD_SD0CURB] + STR r4,[r3,#IOMD_SD0ENDB] + | + MOV_fiq r0, r11_fiq + ORR r0, r0, #MEMC_Son + STR r0, [r0] ; enable the MEMC1a DMA + ] + + ; set long timeout, clear the IL1, T0 and T1 bits + + LDR r2, =VIDC_SOUNDWAIT ; lastditch timeout loop + LDR r0, =(timer0_bit :OR: timer1_bit) + STRB r0, [r3,#IOCIRQCLRA] + + + ; Wait until sound DMA completes (or up to about 100 mS), + ; then check timers. + +10 + [ MEMC_Type = "IOMD" + LDRB r0,[r3, #IOMD_SD0ST] + AND r0, r0, #(IOMD_DMA_O_Bit :OR: IOMD_DMA_I_Bit) + CMPS r0, #(IOMD_DMA_O_Bit :OR: IOMD_DMA_I_Bit) + BEQ %12 + | + LDRB r0, [r3,#IOCIRQSTAB] + ANDS r0, r0, #sound_IRQ_bit + BNE %12 + ] + LDR r0, [r3, #IOCIRQSTAA] + ANDS r0, r0,#timer1_bit ; timeout if timer 1 expires + BNE %11 + + SUBS r2, r2, #1 ; or counter reaches zero + BNE %10 + +11 ORRS r0, r0, #1 ; Failed : clear 0 flag + MOV r2, #0 ; return a timeout value of 0 + B %15 ; ... and quit + + ; finished in reasonable time : check time remaining in t1 + ; Time for DMA should be 10.24ms (1024 bytes at 10us/byte) + ; less up to the time to use the final 16-byte transfer, 160us. + +12 STRB r0, [r3, #Timer1LR] ; latch the current count + LDRB r2, [r3, #Timer1CL] + LDRB r0, [r3, #Timer1CH] + ADD r2, r2, r0, LSL #8 + + SUB r2, r1, r2 + MOV r2, r2, LSR #1 ; Sound DMA time in uS + + LDR r1, =10030 ; inside limits ? + SUBS r0, r2, r1 + BLE %F13 + + LDR r1, =260 ; 10.03 -> 10.29 mS + CMPS r0, r1 + MOVLT r1,#0 ; inside limits : set Z flag + +13 ORRS r1,r1,r1 + + ; return with zero flag set if time (in r2) was within limits + +15 + [ MEMC_Type = "IOMD" + MOV r0, #IOMD_DMA_C_Bit + STR r0, [r3,#IOMD_SD0CR] + | + BIC r0, r0, #MEMC_Son + STR r0, [r0] + ] + MOV r0, r2 ; return the long time value + MOV pc, r14 + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; Data tables: VIDC := mode 0, all palette black + +TestVIDCTAB + + [ VIDC_Type = "VIDC1a" + + & &00000000 + & &04000000 + & &08000000 + & &0C000000 + & &10000000 + & &14000000 + & &18000000 + & &1C000000 + & &20000000 + & &24000000 + & &28000000 + & &2C000000 + & &30000000 + & &34000000 + & &38000000 + & &3C000000 + & &40000000 ; Border -> black + & &44000000 ; Cursor -> black + & &48000000 + & &4C000000 ; Palette programmed (avoid messy screen on reset) +; +; standard mode 0 setup (except display area disabled) +; + + & &807FC000 + & &8408C000 + & &881B0000 + & &8C1EC000 ; HDSR + & &906EC000 ; HDER + & &94770000 + & &9C400000 + & &A04DC000 + & &A4008000 + & &A8050000 ; VBSR + & &AC098000 ; VDSR + & &B0000000 ; VDER < VDSR to disable screen DMA B0000000 + & &B44DC000 ; VBER + & &E00000B2 +; +; Additional setup : cursor blanked, sound frequency test bit set +; + & &C0000100 ; SFR NB. TEST BIT! - also DFlynn requested value + & &98258000 ; HCSR + & &B8004000 ; VCSR + & &BC400000 ; VCER +; don't mess with the stereo image registers: sound code will set them. + & &FFFFFFFF ; That's the lot + +; +; Further registers to turn screen DMA on again (border all over) +; Must have a video start register before video end register to get +; a vertical flyback interrupt. +; + & &B0494000 ; VDER > VDSR to enable screen DMA + & &FFFFFFFF + ] + + [ VIDC_Type = "VIDC20" + +; This differs from the default RISC OS VIDCTAB in running from +; the 24MHZ video ref clock. H register contents are increased by 50%. + +; Program Control Register first, to clear power-down bit + + & &E0000402 ; CR: FIFO load 16 words, 1 bpp, ck/1, rclk + & &E0000402 ; + & &B1000001 ; SCR: sound disabled (+use 24MHz clock) + +; Don't bother programming all 256 palette entries, we'll be here all night +; Since we're setting up a 1 bit-per-pixel mode, just do colours 0 and 1 + + & &10000000 ; Palette address register = 0 + & &00000000 ; Colour 0 = black + & &00000000 ; Colour 1 = black + & &407f7f7f ; Border colour = grey + & &50000000 ; Pointer colour 1 = black + & &60000000 ; Pointer colour 2 = black + & &70000000 ; Pointer colour 3 = black + +; Get a stable display up so we get stable signals + + & &800005F8 ; HCR = 114 + 132 + 144 + 960 + 144 + 42 + & &8100006A ; HSWR = 114 + & &820000EA ; HBSR = 114 + 132 + & &83000174 ; HDSR = 114 + 132 + 144 + & &84000534 ; HDER = 114 + 132 + 144 + 960 + & &850005CA ; HBER = 114 + 132 + 144 + 960 + 144 + & &860000F3 ; HCSR = HDSR + + & &90000137 ; VCR = 3 + 19 + 16 + 256 + 16 + 2 + & &91000002 ; VSWR = 3 + & &92000015 ; VBSR = 3 + 19 + & &93000025 ; VDSR = 3 + 19 + 16 + & &94000024 ; VDER = VDSR -1 to disable sceeen DMA + & &95000135 ; VBER = 3 + 19 + 16 + 256 + 16 + & &96000025 ; VCSR = VDSR + & &97000025 ; VCER = VDSR + + & &C00F1003 ; EREG = comp sync, DACs on, ereg output ext lut + & &D000C385 ; FSYNREG, clk = (3+1)/(5+1) * 24MHz = 16MHz + & &F0013000 ; DCR: bus D[31:0], Hdisc + & &FFFFFFFF + + & &94000125 ; VDER > VDSR to enable screen DMA + & &FFFFFFFF + ; FSIZE is one less than number of rasters in Vflyback + & &00000037 ; (3 + 19 + 16 + 0 + 16 + 2) - 1 + + ; Alternate settings for VGA monitor + +TestVVIDCTAB + & &E0000402 ; CR: FIFO load 16 words, 1 bpp, ck/1, rclk + & &E0000402 ; + & &B1000001 ; SCR: sound disabled (+use 24MHz clock) + + & &10000000 ; Palette address register = 0 + & &00000000 ; Colour 0 = black + & &00000000 ; Colour 1 = black + & &407f7f7f ; Border colour = grey + & &50000000 ; Pointer colour 1 = black + & &60000000 ; Pointer colour 2 = black + & &70000000 ; Pointer colour 3 = black + + & &80000310 ; HCR = 92 + 45 + 0 + 640 + 0 + 16 + & &81000054 ; HSWR = 92 + & &82000080 ; HBSR = 92 + 45 + & &83000080 ; HDSR = 92 + 45 + 0 + & &84000300 ; HDER = 92 + 45 + 0 + 640 + & &85000300 ; HBER = 92 + 45 + 0 + 640 + 0 + & &86000080 ; HCSR = HDSR + + & &9000020B ; VCR = 2 + 32 + 0 + 480 + 0 + 11 + & &91000001 ; VSWR = 2 + & &92000021 ; VBSR = 2 + 32 + & &93000021 ; VDSR = 2 + 32 + 0 + & &94000020 ; VDER = VDSR -1 to disable sceeen DMA + & &95000201 ; VBER = 2 + 32 + 0 + 480 + 0 + & &96000021 ; VCSR = VDSR + & &97000021 ; VCER = VDSR + + & &C0051003 ; EREG = sep/inv sync, DACs on, ereg output ext lut + & &D000C385 ; FSYNREG, clk = (3+1)/(5+1) * 24MHz = 16MHz + & &F0013000 ; DCR: bus D[31:0], Hdisc + & &FFFFFFFF + + ] + + END + + + diff --git a/Version b/Version new file mode 100644 index 0000000000000000000000000000000000000000..d58dbdb8ca51445f918d58cb2f81c5fd71d0a96f --- /dev/null +++ b/Version @@ -0,0 +1,11 @@ +; > Versions.Vicky + + GBLA Version + GBLS VString + GBLS Date + +Version SETA 360 +VString SETS "3.60" +Date SETS "13 Apr 1995" ; release/srcfiler vers 4.27 + + END diff --git a/hdr/EnvNumbers b/hdr/EnvNumbers new file mode 100644 index 0000000000000000000000000000000000000000..68023aef1a6d65b06c8bdccaa0c57bae5e6896ad --- /dev/null +++ b/hdr/EnvNumbers @@ -0,0 +1,61 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + SUBT => &.Hdr.EnvNumbers + +OldOpt SETA {OPT} + OPT OptNoList+OptNoP1List + +; *********************************** +; *** C h a n g e L i s t *** +; *********************************** + +; Date Name Description +; ---- ---- ----------- +; 15-Aug-88 SKS Added numbers in comments +; 09-Jun-94 AMcC Added comment associating this header with +; OS_ChangeEnvironment +; +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Codes in R0 for OS_ChangeEnvironment +; ==================================== + ^ 0 +MemoryLimit # 1 ; 0 R2 ignored + +UndefinedHandler # 1 ; 1 " " +PrefetchAbortHandler # 1 ; 2 " " +DataAbortHandler # 1 ; 3 " " +AddressExceptionHandler # 1 ; 4 " " +OtherExceptionHandler # 1 ; 5 for FPU exception etc. expansion + +ErrorHandler # 1 ; 6 R3 is error buffer pointer +CallBackHandler # 1 ; 7 R3 is register buffer ptr +BreakPointHandler # 1 ; 8 R3 is register buffer ptr + +EscapeHandler # 1 ; 9 +EventHandler # 1 ; 10 +ExitHandler # 1 ; 11 +UnusedSWIHandler # 1 ; 12 + +ExceptionDumpArea # 1 ; 13 + +ApplicationSpaceSize # 1 ; 14 +CAOPointer # 1 ; 15 + +UpCallHandler # 1 ; 16 + +MaxEnvNumber # 1 + + OPT OldOpt + END diff --git a/hdr/ExportVals/!HowTo b/hdr/ExportVals/!HowTo new file mode 100644 index 0000000000000000000000000000000000000000..ef144d4ef0f1182e51a02488881d7f9071762dd9 --- /dev/null +++ b/hdr/ExportVals/!HowTo @@ -0,0 +1,7 @@ +To add a Kernel workspace variable name to PublicWS: + +1) Add a LabelValue line for the variable to s.GetVals +2) Run Mk +3) See what value was generated for the variable in 'values' +3) 'Export' the variable in hdr.KernelWS (see any other exported variable) +4) Add the variable and its value to hdr.PublicWS diff --git a/hdr/ExportVals/Makefile b/hdr/ExportVals/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c2937e9da4e6416f762bc87a2858544f2c499067 --- /dev/null +++ b/hdr/ExportVals/Makefile @@ -0,0 +1,38 @@ +# Copyright 1996 Acorn Computers Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Makefile for ExportVals +# + +# +# Generic options: +# +MKDIR = cdir +AS = aasm +CP = copy +RM = remove +CCFLAGS = -c -depend !Depend -IC: +ASFLAGS = -Stamp -quit +CPFLAGS = ~cfr~v + + +# +# Generic rules: +# +all: + ${AS} ${ASFLAGS} -To null: -From s.GetVals { > values } + settype values text + @echo ok + +# Dynamic dependencies: diff --git a/hdr/ExportVals/Mk,fd7 b/hdr/ExportVals/Mk,fd7 new file mode 100644 index 0000000000000000000000000000000000000000..d645a7f6ff580e2eb720938cbc890d4c27a8a07a --- /dev/null +++ b/hdr/ExportVals/Mk,fd7 @@ -0,0 +1,16 @@ +| Copyright 1996 Acorn Computers Ltd +| +| Licensed under the Apache License, Version 2.0 (the "License"); +| you may not use this file except in compliance with the License. +| You may obtain a copy of the License at +| +| http://www.apache.org/licenses/LICENSE-2.0 +| +| Unless required by applicable law or agreed to in writing, software +| distributed under the License is distributed on an "AS IS" BASIS, +| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +| See the License for the specific language governing permissions and +| limitations under the License. +| +Dir <Obey$Dir> +amu_machine diff --git a/hdr/ExportVals/s/GetVals b/hdr/ExportVals/s/GetVals new file mode 100644 index 0000000000000000000000000000000000000000..298047f5a1fc74635fd9aece810b226bd932ea09 --- /dev/null +++ b/hdr/ExportVals/s/GetVals @@ -0,0 +1,69 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + GET Hdr:ListOpts + GET Hdr:Macros + GET Hdr:System + GET Hdr:Machine.<Machine> + GET ^.PublicWS + GET ^.KernelWS + + MACRO + LabelValue $LabelName + LCLS String +String SETS "Label " :CC: "$LabelName" :CC: " has the value &" +String SETS "$String" :CC: :STR: $LabelName + ! 0, "$String" + MEND + + MACRO + RegisterLabelValue $LabelName + LCLS String + LCLA Register +String SETS "Label " :CC: "$LabelName" :CC: " has the value &" +String SETS "$String" :CC: :STR: ( :INDEX: $LabelName) +Register SETA :BASE: $LabelName + [ Register >= 10 +String SETS "$String" :CC: ", R" :CC: ((:STR: (Register+6)) :RIGHT: 2) + | +String SETS "$String" :CC: ", R" :CC: ((:STR: Register) :RIGHT: 1) + ] + ! 0, "$String" + MEND + + + LabelValue Export_BgEcfOraEor + LabelValue Export_FgEcfOraEor + LabelValue Export_BranchToSWIExit + LabelValue Export_DomainId + LabelValue Export_ESC_Status + LabelValue Export_IRQsema + LabelValue Export_LatchBSoftCopy + LabelValue Export_MEMC_CR_SoftCopy + LabelValue Export_RedirectInHandle + LabelValue Export_RedirectOutHandle + LabelValue Export_ScratchSpace + LabelValue ScratchSpaceSize + LabelValue Export_SoundDMABuffers + LabelValue Export_SoundDMABufferSize + LabelValue Export_SoundWorkSpace + LabelValue Export_SVCSTK + LabelValue Export_SvcTable + LabelValue Export_SysHeapStart + LabelValue Export_VduDriverWorkSpace + LabelValue VDWSSize + LabelValue ScreenBlankFlag + LabelValue ScreenBlankDPMSState + + END diff --git a/hdr/ExportVals/values b/hdr/ExportVals/values new file mode 100644 index 0000000000000000000000000000000000000000..6376db1797946d8ef5c090fca54768d413cea635 --- /dev/null +++ b/hdr/ExportVals/values @@ -0,0 +1,37 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +ARM stand alone Macro Assembler Version 2.00 +Label Export_BgEcfOraEor has the value &000004C0 +Label Export_FgEcfOraEor has the value &00000480 +Label Export_BranchToSWIExit has the value &01F037FC +Label Export_DomainId has the value &00000FF8 +Label Export_ESC_Status has the value &00000104 +Label Export_IRQsema has the value &00000108 +Label Export_LatchBSoftCopy has the value &00000105 +Label Export_MEMC_CR_SoftCopy has the value &00000114 +Label Export_RedirectInHandle has the value &00000AE1 +Label Export_RedirectOutHandle has the value &00000AE2 +Label Export_ScratchSpace has the value &00004000 +Label ScratchSpaceSize has the value &00004000 +Label Export_SoundDMABuffers has the value &01F06000 +Label Export_SoundDMABufferSize has the value &00001000 +Label Export_SoundWorkSpace has the value &01F04000 +Label Export_SVCSTK has the value &01C02000 +Label Export_SvcTable has the value &01F033FC +Label Export_SysHeapStart has the value &01C02000 +Label Export_VduDriverWorkSpace has the value &00001000 +Label VDWSSize has the value &00003000 +Label ScreenBlankFlag has the value &0000047C +Label ScreenBlankDPMSState has the value &0000047D diff --git a/hdr/KernelWS b/hdr/KernelWS new file mode 100644 index 0000000000000000000000000000000000000000..22d3d64faed773db109072436807f1a709673857 --- /dev/null +++ b/hdr/KernelWS @@ -0,0 +1,1424 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + SUBT > Kernel WorkSpace + +OldOpt SETA {OPT} + OPT OptNoList+OptNoP1List + +; *********************************** +; *** C h a n g e L i s t *** +; *********************************** + +; Date Name Description +; ---- ---- ----------- +; 02-Nov-87 APT Added module SWI hash table +; 03-Nov-87 APT Modo-fied module SWI hash table info, removed BRKLST +; 09-Nov-87 APT Removed ESCCNT and ESFLG +; 12-Nov-87 APT Added IRQsema +; 13-Nov-87 APT Added DefaultIRQ1V codespace +; 16-Nov-87 APT PIRQ chain heads +; 18-Nov-87 APT Reordered EvtHan, EvtHan_ws +; 19-Nov-87 APT Moved IRQsema +; 01-Dec-87 APT Added interruptible heap manager workspace +; 08-Dec-87 TMD Added ECFShift, ECFYOffset +; 14-Dec-87 TMD Added DisplayNColour, DisplayModeFlags +; 15-Dec-87 TMD Added KeyAlphabet +; 22-Dec-87 NDR Using ScratchSpace +; 13-Jan-88 APT General scratchspace bash, low workspace reordering. +; Removed spurious 32 bytes of osbyte wspace +; 14-Jan-88 APT *type buffer in scratchspace. +; MOShasFIQ byte added +; 20-Jan-88 APT Workspace juggling for speed & space; also discarded +; Level0 stuff. +; 28-Jan-88 APT MetroGnome moved to "public" location for ADFS +; 02-Feb-88 APT FIQclaim_interlock added +; 05-Feb-88 APT CallBack_Vector +; 09-Feb-88 APT RAM for SWI despatch +; 17-Feb-88 TMD Added VduSaveArea, VduSaveAreaPtr, DisplayModeNo +; 26-Feb-88 APT NoOfCamEntries manifest +; 03-Mar-88 APT Shrank SVC despatch +; 03-Mar-88 APT NoOfCamEntries manifest doubled +; 07-Mar-88 TMD Added DisplayScreenStart, VduOutputCurrentState, +; SpriteMaskSelect, reordered mode variables +; 07-Mar-88 APT Made CamEntries always at &164 +; 07-Mar-88 TMD Added GCharSizes, GCharSizeX, GCharSizeY +; 08-Mar-88 TMD Added GCharSpacing, GCharSpaceX, GCharSpaceY +; 08-Mar-88 TMD Moved GCharSizes..GCharSpaceY into first 1K of workspace +; 15-Mar-88 TMD Added HLineAddr +; 18-Mar-88 TMD Added DisplayXWindLimit, DisplayYWindLimit, +; DisplayXEigFactor, DisplayYEigFactor, PointerXEigFactor +; 18-Mar-88 APT Setting variables scratchspace use revised. +; 21-Mar-88 TMD Removed CursorIndex +; 22-Mar-88 TMD Added TCharSizeX,TCharSizeY,TCharSpaceX,TCharSpaceY +; 29-Mar-88 TMD Added GcolOraEorAddr +; 31-Mar-88 TMD Removed WsFontPtr +; 07-Apr-88 SKS Added HeapSort use of ScratchSpace +; 14-Apr-88 TMD Added SerialFlags +; 28-Apr-88 TMD Added XONXOFFChar +; 5-May-88 APT Added MemorySpeed +; 18-May-88 APT Added CannotReset sema at &107, removed pre-1.20 changes. +; 24-May-88 TMD Added ClipBoxEnable, ClipBoxLCol..ClipBoxTRow, moved in +; ScrLoaSpriteCB, ScrLoaBuffer, SrcSavCommon +; 24-May-88 TMD Flood fill uses ScratchSpace +; 01-Jun-88 TMD Added AlignSpace for ClipBoxCoords +; 03-Jun-88 BCSKS Make Keyboard buffer into a useful part of the system +; Also PrinterBufferSize +; 09-Jun-88 DJS Draw uses ScratchSpace +; 09-Jun-88 BC Gave Econet some private debungling space +; 11-Jun-88 SKS Align IRQ stack to make STMFD not cross two MEMC bdy's +; Made info condit'l on AsmArf; someone had commented it out! +; 15-Jun-88 SKS Added two more instructions in SWIDespatch area +; Moved SLVK definition into kernel; it's not public +; 16-Jun-88 SKS Added 3 more instructions in SWIDespatch area + nailed +; SvcTable address for compatibility +; 22-Jun-88 SKS Moved MEMC_CR_SoftCopy into pubic ws +; 19-Jul-88 APT Added UpCall handler stuff +; 20-Jul-88 SKS Added above entry +; Amended comment about overlaid workspace in vdu +; 15-Aug-88 SKS Inserted DomainId at FF8 (set by Wimp on task swap, used by +; FileSwitch to tag resources) +; 27-Sep-89 JSR Added ColourTrans to users of scratch space +; 24-Oct-89 TMD Added CamEntriesForBigMachines, CamEntriesPointer +; 26-Oct-89 TMD Added MaxCamEntry, removed NoOfCamEntries symbol +; 27-Oct-89 TMD Added VIDCClockSpeed +; 09-Nov-89 TMD Added ResetIndirection +; 15-Jan-91 TMD Added ROMModuleChain +; 04-Feb-91 DDV Added DeviceFS as user of ScratchSpace. +; 04-Feb-91 DDV Added ColourTrans use of ScratchSpace to build diff tables. +; 06-Mar-91 TMD Added IOSystemType +; 07-Mar-91 LVR ADFS uses scratch space for floppy formatting +; 07-Mar-91 TMD Added MonitorLeadType +; 08-Mar-91 TMD Added PrinterBufferAddr, PrinterBufferSize +; 11-Apr-91 TMD Added SerialInHandle, SerialOutHandle +; 24-Apr-91 TMD Added UniqueMachineID +; 09-Jun-91 RM Added KernelMessagesBlock,ErrorSemaphore and MOSConvertBuffer +; 26-Jul-91 JSR Extend GeneralMOSBuffer by 4 bytes to make it a valid +; length for the default error handler's error buffer +; 19-Aug-91 JSR Added *If to list of GeneralMOSBuffer users +; 22-Aug-91 TMD Reduced ErrorSemaphore to a byte, added PortableFlag +; 25-Aug-91 DDV Updated to indicate correct usage of scratch space by ColourTrans +; 09-Jan-92 DDV Added FgPattern, BgPattern and indicate use of ScratchSpace by OS_SetColour +; 20-Jan-92 TMD OS_SetColour no longer uses ScratchSpace +; 17-Feb-92 ECN Added CLibWord and RISCOSLibWord +; 02-Apr-92 TMD Added ScreenBlankFlag +; 27-Jul-92 TMD Create Victoria specific version +; 28-Jul-92 TMD Moved RAMDiscAddress +; 29-Jul-92 TMD Moved SpriteSpaceAddress +; 30-Jul-92 TMD Moved FontCacheAddress +; 31-Jul-92 TMD Moved ScreenEndAdr from source.vdudecl, and moved actual address! +; 03-Aug-92 TMD Added PhysRam (moved from hdr:System) +; 24-Aug-92 TMD Added AbortIndirection +; 26-Aug-92 TMD Added PreVeneerRegDump +; 02-Sep-92 TMD Added FirPalAddr, SecPalAddr +; 10-Sep-92 DDV Added new Vdu Variables for new text expansion buffer +; 17-Sep-92 DDV Moved NColour into the word initialised VDU workspace +; 17-Sep-92 DDV Two new colour words added for text foreground and background. +; 27-Jan-93 TMD Moved RMA to new position +; 29-Jan-93 TMD Put RMA back to old position (you can't branch to above 32M!) +; 01-Feb-93 TMD Added PhysRamTable +; 02-Feb-93 TMD Added VInitSoftCopy and VEndSoftCopy +; 03-Feb-93 TMD Added PhysRamTableEnd +; 04-Feb-93 TMD Added extra slot in PhysRamTable (in case soft-loaded OS splits a bank) +; 08-Feb-93 TMD Added VRAMWidth variable, and extra symbols for skipped bits +; 24-Feb-93 TMD Changed VRAMPhysAddr to VideoPhysAddr, and split off VideoSize from VRAMSize, to allow for +; DRAM-only systems +; 05-Mar-93 TMD Added CMOSRAMCache +; 19-Apr-93 TMD Added DAList, AppSpaceDANode and DANode offset symbols +; 26-Apr-93 TMD Added FreePoolAddress, FreePoolMaxSize, FreePoolSize +; 29-Apr-93 TMD Changed FontCacheAddress, SpriteSpaceAddress, RAMDiscAddress and FreePoolAddress +; in order to make way for L2PT, which is moving above 64M +; 10-May-93 TMD Added SoftCamMapSize +; 11-May-93 TMD Moved SoftCamMapSize into area that's not zapped in clearing all memory routine +; 12-May-93 TMD Added FreePoolDANode, removed FreePoolSize +; 20-May-93 TMD Moved AplWorkSize into AppSpaceDANode +; 27-May-93 TMD Added VideoBandwidth +; 04-Jun-93 TMD Added CurrentMonitorType +; 09-Jun-93 TMD Added CamMapCorruptDebugBlock +; 07-Jul-93 TMD Increased FreePoolMaxSize to 64M (had to reduce RAMDiscMaxSize to 48M and +; move FreePoolAddress down to do this) +; 15-Jul-93 TMD Added KernelModeSelector +; 26-Jul-93 SMC Moved DefaultIRQ1V (had to accommodate IRQs for IOMD DMA) +; 04-Aug-93 TMD Added L2PTSize, removed FreePoolMaxSize +; 14-Aug-93 TMD Removed SpriteSpaceAddress, shuffled things down +; 16-Aug-93 TMD Removed RAMDiscAddress, shuffled things down +; 17-Aug-93 TMD Removed FontCacheAddress, shuffled things down +; Corrected maximum size of system heap to 2M-8K. +; Added node (in bottom 32K) for system heap. +; 25-Aug-93 SMC Added processor vector table at ProcVec_Start +; Added ProcVecPreVeneers +; 02-Sep-93 SMC Moved RMA to &02100000 and changed application space size to 28M. +; 03-Sep-93 TMD Moved InitKbdWs into SkippedTables (was at start of screen originally) +; 07-Oct-93 TMD Put in OldMemoryMap option so I can still use it +; 07-Oct-93 TMD Added ScreenBlankDPMSState, HSWRSoftCopy, VSWRSoftCopy +; 10-Dec-93 BC Added RawMachineID +; 13-Dec-93 BC Removed UniqueMachineID +; 14-Jan-94 TMD Added CDASemaphore +; 18-Jan-94 TMD Added MMUControlSoftCopy +; 15-Jun-94 AMcC Renamed file (was VickySpace) +; The following values are 'exported' to PublicWS: +; Name: Used by: +; ---------------------------------- +; BgEcfOraEor SprExtend +; FgEcfOraEor SprExtend +; BranchToSWIExit TaskWindow +; CannotReset FileCore +; DomainId FileSwitch +; ESC_Status ADFS, DeviceFS +; IRQsema Draw, MsgTrans +; LatchBSoftCopy ADFS, Parallel +; MEMC_CR_SoftCopy ADFS +; RedirectInHandle TaskWindow +; RedirectOutHandle TaskWindow +; ScratchSpace ADFS, Colours, Draw, FileCore +; FileSwitch, FontManager, NetFiler +; SoundDMABufferSize Sound0 +; SoundDMABuffers Sound0 +; SoundWorkSpace Portable, Sound1, Sound2, Voices +; SVCSTK FileSwitch +; SvcTable TaskWindow, Wimp +; SysHeapStart FileSwitch +; VduDriverWorkSpace SprExtend +; +; 31-Oct-94 AMcC/RM/WT Added CLine_Softcopy for Morris monitor id +; 03-Nov-94 AMcC Export ScreenBlankFlag and ScreenBlankDPMSState +; (for DPMSUtils: part of RISC OS releases 3.50 and 3.60) +; 06-Feb-95 SMC Increased SVC stack size to 12K. +; +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Memory map: + +; Dynamic area node format + + ^ 0 + +DANode_Link # 4 ; points to next node +DANode_Number # 4 ; number of this area +DANode_Base # 4 ; base address of area (points in middle of doubly-mapped areas) +DANode_Flags # 4 ; various flags +DANode_Size # 4 ; current size of area +DANode_MaxSize # 4 ; maximum size of area +DANode_Workspace # 4 ; workspace pointer when calling handlers +DANode_Handler # 4 ; pointer to handler routine for area +DANode_Title # 4 ; pointer to area title (variable length) +DANode_NodeSize # 0 + +; The addresses below are only temporary; eventually most of them will be allocated at run time (we hope!) + + [ :DEF: OldMemoryMap +AplWorkMaxSize * &01000000 ; 16M +RMAAddress * &01800000 +RMAMaxSize * &00400000 ; 4M + | +AplWorkMaxSize * &01C00000 ; 28M +RMAAddress * &02100000 +RMAMaxSize * &00B00000 ; 11M + ] + +SVCStackSize * 8*1024 + +SysHeapChunkAddress * &01C00000 +SysHeapMaxSize * &00200000-SVCStackSize + +CursorChunkAddress * &01F00000 ; Fixed size 32K + +ScreenEndAdr * &05000000 ; was &02000000 +ScreenMaxSize * 480*1024 + +; FontCacheAddress * &06000000 ; was &01E00000 ; now dynamic +; FontCacheMaxSize * &01000000 ; 16M + +; SpriteSpaceAddress * &08000000 ; was &01400000 ; now dynamic +; SpriteSpaceMaxSize * &01000000 ; 16M + +; RAMDiscAddress * &07000000 ; was &01000000 ; now dynamic +; RAMDiscMaxSize * &03000000 ; 48M + +FreePoolAddress * &06000000 ; may still go lower! + +PhysRam * &05000000 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; system variables + + ^ 0,R12 + +OSBYTEFirstVar # 0 + +ByteVars # 0 ; The main osbyte variables, accessed + ; via calls &A6 to &FF + +VarStart # 2 ; &A6,&A7 +ROMPtr # 2 ; &A8,&A9 +ROMInfo # 2 ; &AA,&AB +KBTran # 2 ; &AC,&AD +VDUvars # 2 ; &AE,&AF + +CFStime # 1 ; &B0 +InputStream # 1 ; &B1 +KeyBdSema # 1 ; &B2 + +ROMPollSema # 1 ; &B3 +OSHWM # 1 ; &B4 + +RS423mode # 1 ; &B5 +NoIgnore # 1 ; &B6 +CFSRFS # 1 ; &B7 +VULAcopy # 2 ; &B8,&B9 + +ROMatBRK # 1 ; &BA +BASICROM # 1 ; &BB + +ADCchanel # 1 ; &BC +ADCmaxchn # 1 ; &BD +ADCconv # 1 ; &BE + +RS423use # 1 ; &BF +RS423conflag # 1 ; &C0 + +FlashCount # 1 ; &C1 +SpacPeriod # 1 ; &C2 +MarkPeriod # 1 ; &C3 + +KeyRepDelay # 1 ; &C4 +KeyRepRate # 1 ; &C5 + +ExecFileH # 1 ; &C6 +SpoolFileH # 1 ; &C7 + +ESCBREAK # 1 ; &C8 (200) + +KeyBdDisable # 1 ; &C9 +KeyBdStatus # 1 ; &CA + +RS423HandShake # 1 ; &CB +RS423InputSupr # 1 ; &CC +RS423CFSFlag # 1 ; &CD + +EconetOScall # 1 ; &CE +EconetOSrdch # 1 ; &CF +EconetOSwrch # 1 ; &D0 + +SpeechSupr # 1 ; &D1 +SoundSupr # 1 ; &D2 + +BELLchannel # 1 ; &D3 +BELLinfo # 1 ; &D4 +BELLfreq # 1 ; &D5 +BELLdur # 1 ; &D6 + +StartMessSupr # 1 ; &D7 + +SoftKeyLen # 1 ; &D8 + +PageModeLineCount # 1 ; &D9 + +VDUqueueItems # 1 ; &DA + +TABch # 1 ; &DB +ESCch # 1 ; &DC + +IPbufferCh # 4 ; &DD,&DE,&DF,&E0 +RedKeyCh # 4 ; &E1,&E2,&E3,&E4 + +ESCaction # 1 ; &E5 +ESCeffect # 1 ; &E6 + +u6522IRQ # 1 ; &E7 +s6850IRQ # 1 ; &E8 +s6522IRQ # 1 ; &E9 + +TubeFlag # 1 ; &EA + +SpeechFlag # 1 ; &EB + +WrchDest # 1 ; &EC +CurEdit # 1 ; &ED + +SoftResetVars # 0 ; Reset to here on soft reset + +KeyBase # 1 ; &EE +Shadow # 1 ; &EF +Country # 1 ; &F0 + +UserFlag # 1 ; &F1 + +SerULAreg # 1 ; &F2 + +TimerState # 1 ; &F3 + +SoftKeyConsist # 1 ; &F4 + +PrinterDrivType # 1 ; &F5 +PrinterIgnore # 1 ; &F6 + +HardResetVars # 0 ; Reset to here on hard reset + +BREAKvector # 3 ; &F7,&F8,&F9 + +MemDriver # 1 ; &FA - where the VDU drivers write to +MemDisplay # 1 ; &FB - where we display from + +LangROM # 1 ; &FC + +LastBREAK # 1 ; &FD + +KeyOpt # 1 ; &FE + +StartOptions # 1 ; &FF + +PowerOnResetVars # 0 ; Reset to here on power-on reset + +; These two can dovetail in here to use up 2 bytes before the AlignSpace! + +SerialInHandle # 1 ; Handle for serial input stream (0 if not open currently) +SerialOutHandle # 1 ; Handle for serial output stream (-----------""----------) + + AlignSpace + +EventSemaphores # 32 ; One byte for each of 32 events + +TimerAlpha # 8 ; As used by time (bottom 5 bytes) +TimerBeta # 8 ; ................................ +; both aligned to word boundaries + +RealTime # 8 ; 5-byte fast real-time + +PrinterActive # 4 ; Handle/active flag for printer (word aligned) + +IntervalTimer # 5 ; Up Counter synchronous with TIME. +; Event generated when Zero is reached +; bottom byte aligned to word boundary + +SecondsTime # 1 ; the soft copy (centi-)seconds of the RTC +CentiTime # 1 ; """""""""""""""""""""""""""""""""""""""" + +FlashState # 1 ; which flash colours are we using + +SecondsDirty # 1 ; the dirty flag for start up! + +MinTick # 1 ; the minutes odd/even state + +DCDDSRCopy # 1 ; copy of ACIA bits to check for change + +TVVertical # 1 ; *TV first parameter + +TVInterlace # 1 ; *TV second parameter + +CentiCounter # 1 ; Counter for VDU CTRL timing + +Alphabet # 1 ; Current alphabet number + +Keyboard # 1 ; Current keyboard number + +KeyAlphabet # 1 ; Alphabet associated with current keyboard + + GBLS PrinterPrefix +PrinterPrefix SETS "PrinterType$" + +PrinterTypeName # 6 + :LEN: (PrinterPrefix) + + AlignSpace + +SerialFlags # 4 ; New serial flags + +XONXOFFChar # 1 ; Character to send before rest (0 if none) + + AlignSpace + +OSBYTEVarSize * @-OSBYTEFirstVar + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +; End of variables' space + + +; *********************************** +; *** Main Vdu Driver Workspace *** +; *********************************** + + ^ 0 + +FgEcf # 4 * 8 ; Foreground Ecf, set by GCOL(a,0-127) +BgEcf # 4 * 8 ; Background Ecf, set by GCOL(a,128-255) +GPLFMD # 4 ; Foreground action, set by GCOL(a,0-127) +GPLBMD # 4 ; Background action, set by GCOL(a,128-255) +GFCOL # 4 ; Foreground colour, set by GCOL(a,0-127) +GBCOL # 4 ; Background colour, set by GCOL(a,128-255) + +GWLCol # 4 ; Graphics window left column -- +GWBRow # 4 ; Graphics window bottom row | +GWRCol # 4 ; Graphics window right column | +GWTRow # 4 ; Graphics window top row -- + +qqqPad # 3 +QQ # 17 ;Queue - QQ+1 is on a word boundary +QOffset # 4 ;Value to add to VDUqueueItems to point to next queue posn. +JVec # 4 ;Jump vector to internal routines + +; Start of MODE table workspace + +ScreenSize # 4 ; number of bytes needed for this mode (assumed 1st in list) + +XWindLimit # 4 ; Maximum value of GWRCol (internal representation) + +; LineLength must be immediately after YWindLimit + +YWindLimit # 4 ; Maximum value of GWTRow (internal representation) + +LineLength # 4 ; Length of one pixel row in bytes + +NColour # 4 ; Number of colours minus 1 + +; End of word mode variables + +YShftFactor # 4 ; Number of places to shift YCoord in address generation after + ; multiplying by 5, holds + ; 7,6,5 or 4 for 8,4,2 or 1 bits per pixel (640x256 mode) or + ; 6,5,4 or 3 for 8,4,2 or 1 bits per pixel (320x256 mode). + +ModeFlags # 4 ; Bit 0 => non-graphic, Bit 1 => teletext, Bit 2 => gap mode + +XEigFactor # 4 ; Number of places to shift XCoord in external to internal + ; coordinate conversion, holds + ; 1 for 640x256 mode + ; 2 for 320x256 mode + ; 3 for 160x256 (BBC micro mode 2) + +YEigFactor # 4 ; number of shifts to convert between internal/external Y + +Log2BPC # 4 ; Log to base 2 of BytesPerChar ie (0,1,2,3,4) + +Log2BPP # 4 ; Log to base 2 of BitsPerPix ie (0,1,2,3) + +ECFIndex # 4 ; Index into default ECF tables + +ScrRCol # 4 ; Maximum column number in this screen mode +ScrBRow # 4 ; Maximum row number in this screen mode + +PalIndex # 4 ; Index into palette tables (0,1,2,3) + +; End of table-initialised workspace + +; Next 3 must be together in this order ! + +XShftFactor # 4 ; Number of places to shift XCoord in address generation, + ; holds 2,3,4 or 5 for 8,4,2,1 bits per pixel respectivly +GColAdr # 4 ; Address of Ecf to plot - either FgEcf or BgEcf + +ScreenStart # 4 ; Start address of screen (for VDU drivers) + +NPix # 4 ; Number of pixels per word minus 1, holds + ; holds 3,7,15 or 31 for 8,4,2,1 bits per pixel modes + +AspectRatio # 4 ; Pixel shape : 0 square, 1 horz rect, 2 vert rect + +BitsPerPix # 4 ; Bits per pixel (1,2,4,8) + +BytesPerChar # 4 ; Bytes per one line of character + ; (same as BitsPerPix except in double pixel modes) + +CursorFudgeFactor # 4 ; Factor for horizontal cursor positioning + +RowMult # 4 ; Row multiplier for text manipulation + +RowLength # 4 ; Bytes per text row in this mode (eg 640,1280,5120) + +; The following (up to and including NewPtY) must be together in this order +; (relied upon by DefaultWindows) + +TWLCol # 4 ; Text window left column -- +TWBRow # 4 ; Text window bottom row | +TWRCol # 4 ; Text window right column | +TWTRow # 4 ; Text window top row -- + +OrgX # 4 ; Screen origin (external representation) +OrgY # 4 + +GCsX # 4 ; Graphics cursor (external representation) +GCsY # 4 + +OlderCsX # 4 ; Very old X coordinate (internal) +OlderCsY # 4 ; Very old Y coordinate (internal) + +OldCsX # 4 ; Old graphics cursor (internal representation) -- +OldCsY # 4 ; | + ; | +GCsIX # 4 ; Graphics cursor (internal representation) | +GCsIY # 4 ; | + ; | +NewPtX # 4 ; Newest point (internal representation) | +NewPtY # 4 ; -- + +; End of together block + +TForeCol # 4 ; Text foreground colour +TBackCol # 4 ; Text background colour + +CursorX # 4 ; Text cursor X position ; these 3 must be in same order as ... +CursorY # 4 ; Text cursor Y position +CursorAddr # 4 ; Screen address of (output) cursor + +InputCursorX # 4 ; Input cursor X position ; ... these 3 +InputCursorY # 4 ; Input cursor Y position +InputCursorAddr # 4 ; Screen address of input cursor + +EORtoggle # 4 ; Toggle between gap and non-gap +RowsToDo # 4 ; in the CLS + +VduStatus # 4 ; Vdu2, Window, Shadow bits (others in CursorFlags) + +CBWS # 8 ; Clear block (VDU 23,8..) workspace +CBStart # 2 +CBEnd # 2 + +CursorDesiredState # 4 +CursorStartOffset # 4 +CursorEndOffset # 4 +CursorCounter # 4 +CursorSpeed # 4 +Reg10Copy # 4 + +CursorFill # 4 ; Word to EOR cursor ; MUST be immediately before CursorNbit + +CursorNbit # 4 ; Pointer to cursor code for current mode + +DisplayStart # 4 ; Start address of screen (for display) +DriverBankAddr # 4 ; Default start address for VDU drivers +DisplayBankAddr # 4 ; Default start address for display +DisplayNColour # 4 ; No. of colours -1 for displayed mode +DisplayModeFlags # 4 ; ModeFlags for displayed mode +DisplayModeNo # 4 ; ModeNo for displayed mode +DisplayScreenStart # 4 ; Where VDU outputs to when outputting to screen + +DisplayXWindLimit # 4 ; Used for pointer programming +DisplayYWindLimit # 4 +DisplayXEigFactor # 4 +DisplayYEigFactor # 4 +PointerXEigFactor # 4 + +Ecf1 # 8 ; The Ecf patterns +Ecf2 # 8 +Ecf3 # 8 +Ecf4 # 8 + +DotLineStyle # 8 ; Dot dash line pattern + +ModeNo # 4 ; Current mode number + +TFTint # 4 ; Text foreground tint (in bits 6,7) +TBTint # 4 ; Text background tint +GFTint # 4 ; Graphics foreground tint +GBTint # 4 ; Graphics background tint + +TotalScreenSize # 4 ; Amount configured for screen (in bytes) + +MaxMode # 4 ; Maximum mode number allowed (20 for now) + +VinitCopy # 4 ; Copy of Vinit for VDU 23;12 or 13 + +CursorFlags # 4 ; Silly Master cursor movement flags + +CursorStack # 4 ; Bit stack of nested cursor states (0 => on, 1 => off) + ; (bit 31 = TOS) + +ECFShift # 4 ; number of bits to rotate right ECF OR and EOR masks by +ECFYOffset # 4 ; vertical offset to ECF index + +WsVdu5 # 0 ; Vdu 5 workspace +WsScr # 4 +WsEcfPtr # 4 +; WsFontPtr # 4 ; not needed any more, kept in register +EndVerti # 4 +StartMask # 4 +EndMask # 4 +FontOffset # 4 +TempPlain # 16 ; only used for MODE 10 + +VIDCClockSpeed # 4 ; current VIDC clock speed in kHz + +CurrentMonitorType # 4 ; initialised from configured one + +KernelModeSelector # 4 ; pointer to block in system heap where + ; current mode selector is copied + +GraphicWs # 300 ; All graphics workspace is overlaid here +EndGraphicWs # 0 + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 + +GCharSizes # 0 +GCharSizeX # 4 ; width of VDU 5 chars in pixels +GCharSizeY # 4 ; height of VDU 5 chars in pixels + +GCharSpacing # 0 +GCharSpaceX # 4 ; horizontal spacing between VDU 5 chars in pixels +GCharSpaceY # 4 ; vertical ------------------""----------------- + +TCharSizes # 0 +TCharSizeX # 4 ; width of VDU 4 chars in pixels +TCharSizeY # 4 ; height of VDU 4 chars in pixels + +TCharSpacing # 0 +TCharSpaceX # 4 ; horizontal spacing between VDU 4 chars in pixels +TCharSpaceY # 4 ; vertical ------------------""----------------- + +HLineAddr # 4 ; address of exported HLine +GcolOraEorAddr # 4 ; address of FgEcfOraEor etc + +FirPalSetting # 4*28 ; First palette settings (not used on VIDC20) +FirPalAddr * FirPalSetting ; Address of block for first palette setting (only used on VIDC20) +SecPalSetting # 4*28 ; Second palette settings (not used on VIDC20) +SecPalAddr * SecPalSetting ; Address of block for second palette setting (only used on VIDC20) + +TextFgColour # 4 ; Fg/Bg colour stored as a colour number, computed on VDU 18 and re-poked! +TextBgColour # 4 ; + +; In this brave new world there is a pointer to the text expansion +; buffer used for VDU 4 / 5 text plotting. + +; This now lives in the system heap. + +TextExpandArea # 4 ; Pointer to Text expand area (in system heap) +TextExpandArea_Size * (8*1024) + +HSWRSoftCopy # 4 ; soft copy of h.sync width register (for DPMS) +VSWRSoftCopy # 4 ; soft copy of v.sync width register (for DPMS) + +;ScreenBlankFlag # 1 ; 0 => unblanked, 1 => blanked + +Export_ScreenBlankFlag # 1 + ASSERT Export_ScreenBlankFlag = ScreenBlankFlag + ASSERT ?Export_ScreenBlankFlag = ?ScreenBlankFlag + +;ScreenBlankDPMSState # 1 ; 0 => just blank video + ; 1 => blank to stand-by (hsync off) + ; 2 => blank to suspend (vsync off) + ; 3 => blank to off (H+V off) + +Export_ScreenBlankDPMSState # 1 + ASSERT Export_ScreenBlankDPMSState = ScreenBlankDPMSState + ASSERT ?Export_ScreenBlankDPMSState = ?ScreenBlankDPMSState + + + [ AssemblingArthur + ! 0,"64 ":CC::STR:@ + ] + AlignSpace 64 + +Export_FgEcfOraEor # 4*16 ; Interleaved zgora & zgeor + ASSERT Export_FgEcfOraEor = FgEcfOraEor + ASSERT ?Export_FgEcfOraEor = ?FgEcfOraEor + +Export_BgEcfOraEor # 4*16 ; Interleaved zgora & zgeor + ASSERT Export_BgEcfOraEor = BgEcfOraEor + ASSERT ?Export_BgEcfOraEor = ?BgEcfOraEor + +BgEcfStore # 4*16 ; Interleaved zgora & zgeor to store background + +;Current state of pattern +LineDotCnt # 4 ; Count down to restarting pattern +LineDotPatLSW # 4 ; Current state of pattern LSWord +LineDotPatMSW # 4 ; " " " " MSWord + +DotLineLength # 4 ; Dot Pattern repeat length as given in *FX163,242,n + +BBCcompatibleECFs # 4 ; 0 => BBC compatible, 1 => native + +SpAreaStart # 4 ; Start of sprite area +SpChooseName # 16 ; No comment says Richard +SpChoosePtr # 4 + +PointerHeights # 4 ; 4 x 1 byte +PointerActiveXs # 4 ; 4 x 1 byte +PointerActiveYs # 4 ; 4 x 1 byte +PointerShapeNumber # 4 ; only bottom byte used +PointerX # 4 ; co-ordinates of pointer (not always = mouse) +PointerY # 4 + +VIDCControlCopy # 4 ; Soft copy of VIDC control register +VertAdjust # 4 ; offset to add to vertical VIDC registers + +TeletextOffset # 4 ; Offset to current teletext flash bank + +TeletextCount # 4 ; Number of vsyncs till next teletext flash + +WrchNbit # 4 ; Pointer to char code for current mode + +BeepBlock # 8 ; OSWORD block for VDU 7 + +ScreenMemoryClaimed # 1 ; NZ => memory has been claimed or is unusable + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 ; Align workspace to 16 bytes + +TTXDoubleCounts # 25 ; Number of double height chars on each line + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 ; Align workspace to 16 bytes + +RAMMaskTb # 32*4 ; Copy of MaskTb for this mode (up to 32 words) + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 ; Align workspace to 16 bytes + +VduOutputCurrentState # 0 ; values of R0-R3 to return from SwitchOutputToSprite + ; or Mask; next 4 must be in this order +SpriteMaskSelect # 4 ; value of R0 to be given to SWI OS_SpriteOp to set up + ; current state +VduSpriteArea # 4 ; Pointer to sprite area containing VDU output sprite + ; (0 if output is to screen) +VduSprite # 4 ; Pointer to VDU output sprite (0 if output to screen) + +VduSaveAreaPtr # 4 ; Pointer to save area for VDU variables + + + [ AssemblingArthur + ! 0,"16,12 ":CC::STR:@ + ] + AlignSpace 16, 12 ; Make ClipBoxCoords a valid immediate, + ; with ClipBoxEnable immediately before it +ClipBoxInfo # 0 +ClipBoxEnable # 4 ; 0 => clip box disabled, 1 => enabled + +ClipBoxCoords # 0 ; Internal coords of modified area of screen +ClipBoxLCol # 4 +ClipBoxBRow # 4 +ClipBoxRCol # 4 +ClipBoxTRow # 4 + +FgPattern # 4*8 ; foreground pattern as defined by OS_SetColour +BgPattern # 4*8 ; background pattern as defined by OS_SetColour + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 ; Align workspace to 16 bytes + +TextExpand # 4*1024 ; Tim's massive text expansion table for whizzy WRCH +; TextPlain is now always hard against the end of TextExpand for this mode + +TTXSoftFonts * TextExpand + 2*1024 ; Soft fonts in teletext mode + + [ AssemblingArthur + ! 0,"64 ":CC::STR:@ + ] + AlignSpace 64 ; Align workspace to 64 bytes + +; Teletext map and copy/move buffer are overlaid + +TTXMapSize * 41*25*4 ; (&1004 bytes) +LargeCommon # TTXMapSize ; the largest area +TTXMap * LargeCommon + +ScrLoaSpriteCB * LargeCommon ; (size = SpriteCBsize + MaxSpritePaletteSize) +ScrLoaBuffer * LargeCommon ; (size = one pixel row) +ScrSavCommon * LargeCommon ; (size = SpriteAreaCBsize + SpriteCBsize + ; + MaxSpritePaletteSize) + +FldQueueSize * ScratchSpaceSize +FldQueueStart * ScratchSpace + + [ AssemblingArthur + ! 0,"64 ":CC::STR:@ + ] + AlignSpace 64 ; Align workspace to 64 bytes + +Font # &700 ; 7 pages of (soft) font + +SaveAreaSize * 12*1024-@ + +VduSaveArea # SaveAreaSize ; save area for switching output to sprites + +VDWSSize # 0 + + ASSERT VDWSSize <= 12 * 1024 + +; ***************************************************************************** +; Space in the first 32K is allocated below +; ***************************************************************************** +; Real workspace definition + +; Basic kernel space - defined locations for external modules + + ^ &100 +IRQ1V # 4 ; &100 + +Export_ESC_Status # 1 ; &104 + ASSERT Export_ESC_Status = ESC_Status + ASSERT ?Export_ESC_Status = ?ESC_Status + +Export_LatchBSoftCopy # 1 ; &105 + ASSERT Export_LatchBSoftCopy = LatchBSoftCopy + ASSERT ?Export_LatchBSoftCopy = ?LatchBSoftCopy + +IOCControlSoftCopy # 1 ; &106 + +Export_CannotReset # 1 ; &107 + ASSERT Export_CannotReset = CannotReset + ASSERT ?Export_CannotReset = ?CannotReset + +Export_IRQsema # 4 ; &108 + ASSERT Export_IRQsema = IRQsema + ASSERT ?Export_IRQsema = ?IRQsema + +MetroGnome # 4 ; &10C +MemorySpeed # 4 ; &110 + +Export_MEMC_CR_SoftCopy # 4 ; &114 + ASSERT Export_MEMC_CR_SoftCopy = MEMC_CR_SoftCopy + ASSERT ?Export_MEMC_CR_SoftCopy = ?MEMC_CR_SoftCopy + +ResetIndirection # 4 ; &118 + +; Now all internal definitions + +; Up to here is initialized on reset + +; Next come handler variables + +MemLimit # 4 +UndHan # 4 +PAbHan # 4 +DAbHan # 4 +AdXHan # 4 + +ErrHan # 4 +ErrBuf # 4 +ErrHan_ws # 4 + +CallAd_ws # 4 ; smart Rs ordering: +CallAd # 4 ; can do LDMIA of r12, pc +CallBf # 4 + +BrkAd_ws # 4 +BrkAd # 4 +BrkBf # 4 + +EscHan_ws # 4 +EscHan # 4 + +EvtHan_ws # 4 +EvtHan # 4 + +; The next lot of workspace is in the space vacated by the small soft CAM map area +; (256 words) which is no longer adequate, so we can reuse it + +JordanWS # 0 +VInitSoftCopy # 4 ; soft copy of VInit so we can set L bit correctly +VEndSoftCopy # 4 ; soft copy of VEnd ------------""--------------- +DAList # 4 ; Pointer to first node on dynamic area list + + AlignSpace 16 ; skipped bit must start on 16-byte boundary + +SkippedTables # 0 +PhysRamTable # 0 ; 6 pairs of words (physaddr, size) indicating + ; RAM present in machine (NB normally you would need at most 5 + ; on IOMD machines, but the extra one is if a soft-loaded ROM image + ; causes a bank to split +VideoPhysAddr # 4 ; Address of video RAM (in the case of DRAM-only machines, +VideoSize # 4 ; this is actually a chunk out of DRAM) +DRAMPhysAddrA # 4 ; Next the DRAM - note that any banks with no memory +DRAMSizeA # 4 ; in them will be omitted from this table, so that +DRAMPhysAddrB # 4 ; eg DRAMPhysAddrA corresponds to the first bank with +DRAMSizeB # 4 ; DRAM in it, not necessarily bank 0 +DRAMPhysAddrC # 4 ; If not all the slots are occupied, then +DRAMSizeC # 4 ; the remaining entries in this table have size fields +DRAMPhysAddrD # 4 ; of zero (and probably addresses of zero too) +DRAMSizeD # 4 +DRAMPhysAddrE # 4 +DRAMSizeE # 4 + [ MorrisSupport +DRAMPhysAddrExtra # 4 * 12 ; The DRAM used with MORRIS can fragment into four +DRAMSizeExtra # 4 * 12 ; blocks so allocate 3 extra word pairs per bank + ] +PhysRamTableEnd # 0 + ! 0, "VideoPhysAddr held at ":CC::STR:(VideoPhysAddr) + +VRAMSize # 4 ; Amount of VRAM (in bytes) (may be more than 2M) +VRAMWidth # 4 ; 0 => no VRAM, 1 => 32-bits wide, 2 => 64-bits wide +VideoBandwidth # 4 ; video bandwidth in bytes/sec +L2PTSize # 4 ; Amount of memory (in bytes) used for static L2PT + ; - this consists of fixed size first bit, plus variable size + ; bit for the free pool L2, which follows directly after it +SoftCamMapSize # 4 ; Amount of memory (in bytes) used for soft CAM map + ; (whole number of pages) +InitKbdWs # 16 ; Workspace for reset keyboard IRQ code (was 12 changed for Morris) + +CLine_Softcopy # 1 ; Added for Morris - Monitor id + + AlignSpace 16 ; skipped bit must end on 16-byte boundary +SkippedTablesEnd # 0 + +CMOSRAMCache # 240 ; Cache for CMOS RAM +AppSpaceDANode # DANode_NodeSize ; Dummy area node for application space (not on list) +FreePoolDANode # DANode_NodeSize ; Area node for free pool +SysHeapDANode # DANode_NodeSize ; Area node for system heap +CDASemaphore # 4 ; Semaphore for OS_ChangeDynamicArea - non-zero => routine threaded +MMUControlSoftCopy # 4 ; Soft copy of ARM600/700 control register + +AplWorkSize * AppSpaceDANode + DANode_Size + +ProcVec_Start # 0 ; Start of processor vector table +ProcVec_Branch0 # 4 ; Branch through zero +ProcVec_UndInst # 4 ; Undefined instruction vector +ProcVec_SWI # 4 ; SWI vector +ProcVec_PrefAb # 4 ; Prefetch abort vector +ProcVec_DataAb # 4 ; Data abort vector +ProcVec_AddrEx # 4 ; Address exception vector (not useful on ARM600/700) +ProcVec_IRQ # 4 ; IRQ vector +ProcVec_End # 0 + +ProcVecPreVeneersSize * 4*4 ; Space for preveneers for loading handler addresses from 0 page. +ProcVecPreVeneers # ProcVecPreVeneersSize + + ASSERT @ <= &500 ; a convenient address to remember + # (&500-@) + +CamMapCorruptDebugBlock # &40 ; somewhere to dump registers in case of emergency + + ASSERT @ <= JordanWS+256*4 + # (JordanWS+256*4-@) ; pad out to original size + +CamEntriesPointer # 4 ; points to where CAM soft copy is + ; (CamEntries for machines up to 8MBytes, + ; CamEntriesForBigMachines for larger machines) + +MaxCamEntry # 4 ; maximum index into the cam map, ie + ; 511 for 16MByte machines, 383 for 12MBytes + ; 255 for 8MBytes, otherwise 127 + +RAMLIMIT # 4 + + # 4 ; dummy slot where AplWorkSize used to be + +HiServ_ws # 4 +HiServ # 4 +SExitA # 4 +SExitA_ws # 4 +UpCallHan_ws # 4 +UpCallHan # 4 + +ROMModuleChain # 4 ; pointer to head of ROM module chain + +; now a section that it's handy to have in simply loadable places + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 + +KeyWorkSpaceSize * &200 +KeyWorkSpace # KeyWorkSpaceSize + +; The following were reordered on 26-Jul-91. Old ordering was: +; GeneralMOSBuffer +; ModuleSWI_HashTab +; Module_List +; Curr_Active_Object +; VecPtrTab +; ExceptionDump + +ModuleSHT_Entries * 16 +ModuleSWI_HashTab # 4*ModuleSHT_Entries + +Module_List # 4 +Curr_Active_Object # 4 + +; Vector Claim & Release tables etc + +VecPtrTab # NVECTORS * 4 + +ExceptionDump # 4 + +; GeneralMOSBuffer: re-use with caution! +; Here's just some of the users: +; user use(s) +; default error handler error buffer (must be 246+4 bytes big) +; *If expression to be evaluated to control the *If +; Command line to be submited on the expression +; evaluating to non-zero (the THEN clause). +GeneralMOSBuffer # 256+4 + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 ; Ensures we can MOV rn, #OsbyteVars if <=&1000 + +OsbyteVars # OSBYTEVarSize + ASSERT OsbyteVars < &10000 ; Must keep in first 64K so address can be read by + ; (and stored in) OS_Bytes &A6,&A7. SKS + +; These must be in first 4K +NBuffers * 10 +BuffInPtrs # 4 * NBuffers +BuffOutPtrs # 4 * NBuffers + +VariableList # 4 + +; Oscli stuff +OscliCBtopUID # 4 +OscliCBbotUID # 4 +OscliCBcurrend # 4 + +ReturnCode # 4 +RCLimit # 4 + +SpriteSize # 4 ; saved on startup for Sprite code and RAMFS +RAMDiscSize # 4 +FontCacheSize # 4 ; and font manager + +TickNodeChain # 4 + +; Workspace + +EnvTime # 5 + +Export_RedirectInHandle # 1 + ASSERT Export_RedirectInHandle = RedirectInHandle + ASSERT ?Export_RedirectInHandle = ?RedirectInHandle + +Export_RedirectOutHandle # 1 + ASSERT Export_RedirectOutHandle = RedirectOutHandle + ASSERT ?Export_RedirectOutHandle = ?RedirectOutHandle + +MOShasFIQ # 1 +FIQclaim_interlock # 1 +CallBack_Flag # 1 +IRQ_CallBack_Flag * CallBack_Flag +IOSystemType # 1 ; 0 => old I/O subsystem, 1 => IOEB+82C710 system, 2..255 => ? +MonitorLeadType # 1 ; some function of the monitor lead inputs, as yet undetermined + + AlignSpace + +EnvString # 256 + + +DUMPER # 16 * 4 + +; more system workspace +Page_Size # 4 +PIRQ_Chain # 4 +PFIQasIRQ_Chain # 4 + +; !!!! Free space (752 bytes) left by old IRQ despatch (new IRQ despatch +; !!!! moved as it required more space). +OldIRQ1Vspace # 752 + + [ med_00001_debug + ! 0,"med-00001 queue start, queue size, cda amount at &" :CC: :STR:(OldIRQ1Vspace) +med_00001_debug_start * OldIRQ1Vspace +med_00001_debug_size * OldIRQ1Vspace+4 +med_00001_debug_cda * OldIRQ1Vspace+8 + ] + + +CallBack_Vector # 4 + +; interruptible heap manager workspace + +HeapSavedReg_R0 # 4 +HeapSavedReg_R1 # 4 +HeapSavedReg_R2 # 4 +HeapSavedReg_R3 # 4 +HeapSavedReg_R4 # 4 +HeapSavedReg_R13 # 4 +HeapReturnedReg_R0 # 4 +HeapReturnedReg_R1 # 4 +HeapReturnedReg_R2 # 4 +HeapReturnedReg_R3 # 4 +HeapReturnedReg_R4 # 4 +HeapReturnedReg_R13 # 4 +HeapReturnedReg_PC # 4 ; also acts as interlock + +PrinterBufferAddr # 4 ; holds address of printer buffer +PrinterBufferSize # 4 ; size of printer buffer - not to be confused with PrintBuffSize + ; which is the (constant) default size for the MOS's smallish buffer +RawMachineID # 8 ; 64 bits for unique machine ID +KernelMessagesBlock # 20 ; 5 Words for messagetrans message block. +ErrorSemaphore # 1 ; Error semaphore to avoid looping on error translation. + [ StorkPowerSave +PortableFlags # 1 ; +PowerSave * &80 + | +PortableFlag # 1 ; Non-zero => got an error from Portable_Speed, so don't try it again + ] + + AlignSpace + +MOSConvertBuffer # 12 ; Enough romm for 8 hex digits. +AbortIndirection # 4 ; Pointer to list of addresses and trap routines +PreVeneerRegDump # 17*4 ; room for r0-r15, spsr + + [ AssemblingArthur + ! 0, "low space free ":CC::STR:(&FE8-@) + ] + ASSERT @ < &FE8 + +; Words for old tools of assorted varieties +; Don't move the following as their positions are assumed by other modules + + ^ &FE8 +CLibCounter # 1 ; Counter for Shared C Library tmpnam function + + AlignSpace + +; ECN 17-Feb-92 +; Added RISCOSLibWord and CLibWord. The ROM RISCOSLib and CLib must continue +; to work even when they are killed since ROM apps are hard linked to the +; ROM libraries. They cannot use the private word since the block pointed +; to by this will be freed. +RISCOSLibWord # 4 +CLibWord # 4 +FPEAnchor # 4 + +Export_DomainId # 4 ; SKS added for domain identification + ASSERT Export_DomainId = DomainId + ASSERT ?Export_DomainId = ?DomainId + +Modula2_Private # 4 ; MICK has FFC and uses it it in USR mode + +Export_VduDriverWorkSpace # VDWSSize + ASSERT Export_VduDriverWorkSpace = VduDriverWorkSpace + ASSERT ?Export_VduDriverWorkSpace = ?VduDriverWorkSpace + + ASSERT (VduDriverWorkSpace :AND: 63) = 0 ; For Tim (VDU5) + + + [ AssemblingArthur + ! 0, "high space free ":CC::STR:(&4000-@) + ] + + ^ &4000 +ScratchSpaceSize * &4000 + +Export_ScratchSpace # ScratchSpaceSize + ASSERT Export_ScratchSpace = ScratchSpace + ASSERT ?Export_ScratchSpace = ?ScratchSpace + + ASSERT @ <= &8000 ; Start of apl + +; ***************************************************************************** +; Users of ScratchSpace declare yourself here: + +; NRaine: Filling a polygon uses ScratchSpace to flatten the path + +; DSeal: Draw module uses ScratchSpace on fill operations (this supercedes +; NRaine's declaration above). + +; SKS: HeapSort with (r1 & 0x80000000) & ~(r1 & 0x20000000) & (r5 <= 16K) +; uses ScratchSpace as a temp slot for data shuffling after sorting + +; TMD: Flood fill uses ScratchSpace for the flood queue. + +; Tidying the RMA uses ScratchSpace while all modules are dead + +; GSTRANS workspace: GSINIT puts state into the workspacem and GSREAD uses it. +; DO NOT do any operations between GSINIT/GSREAD SWIS. +; SWIs called: OSWord in time var code +; BinaryToDecimal, ReadUnsigned + +; LVR: ADFS uses scratch space to format floppies on 1772 based machines + +; DDV: ColourTrans uses scratch space to build palette tables when in +; ColourTrans_SelecTable/RetrunColourNumber and also whilst generating +; stipple pattterns. + +GSVarWSpace * ScratchSpace + + ^ 0 +GSNameBuff # &100 +GS_Stack # &200 +GS_StackPtr_Lim * &200 / 4 ; Number of words in stack. +GS_StackPtr # 4 + + ^ @ + ScratchSpace + +; Pointers for SubstituteArgs: no external calls. +; Ensure these don't overlap FileSwitch's buffers below! + +MacExStartPtrs # 44 +MacExEndPtrs # 44 + +; OS_CLI has a buffer for alias expansion: ReadVarVal and SubstituteArgs +; are called while the buffer is held. Also used for module prefixes: +; Module called twice in this case. + +AliasExpansionBuffer # 100 + +; *list/*type need an argument expansion buffer: ReadArgs called with it. + +ArgumentBuffer * AliasExpansionBuffer + +; EvaluateExpression space. Calls ReadUnsigned, BinaryToDecimal and ReadVarVal. + +ExprWSpace * @ + + ^ 0, R12 +ExprBuff # &100 +exprBracDif # 2 ; keep exprSTRACC aligned +tos_op # 2 ; 1 byte for use as STRACC-1 +ExprSVCstack # 4 +exprSTRACC * @ - ExprBuff + ExprWSpace + +ExprStackLimit * exprSTRACC + &100 +ExprStackStart * ScratchSpace + ScratchSpaceSize + + +; Tutu needs some for argument substitution + expansion for run/load types +; Only OS call during xform is XOS_SubstituteArgs and XOS_Heap(Claim,SysHeap) + + ^ 0 ; Offset from ScratchSpace +rav_substituted # 256 +rav_arglist # 256 + +TopOfPageZero # 0 + + ^ &8000 ; The actual top of Page Zero +EconetDebugSpace |#| &20 * 4 ; Thirty two words (&7F80) + + ASSERT @ > TopOfPageZero ; Make sure we don't clash + +; ***************************************************************************** +; *** Cursor, Sound DMA, SWI, and OSCLI workspace. *** +; *** Sits in the 32K above 31M, ie. &01F000000..&01F07FFF *** +; *** Has the physical address &02078000, ie. 32M + 512K - 32K *** +; ***************************************************************************** + +TopOfDMAPhysRAM * &80000 ; OFFSET in physram +TopOfDMAWorkSpace * CursorChunkAddress + 32*1024 +OffsetLogicalToPhysical * TopOfDMAPhysRAM - TopOfDMAWorkSpace + + ^ TopOfDMAWorkSpace ; Note we will be going down + +; Sound + +SoundWorkSpaceSize * &1000 + +Export_SoundDMABufferSize * &1000 + ASSERT Export_SoundDMABufferSize = SoundDMABufferSize + +SoundEvtSize * &1000 + +Export_SoundDMABuffers |#| SoundDMABufferSize * 2 + ASSERT Export_SoundDMABuffers = SoundDMABuffers + ASSERT ?Export_SoundDMABuffers = ?SoundDMABuffers + +Export_SoundWorkSpace |#| SoundWorkSpaceSize + SoundEvtSize + ASSERT Export_SoundWorkSpace = SoundWorkSpace + ASSERT ?Export_SoundWorkSpace = ?SoundWorkSpace + +; Cursor + +CursorDataSize * &800 +CursorData |#| CursorDataSize +CursorSoundRAM * CursorData +CursorSoundPhysRAM * CursorSoundRAM + OffsetLogicalToPhysical + +; SWI despatcher + +Export_BranchToSWIExit |#| 4 + ASSERT Export_BranchToSWIExit = BranchToSWIExit + ASSERT ?Export_BranchToSWIExit = ?BranchToSWIExit + +Export_SvcTable |#| &400 + ASSERT Export_SvcTable = SvcTable + ASSERT ?Export_SvcTable = ?SvcTable + + ASSERT SvcTable = &01F033FC ; Required for SVC table pokers, 1.20 compatible +SWIDespatch_Size * 29*4 +SWIDespatch |#| SWIDespatch_Size + + +; Buffers + +KeyBuffSize * &100 +RS423InBuffSize * &100 +RS423OutBuffSize * &C0 +PrintBuffSize * &400 +Sound0BuffSize * 4 +Sound1BuffSize * 4 +Sound2BuffSize * 4 +Sound3BuffSize * 4 +SpeechBuffSize * 4 +MouseBuffSize * &40 +KeyBuff |#| KeyBuffSize +RS423InBuff |#| RS423InBuffSize +RS423OutBuff |#| RS423OutBuffSize +PrintBuff |#| PrintBuffSize +Sound0Buff |#| Sound0BuffSize +Sound1Buff |#| Sound1BuffSize +Sound2Buff |#| Sound2BuffSize +Sound3Buff |#| Sound3BuffSize +SpeechBuff |#| SpeechBuffSize +MouseBuff |#| MouseBuffSize + +; Oscli buffering + +OscliBuffSize * &100 +OscliNoBuffs * 16 +OscliCircBuffLimit |#| 0 +OscliCircBuffStart |#| OscliBuffSize * OscliNoBuffs +RedirectBuff |#| OscliBuffSize + +; Default IRQ despatch moved here as a result of IOMD having an extra +; 6 interrupts for I/O and sound DMA (this is really IOMD specific, not +; ARM600/700 specific but for the moment it is assumed that they are +; used on the same machines). + [ MorrisSupport +DefIRQ1Vspace * 12*4+12*23+2*256+64 + 5*12+3*4+32 ;Morris adds 5 more + | +DefIRQ1Vspace * 12*4+12*23+2*256+64 ; for size checking in MOS + ] +DefaultIRQ1V |#| DefIRQ1Vspace + + [ AssemblingArthur + ! 0, "Aligning IRQ stack from ":CC::STR:@ + ] + [ @-7*4 :AND: 15 <> 0 + |#| (@-7*4):AND:15 + ] +IRQSTK # 0 ; Overflow will give abort + [ AssemblingArthur + ! 0, "IRQ stack size ":CC::STR:(IRQSTK-CursorChunkAddress) + ] + + ASSERT @ > ( CursorChunkAddress + &1000 ) ; Check minimum stack + +; ***************************************************************************** +; High system workspace +; ***************************************************************************** + + ^ SysHeapChunkAddress + + # SVCStackSize ; svcstk size. Overflow will give abort +Export_SVCSTK # 0 + ASSERT Export_SVCSTK = SVCSTK + ASSERT ?Export_SVCSTK = ?SVCSTK + +Export_SysHeapStart # 0 + ASSERT Export_SysHeapStart = SysHeapStart + ASSERT ?Export_SysHeapStart = ?SysHeapStart + + OPT OldOpt + END diff --git a/hdr/KeyWS b/hdr/KeyWS new file mode 100644 index 0000000000000000000000000000000000000000..392f82db98b14cd10d927401e7ec25411cc680d2 --- /dev/null +++ b/hdr/KeyWS @@ -0,0 +1,156 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Hdr.KeyWS + +; *********************************** +; *** C h a n g e L i s t *** +; *********************************** + +; Date Name Description +; ---- ---- ----------- +; 06-Feb-91 TMD Added LastLED +; 09-Mar-92 TMD Added JustGotKbID +; 24-Feb-93 SMC Reorganised for new keyboard/mouse interfaces +; 19-Jul-93 JSR Changed conditional from A1Keyboard to Keyboard_Type = "A1A500" + +; Keyboard variables + + GBLS keyprefix +keyprefix SETS "Key$" + + ^ 0, R11 + +CurrKey # 1 ; current key in two key rollover +OldKey # 1 ; old key in two key rollover +KbId # 1 +LastKbId # 1 +AutoRepeatCount # 1 +Debouncing # 1 ; NZ => do delay next, Z => do repeat +MouseButtons # 1 ; bit0=R, bit1=C, bit2=L +PendingAltType # 1 ; 1 => A, 2 => SA, 3 => CA, 4 => CSA +ModulesOK # 1 ; bit0=1 => modules are initialised + ; bit1=1 => we have offered service +LastLED # 1 ; last request for LED change, so we don't send repeated ones +MouseType # 1 ; current pointer device type + + [ Keyboard_Type = "A1A500" +JustGotKbId # 1 +RequestMouse # 1 +RequestLED # 1 +RequestSPD # 1 +RequestKbId # 1 +SPDRec # 1 ; number to be received +ResetState # 1 ; next thing to go in reset handshake +KeyRow # 1 ; half received key up or down +Reply # 1 ; next reply to be sent (&FF if nowt) +KbIdHalf # 1 +MouseCount # 1 ; 0 => X next, 1 => Y next +MouseDelta # 2 ; delta X,Y + ] + + # 3 :AND: (- :INDEX: @) + +InkeyCounter # 4 +MouseX # 4 +MouseY # 4 +SoftKeyPtr # 4 +MouseXMult # 4 +MouseYMult # 4 +KeyVec # 4 + + [ Keyboard_Type = "A1A500" +SPDinput # 4 +SPDoutput # 4 + [ AssemblePointerV +MouseXCount # 4 +MouseYCount # 4 + ] + ] + +MouseBounds # 16 +MouseBoundLCol * MouseBounds+0 +MouseBoundBRow * MouseBounds+4 +MouseBoundRCol * MouseBounds+8 +MouseBoundTRow * MouseBounds+12 + +KeysDown # 20 ; bitmap of all down keys + +SoftKeyName # 3 + :LEN:(keyprefix) ; up to 2 digits + terminator + +SoftKeyExpand # 255 ; current key expansion + + ASSERT (:INDEX: @) < KeyWorkSpaceSize +UserKeyWorkSpaceSize * KeyWorkSpaceSize-(:INDEX: @) +UserKeyWorkSpace # UserKeyWorkSpaceSize + + +; PMF -> VDU communication stuff put in here because both VDU and PMF +; 'GET' this file + + GBLA ExtEntries +ExtEntries SETA 0 + + MACRO + AddExtEntry $EntryName +Index_$EntryName * ExtEntries + [ AssemblingArthur +Value_$ExtEntries * $EntryName + | + [ DoingVdu +Value_$ExtEntries * $EntryName + ] + ] +ExtEntries SETA ExtEntries +1 + MEND + + MACRO +$Table OutputExternals +$Table + LCLA count +count SETA 0 + WHILE count < ExtEntries + & Value_$count - $Table -4 +count SETA count + 1 + WEND + MEND + + MACRO + ByteToNosbod $EntryName + [ AssemblingArthur + VDWS WsPtr + BL $EntryName + | + MOV R0, #Index_$EntryName + BL ByteToNosbod + ] + MEND + + AddExtEntry DoReadPOSVPOSI + AddExtEntry DoReadPOSVPOSO + AddExtEntry DoOSBYTE87 + AddExtEntry DoResetFont + AddExtEntry DoReadFont + AddExtEntry DoReadVDUStatus + AddExtEntry DoReadVDUVariable + AddExtEntry DoReadPalette + AddExtEntry DoSetPalette + AddExtEntry DoPointerStuff + AddExtEntry DoSetScreenStart + AddExtEntry DoSetDriverBank + AddExtEntry DoSetDisplayBank + AddExtEntry DoOsbyte163_242 + AddExtEntry DoOsWord13 + + END diff --git a/hdr/ModHand b/hdr/ModHand new file mode 100644 index 0000000000000000000000000000000000000000..8a8bb576a0c7287c40922143754a7027619a7796 --- /dev/null +++ b/hdr/ModHand @@ -0,0 +1,107 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + SUBT Module handler reason codes etc. => &.Hdr.ModHand + +OldOpt SETA {OPT} + OPT OptNoList+OptNoP1List + +; *********************************** +; *** C h a n g e L i s t *** +; *********************************** + +; Date Name Description +; ---- ---- ----------- +; 27-Nov-86 BC Added Module_Ticker +; 15-Jan-87 SKS Added SWI base addresses +; 21-Jan-87 APT New Module_LoadAddr added. +; 26-Jan-87 BC Removed Module_Ticker +; 5-Feb-87 APT Added flag manifests +; 9-Feb-87 APT Added more reason codes +; 17-Feb-87 BC Added Module name server entries +; 25-Feb-87 APT Help-is-code flag added +; 2-Apr-87 APT ExtendBlock reason code added +; 23-Apr-87 APT Help-is-code flag moved into high byte +; 17-Jun-87 APT NewIncarnation, AddPoduleModule reason codes +; 24-Jun-87 APT RenameIncarnation r.c. +; 15-Jul-87 APT MakePreferred +; 29-Jul-87 APT LookupName +; 17-Aug-87 APT EnumerateROM_Modules +; 23-Jan-91 TMD EnumerateROM_ModulesWithInfo + +ModHandReason_Run * 0 +ModHandReason_Load * 1 +ModHandReason_Enter * 2 +ModHandReason_ReInit * 3 +ModHandReason_Delete * 4 +ModHandReason_RMADesc * 5 +ModHandReason_Claim * 6 +ModHandReason_Free * 7 +ModHandReason_Tidy * 8 +ModHandReason_Clear * 9 +ModHandReason_AddArea * 10 +ModHandReason_CopyArea * 11 +ModHandReason_GetNames * 12 +ModHandReason_ExtendBlock * 13 +ModHandReason_NewIncarnation * 14 +ModHandReason_RenameIncarnation * 15 +ModHandReason_MakePreferred * 16 +ModHandReason_AddPoduleModule * 17 +ModHandReason_LookupName * 18 +ModHandReason_EnumerateROM_Modules * 19 +ModHandReason_EnumerateROM_ModulesWithInfo * 20 + +; Real module offsets + + ^ 0 +Module_Start # 4 +Module_Init # 4 +Module_Die # 4 +Module_Service # 4 +Module_Title # 4 +Module_HelpStr # 4 +Module_HC_Table # 4 ; help and command table. + +; optional SWI handler offsets +Module_SWIChunk # 4 +Module_SWIEntry # 4 +Module_NameTable # 4 +Module_NameCode # 4 + +; optional Message filename offset +Module_MsgFile # 4 + +; Magic number for RM load addr + +Module_LoadAddr * &FFFFFA00 ; magic number from Stu/Bruce standard : + ; the two zeroes are ignored. + ; &FFFFFE00 on Proto-Arfur < .032 + +Module_SWIChunkSize * 2_1000000 + +Module_SWISystemBase * 1 :SHL: 18 +Module_SWIApplicationBase * 2 :SHL: 18 +Module_SWIUserBase * 3 :SHL: 18 + + +; flags for the information word : + +FS_Command_Flag * 1 :SHL: 31 +Status_Keyword_Flag * 1 :SHL: 30 +Help_Is_Code_Flag * 1 :SHL: 29 +International_Help * 1 :SHL: 28 + + OPT OldOpt + + END diff --git a/hdr/Old/Arthur/PublicWS b/hdr/Old/Arthur/PublicWS new file mode 100644 index 0000000000000000000000000000000000000000..c2aa021ed026e44644776409e86de08f6f88d03c --- /dev/null +++ b/hdr/Old/Arthur/PublicWS @@ -0,0 +1,90 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + SUBT > Public Work Space + +OldOpt SETA {OPT} + OPT OptNoList+OptNoP1List + +; *********************************** +; *** C h a n g e L i s t *** +; *********************************** + +; Date Name Description +; ---- ---- ----------- +; 15-Jun-94 AMcC Created - holds values 'exported' from Kernel WorkSpace +; Corresponds to Values set in Space200 +; + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Memory map values: + + ^ &00000104 +ESC_Status # 1 + + ^ &00000105 +LatchBSoftCopy # 1 + + ^ &00000107 +CannotReset # 1 + + ^ &00000108 +IRQsema # 4 + + ^ &00000114 +MEMC_CR_SoftCopy # 4 + + ^ &00000480 +FgEcfOraEor # 4*16 ; Interleaved zgora & zgeor (from Vdu Driver Workspace) + + ^ &000004C0 +BgEcfOraEor # 4*16 ; Interleaved zgora & zgeor (from Vdu Driver Workspace) + + ^ &00000AD1 ; RedirectInHandle +RedirectInHandle # 1 + + ^ &00000AD2 ; RedirectOutHandle +RedirectOutHandle # 1 + + ^ &00000FF8 +DomainId # 4 ; domain identification + + ^ &00001000 +VduDriverWorkSpace # &3000 + + ^ &00004000 +ScratchSpace # &4000 + + ^ &01C02000 +SVCSTK # 0 + + ^ &01C02000 +SysHeapStart # 0 + + ^ &01F033FC +SvcTable # &400 + + ^ &01F037FC +BranchToSWIExit # 4 ; from SWI despatcher + + ^ &01F04000 +SoundWorkSpace # &2000 + +SoundDMABufferSize * &1000 + + ^ &01F06000 +SoundDMABuffers # SoundDMABufferSize * 2 + + OPT OldOpt + END diff --git a/hdr/Old/Arthur/Space200 b/hdr/Old/Arthur/Space200 new file mode 100644 index 0000000000000000000000000000000000000000..8a126a1a06343d8acfe4fa809bcebebd74b16fad --- /dev/null +++ b/hdr/Old/Arthur/Space200 @@ -0,0 +1,1017 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + SUBT > &.Hdr.NewSpace + +OldOpt SETA {OPT} + OPT OptNoList+OptNoP1List + +; *********************************** +; *** C h a n g e L i s t *** +; *********************************** + +; Date Name Description +; ---- ---- ----------- +; 02-Nov-87 APT Added module SWI hash table +; 03-Nov-87 APT Modo-fied module SWI hash table info, removed BRKLST +; 09-Nov-87 APT Removed ESCCNT and ESFLG +; 12-Nov-87 APT Added IRQsema +; 13-Nov-87 APT Added DefaultIRQ1V codespace +; 16-Nov-87 APT PIRQ chain heads +; 18-Nov-87 APT Reordered EvtHan, EvtHan_ws +; 19-Nov-87 APT Moved IRQsema +; 01-Dec-87 APT Added interruptible heap manager workspace +; 08-Dec-87 TMD Added ECFShift, ECFYOffset +; 14-Dec-87 TMD Added DisplayNColour, DisplayModeFlags +; 15-Dec-87 TMD Added KeyAlphabet +; 22-Dec-87 NDR Using ScratchSpace +; 13-Jan-88 APT General scratchspace bash, low workspace reordering. +; Removed spurious 32 bytes of osbyte wspace +; 14-Jan-88 APT *type buffer in scratchspace. +; MOShasFIQ byte added +; 20-Jan-88 APT Workspace juggling for speed & space; also discarded +; Level0 stuff. +; 28-Jan-88 APT MetroGnome moved to "public" location for ADFS +; 02-Feb-88 APT FIQclaim_interlock added +; 05-Feb-88 APT CallBack_Vector +; 09-Feb-88 APT RAM for SWI despatch +; 17-Feb-88 TMD Added VduSaveArea, VduSaveAreaPtr, DisplayModeNo +; 26-Feb-88 APT NoOfCamEntries manifest +; 03-Mar-88 APT Shrank SVC despatch +; 03-Mar-88 APT NoOfCamEntries manifest doubled +; 07-Mar-88 TMD Added DisplayScreenStart, VduOutputCurrentState, +; SpriteMaskSelect, reordered mode variables +; 07-Mar-88 APT Made CamEntries always at &164 +; 07-Mar-88 TMD Added GCharSizes, GCharSizeX, GCharSizeY +; 08-Mar-88 TMD Added GCharSpacing, GCharSpaceX, GCharSpaceY +; 08-Mar-88 TMD Moved GCharSizes..GCharSpaceY into first 1K of workspace +; 15-Mar-88 TMD Added HLineAddr +; 18-Mar-88 TMD Added DisplayXWindLimit, DisplayYWindLimit, +; DisplayXEigFactor, DisplayYEigFactor, PointerXEigFactor +; 18-Mar-88 APT Setting variables scratchspace use revised. +; 21-Mar-88 TMD Removed CursorIndex +; 22-Mar-88 TMD Added TCharSizeX,TCharSizeY,TCharSpaceX,TCharSpaceY +; 29-Mar-88 TMD Added GcolOraEorAddr +; 31-Mar-88 TMD Removed WsFontPtr +; 07-Apr-88 SKS Added HeapSort use of ScratchSpace +; 14-Apr-88 TMD Added SerialFlags +; 28-Apr-88 TMD Added XONXOFFChar +; 5-May-88 APT Added MemorySpeed +; 18-May-88 APT Added CannotReset sema at &107, removed pre-1.20 changes. +; 24-May-88 TMD Added ClipBoxEnable, ClipBoxLCol..ClipBoxTRow, moved in +; ScrLoaSpriteCB, ScrLoaBuffer, SrcSavCommon +; 24-May-88 TMD Flood fill uses ScratchSpace +; 01-Jun-88 TMD Added AlignSpace for ClipBoxCoords +; 03-Jun-88 BCSKS Make Keyboard buffer into a useful part of the system +; Also PrinterBufferSize +; 09-Jun-88 DJS Draw uses ScratchSpace +; 09-Jun-88 BC Gave Econet some private debungling space +; 11-Jun-88 SKS Align IRQ stack to make STMFD not cross two MEMC bdy's +; Made info condit'l on AsmArf; someone had commented it out! +; 15-Jun-88 SKS Added two more instructions in SWIDespatch area +; Moved SLVK definition into kernel; it's not public +; 16-Jun-88 SKS Added 3 more instructions in SWIDespatch area + nailed +; SvcTable address for compatibility +; 22-Jun-88 SKS Moved MEMC_CR_SoftCopy into pubic ws +; 19-Jul-88 APT Added UpCall handler stuff +; 20-Jul-88 SKS Added above entry +; Amended comment about overlaid workspace in vdu +; 15-Aug-88 SKS Inserted DomainId at FF8 (set by Wimp on task swap, used by +; FileSwitch to tag resources) + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Memory map: + +CursorChunkAddress * 31*1024*1024 +FontCacheAddress * 30*1024*1024 +SysHeapChunkAddress * 28*1024*1024 +RMAAddress * 24*1024*1024 +SpriteSpaceAddress * 20*1024*1024 +RAMDiscAddress * 16*1024*1024 + +; **********+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; system variables + + ^ 0,R12 + +OSBYTEFirstVar # 0 + +ByteVars # 0 ; The main osbyte variables, accessed + ; via calls &A6 to &FF + +VarStart # 2 ; &A6,&A7 +ROMPtr # 2 ; &A8,&A9 +ROMInfo # 2 ; &AA,&AB +KBTran # 2 ; &AC,&AD +VDUvars # 2 ; &AE,&AF + +CFStime # 1 ; &B0 +InputStream # 1 ; &B1 +KeyBdSema # 1 ; &B2 + +ROMPollSema # 1 ; &B3 +OSHWM # 1 ; &B4 + +RS423mode # 1 ; &B5 +NoIgnore # 1 ; &B6 +CFSRFS # 1 ; &B7 +VULAcopy # 2 ; &B8,&B9 + +ROMatBRK # 1 ; &BA +BASICROM # 1 ; &BB + +ADCchanel # 1 ; &BC +ADCmaxchn # 1 ; &BD +ADCconv # 1 ; &BE + +RS423use # 1 ; &BF +RS423conflag # 1 ; &C0 + +FlashCount # 1 ; &C1 +SpacPeriod # 1 ; &C2 +MarkPeriod # 1 ; &C3 + +KeyRepDelay # 1 ; &C4 +KeyRepRate # 1 ; &C5 + +ExecFileH # 1 ; &C6 +SpoolFileH # 1 ; &C7 + +ESCBREAK # 1 ; &C8 (200) + +KeyBdDisable # 1 ; &C9 +KeyBdStatus # 1 ; &CA + +RS423HandShake # 1 ; &CB +RS423InputSupr # 1 ; &CC +RS423CFSFlag # 1 ; &CD + +EconetOScall # 1 ; &CE +EconetOSrdch # 1 ; &CF +EconetOSwrch # 1 ; &D0 + +SpeechSupr # 1 ; &D1 +SoundSupr # 1 ; &D2 + +BELLchannel # 1 ; &D3 +BELLinfo # 1 ; &D4 +BELLfreq # 1 ; &D5 +BELLdur # 1 ; &D6 + +StartMessSupr # 1 ; &D7 + +SoftKeyLen # 1 ; &D8 + +PageModeLineCount # 1 ; &D9 + +VDUqueueItems # 1 ; &DA + +TABch # 1 ; &DB +ESCch # 1 ; &DC + +IPbufferCh # 4 ; &DD,&DE,&DF,&E0 +RedKeyCh # 4 ; &E1,&E2,&E3,&E4 + +ESCaction # 1 ; &E5 +ESCeffect # 1 ; &E6 + +u6522IRQ # 1 ; &E7 +s6850IRQ # 1 ; &E8 +s6522IRQ # 1 ; &E9 + +TubeFlag # 1 ; &EA + +SpeechFlag # 1 ; &EB + +WrchDest # 1 ; &EC +CurEdit # 1 ; &ED + +SoftResetVars # 0 ; Reset to here on soft reset + +KeyBase # 1 ; &EE +Shadow # 1 ; &EF +Country # 1 ; &F0 + +UserFlag # 1 ; &F1 + +SerULAreg # 1 ; &F2 + +TimerState # 1 ; &F3 + +SoftKeyConsist # 1 ; &F4 + +PrinterDrivType # 1 ; &F5 +PrinterIgnore # 1 ; &F6 + +HardResetVars # 0 ; Reset to here on hard reset + +BREAKvector # 3 ; &F7,&F8,&F9 + +MemDriver # 1 ; &FA - where the VDU drivers write to +MemDisplay # 1 ; &FB - where we display from + +LangROM # 1 ; &FC + +LastBREAK # 1 ; &FD + +KeyOpt # 1 ; &FE + +StartOptions # 1 ; &FF + +PowerOnResetVars # 0 ; Reset to here on power-on reset + + AlignSpace + +EventSemaphores # 32 ; One byte for each of 32 events + +TimerAlpha # 8 ; As used by time (bottom 5 bytes) +TimerBeta # 8 ; ................................ +; both aligned to word boundaries + +RealTime # 8 ; 5-byte fast real-time + +PrinterActive # 4 ; Handle/active flag for printer (word aligned) + +IntervalTimer # 5 ; Up Counter synchronous with TIME. +; Event generated when Zero is reached +; bottom byte aligned to word boundary + +SecondsTime # 1 ; the soft copy (centi-)seconds of the RTC +CentiTime # 1 ; """""""""""""""""""""""""""""""""""""""" + +FlashState # 1 ; which flash colours are we using + +SecondsDirty # 1 ; the dirty flag for start up! + +MinTick # 1 ; the minutes odd/even state + +DCDDSRCopy # 1 ; copy of ACIA bits to check for change + +TVVertical # 1 ; *TV first parameter + +TVInterlace # 1 ; *TV second parameter + +CentiCounter # 1 ; Counter for VDU CTRL timing + +Alphabet # 1 ; Current alphabet number + +Keyboard # 1 ; Current keyboard number + +KeyAlphabet # 1 ; Alphabet associated with current keyboard + + GBLS PrinterPrefix +PrinterPrefix SETS "PrinterType$" + +PrinterTypeName # 6 + :LEN: (PrinterPrefix) + + AlignSpace + +SerialFlags # 4 ; New serial flags + +XONXOFFChar # 1 ; Character to send before rest (0 if none) + + AlignSpace + +OSBYTEVarSize * @-OSBYTEFirstVar + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +; End of variables' space + + +; *********************************** +; *** Main Vdu Driver Workspace *** +; *********************************** + + ^ 0 + +FgEcf # 4 * 8 ; Foreground Ecf, set by GCOL(a,0-127) +BgEcf # 4 * 8 ; Background Ecf, set by GCOL(a,128-255) +GPLFMD # 4 ; Foreground action, set by GCOL(a,0-127) +GPLBMD # 4 ; Background action, set by GCOL(a,128-255) +GFCOL # 4 ; Foreground colour, set by GCOL(a,0-127) +GBCOL # 4 ; Background colour, set by GCOL(a,128-255) + +GWLCol # 4 ; Graphics window left column -- +GWBRow # 4 ; Graphics window bottom row | +GWRCol # 4 ; Graphics window right column | +GWTRow # 4 ; Graphics window top row -- + +qqqPad # 3 +QQ # 17 ;Queue - QQ+1 is on a word boundary +QOffset # 4 ;Value to add to VDUqueueItems to point to next queue posn. +JVec # 4 ;Jump vector to internal routines + +; Start of MODE table workspace + +ScreenSize # 4 ; number of bytes needed for this mode (assumed 1st in list) + +XWindLimit # 4 ; Maximum value of GWRCol (internal representation) + +; LineLength must be immediately after YWindLimit + +YWindLimit # 4 ; Maximum value of GWTRow (internal representation) + +LineLength # 4 ; Length of one pixel row in bytes + +; End of word mode variables + +YShftFactor # 4 ; Number of places to shift YCoord in address generation after + ; multiplying by 5, holds + ; 7,6,5 or 4 for 8,4,2 or 1 bits per pixel (640x256 mode) or + ; 6,5,4 or 3 for 8,4,2 or 1 bits per pixel (320x256 mode). + +ModeFlags # 4 ; Bit 0 => non-graphic, Bit 1 => teletext, Bit 2 => gap mode + +XEigFactor # 4 ; Number of places to shift XCoord in external to internal + ; coordinate conversion, holds + ; 1 for 640x256 mode + ; 2 for 320x256 mode + ; 3 for 160x256 (BBC micro mode 2) + +YEigFactor # 4 ; number of shifts to convert between internal/external Y + +NColour # 4 ; Number of colours minus 1 + +Log2BPC # 4 ; Log to base 2 of BytesPerChar ie (0,1,2,3,4) + +Log2BPP # 4 ; Log to base 2 of BitsPerPix ie (0,1,2,3) + +ECFIndex # 4 ; Index into default ECF tables + +ScrRCol # 4 ; Maximum column number in this screen mode +ScrBRow # 4 ; Maximum row number in this screen mode + +PalIndex # 4 ; Index into palette tables (0,1,2,3) + +; End of table-initialised workspace + +; Next 3 must be together in this order ! + +XShftFactor # 4 ; Number of places to shift XCoord in address generation, + ; holds 2,3,4 or 5 for 8,4,2,1 bits per pixel respectivly +GColAdr # 4 ; Address of Ecf to plot - either FgEcf or BgEcf + +ScreenStart # 4 ; Start address of screen (for VDU drivers) + +NPix # 4 ; Number of pixels per word minus 1, holds + ; holds 3,7,15 or 31 for 8,4,2,1 bits per pixel modes + +AspectRatio # 4 ; Pixel shape : 0 square, 1 horz rect, 2 vert rect + +BitsPerPix # 4 ; Bits per pixel (1,2,4,8) + +BytesPerChar # 4 ; Bytes per one line of character + ; (same as BitsPerPix except in double pixel modes) + +CursorFudgeFactor # 4 ; Factor for horizontal cursor positioning + +RowMult # 4 ; Row multiplier for text manipulation + +RowLength # 4 ; Bytes per text row in this mode (eg 640,1280,5120) + +; The following (up to and including NewPtY) must be together in this order +; (relied upon by DefaultWindows) + +TWLCol # 4 ; Text window left column -- +TWBRow # 4 ; Text window bottom row | +TWRCol # 4 ; Text window right column | +TWTRow # 4 ; Text window top row -- + +OrgX # 4 ; Screen origin (external representation) +OrgY # 4 + +GCsX # 4 ; Graphics cursor (external representation) +GCsY # 4 + +OlderCsX # 4 ; Very old X coordinate (internal) +OlderCsY # 4 ; Very old Y coordinate (internal) + +OldCsX # 4 ; Old graphics cursor (internal representation) -- +OldCsY # 4 ; | + ; | +GCsIX # 4 ; Graphics cursor (internal representation) | +GCsIY # 4 ; | + ; | +NewPtX # 4 ; Newest point (internal representation) | +NewPtY # 4 ; -- + +; End of together block + +TForeCol # 4 ; Text foreground colour +TBackCol # 4 ; Text background colour + +CursorX # 4 ; Text cursor X position ; these 3 must be in same order as ... +CursorY # 4 ; Text cursor Y position +CursorAddr # 4 ; Screen address of (output) cursor + +InputCursorX # 4 ; Input cursor X position ; ... these 3 +InputCursorY # 4 ; Input cursor Y position +InputCursorAddr # 4 ; Screen address of input cursor + +EORtoggle # 4 ; Toggle between gap and non-gap +RowsToDo # 4 ; in the CLS + +VduStatus # 4 ; Vdu2, Window, Shadow bits (others in CursorFlags) + +CBWS # 8 ; Clear block (VDU 23,8..) workspace +CBStart # 2 +CBEnd # 2 + +CursorDesiredState # 4 +CursorStartOffset # 4 +CursorEndOffset # 4 +CursorCounter # 4 +CursorSpeed # 4 +Reg10Copy # 4 + +CursorFill # 4 ; Word to EOR cursor ; MUST be immediately before CursorNbit + +CursorNbit # 4 ; Pointer to cursor code for current mode + +DisplayStart # 4 ; Start address of screen (for display) +DriverBankAddr # 4 ; Default start address for VDU drivers +DisplayBankAddr # 4 ; Default start address for display +DisplayNColour # 4 ; No. of colours -1 for displayed mode +DisplayModeFlags # 4 ; ModeFlags for displayed mode +DisplayModeNo # 4 ; ModeNo for displayed mode +DisplayScreenStart # 4 ; Where VDU outputs to when outputting to screen + +DisplayXWindLimit # 4 ; Used for pointer programming +DisplayYWindLimit # 4 +DisplayXEigFactor # 4 +DisplayYEigFactor # 4 +PointerXEigFactor # 4 + +Ecf1 # 8 ; The Ecf patterns +Ecf2 # 8 +Ecf3 # 8 +Ecf4 # 8 + +DotLineStyle # 8 ; Dot dash line pattern + +ModeNo # 4 ; Current mode number + +TFTint # 4 ; Text foreground tint (in bits 6,7) +TBTint # 4 ; Text background tint +GFTint # 4 ; Graphics foreground tint +GBTint # 4 ; Graphics background tint + +TotalScreenSize # 4 ; Amount configured for screen (in bytes) + +MaxMode # 4 ; Maximum mode number allowed (20 for now) + +VinitCopy # 4 ; Copy of Vinit for VDU 23;12 or 13 + +CursorFlags # 4 ; Silly Master cursor movement flags + +CursorStack # 4 ; Bit stack of nested cursor states (0 => on, 1 => off) + ; (bit 31 = TOS) + +ECFShift # 4 ; number of bits to rotate right ECF OR and EOR masks by +ECFYOffset # 4 ; vertical offset to ECF index + +WsVdu5 # 0 ; Vdu 5 workspace +WsScr # 4 +WsEcfPtr # 4 +; WsFontPtr # 4 ; not needed any more, kept in register +EndVerti # 4 +StartMask # 4 +EndMask # 4 +FontOffset # 4 +TempPlain # 16 ; only used for MODE 10 + +GraphicWs # 300 ; All graphics workspace is overlaid here +EndGraphicWs # 0 + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 + +GCharSizes # 0 +GCharSizeX # 4 ; width of VDU 5 chars in pixels +GCharSizeY # 4 ; height of VDU 5 chars in pixels + +GCharSpacing # 0 +GCharSpaceX # 4 ; horizontal spacing between VDU 5 chars in pixels +GCharSpaceY # 4 ; vertical ------------------""----------------- + +TCharSizes # 0 +TCharSizeX # 4 ; width of VDU 4 chars in pixels +TCharSizeY # 4 ; height of VDU 4 chars in pixels + +TCharSpacing # 0 +TCharSpaceX # 4 ; horizontal spacing between VDU 4 chars in pixels +TCharSpaceY # 4 ; vertical ------------------""----------------- + +HLineAddr # 4 ; address of exported HLine +GcolOraEorAddr # 4 ; address of FgEcfOraEor etc + +FirPalSetting # 4*28 ; First palette settings +SecPalSetting # 4*28 ; Second palette settings + + [ AssemblingArthur + ! 0,"64 ":CC::STR:@ + ] + AlignSpace 64 + +FgEcfOraEor # 4*16 ; Interleaved zgora & zgeor +BgEcfOraEor # 4*16 ; Interleaved zgora & zgeor +BgEcfStore # 4*16 ; Interleaved zgora & zgeor to store background + +;Current state of pattern +LineDotCnt # 4 ; Count down to restarting pattern +LineDotPatLSW # 4 ; Current state of pattern LSWord +LineDotPatMSW # 4 ; " " " " MSWord + +DotLineLength # 4 ; Dot Pattern repeat length as given in *FX163,242,n + +BBCcompatibleECFs # 4 ; 0 => BBC compatible, 1 => native + +SpAreaStart # 4 ; Start of sprite area +SpChooseName # 16 ; No comment says Richard +SpChoosePtr # 4 + +PointerHeights # 4 ; 4 x 1 byte +PointerActiveXs # 4 ; 4 x 1 byte +PointerActiveYs # 4 ; 4 x 1 byte +PointerShapeNumber # 4 ; only bottom byte used +PointerX # 4 ; co-ordinates of pointer (not always = mouse) +PointerY # 4 + +VIDCControlCopy # 4 ; Soft copy of VIDC control register +VertAdjust # 4 ; offset to add to vertical VIDC registers + +TeletextOffset # 4 ; Offset to current teletext flash bank + +TeletextCount # 4 ; Number of vsyncs till next teletext flash + +WrchNbit # 4 ; Pointer to char code for current mode + +BeepBlock # 8 ; OSWORD block for VDU 7 + +ScreenMemoryClaimed # 1 ; NZ => memory has been claimed or is unusable + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 ; Align workspace to 16 bytes + +TTXDoubleCounts # 25 ; Number of double height chars on each line + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 ; Align workspace to 16 bytes + +RAMMaskTb # 32*4 ; Copy of MaskTb for this mode (up to 32 words) + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 ; Align workspace to 16 bytes + +VduOutputCurrentState # 0 ; values of R0-R3 to return from SwitchOutputToSprite + ; or Mask; next 4 must be in this order +SpriteMaskSelect # 4 ; value of R0 to be given to SWI OS_SpriteOp to set up + ; current state +VduSpriteArea # 4 ; Pointer to sprite area containing VDU output sprite + ; (0 if output is to screen) +VduSprite # 4 ; Pointer to VDU output sprite (0 if output to screen) + +VduSaveAreaPtr # 4 ; Pointer to save area for VDU variables + + + [ AssemblingArthur + ! 0,"16,12 ":CC::STR:@ + ] + AlignSpace 16, 12 ; Make ClipBoxCoords a valid immediate, + ; with ClipBoxEnable immediately before it +ClipBoxInfo # 0 +ClipBoxEnable # 4 ; 0 => clip box disabled, 1 => enabled + +ClipBoxCoords # 0 ; Internal coords of modified area of screen +ClipBoxLCol # 4 +ClipBoxBRow # 4 +ClipBoxRCol # 4 +ClipBoxTRow # 4 + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 ; Align workspace to 16 bytes + +TextExpand # 4*1024 ; Tim's massive text expansion table for whizzy WRCH +; TextPlain is now always hard against the end of TextExpand for this mode + +TTXSoftFonts * TextExpand + 2*1024 ; Soft fonts in teletext mode + + [ AssemblingArthur + ! 0,"64 ":CC::STR:@ + ] + AlignSpace 64 ; Align workspace to 64 bytes + +; Teletext map and copy/move buffer are overlaid + +TTXMapSize * 41*25*4 ; (&1004 bytes) +LargeCommon # TTXMapSize ; the largest area +TTXMap * LargeCommon + +ScrLoaSpriteCB * LargeCommon ; (size = SpriteCBsize + MaxSpritePaletteSize) +ScrLoaBuffer * LargeCommon ; (size = one pixel row) +ScrSavCommon * LargeCommon ; (size = SpriteAreaCBsize + SpriteCBsize + ; + MaxSpritePaletteSize) + +FldQueueSize * ScratchSpaceSize +FldQueueStart * ScratchSpace + + [ AssemblingArthur + ! 0,"64 ":CC::STR:@ + ] + AlignSpace 64 ; Align workspace to 64 bytes + +Font # &700 ; 7 pages of (soft) font + +SaveAreaSize * 12*1024-@ + +VduSaveArea # SaveAreaSize ; save area for switching output to sprites + +VDWSSize # 0 + + ASSERT VDWSSize <= 12 * 1024 + +; ***************************************************************************** +; Space in the first 32K is allocated below +; ***************************************************************************** +; Real workspace definition + +; Basic kernel space - defined locations for external modules + + ^ &100 +IRQ1V # 4 ; &100 + +ESC_Status # 1 ; &104 +LatchBSoftCopy # 1 ; &105 +IOCControlSoftCopy # 1 ; &106 +CannotReset # 1 ; &107 + +IRQsema # 4 ; &108 +MetroGnome # 4 ; &10C +MemorySpeed # 4 ; &110 + +MEMC_CR_SoftCopy # 4 ; &114 + + +; Now all internal definitions + +; Up to here is initialized on reset + +; Next come handler variables + +MemLimit # 4 +UndHan # 4 +PAbHan # 4 +DAbHan # 4 +AdXHan # 4 + +ErrHan # 4 +ErrBuf # 4 +ErrHan_ws # 4 + +CallAd_ws # 4 ; smart Rs ordering: +CallAd # 4 ; can do LDMIA of r12, pc +CallBf # 4 + +BrkAd_ws # 4 +BrkAd # 4 +BrkBf # 4 + +EscHan_ws # 4 +EscHan # 4 + +EvtHan_ws # 4 +EvtHan # 4 + +RAMLIMIT # 4 + +NoOfCamEntries * 255 ; we have entries 0-n.o.c.e. +CamEntries # 4 * (NoOfCamEntries+1) ; keep CAM entries + PPL in here + ASSERT CamEntries = &164 ; Fixed for PCEmulator + +AplWorkSize # 4 + +HiServ_ws # 4 +HiServ # 4 +SExitA # 4 +SExitA_ws # 4 +UpCallHan_ws # 4 +UpCallHan # 4 + + +; now a section that it's handy to have in simply loadable places + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 + +KeyWorkSpaceSize * &200 +KeyWorkSpace # KeyWorkSpaceSize + +; general MOS buffer: re-use with caution! + +GeneralMOSBuffer # 256 + +ModuleSHT_Entries * 16 +ModuleSWI_HashTab # 4*ModuleSHT_Entries + +Module_List # 4 +Curr_Active_Object # 4 + +; Vector Claim & Release tables etc + +VecPtrTab # NVECTORS * 4 + +ExceptionDump # 4 + + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 ; Ensures we can MOV rn, #OsbyteVars if <=&1000 + +OsbyteVars # OSBYTEVarSize + ASSERT OsbyteVars < &10000 ; Must keep in first 64K so address can be read by + ; (and stored in) OS_Bytes &A6,&A7. SKS + +; These must be in first 4K +NBuffers * 10 +BuffInPtrs # 4 * NBuffers +BuffOutPtrs # 4 * NBuffers + +VariableList # 4 + +; Oscli stuff +OscliCBtopUID # 4 +OscliCBbotUID # 4 +OscliCBcurrend # 4 + +ReturnCode # 4 +RCLimit # 4 + +SpriteSize # 4 ; saved on startup for Sprite code and RAMFS +RAMDiscSize # 4 +FontCacheSize # 4 ; and font manager + +TickNodeChain # 4 + +; Workspace + +EnvTime # 5 +RedirectInHandle # 1 +RedirectOutHandle # 1 +MOShasFIQ # 1 +FIQclaim_interlock # 1 +CallBack_Flag # 1 +IRQ_CallBack_Flag * CallBack_Flag + + AlignSpace + +EnvString # 256 + + +DUMPER # 16 * 4 + +; more system workspace +Page_Size # 4 +PIRQ_Chain # 4 +PFIQasIRQ_Chain # 4 + +; IRQ despatch +DefIRQ1Vspace * 9*4+12*17+2*256 ; for size checking in MOS +DefaultIRQ1V # DefIRQ1Vspace ; assembly + + +CallBack_Vector # 4 + +; interruptible heap manager workspace + +HeapSavedReg_R0 # 4 +HeapSavedReg_R1 # 4 +HeapSavedReg_R2 # 4 +HeapSavedReg_R3 # 4 +HeapSavedReg_R4 # 4 +HeapSavedReg_R13 # 4 +HeapReturnedReg_R0 # 4 +HeapReturnedReg_R1 # 4 +HeapReturnedReg_R2 # 4 +HeapReturnedReg_R3 # 4 +HeapReturnedReg_R4 # 4 +HeapReturnedReg_R13 # 4 +HeapReturnedReg_PC # 4 ; also acts as interlock + + [ AssemblingArthur + ! 0, "low space free ":CC::STR:(&FF4-@) + ] + ASSERT @ < &FF4 + +; Words for old tools of assorted varieties + ^ &FF4 +FPEAnchor # 4 +DomainId # 4 ; SKS added for domain identification +Modula2_Private # 4 ; MICK has FFC and uses it it in USR mode + +VduDriverWorkSpace # VDWSSize + ASSERT (VduDriverWorkSpace :AND: 63) = 0 ; For Tim (VDU5) + + + [ AssemblingArthur + ! 0, "high space free ":CC::STR:(&4000-@) + ] + + ^ &4000 +ScratchSpaceSize * &4000 +ScratchSpace # ScratchSpaceSize + + ASSERT @ <= &8000 ; Start of apl + +; ***************************************************************************** +; Users of ScratchSpace declare yourself here: + +; NRaine: Filling a polygon uses ScratchSpace to flatten the path + +; DSeal: Draw module uses ScratchSpace on fill operations (this supercedes +; NRaine's declaration above). + +; SKS: HeapSort with (r1 & 0x80000000) & ~(r1 & 0x20000000) & (r5 <= 16K) +; uses ScratchSpace as a temp slot for data shuffling after sorting + +; TMD: Flood fill uses ScratchSpace for the flood queue. + +; Tidying the RMA uses ScratchSpace while all modules are dead + +; GSTRANS workspace: GSINIT puts state into the workspacem and GSREAD uses it. +; DO NOT do any operations between GSINIT/GSREAD SWIS. +; SWIs called: OSWord in time var code +; BinaryToDecimal, ReadUnsigned + +GSVarWSpace * ScratchSpace + + ^ 0 +GSNameBuff # &100 +GS_Stack # &200 +GS_StackPtr_Lim * &200 / 4 ; Number of words in stack. +GS_StackPtr # 4 + + ^ @ + ScratchSpace + +; Pointers for SubstituteArgs: no external calls. +; Ensure these don't overlap FileSwitch's buffers below! + +MacExStartPtrs # 44 +MacExEndPtrs # 44 + +; OS_CLI has a buffer for alias expansion: ReadVarVal and SubstituteArgs +; are called while the buffer is held. Also used for module prefixes: +; Module called twice in this case. + +AliasExpansionBuffer # 100 + +; *list/*type need an argument expansion buffer: ReadArgs called with it. + +ArgumentBuffer * AliasExpansionBuffer + +; EvaluateExpression space. Calls ReadUnsigned, BinaryToDecimal and ReadVarVal. + +ExprWSpace * @ + + ^ 0, R12 +ExprBuff # &100 +exprBracDif # 2 ; keep exprSTRACC aligned +tos_op # 2 ; 1 byte for use as STRACC-1 +ExprSVCstack # 4 +exprSTRACC * @ - ExprBuff + ExprWSpace + +ExprStackLimit * exprSTRACC + &100 +ExprStackStart * ScratchSpace + ScratchSpaceSize + + +; Tutu needs some for argument substitution + expansion for run/load types +; Only OS call during xform is XOS_SubstituteArgs and XOS_Heap(Claim,SysHeap) + + ^ 0 ; Offset from ScratchSpace +rav_substituted # 256 +rav_arglist # 256 + +TopOfPageZero # 0 + + ^ &8000 ; The actual top of Page Zero +EconetDebugSpace |#| &20 * 4 ; Thirty two words (&7F80) + + ASSERT @ > TopOfPageZero ; Make sure we don't clash + +; ***************************************************************************** +; *** Cursor, Sound DMA, SWI, and OSCLI workspace. *** +; *** Sits in the 32K above 31M, ie. &01F000000..&01F07FFF *** +; *** Has the physical address &02078000, ie. 32M + 512K - 32K *** +; ***************************************************************************** + +TopOfDMAPhysRAM * &80000 ; OFFSET in physram +TopOfDMAWorkSpace * CursorChunkAddress + 32*1024 +OffsetLogicalToPhysical * TopOfDMAPhysRAM - TopOfDMAWorkSpace + + ^ TopOfDMAWorkSpace ; Note we will be going down + +; Sound + +SoundWorkSpaceSize * &1000 +SoundDMABufferSize * &1000 +SoundEvtSize * &1000 +SoundDMABuffers |#| SoundDMABufferSize * 2 +SoundWorkSpace |#| SoundWorkSpaceSize + SoundEvtSize + +; Cursor + +CursorDataSize * &800 +CursorData |#| CursorDataSize +CursorSoundRAM * CursorData +CursorSoundPhysRAM * CursorSoundRAM + OffsetLogicalToPhysical + +; SWI despatcher + +BranchToSWIExit |#| 4 +SvcTable |#| &400 + ASSERT SvcTable = &01F033FC ; Required for SVC table pokers, 1.20 compatible +SWIDespatch_Size * 29*4 +SWIDespatch |#| SWIDespatch_Size + + +; Buffers + +KeyBuffSize * &100 +RS423InBuffSize * &100 +RS423OutBuffSize * &C0 +PrintBuffSize * &400 +Sound0BuffSize * 4 +Sound1BuffSize * 4 +Sound2BuffSize * 4 +Sound3BuffSize * 4 +SpeechBuffSize * 4 +MouseBuffSize * &40 +KeyBuff |#| KeyBuffSize +RS423InBuff |#| RS423InBuffSize +RS423OutBuff |#| RS423OutBuffSize +PrintBuff |#| PrintBuffSize +Sound0Buff |#| Sound0BuffSize +Sound1Buff |#| Sound1BuffSize +Sound2Buff |#| Sound2BuffSize +Sound3Buff |#| Sound3BuffSize +SpeechBuff |#| SpeechBuffSize +MouseBuff |#| MouseBuffSize + +; Oscli buffering + +OscliBuffSize * &100 +OscliNoBuffs * 16 +OscliCircBuffLimit |#| 0 +OscliCircBuffStart |#| OscliBuffSize * OscliNoBuffs +RedirectBuff |#| OscliBuffSize + + [ AssemblingArthur + ! 0, "Aligning IRQ stack from ":CC::STR:@ + ] + [ @-7*4 :AND: 15 <> 0 + |#| (@-7*4):AND:15 + ] +IRQSTK # 0 ; Overflow will give abort + [ AssemblingArthur + ! 0, "IRQ stack size ":CC::STR:(IRQSTK-CursorChunkAddress) + ] + + ASSERT @ > ( CursorChunkAddress + &1000 ) ; Check minimum stack + +; ***************************************************************************** +; High system workspace +; ***************************************************************************** + + ^ SysHeapChunkAddress + + # 8*1024 ; svcstk size. Overflow will give abort +SVCSTK # 0 +SysHeapStart # 0 + + + OPT OldOpt + END diff --git a/hdr/Old/NewSpace b/hdr/Old/NewSpace new file mode 100644 index 0000000000000000000000000000000000000000..50f3233530f782e3cb8e78f3d8a3befe7493c868 --- /dev/null +++ b/hdr/Old/NewSpace @@ -0,0 +1,1172 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + SUBT > &.Hdr.NewSpace + +OldOpt SETA {OPT} + OPT OptNoList+OptNoP1List + +; *********************************** +; *** C h a n g e L i s t *** +; *********************************** + +; Date Name Description +; ---- ---- ----------- +; 02-Nov-87 APT Added module SWI hash table +; 03-Nov-87 APT Modo-fied module SWI hash table info, removed BRKLST +; 09-Nov-87 APT Removed ESCCNT and ESFLG +; 12-Nov-87 APT Added IRQsema +; 13-Nov-87 APT Added DefaultIRQ1V codespace +; 16-Nov-87 APT PIRQ chain heads +; 18-Nov-87 APT Reordered EvtHan, EvtHan_ws +; 19-Nov-87 APT Moved IRQsema +; 01-Dec-87 APT Added interruptible heap manager workspace +; 08-Dec-87 TMD Added ECFShift, ECFYOffset +; 14-Dec-87 TMD Added DisplayNColour, DisplayModeFlags +; 15-Dec-87 TMD Added KeyAlphabet +; 22-Dec-87 NDR Using ScratchSpace +; 13-Jan-88 APT General scratchspace bash, low workspace reordering. +; Removed spurious 32 bytes of osbyte wspace +; 14-Jan-88 APT *type buffer in scratchspace. +; MOShasFIQ byte added +; 20-Jan-88 APT Workspace juggling for speed & space; also discarded +; Level0 stuff. +; 28-Jan-88 APT MetroGnome moved to "public" location for ADFS +; 02-Feb-88 APT FIQclaim_interlock added +; 05-Feb-88 APT CallBack_Vector +; 09-Feb-88 APT RAM for SWI despatch +; 17-Feb-88 TMD Added VduSaveArea, VduSaveAreaPtr, DisplayModeNo +; 26-Feb-88 APT NoOfCamEntries manifest +; 03-Mar-88 APT Shrank SVC despatch +; 03-Mar-88 APT NoOfCamEntries manifest doubled +; 07-Mar-88 TMD Added DisplayScreenStart, VduOutputCurrentState, +; SpriteMaskSelect, reordered mode variables +; 07-Mar-88 APT Made CamEntries always at &164 +; 07-Mar-88 TMD Added GCharSizes, GCharSizeX, GCharSizeY +; 08-Mar-88 TMD Added GCharSpacing, GCharSpaceX, GCharSpaceY +; 08-Mar-88 TMD Moved GCharSizes..GCharSpaceY into first 1K of workspace +; 15-Mar-88 TMD Added HLineAddr +; 18-Mar-88 TMD Added DisplayXWindLimit, DisplayYWindLimit, +; DisplayXEigFactor, DisplayYEigFactor, PointerXEigFactor +; 18-Mar-88 APT Setting variables scratchspace use revised. +; 21-Mar-88 TMD Removed CursorIndex +; 22-Mar-88 TMD Added TCharSizeX,TCharSizeY,TCharSpaceX,TCharSpaceY +; 29-Mar-88 TMD Added GcolOraEorAddr +; 31-Mar-88 TMD Removed WsFontPtr +; 07-Apr-88 SKS Added HeapSort use of ScratchSpace +; 14-Apr-88 TMD Added SerialFlags +; 28-Apr-88 TMD Added XONXOFFChar +; 5-May-88 APT Added MemorySpeed +; 18-May-88 APT Added CannotReset sema at &107, removed pre-1.20 changes. +; 24-May-88 TMD Added ClipBoxEnable, ClipBoxLCol..ClipBoxTRow, moved in +; ScrLoaSpriteCB, ScrLoaBuffer, SrcSavCommon +; 24-May-88 TMD Flood fill uses ScratchSpace +; 01-Jun-88 TMD Added AlignSpace for ClipBoxCoords +; 03-Jun-88 BCSKS Make Keyboard buffer into a useful part of the system +; Also PrinterBufferSize +; 09-Jun-88 DJS Draw uses ScratchSpace +; 09-Jun-88 BC Gave Econet some private debungling space +; 11-Jun-88 SKS Align IRQ stack to make STMFD not cross two MEMC bdy's +; Made info condit'l on AsmArf; someone had commented it out! +; 15-Jun-88 SKS Added two more instructions in SWIDespatch area +; Moved SLVK definition into kernel; it's not public +; 16-Jun-88 SKS Added 3 more instructions in SWIDespatch area + nailed +; SvcTable address for compatibility +; 22-Jun-88 SKS Moved MEMC_CR_SoftCopy into pubic ws +; 19-Jul-88 APT Added UpCall handler stuff +; 20-Jul-88 SKS Added above entry +; Amended comment about overlaid workspace in vdu +; 15-Aug-88 SKS Inserted DomainId at FF8 (set by Wimp on task swap, used by +; FileSwitch to tag resources) +; 27-Sep-89 JSR Added ColourTrans to users of scratch space +; 24-Oct-89 TMD Added CamEntriesForBigMachines, CamEntriesPointer +; 26-Oct-89 TMD Added MaxCamEntry, removed NoOfCamEntries symbol +; 27-Oct-89 TMD Added VIDCClockSpeed +; 09-Nov-89 TMD Added ResetIndirection +; 15-Jan-91 TMD Added ROMModuleChain +; 04-Feb-91 DDV Added DeviceFS as user of ScratchSpace. +; 04-Feb-91 DDV Added ColourTrans use of ScratchSpace to build diff tables. +; 06-Mar-91 TMD Added IOSystemType +; 07-Mar-91 LVR ADFS uses scratch space for floppy formatting +; 07-Mar-91 TMD Added MonitorLeadType +; 08-Mar-91 TMD Added PrinterBufferAddr, PrinterBufferSize +; 11-Apr-91 TMD Added SerialInHandle, SerialOutHandle +; 24-Apr-91 TMD Added UniqueMachineID +; 09-Jun-91 RM Added KernelMessagesBlock,ErrorSemaphore and MOSConvertBuffer +; 26-Jul-91 JSR Extend GeneralMOSBuffer by 4 bytes to make it a valid +; length for the default error handler's error buffer +; 19-Aug-91 JSR Added *If to list of GeneralMOSBuffer users +; 22-Aug-91 TMD Reduced ErrorSemaphore to a byte, added PortableFlag +; 25-Aug-91 DDV Updated to indicate correct usage of scratch space by ColourTrans +; 09-Jan-92 DDV Added FgPattern, BgPattern and indicate use of ScratchSpace by OS_SetColour +; 20-Jan-92 TMD OS_SetColour no longer uses ScratchSpace +; 17-Feb-92 ECN Added CLibWord and RISCOSLibWord +; 02-Apr-92 TMD Added ScreenBlankFlag +; 03-Aug-92 TMD Kept in step with hdr:VickySpace, added PhysRam (from hdr:System) +; 09-Sep-92 TMD Added FirPalAddr, SecPalAddr +; 10-Sep-92 DDV Added pointer to the System heap copy of the Whizzy text expansion buffer +; 07-Oct-92 TMD Brought in line with VickySpace with respect to new VIDC stuff +; 04-Jun-93 TMD Added CurrentMonitorType +; 15-Jul-93 TMD Added KernelModeSelector +; 25-Aug-93 SMC Added processor vector table at ProcVec_Start +; Added ProcVecPreVeneers +; 07-Oct-93 TMD Added ScreenBlankDPMSState, HSWRSoftCopy, VSWRSoftCopy +; +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Memory map: + +AplWorkMaxSize * &01000000 ; 16M + +RMAAddress * &01800000 +RMAMaxSize * &00400000 ; 4M + +SysHeapChunkAddress * &01C00000 +SysHeapMaxSize * &00200000 ; 2M + +CursorChunkAddress * &01F00000 ; Fixed size 32K + +ScreenEndAdr * &02000000 +ScreenMaxSize * 480*1024 + +FontCacheAddress * &01E00000 +FontCacheMaxSize * &00100000 ; 1M + +SpriteSpaceAddress * &01400000 +SpriteSpaceMaxSize * &00400000 ; 4M + +RAMDiscAddress * &01000000 +RAMDiscMaxSize * &00400000 ; 4M + +PhysRam * &02000000 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; system variables + + ^ 0,R12 + +OSBYTEFirstVar # 0 + +ByteVars # 0 ; The main osbyte variables, accessed + ; via calls &A6 to &FF + +VarStart # 2 ; &A6,&A7 +ROMPtr # 2 ; &A8,&A9 +ROMInfo # 2 ; &AA,&AB +KBTran # 2 ; &AC,&AD +VDUvars # 2 ; &AE,&AF + +CFStime # 1 ; &B0 +InputStream # 1 ; &B1 +KeyBdSema # 1 ; &B2 + +ROMPollSema # 1 ; &B3 +OSHWM # 1 ; &B4 + +RS423mode # 1 ; &B5 +NoIgnore # 1 ; &B6 +CFSRFS # 1 ; &B7 +VULAcopy # 2 ; &B8,&B9 + +ROMatBRK # 1 ; &BA +BASICROM # 1 ; &BB + +ADCchanel # 1 ; &BC +ADCmaxchn # 1 ; &BD +ADCconv # 1 ; &BE + +RS423use # 1 ; &BF +RS423conflag # 1 ; &C0 + +FlashCount # 1 ; &C1 +SpacPeriod # 1 ; &C2 +MarkPeriod # 1 ; &C3 + +KeyRepDelay # 1 ; &C4 +KeyRepRate # 1 ; &C5 + +ExecFileH # 1 ; &C6 +SpoolFileH # 1 ; &C7 + +ESCBREAK # 1 ; &C8 (200) + +KeyBdDisable # 1 ; &C9 +KeyBdStatus # 1 ; &CA + +RS423HandShake # 1 ; &CB +RS423InputSupr # 1 ; &CC +RS423CFSFlag # 1 ; &CD + +EconetOScall # 1 ; &CE +EconetOSrdch # 1 ; &CF +EconetOSwrch # 1 ; &D0 + +SpeechSupr # 1 ; &D1 +SoundSupr # 1 ; &D2 + +BELLchannel # 1 ; &D3 +BELLinfo # 1 ; &D4 +BELLfreq # 1 ; &D5 +BELLdur # 1 ; &D6 + +StartMessSupr # 1 ; &D7 + +SoftKeyLen # 1 ; &D8 + +PageModeLineCount # 1 ; &D9 + +VDUqueueItems # 1 ; &DA + +TABch # 1 ; &DB +ESCch # 1 ; &DC + +IPbufferCh # 4 ; &DD,&DE,&DF,&E0 +RedKeyCh # 4 ; &E1,&E2,&E3,&E4 + +ESCaction # 1 ; &E5 +ESCeffect # 1 ; &E6 + +u6522IRQ # 1 ; &E7 +s6850IRQ # 1 ; &E8 +s6522IRQ # 1 ; &E9 + +TubeFlag # 1 ; &EA + +SpeechFlag # 1 ; &EB + +WrchDest # 1 ; &EC +CurEdit # 1 ; &ED + +SoftResetVars # 0 ; Reset to here on soft reset + +KeyBase # 1 ; &EE +Shadow # 1 ; &EF +Country # 1 ; &F0 + +UserFlag # 1 ; &F1 + +SerULAreg # 1 ; &F2 + +TimerState # 1 ; &F3 + +SoftKeyConsist # 1 ; &F4 + +PrinterDrivType # 1 ; &F5 +PrinterIgnore # 1 ; &F6 + +HardResetVars # 0 ; Reset to here on hard reset + +BREAKvector # 3 ; &F7,&F8,&F9 + +MemDriver # 1 ; &FA - where the VDU drivers write to +MemDisplay # 1 ; &FB - where we display from + +LangROM # 1 ; &FC + +LastBREAK # 1 ; &FD + +KeyOpt # 1 ; &FE + +StartOptions # 1 ; &FF + +PowerOnResetVars # 0 ; Reset to here on power-on reset + +; These two can dovetail in here to use up 2 bytes before the AlignSpace! + +SerialInHandle # 1 ; Handle for serial input stream (0 if not open currently) +SerialOutHandle # 1 ; Handle for serial output stream (-----------""----------) + + AlignSpace + +EventSemaphores # 32 ; One byte for each of 32 events + +TimerAlpha # 8 ; As used by time (bottom 5 bytes) +TimerBeta # 8 ; ................................ +; both aligned to word boundaries + +RealTime # 8 ; 5-byte fast real-time + +PrinterActive # 4 ; Handle/active flag for printer (word aligned) + +IntervalTimer # 5 ; Up Counter synchronous with TIME. +; Event generated when Zero is reached +; bottom byte aligned to word boundary + +SecondsTime # 1 ; the soft copy (centi-)seconds of the RTC +CentiTime # 1 ; """""""""""""""""""""""""""""""""""""""" + +FlashState # 1 ; which flash colours are we using + +SecondsDirty # 1 ; the dirty flag for start up! + +MinTick # 1 ; the minutes odd/even state + +DCDDSRCopy # 1 ; copy of ACIA bits to check for change + +TVVertical # 1 ; *TV first parameter + +TVInterlace # 1 ; *TV second parameter + +CentiCounter # 1 ; Counter for VDU CTRL timing + +Alphabet # 1 ; Current alphabet number + +Keyboard # 1 ; Current keyboard number + +KeyAlphabet # 1 ; Alphabet associated with current keyboard + + GBLS PrinterPrefix +PrinterPrefix SETS "PrinterType$" + +PrinterTypeName # 6 + :LEN: (PrinterPrefix) + + AlignSpace + +SerialFlags # 4 ; New serial flags + +XONXOFFChar # 1 ; Character to send before rest (0 if none) + + AlignSpace + +OSBYTEVarSize * @-OSBYTEFirstVar + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +; End of variables' space + + +; *********************************** +; *** Main Vdu Driver Workspace *** +; *********************************** + + ^ 0 + +FgEcf # 4 * 8 ; Foreground Ecf, set by GCOL(a,0-127) +BgEcf # 4 * 8 ; Background Ecf, set by GCOL(a,128-255) +GPLFMD # 4 ; Foreground action, set by GCOL(a,0-127) +GPLBMD # 4 ; Background action, set by GCOL(a,128-255) +GFCOL # 4 ; Foreground colour, set by GCOL(a,0-127) +GBCOL # 4 ; Background colour, set by GCOL(a,128-255) + +GWLCol # 4 ; Graphics window left column -- +GWBRow # 4 ; Graphics window bottom row | +GWRCol # 4 ; Graphics window right column | +GWTRow # 4 ; Graphics window top row -- + +qqqPad # 3 +QQ # 17 ;Queue - QQ+1 is on a word boundary +QOffset # 4 ;Value to add to VDUqueueItems to point to next queue posn. +JVec # 4 ;Jump vector to internal routines + +; Start of MODE table workspace + +ScreenSize # 4 ; number of bytes needed for this mode (assumed 1st in list) + +XWindLimit # 4 ; Maximum value of GWRCol (internal representation) + +; LineLength must be immediately after YWindLimit + +YWindLimit # 4 ; Maximum value of GWTRow (internal representation) + +LineLength # 4 ; Length of one pixel row in bytes + +NColour # 4 ; Number of colours minus 1 + +; End of word mode variables + +YShftFactor # 4 ; Number of places to shift YCoord in address generation after + ; multiplying by 5, holds + ; 7,6,5 or 4 for 8,4,2 or 1 bits per pixel (640x256 mode) or + ; 6,5,4 or 3 for 8,4,2 or 1 bits per pixel (320x256 mode). + +ModeFlags # 4 ; Bit 0 => non-graphic, Bit 1 => teletext, Bit 2 => gap mode + +XEigFactor # 4 ; Number of places to shift XCoord in external to internal + ; coordinate conversion, holds + ; 1 for 640x256 mode + ; 2 for 320x256 mode + ; 3 for 160x256 (BBC micro mode 2) + +YEigFactor # 4 ; number of shifts to convert between internal/external Y + +Log2BPC # 4 ; Log to base 2 of BytesPerChar ie (0,1,2,3,4) + +Log2BPP # 4 ; Log to base 2 of BitsPerPix ie (0,1,2,3) + +ECFIndex # 4 ; Index into default ECF tables + +ScrRCol # 4 ; Maximum column number in this screen mode +ScrBRow # 4 ; Maximum row number in this screen mode + +PalIndex # 4 ; Index into palette tables (0,1,2,3) + +; End of table-initialised workspace + +; Next 3 must be together in this order ! + +XShftFactor # 4 ; Number of places to shift XCoord in address generation, + ; holds 2,3,4 or 5 for 8,4,2,1 bits per pixel respectivly +GColAdr # 4 ; Address of Ecf to plot - either FgEcf or BgEcf + +ScreenStart # 4 ; Start address of screen (for VDU drivers) + +NPix # 4 ; Number of pixels per word minus 1, holds + ; holds 3,7,15 or 31 for 8,4,2,1 bits per pixel modes + +AspectRatio # 4 ; Pixel shape : 0 square, 1 horz rect, 2 vert rect + +BitsPerPix # 4 ; Bits per pixel (1,2,4,8) + +BytesPerChar # 4 ; Bytes per one line of character + ; (same as BitsPerPix except in double pixel modes) + +CursorFudgeFactor # 4 ; Factor for horizontal cursor positioning + +RowMult # 4 ; Row multiplier for text manipulation + +RowLength # 4 ; Bytes per text row in this mode (eg 640,1280,5120) + +; The following (up to and including NewPtY) must be together in this order +; (relied upon by DefaultWindows) + +TWLCol # 4 ; Text window left column -- +TWBRow # 4 ; Text window bottom row | +TWRCol # 4 ; Text window right column | +TWTRow # 4 ; Text window top row -- + +OrgX # 4 ; Screen origin (external representation) +OrgY # 4 + +GCsX # 4 ; Graphics cursor (external representation) +GCsY # 4 + +OlderCsX # 4 ; Very old X coordinate (internal) +OlderCsY # 4 ; Very old Y coordinate (internal) + +OldCsX # 4 ; Old graphics cursor (internal representation) -- +OldCsY # 4 ; | + ; | +GCsIX # 4 ; Graphics cursor (internal representation) | +GCsIY # 4 ; | + ; | +NewPtX # 4 ; Newest point (internal representation) | +NewPtY # 4 ; -- + +; End of together block + +TForeCol # 4 ; Text foreground colour +TBackCol # 4 ; Text background colour + +CursorX # 4 ; Text cursor X position ; these 3 must be in same order as ... +CursorY # 4 ; Text cursor Y position +CursorAddr # 4 ; Screen address of (output) cursor + +InputCursorX # 4 ; Input cursor X position ; ... these 3 +InputCursorY # 4 ; Input cursor Y position +InputCursorAddr # 4 ; Screen address of input cursor + +EORtoggle # 4 ; Toggle between gap and non-gap +RowsToDo # 4 ; in the CLS + +VduStatus # 4 ; Vdu2, Window, Shadow bits (others in CursorFlags) + +CBWS # 8 ; Clear block (VDU 23,8..) workspace +CBStart # 2 +CBEnd # 2 + +CursorDesiredState # 4 +CursorStartOffset # 4 +CursorEndOffset # 4 +CursorCounter # 4 +CursorSpeed # 4 +Reg10Copy # 4 + +CursorFill # 4 ; Word to EOR cursor ; MUST be immediately before CursorNbit + +CursorNbit # 4 ; Pointer to cursor code for current mode + +DisplayStart # 4 ; Start address of screen (for display) +DriverBankAddr # 4 ; Default start address for VDU drivers +DisplayBankAddr # 4 ; Default start address for display +DisplayNColour # 4 ; No. of colours -1 for displayed mode +DisplayModeFlags # 4 ; ModeFlags for displayed mode +DisplayModeNo # 4 ; ModeNo for displayed mode +DisplayScreenStart # 4 ; Where VDU outputs to when outputting to screen + +DisplayXWindLimit # 4 ; Used for pointer programming +DisplayYWindLimit # 4 +DisplayXEigFactor # 4 +DisplayYEigFactor # 4 +PointerXEigFactor # 4 + +Ecf1 # 8 ; The Ecf patterns +Ecf2 # 8 +Ecf3 # 8 +Ecf4 # 8 + +DotLineStyle # 8 ; Dot dash line pattern + +ModeNo # 4 ; Current mode number + +TFTint # 4 ; Text foreground tint (in bits 6,7) +TBTint # 4 ; Text background tint +GFTint # 4 ; Graphics foreground tint +GBTint # 4 ; Graphics background tint + +TotalScreenSize # 4 ; Amount configured for screen (in bytes) + +MaxMode # 4 ; Maximum mode number allowed (20 for now) + +VinitCopy # 4 ; Copy of Vinit for VDU 23;12 or 13 + +CursorFlags # 4 ; Silly Master cursor movement flags + +CursorStack # 4 ; Bit stack of nested cursor states (0 => on, 1 => off) + ; (bit 31 = TOS) + +ECFShift # 4 ; number of bits to rotate right ECF OR and EOR masks by +ECFYOffset # 4 ; vertical offset to ECF index + +WsVdu5 # 0 ; Vdu 5 workspace +WsScr # 4 +WsEcfPtr # 4 +; WsFontPtr # 4 ; not needed any more, kept in register +EndVerti # 4 +StartMask # 4 +EndMask # 4 +FontOffset # 4 +TempPlain # 16 ; only used for MODE 10 + +VIDCClockSpeed # 4 ; current VIDC clock speed in kHz + +CurrentMonitorType # 4 ; initialised from configured one + +KernelModeSelector # 4 ; pointer to block in system heap where + ; current mode selector is copied + +GraphicWs # 300 ; All graphics workspace is overlaid here +EndGraphicWs # 0 + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 + +GCharSizes # 0 +GCharSizeX # 4 ; width of VDU 5 chars in pixels +GCharSizeY # 4 ; height of VDU 5 chars in pixels + +GCharSpacing # 0 +GCharSpaceX # 4 ; horizontal spacing between VDU 5 chars in pixels +GCharSpaceY # 4 ; vertical ------------------""----------------- + +TCharSizes # 0 +TCharSizeX # 4 ; width of VDU 4 chars in pixels +TCharSizeY # 4 ; height of VDU 4 chars in pixels + +TCharSpacing # 0 +TCharSpaceX # 4 ; horizontal spacing between VDU 4 chars in pixels +TCharSpaceY # 4 ; vertical ------------------""----------------- + +HLineAddr # 4 ; address of exported HLine +GcolOraEorAddr # 4 ; address of FgEcfOraEor etc + +FirPalSetting # 4*28 ; First palette settings (not used on VIDC20) +FirPalAddr * FirPalSetting ; Address of block for first palette setting (only used on VIDC20) +SecPalSetting # 4*28 ; Second palette settings (not used on VIDC20) +SecPalAddr * SecPalSetting ; Address of block for second palette setting (only used on VIDC20) + +TextFgColour # 4 ; Fg/Bg colour stored as a colour number, computed on VDU 18 and re-poked! +TextBgColour # 4 ; + +; In this brave new world there is a pointer to the text expansion +; buffer used for VDU 4 / 5 text plotting. + +; This now lives in the system heap. + +TextExpandArea # 4 ; Pointer to Text expand area (in system heap) +TextExpandArea_Size * (8*1024) + +HSWRSoftCopy # 4 ; soft copy of h.sync width register (for DPMS) +VSWRSoftCopy # 4 ; soft copy of v.sync width register (for DPMS) + +ScreenBlankFlag # 1 ; 0 => unblanked, 1 => blanked +ScreenBlankDPMSState # 1 ; 0 => just blank video + ; 1 => blank to stand-by (hsync off) + ; 2 => blank to suspend (vsync off) + ; 3 => blank to off (H+V off) + + [ AssemblingArthur + ! 0,"64 ":CC::STR:@ + ] + AlignSpace 64 + +FgEcfOraEor # 4*16 ; Interleaved zgora & zgeor +BgEcfOraEor # 4*16 ; Interleaved zgora & zgeor +BgEcfStore # 4*16 ; Interleaved zgora & zgeor to store background + +;Current state of pattern +LineDotCnt # 4 ; Count down to restarting pattern +LineDotPatLSW # 4 ; Current state of pattern LSWord +LineDotPatMSW # 4 ; " " " " MSWord + +DotLineLength # 4 ; Dot Pattern repeat length as given in *FX163,242,n + +BBCcompatibleECFs # 4 ; 0 => BBC compatible, 1 => native + +SpAreaStart # 4 ; Start of sprite area +SpChooseName # 16 ; No comment says Richard +SpChoosePtr # 4 + +PointerHeights # 4 ; 4 x 1 byte +PointerActiveXs # 4 ; 4 x 1 byte +PointerActiveYs # 4 ; 4 x 1 byte +PointerShapeNumber # 4 ; only bottom byte used +PointerX # 4 ; co-ordinates of pointer (not always = mouse) +PointerY # 4 + +VIDCControlCopy # 4 ; Soft copy of VIDC control register +VertAdjust # 4 ; offset to add to vertical VIDC registers + +TeletextOffset # 4 ; Offset to current teletext flash bank + +TeletextCount # 4 ; Number of vsyncs till next teletext flash + +WrchNbit # 4 ; Pointer to char code for current mode + +BeepBlock # 8 ; OSWORD block for VDU 7 + +ScreenMemoryClaimed # 1 ; NZ => memory has been claimed or is unusable + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 ; Align workspace to 16 bytes + +TTXDoubleCounts # 25 ; Number of double height chars on each line + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 ; Align workspace to 16 bytes + +RAMMaskTb # 32*4 ; Copy of MaskTb for this mode (up to 32 words) + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 ; Align workspace to 16 bytes + +VduOutputCurrentState # 0 ; values of R0-R3 to return from SwitchOutputToSprite + ; or Mask; next 4 must be in this order +SpriteMaskSelect # 4 ; value of R0 to be given to SWI OS_SpriteOp to set up + ; current state +VduSpriteArea # 4 ; Pointer to sprite area containing VDU output sprite + ; (0 if output is to screen) +VduSprite # 4 ; Pointer to VDU output sprite (0 if output to screen) + +VduSaveAreaPtr # 4 ; Pointer to save area for VDU variables + + + [ AssemblingArthur + ! 0,"16,12 ":CC::STR:@ + ] + AlignSpace 16, 12 ; Make ClipBoxCoords a valid immediate, + ; with ClipBoxEnable immediately before it +ClipBoxInfo # 0 +ClipBoxEnable # 4 ; 0 => clip box disabled, 1 => enabled + +ClipBoxCoords # 0 ; Internal coords of modified area of screen +ClipBoxLCol # 4 +ClipBoxBRow # 4 +ClipBoxRCol # 4 +ClipBoxTRow # 4 + +FgPattern # 4*8 ; foreground pattern as defined by OS_SetColour +BgPattern # 4*8 ; background pattern as defined by OS_SetColour + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + + AlignSpace 16 ; Align workspace to 16 bytes + +TextExpand # 4*1024 ; Tim's massive text expansion table for whizzy WRCH +; TextPlain is now always hard against the end of TextExpand for this mode + +TTXSoftFonts * TextExpand + 2*1024 ; Soft fonts in teletext mode + + [ AssemblingArthur + ! 0,"64 ":CC::STR:@ + ] + AlignSpace 64 ; Align workspace to 64 bytes + +; Teletext map and copy/move buffer are overlaid + +TTXMapSize * 41*25*4 ; (&1004 bytes) +LargeCommon # TTXMapSize ; the largest area +TTXMap * LargeCommon + +ScrLoaSpriteCB * LargeCommon ; (size = SpriteCBsize + MaxSpritePaletteSize) +ScrLoaBuffer * LargeCommon ; (size = one pixel row) +ScrSavCommon * LargeCommon ; (size = SpriteAreaCBsize + SpriteCBsize + ; + MaxSpritePaletteSize) + +FldQueueSize * ScratchSpaceSize +FldQueueStart * ScratchSpace + + [ AssemblingArthur + ! 0,"64 ":CC::STR:@ + ] + AlignSpace 64 ; Align workspace to 64 bytes + +Font # &700 ; 7 pages of (soft) font + +SaveAreaSize * 12*1024-@ + +VduSaveArea # SaveAreaSize ; save area for switching output to sprites + +VDWSSize # 0 + + ASSERT VDWSSize <= 12 * 1024 + +; ***************************************************************************** +; Space in the first 32K is allocated below +; ***************************************************************************** +; Real workspace definition + +; Basic kernel space - defined locations for external modules + + ^ &100 +IRQ1V # 4 ; &100 + +ESC_Status # 1 ; &104 +LatchBSoftCopy # 1 ; &105 +IOCControlSoftCopy # 1 ; &106 +CannotReset # 1 ; &107 + +IRQsema # 4 ; &108 +MetroGnome # 4 ; &10C +MemorySpeed # 4 ; &110 + +MEMC_CR_SoftCopy # 4 ; &114 +ResetIndirection # 4 ; &118 + +; Now all internal definitions + +; Up to here is initialized on reset + +; Next come handler variables + +MemLimit # 4 +UndHan # 4 +PAbHan # 4 +DAbHan # 4 +AdXHan # 4 + +ErrHan # 4 +ErrBuf # 4 +ErrHan_ws # 4 + +CallAd_ws # 4 ; smart Rs ordering: +CallAd # 4 ; can do LDMIA of r12, pc +CallBf # 4 + +BrkAd_ws # 4 +BrkAd # 4 +BrkBf # 4 + +EscHan_ws # 4 +EscHan # 4 + +EvtHan_ws # 4 +EvtHan # 4 + +CamEntries # 4 * 256 ; CAM entries + PPL in here for machines up to + ; 8 MBytes - for larger machines they're stored + ; in CamEntriesForBigMachines - the location + ; CamEntriesPointer points to whichever is used + ASSERT CamEntries = &164 ; Fixed for PCEmulator (doesn't work with >= 8MBytes) + +CamEntriesPointer # 4 ; points to where CAM soft copy is + ; (CamEntries for machines up to 8MBytes, + ; CamEntriesForBigMachines for larger machines) + +MaxCamEntry # 4 ; maximum index into the cam map, ie + ; 511 for 16MByte machines, 383 for 12MBytes + ; 255 for 8MBytes, otherwise 127 + +RAMLIMIT # 4 + +AplWorkSize # 4 + +HiServ_ws # 4 +HiServ # 4 +SExitA # 4 +SExitA_ws # 4 +UpCallHan_ws # 4 +UpCallHan # 4 + +ROMModuleChain # 4 ; pointer to head of ROM module chain + +; now a section that it's handy to have in simply loadable places + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 + +KeyWorkSpaceSize * &200 +KeyWorkSpace # KeyWorkSpaceSize + +; The following were reordered on 26-Jul-91. Old ordering was: +; GeneralMOSBuffer +; ModuleSWI_HashTab +; Module_List +; Curr_Active_Object +; VecPtrTab +; ExceptionDump + +ModuleSHT_Entries * 16 +ModuleSWI_HashTab # 4*ModuleSHT_Entries + +Module_List # 4 +Curr_Active_Object # 4 + +; Vector Claim & Release tables etc + +VecPtrTab # NVECTORS * 4 + +ExceptionDump # 4 + +; GeneralMOSBuffer: re-use with caution! +; Here's just some of the users: +; user use(s) +; default error handler error buffer (must be 246+4 bytes big) +; *If expression to be evaluated to control the *If +; Command line to be submited on the expression +; evaluating to non-zero (the THEN clause). +GeneralMOSBuffer # 256+4 + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 ; Ensures we can MOV rn, #OsbyteVars if <=&1000 + +OsbyteVars # OSBYTEVarSize + ASSERT OsbyteVars < &10000 ; Must keep in first 64K so address can be read by + ; (and stored in) OS_Bytes &A6,&A7. SKS + +; These must be in first 4K +NBuffers * 10 +BuffInPtrs # 4 * NBuffers +BuffOutPtrs # 4 * NBuffers + +VariableList # 4 + +; Oscli stuff +OscliCBtopUID # 4 +OscliCBbotUID # 4 +OscliCBcurrend # 4 + +ReturnCode # 4 +RCLimit # 4 + +SpriteSize # 4 ; saved on startup for Sprite code and RAMFS +RAMDiscSize # 4 +FontCacheSize # 4 ; and font manager + +TickNodeChain # 4 + +; Workspace + +EnvTime # 5 +RedirectInHandle # 1 +RedirectOutHandle # 1 +MOShasFIQ # 1 +FIQclaim_interlock # 1 +CallBack_Flag # 1 +IRQ_CallBack_Flag * CallBack_Flag +IOSystemType # 1 ; 0 => old I/O subsystem, 1 => IOEB+82C710 system, 2..255 => ? +MonitorLeadType # 1 ; some function of the monitor lead inputs, as yet undetermined + + AlignSpace + +EnvString # 256 + + +DUMPER # 16 * 4 + +; more system workspace +Page_Size # 4 +PIRQ_Chain # 4 +PFIQasIRQ_Chain # 4 + +; IRQ despatch +DefIRQ1Vspace * 9*4+12*17+2*256 ; for size checking in MOS +DefaultIRQ1V # DefIRQ1Vspace ; assembly + + +CallBack_Vector # 4 + +; interruptible heap manager workspace + +HeapSavedReg_R0 # 4 +HeapSavedReg_R1 # 4 +HeapSavedReg_R2 # 4 +HeapSavedReg_R3 # 4 +HeapSavedReg_R4 # 4 +HeapSavedReg_R13 # 4 +HeapReturnedReg_R0 # 4 +HeapReturnedReg_R1 # 4 +HeapReturnedReg_R2 # 4 +HeapReturnedReg_R3 # 4 +HeapReturnedReg_R4 # 4 +HeapReturnedReg_R13 # 4 +HeapReturnedReg_PC # 4 ; also acts as interlock + +PrinterBufferAddr # 4 ; holds address of printer buffer +PrinterBufferSize # 4 ; size of printer buffer - not to be confused with PrintBuffSize + ; which is the (constant) default size for the MOS's smallish buffer +UniqueMachineID # 8 ; 64 bits for unique machine ID +KernelMessagesBlock # 20 ; 5 Words for messagetrans message block. +ErrorSemaphore # 1 ; Error semaphore to avoid looping on error translation. +PortableFlag # 1 ; Non-zero => got an error from Portable_Speed, so don't try it again + + AlignSpace + +MOSConvertBuffer # 12 ; Enough romm for 8 hex digits. + +ProcVec_Start # 0 ; Start of processor vector table +ProcVec_Branch0 # 4 ; Branch through zero +ProcVec_UndInst # 4 ; Undefined instruction vector +ProcVec_SWI # 4 ; SWI vector +ProcVec_PrefAb # 4 ; Prefetch abort vector +ProcVec_DataAb # 4 ; Data abort vector +ProcVec_AddrEx # 4 ; Address exception vector (not useful on ARM600/700) +ProcVec_IRQ # 4 ; IRQ vector +ProcVec_End # 0 + +ProcVecPreVeneersSize * 4*4 ; Space for preveneers for loading handler addresses from 0 page. +ProcVecPreVeneers # ProcVecPreVeneersSize + + [ AssemblingArthur + ! 0, "low space free ":CC::STR:(&FEC-@) + ] + ASSERT @ < &FEC + +; Words for old tools of assorted varieties + ^ &FEC +; ECN 17-Feb-92 +; Added RISCOSLibWord and CLibWord. The ROM RISCOSLib and CLib must continue +; to work even when they are killed since ROM apps are hard linked to the +; ROM libraries. They cannot use the private word since the block pointed +; to by this will be freed. +RISCOSLibWord # 4 +CLibWord # 4 +FPEAnchor # 4 +DomainId # 4 ; SKS added for domain identification +Modula2_Private # 4 ; MICK has FFC and uses it it in USR mode + +VduDriverWorkSpace # VDWSSize + ASSERT (VduDriverWorkSpace :AND: 63) = 0 ; For Tim (VDU5) + + + [ AssemblingArthur + ! 0, "high space free ":CC::STR:(&4000-@) + ] + + ^ &4000 +ScratchSpaceSize * &4000 +ScratchSpace # ScratchSpaceSize + + ASSERT @ <= &8000 ; Start of apl + +; ***************************************************************************** +; Users of ScratchSpace declare yourself here: + +; NRaine: Filling a polygon uses ScratchSpace to flatten the path + +; DSeal: Draw module uses ScratchSpace on fill operations (this supercedes +; NRaine's declaration above). + +; SKS: HeapSort with (r1 & 0x80000000) & ~(r1 & 0x20000000) & (r5 <= 16K) +; uses ScratchSpace as a temp slot for data shuffling after sorting + +; TMD: Flood fill uses ScratchSpace for the flood queue. + +; Tidying the RMA uses ScratchSpace while all modules are dead + +; GSTRANS workspace: GSINIT puts state into the workspacem and GSREAD uses it. +; DO NOT do any operations between GSINIT/GSREAD SWIS. +; SWIs called: OSWord in time var code +; BinaryToDecimal, ReadUnsigned + +; LVR: ADFS uses scratch space to format floppies on 1772 based machines + +; DDV: ColourTrans uses scratch space to build palette tables when in +; ColourTrans_SelecTable/RetrunColourNumber and also whilst generating +; stipple pattterns. + +GSVarWSpace * ScratchSpace + + ^ 0 +GSNameBuff # &100 +GS_Stack # &200 +GS_StackPtr_Lim * &200 / 4 ; Number of words in stack. +GS_StackPtr # 4 + + ^ @ + ScratchSpace + +; Pointers for SubstituteArgs: no external calls. +; Ensure these don't overlap FileSwitch's buffers below! + +MacExStartPtrs # 44 +MacExEndPtrs # 44 + +; OS_CLI has a buffer for alias expansion: ReadVarVal and SubstituteArgs +; are called while the buffer is held. Also used for module prefixes: +; Module called twice in this case. + +AliasExpansionBuffer # 100 + +; *list/*type need an argument expansion buffer: ReadArgs called with it. + +ArgumentBuffer * AliasExpansionBuffer + +; EvaluateExpression space. Calls ReadUnsigned, BinaryToDecimal and ReadVarVal. + +ExprWSpace * @ + + ^ 0, R12 +ExprBuff # &100 +exprBracDif # 2 ; keep exprSTRACC aligned +tos_op # 2 ; 1 byte for use as STRACC-1 +ExprSVCstack # 4 +exprSTRACC * @ - ExprBuff + ExprWSpace + +ExprStackLimit * exprSTRACC + &100 +ExprStackStart * ScratchSpace + ScratchSpaceSize + + +; Tutu needs some for argument substitution + expansion for run/load types +; Only OS call during xform is XOS_SubstituteArgs and XOS_Heap(Claim,SysHeap) + + ^ 0 ; Offset from ScratchSpace +rav_substituted # 256 +rav_arglist # 256 + +TopOfPageZero # 0 + + ^ &8000 ; The actual top of Page Zero +EconetDebugSpace |#| &20 * 4 ; Thirty two words (&7F80) + + ASSERT @ > TopOfPageZero ; Make sure we don't clash + +; ***************************************************************************** +; *** Cursor, Sound DMA, SWI, and OSCLI workspace. *** +; *** Sits in the 32K above 31M, ie. &01F000000..&01F07FFF *** +; *** Has the physical address &02078000, ie. 32M + 512K - 32K *** +; ***************************************************************************** + +TopOfDMAPhysRAM * &80000 ; OFFSET in physram +TopOfDMAWorkSpace * CursorChunkAddress + 32*1024 +OffsetLogicalToPhysical * TopOfDMAPhysRAM - TopOfDMAWorkSpace + + ^ TopOfDMAWorkSpace ; Note we will be going down + +; Sound + +SoundWorkSpaceSize * &1000 +SoundDMABufferSize * &1000 +SoundEvtSize * &1000 +SoundDMABuffers |#| SoundDMABufferSize * 2 +SoundWorkSpace |#| SoundWorkSpaceSize + SoundEvtSize + +; Cursor + +CursorDataSize * &800 +CursorData |#| CursorDataSize +CursorSoundRAM * CursorData +CursorSoundPhysRAM * CursorSoundRAM + OffsetLogicalToPhysical + +; SWI despatcher + +BranchToSWIExit |#| 4 +SvcTable |#| &400 + ASSERT SvcTable = &01F033FC ; Required for SVC table pokers, 1.20 compatible +SWIDespatch_Size * 29*4 +SWIDespatch |#| SWIDespatch_Size + + +; Buffers + +KeyBuffSize * &100 +RS423InBuffSize * &100 +RS423OutBuffSize * &C0 +PrintBuffSize * &400 +Sound0BuffSize * 4 +Sound1BuffSize * 4 +Sound2BuffSize * 4 +Sound3BuffSize * 4 +SpeechBuffSize * 4 +MouseBuffSize * &40 +KeyBuff |#| KeyBuffSize +RS423InBuff |#| RS423InBuffSize +RS423OutBuff |#| RS423OutBuffSize +PrintBuff |#| PrintBuffSize +Sound0Buff |#| Sound0BuffSize +Sound1Buff |#| Sound1BuffSize +Sound2Buff |#| Sound2BuffSize +Sound3Buff |#| Sound3BuffSize +SpeechBuff |#| SpeechBuffSize +MouseBuff |#| MouseBuffSize + +; Oscli buffering + +OscliBuffSize * &100 +OscliNoBuffs * 16 +OscliCircBuffLimit |#| 0 +OscliCircBuffStart |#| OscliBuffSize * OscliNoBuffs +RedirectBuff |#| OscliBuffSize + +; New soft CAM address for 12MByte or 16MByte machines + +CamEntriesForBigMachines |#| 512*4 ; 512 entries, each is a word + + [ AssemblingArthur + ! 0, "Aligning IRQ stack from ":CC::STR:@ + ] + [ @-7*4 :AND: 15 <> 0 + |#| (@-7*4):AND:15 + ] +IRQSTK # 0 ; Overflow will give abort + [ AssemblingArthur + ! 0, "IRQ stack size ":CC::STR:(IRQSTK-CursorChunkAddress) + ] + + ASSERT @ > ( CursorChunkAddress + &1000 ) ; Check minimum stack + +; ***************************************************************************** +; High system workspace +; ***************************************************************************** + + ^ SysHeapChunkAddress + + # 8*1024 ; svcstk size. Overflow will give abort +SVCSTK # 0 +SysHeapStart # 0 + + + OPT OldOpt + END diff --git a/hdr/Old/VickySpace b/hdr/Old/VickySpace new file mode 100644 index 0000000000000000000000000000000000000000..c060e361fc551558c11b02b52f30938d3f371c12 --- /dev/null +++ b/hdr/Old/VickySpace @@ -0,0 +1,1296 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + SUBT > &.Hdr.VickySpace + +OldOpt SETA {OPT} + OPT OptNoList+OptNoP1List + +; *********************************** +; *** C h a n g e L i s t *** +; *********************************** + +; Date Name Description +; ---- ---- ----------- +; 02-Nov-87 APT Added module SWI hash table +; 03-Nov-87 APT Modo-fied module SWI hash table info, removed BRKLST +; 09-Nov-87 APT Removed ESCCNT and ESFLG +; 12-Nov-87 APT Added IRQsema +; 13-Nov-87 APT Added DefaultIRQ1V codespace +; 16-Nov-87 APT PIRQ chain heads +; 18-Nov-87 APT Reordered EvtHan, EvtHan_ws +; 19-Nov-87 APT Moved IRQsema +; 01-Dec-87 APT Added interruptible heap manager workspace +; 08-Dec-87 TMD Added ECFShift, ECFYOffset +; 14-Dec-87 TMD Added DisplayNColour, DisplayModeFlags +; 15-Dec-87 TMD Added KeyAlphabet +; 22-Dec-87 NDR Using ScratchSpace +; 13-Jan-88 APT General scratchspace bash, low workspace reordering. +; Removed spurious 32 bytes of osbyte wspace +; 14-Jan-88 APT *type buffer in scratchspace. +; MOShasFIQ byte added +; 20-Jan-88 APT Workspace juggling for speed & space; also discarded +; Level0 stuff. +; 28-Jan-88 APT MetroGnome moved to "public" location for ADFS +; 02-Feb-88 APT FIQclaim_interlock added +; 05-Feb-88 APT CallBack_Vector +; 09-Feb-88 APT RAM for SWI despatch +; 17-Feb-88 TMD Added VduSaveArea, VduSaveAreaPtr, DisplayModeNo +; 26-Feb-88 APT NoOfCamEntries manifest +; 03-Mar-88 APT Shrank SVC despatch +; 03-Mar-88 APT NoOfCamEntries manifest doubled +; 07-Mar-88 TMD Added DisplayScreenStart, VduOutputCurrentState, +; SpriteMaskSelect, reordered mode variables +; 07-Mar-88 APT Made CamEntries always at &164 +; 07-Mar-88 TMD Added GCharSizes, GCharSizeX, GCharSizeY +; 08-Mar-88 TMD Added GCharSpacing, GCharSpaceX, GCharSpaceY +; 08-Mar-88 TMD Moved GCharSizes..GCharSpaceY into first 1K of workspace +; 15-Mar-88 TMD Added HLineAddr +; 18-Mar-88 TMD Added DisplayXWindLimit, DisplayYWindLimit, +; DisplayXEigFactor, DisplayYEigFactor, PointerXEigFactor +; 18-Mar-88 APT Setting variables scratchspace use revised. +; 21-Mar-88 TMD Removed CursorIndex +; 22-Mar-88 TMD Added TCharSizeX,TCharSizeY,TCharSpaceX,TCharSpaceY +; 29-Mar-88 TMD Added GcolOraEorAddr +; 31-Mar-88 TMD Removed WsFontPtr +; 07-Apr-88 SKS Added HeapSort use of ScratchSpace +; 14-Apr-88 TMD Added SerialFlags +; 28-Apr-88 TMD Added XONXOFFChar +; 5-May-88 APT Added MemorySpeed +; 18-May-88 APT Added CannotReset sema at &107, removed pre-1.20 changes. +; 24-May-88 TMD Added ClipBoxEnable, ClipBoxLCol..ClipBoxTRow, moved in +; ScrLoaSpriteCB, ScrLoaBuffer, SrcSavCommon +; 24-May-88 TMD Flood fill uses ScratchSpace +; 01-Jun-88 TMD Added AlignSpace for ClipBoxCoords +; 03-Jun-88 BCSKS Make Keyboard buffer into a useful part of the system +; Also PrinterBufferSize +; 09-Jun-88 DJS Draw uses ScratchSpace +; 09-Jun-88 BC Gave Econet some private debungling space +; 11-Jun-88 SKS Align IRQ stack to make STMFD not cross two MEMC bdy's +; Made info condit'l on AsmArf; someone had commented it out! +; 15-Jun-88 SKS Added two more instructions in SWIDespatch area +; Moved SLVK definition into kernel; it's not public +; 16-Jun-88 SKS Added 3 more instructions in SWIDespatch area + nailed +; SvcTable address for compatibility +; 22-Jun-88 SKS Moved MEMC_CR_SoftCopy into pubic ws +; 19-Jul-88 APT Added UpCall handler stuff +; 20-Jul-88 SKS Added above entry +; Amended comment about overlaid workspace in vdu +; 15-Aug-88 SKS Inserted DomainId at FF8 (set by Wimp on task swap, used by +; FileSwitch to tag resources) +; 27-Sep-89 JSR Added ColourTrans to users of scratch space +; 24-Oct-89 TMD Added CamEntriesForBigMachines, CamEntriesPointer +; 26-Oct-89 TMD Added MaxCamEntry, removed NoOfCamEntries symbol +; 27-Oct-89 TMD Added VIDCClockSpeed +; 09-Nov-89 TMD Added ResetIndirection +; 15-Jan-91 TMD Added ROMModuleChain +; 04-Feb-91 DDV Added DeviceFS as user of ScratchSpace. +; 04-Feb-91 DDV Added ColourTrans use of ScratchSpace to build diff tables. +; 06-Mar-91 TMD Added IOSystemType +; 07-Mar-91 LVR ADFS uses scratch space for floppy formatting +; 07-Mar-91 TMD Added MonitorLeadType +; 08-Mar-91 TMD Added PrinterBufferAddr, PrinterBufferSize +; 11-Apr-91 TMD Added SerialInHandle, SerialOutHandle +; 24-Apr-91 TMD Added UniqueMachineID +; 09-Jun-91 RM Added KernelMessagesBlock,ErrorSemaphore and MOSConvertBuffer +; 26-Jul-91 JSR Extend GeneralMOSBuffer by 4 bytes to make it a valid +; length for the default error handler's error buffer +; 19-Aug-91 JSR Added *If to list of GeneralMOSBuffer users +; 22-Aug-91 TMD Reduced ErrorSemaphore to a byte, added PortableFlag +; 25-Aug-91 DDV Updated to indicate correct usage of scratch space by ColourTrans +; 09-Jan-92 DDV Added FgPattern, BgPattern and indicate use of ScratchSpace by OS_SetColour +; 20-Jan-92 TMD OS_SetColour no longer uses ScratchSpace +; 17-Feb-92 ECN Added CLibWord and RISCOSLibWord +; 02-Apr-92 TMD Added ScreenBlankFlag +; 27-Jul-92 TMD Create Victoria specific version +; 28-Jul-92 TMD Moved RAMDiscAddress +; 29-Jul-92 TMD Moved SpriteSpaceAddress +; 30-Jul-92 TMD Moved FontCacheAddress +; 31-Jul-92 TMD Moved ScreenEndAdr from source.vdudecl, and moved actual address! +; 03-Aug-92 TMD Added PhysRam (moved from hdr:System) +; 24-Aug-92 TMD Added AbortIndirection +; 26-Aug-92 TMD Added PreVeneerRegDump +; 02-Sep-92 TMD Added FirPalAddr, SecPalAddr +; 10-Sep-92 DDV Added new Vdu Variables for new text expansion buffer +; 17-Sep-92 DDV Moved NColour into the word initialised VDU workspace +; 17-Sep-92 DDV Two new colour words added for text foreground and background. +; 27-Jan-93 TMD Moved RMA to new position +; 29-Jan-93 TMD Put RMA back to old position (you can't branch to above 32M!) +; 01-Feb-93 TMD Added PhysRamTable +; 02-Feb-93 TMD Added VInitSoftCopy and VEndSoftCopy +; 03-Feb-93 TMD Added PhysRamTableEnd +; 04-Feb-93 TMD Added extra slot in PhysRamTable (in case soft-loaded OS splits a bank) +; 08-Feb-93 TMD Added VRAMWidth variable, and extra symbols for skipped bits +; 24-Feb-93 TMD Changed VRAMPhysAddr to VideoPhysAddr, and split off VideoSize from VRAMSize, to allow for +; DRAM-only systems +; 05-Mar-93 TMD Added CMOSRAMCache +; 19-Apr-93 TMD Added DAList, AppSpaceDANode and DANode offset symbols +; 26-Apr-93 TMD Added FreePoolAddress, FreePoolMaxSize, FreePoolSize +; 29-Apr-93 TMD Changed FontCacheAddress, SpriteSpaceAddress, RAMDiscAddress and FreePoolAddress +; in order to make way for L2PT, which is moving above 64M +; 10-May-93 TMD Added SoftCamMapSize +; 11-May-93 TMD Moved SoftCamMapSize into area that's not zapped in clearing all memory routine +; 12-May-93 TMD Added FreePoolDANode, removed FreePoolSize +; 20-May-93 TMD Moved AplWorkSize into AppSpaceDANode +; 27-May-93 TMD Added VideoBandwidth +; 04-Jun-93 TMD Added CurrentMonitorType +; 09-Jun-93 TMD Added CamMapCorruptDebugBlock +; 07-Jul-93 TMD Increased FreePoolMaxSize to 64M (had to reduce RAMDiscMaxSize to 48M and +; move FreePoolAddress down to do this) +; 15-Jul-93 TMD Added KernelModeSelector +; 26-Jul-93 SMC Moved DefaultIRQ1V (had to accommodate IRQs for IOMD DMA) +; 04-Aug-93 TMD Added L2PTSize, removed FreePoolMaxSize +; 14-Aug-93 TMD Removed SpriteSpaceAddress, shuffled things down +; 16-Aug-93 TMD Removed RAMDiscAddress, shuffled things down +; 17-Aug-93 TMD Removed FontCacheAddress, shuffled things down +; Corrected maximum size of system heap to 2M-8K. +; Added node (in bottom 32K) for system heap. +; 25-Aug-93 SMC Added processor vector table at ProcVec_Start +; Added ProcVecPreVeneers +; 02-Sep-93 SMC Moved RMA to &02100000 and changed application space size to 28M. +; 03-Sep-93 TMD Moved InitKbdWs into SkippedTables (was at start of screen originally) +; 07-Oct-93 TMD Put in OldMemoryMap option so I can still use it +; 07-Oct-93 TMD Added ScreenBlankDPMSState, HSWRSoftCopy, VSWRSoftCopy +; 10-Dec-93 BC Added RawMachineID +; 13-Dec-93 BC Removed UniqueMachineID +; 14-Jan-94 TMD Added CDASemaphore +; 18-Jan-94 TMD Added MMUControlSoftCopy +; +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Memory map: + +; Dynamic area node format + + ^ 0 + +DANode_Link # 4 ; points to next node +DANode_Number # 4 ; number of this area +DANode_Base # 4 ; base address of area (points in middle of doubly-mapped areas) +DANode_Flags # 4 ; various flags +DANode_Size # 4 ; current size of area +DANode_MaxSize # 4 ; maximum size of area +DANode_Workspace # 4 ; workspace pointer when calling handlers +DANode_Handler # 4 ; pointer to handler routine for area +DANode_Title # 4 ; pointer to area title (variable length) +DANode_NodeSize # 0 + +; The addresses below are only temporary; eventually most of them will be allocated at run time (we hope!) + + [ :DEF: OldMemoryMap +AplWorkMaxSize * &01000000 ; 16M +RMAAddress * &01800000 +RMAMaxSize * &00400000 ; 4M + | +AplWorkMaxSize * &01C00000 ; 28M +RMAAddress * &02100000 +RMAMaxSize * &00B00000 ; 11M + ] + +SysHeapChunkAddress * &01C00000 +SysHeapMaxSize * &00200000-8*1024 ; 2M - 8K + +CursorChunkAddress * &01F00000 ; Fixed size 32K + +ScreenEndAdr * &05000000 ; was &02000000 +ScreenMaxSize * 480*1024 + +; FontCacheAddress * &06000000 ; was &01E00000 ; now dynamic +; FontCacheMaxSize * &01000000 ; 16M + +; SpriteSpaceAddress * &08000000 ; was &01400000 ; now dynamic +; SpriteSpaceMaxSize * &01000000 ; 16M + +; RAMDiscAddress * &07000000 ; was &01000000 ; now dynamic +; RAMDiscMaxSize * &03000000 ; 48M + +FreePoolAddress * &06000000 ; may still go lower! + +PhysRam * &05000000 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; system variables + + ^ 0,R12 + +OSBYTEFirstVar # 0 + +ByteVars # 0 ; The main osbyte variables, accessed + ; via calls &A6 to &FF + +VarStart # 2 ; &A6,&A7 +ROMPtr # 2 ; &A8,&A9 +ROMInfo # 2 ; &AA,&AB +KBTran # 2 ; &AC,&AD +VDUvars # 2 ; &AE,&AF + +CFStime # 1 ; &B0 +InputStream # 1 ; &B1 +KeyBdSema # 1 ; &B2 + +ROMPollSema # 1 ; &B3 +OSHWM # 1 ; &B4 + +RS423mode # 1 ; &B5 +NoIgnore # 1 ; &B6 +CFSRFS # 1 ; &B7 +VULAcopy # 2 ; &B8,&B9 + +ROMatBRK # 1 ; &BA +BASICROM # 1 ; &BB + +ADCchanel # 1 ; &BC +ADCmaxchn # 1 ; &BD +ADCconv # 1 ; &BE + +RS423use # 1 ; &BF +RS423conflag # 1 ; &C0 + +FlashCount # 1 ; &C1 +SpacPeriod # 1 ; &C2 +MarkPeriod # 1 ; &C3 + +KeyRepDelay # 1 ; &C4 +KeyRepRate # 1 ; &C5 + +ExecFileH # 1 ; &C6 +SpoolFileH # 1 ; &C7 + +ESCBREAK # 1 ; &C8 (200) + +KeyBdDisable # 1 ; &C9 +KeyBdStatus # 1 ; &CA + +RS423HandShake # 1 ; &CB +RS423InputSupr # 1 ; &CC +RS423CFSFlag # 1 ; &CD + +EconetOScall # 1 ; &CE +EconetOSrdch # 1 ; &CF +EconetOSwrch # 1 ; &D0 + +SpeechSupr # 1 ; &D1 +SoundSupr # 1 ; &D2 + +BELLchannel # 1 ; &D3 +BELLinfo # 1 ; &D4 +BELLfreq # 1 ; &D5 +BELLdur # 1 ; &D6 + +StartMessSupr # 1 ; &D7 + +SoftKeyLen # 1 ; &D8 + +PageModeLineCount # 1 ; &D9 + +VDUqueueItems # 1 ; &DA + +TABch # 1 ; &DB +ESCch # 1 ; &DC + +IPbufferCh # 4 ; &DD,&DE,&DF,&E0 +RedKeyCh # 4 ; &E1,&E2,&E3,&E4 + +ESCaction # 1 ; &E5 +ESCeffect # 1 ; &E6 + +u6522IRQ # 1 ; &E7 +s6850IRQ # 1 ; &E8 +s6522IRQ # 1 ; &E9 + +TubeFlag # 1 ; &EA + +SpeechFlag # 1 ; &EB + +WrchDest # 1 ; &EC +CurEdit # 1 ; &ED + +SoftResetVars # 0 ; Reset to here on soft reset + +KeyBase # 1 ; &EE +Shadow # 1 ; &EF +Country # 1 ; &F0 + +UserFlag # 1 ; &F1 + +SerULAreg # 1 ; &F2 + +TimerState # 1 ; &F3 + +SoftKeyConsist # 1 ; &F4 + +PrinterDrivType # 1 ; &F5 +PrinterIgnore # 1 ; &F6 + +HardResetVars # 0 ; Reset to here on hard reset + +BREAKvector # 3 ; &F7,&F8,&F9 + +MemDriver # 1 ; &FA - where the VDU drivers write to +MemDisplay # 1 ; &FB - where we display from + +LangROM # 1 ; &FC + +LastBREAK # 1 ; &FD + +KeyOpt # 1 ; &FE + +StartOptions # 1 ; &FF + +PowerOnResetVars # 0 ; Reset to here on power-on reset + +; These two can dovetail in here to use up 2 bytes before the AlignSpace! + +SerialInHandle # 1 ; Handle for serial input stream (0 if not open currently) +SerialOutHandle # 1 ; Handle for serial output stream (-----------""----------) + + AlignSpace + +EventSemaphores # 32 ; One byte for each of 32 events + +TimerAlpha # 8 ; As used by time (bottom 5 bytes) +TimerBeta # 8 ; ................................ +; both aligned to word boundaries + +RealTime # 8 ; 5-byte fast real-time + +PrinterActive # 4 ; Handle/active flag for printer (word aligned) + +IntervalTimer # 5 ; Up Counter synchronous with TIME. +; Event generated when Zero is reached +; bottom byte aligned to word boundary + +SecondsTime # 1 ; the soft copy (centi-)seconds of the RTC +CentiTime # 1 ; """""""""""""""""""""""""""""""""""""""" + +FlashState # 1 ; which flash colours are we using + +SecondsDirty # 1 ; the dirty flag for start up! + +MinTick # 1 ; the minutes odd/even state + +DCDDSRCopy # 1 ; copy of ACIA bits to check for change + +TVVertical # 1 ; *TV first parameter + +TVInterlace # 1 ; *TV second parameter + +CentiCounter # 1 ; Counter for VDU CTRL timing + +Alphabet # 1 ; Current alphabet number + +Keyboard # 1 ; Current keyboard number + +KeyAlphabet # 1 ; Alphabet associated with current keyboard + + GBLS PrinterPrefix +PrinterPrefix SETS "PrinterType$" + +PrinterTypeName # 6 + :LEN: (PrinterPrefix) + + AlignSpace + +SerialFlags # 4 ; New serial flags + +XONXOFFChar # 1 ; Character to send before rest (0 if none) + + AlignSpace + +OSBYTEVarSize * @-OSBYTEFirstVar + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +; End of variables' space + + +; *********************************** +; *** Main Vdu Driver Workspace *** +; *********************************** + + ^ 0 + +FgEcf # 4 * 8 ; Foreground Ecf, set by GCOL(a,0-127) +BgEcf # 4 * 8 ; Background Ecf, set by GCOL(a,128-255) +GPLFMD # 4 ; Foreground action, set by GCOL(a,0-127) +GPLBMD # 4 ; Background action, set by GCOL(a,128-255) +GFCOL # 4 ; Foreground colour, set by GCOL(a,0-127) +GBCOL # 4 ; Background colour, set by GCOL(a,128-255) + +GWLCol # 4 ; Graphics window left column -- +GWBRow # 4 ; Graphics window bottom row | +GWRCol # 4 ; Graphics window right column | +GWTRow # 4 ; Graphics window top row -- + +qqqPad # 3 +QQ # 17 ;Queue - QQ+1 is on a word boundary +QOffset # 4 ;Value to add to VDUqueueItems to point to next queue posn. +JVec # 4 ;Jump vector to internal routines + +; Start of MODE table workspace + +ScreenSize # 4 ; number of bytes needed for this mode (assumed 1st in list) + +XWindLimit # 4 ; Maximum value of GWRCol (internal representation) + +; LineLength must be immediately after YWindLimit + +YWindLimit # 4 ; Maximum value of GWTRow (internal representation) + +LineLength # 4 ; Length of one pixel row in bytes + +NColour # 4 ; Number of colours minus 1 + +; End of word mode variables + +YShftFactor # 4 ; Number of places to shift YCoord in address generation after + ; multiplying by 5, holds + ; 7,6,5 or 4 for 8,4,2 or 1 bits per pixel (640x256 mode) or + ; 6,5,4 or 3 for 8,4,2 or 1 bits per pixel (320x256 mode). + +ModeFlags # 4 ; Bit 0 => non-graphic, Bit 1 => teletext, Bit 2 => gap mode + +XEigFactor # 4 ; Number of places to shift XCoord in external to internal + ; coordinate conversion, holds + ; 1 for 640x256 mode + ; 2 for 320x256 mode + ; 3 for 160x256 (BBC micro mode 2) + +YEigFactor # 4 ; number of shifts to convert between internal/external Y + +Log2BPC # 4 ; Log to base 2 of BytesPerChar ie (0,1,2,3,4) + +Log2BPP # 4 ; Log to base 2 of BitsPerPix ie (0,1,2,3) + +ECFIndex # 4 ; Index into default ECF tables + +ScrRCol # 4 ; Maximum column number in this screen mode +ScrBRow # 4 ; Maximum row number in this screen mode + +PalIndex # 4 ; Index into palette tables (0,1,2,3) + +; End of table-initialised workspace + +; Next 3 must be together in this order ! + +XShftFactor # 4 ; Number of places to shift XCoord in address generation, + ; holds 2,3,4 or 5 for 8,4,2,1 bits per pixel respectivly +GColAdr # 4 ; Address of Ecf to plot - either FgEcf or BgEcf + +ScreenStart # 4 ; Start address of screen (for VDU drivers) + +NPix # 4 ; Number of pixels per word minus 1, holds + ; holds 3,7,15 or 31 for 8,4,2,1 bits per pixel modes + +AspectRatio # 4 ; Pixel shape : 0 square, 1 horz rect, 2 vert rect + +BitsPerPix # 4 ; Bits per pixel (1,2,4,8) + +BytesPerChar # 4 ; Bytes per one line of character + ; (same as BitsPerPix except in double pixel modes) + +CursorFudgeFactor # 4 ; Factor for horizontal cursor positioning + +RowMult # 4 ; Row multiplier for text manipulation + +RowLength # 4 ; Bytes per text row in this mode (eg 640,1280,5120) + +; The following (up to and including NewPtY) must be together in this order +; (relied upon by DefaultWindows) + +TWLCol # 4 ; Text window left column -- +TWBRow # 4 ; Text window bottom row | +TWRCol # 4 ; Text window right column | +TWTRow # 4 ; Text window top row -- + +OrgX # 4 ; Screen origin (external representation) +OrgY # 4 + +GCsX # 4 ; Graphics cursor (external representation) +GCsY # 4 + +OlderCsX # 4 ; Very old X coordinate (internal) +OlderCsY # 4 ; Very old Y coordinate (internal) + +OldCsX # 4 ; Old graphics cursor (internal representation) -- +OldCsY # 4 ; | + ; | +GCsIX # 4 ; Graphics cursor (internal representation) | +GCsIY # 4 ; | + ; | +NewPtX # 4 ; Newest point (internal representation) | +NewPtY # 4 ; -- + +; End of together block + +TForeCol # 4 ; Text foreground colour +TBackCol # 4 ; Text background colour + +CursorX # 4 ; Text cursor X position ; these 3 must be in same order as ... +CursorY # 4 ; Text cursor Y position +CursorAddr # 4 ; Screen address of (output) cursor + +InputCursorX # 4 ; Input cursor X position ; ... these 3 +InputCursorY # 4 ; Input cursor Y position +InputCursorAddr # 4 ; Screen address of input cursor + +EORtoggle # 4 ; Toggle between gap and non-gap +RowsToDo # 4 ; in the CLS + +VduStatus # 4 ; Vdu2, Window, Shadow bits (others in CursorFlags) + +CBWS # 8 ; Clear block (VDU 23,8..) workspace +CBStart # 2 +CBEnd # 2 + +CursorDesiredState # 4 +CursorStartOffset # 4 +CursorEndOffset # 4 +CursorCounter # 4 +CursorSpeed # 4 +Reg10Copy # 4 + +CursorFill # 4 ; Word to EOR cursor ; MUST be immediately before CursorNbit + +CursorNbit # 4 ; Pointer to cursor code for current mode + +DisplayStart # 4 ; Start address of screen (for display) +DriverBankAddr # 4 ; Default start address for VDU drivers +DisplayBankAddr # 4 ; Default start address for display +DisplayNColour # 4 ; No. of colours -1 for displayed mode +DisplayModeFlags # 4 ; ModeFlags for displayed mode +DisplayModeNo # 4 ; ModeNo for displayed mode +DisplayScreenStart # 4 ; Where VDU outputs to when outputting to screen + +DisplayXWindLimit # 4 ; Used for pointer programming +DisplayYWindLimit # 4 +DisplayXEigFactor # 4 +DisplayYEigFactor # 4 +PointerXEigFactor # 4 + +Ecf1 # 8 ; The Ecf patterns +Ecf2 # 8 +Ecf3 # 8 +Ecf4 # 8 + +DotLineStyle # 8 ; Dot dash line pattern + +ModeNo # 4 ; Current mode number + +TFTint # 4 ; Text foreground tint (in bits 6,7) +TBTint # 4 ; Text background tint +GFTint # 4 ; Graphics foreground tint +GBTint # 4 ; Graphics background tint + +TotalScreenSize # 4 ; Amount configured for screen (in bytes) + +MaxMode # 4 ; Maximum mode number allowed (20 for now) + +VinitCopy # 4 ; Copy of Vinit for VDU 23;12 or 13 + +CursorFlags # 4 ; Silly Master cursor movement flags + +CursorStack # 4 ; Bit stack of nested cursor states (0 => on, 1 => off) + ; (bit 31 = TOS) + +ECFShift # 4 ; number of bits to rotate right ECF OR and EOR masks by +ECFYOffset # 4 ; vertical offset to ECF index + +WsVdu5 # 0 ; Vdu 5 workspace +WsScr # 4 +WsEcfPtr # 4 +; WsFontPtr # 4 ; not needed any more, kept in register +EndVerti # 4 +StartMask # 4 +EndMask # 4 +FontOffset # 4 +TempPlain # 16 ; only used for MODE 10 + +VIDCClockSpeed # 4 ; current VIDC clock speed in kHz + +CurrentMonitorType # 4 ; initialised from configured one + +KernelModeSelector # 4 ; pointer to block in system heap where + ; current mode selector is copied + +GraphicWs # 300 ; All graphics workspace is overlaid here +EndGraphicWs # 0 + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 + +GCharSizes # 0 +GCharSizeX # 4 ; width of VDU 5 chars in pixels +GCharSizeY # 4 ; height of VDU 5 chars in pixels + +GCharSpacing # 0 +GCharSpaceX # 4 ; horizontal spacing between VDU 5 chars in pixels +GCharSpaceY # 4 ; vertical ------------------""----------------- + +TCharSizes # 0 +TCharSizeX # 4 ; width of VDU 4 chars in pixels +TCharSizeY # 4 ; height of VDU 4 chars in pixels + +TCharSpacing # 0 +TCharSpaceX # 4 ; horizontal spacing between VDU 4 chars in pixels +TCharSpaceY # 4 ; vertical ------------------""----------------- + +HLineAddr # 4 ; address of exported HLine +GcolOraEorAddr # 4 ; address of FgEcfOraEor etc + +FirPalSetting # 4*28 ; First palette settings (not used on VIDC20) +FirPalAddr * FirPalSetting ; Address of block for first palette setting (only used on VIDC20) +SecPalSetting # 4*28 ; Second palette settings (not used on VIDC20) +SecPalAddr * SecPalSetting ; Address of block for second palette setting (only used on VIDC20) + +TextFgColour # 4 ; Fg/Bg colour stored as a colour number, computed on VDU 18 and re-poked! +TextBgColour # 4 ; + +; In this brave new world there is a pointer to the text expansion +; buffer used for VDU 4 / 5 text plotting. + +; This now lives in the system heap. + +TextExpandArea # 4 ; Pointer to Text expand area (in system heap) +TextExpandArea_Size * (8*1024) + +HSWRSoftCopy # 4 ; soft copy of h.sync width register (for DPMS) +VSWRSoftCopy # 4 ; soft copy of v.sync width register (for DPMS) + +ScreenBlankFlag # 1 ; 0 => unblanked, 1 => blanked +ScreenBlankDPMSState # 1 ; 0 => just blank video + ; 1 => blank to stand-by (hsync off) + ; 2 => blank to suspend (vsync off) + ; 3 => blank to off (H+V off) + [ AssemblingArthur + ! 0,"64 ":CC::STR:@ + ] + AlignSpace 64 + +FgEcfOraEor # 4*16 ; Interleaved zgora & zgeor +BgEcfOraEor # 4*16 ; Interleaved zgora & zgeor +BgEcfStore # 4*16 ; Interleaved zgora & zgeor to store background + +;Current state of pattern +LineDotCnt # 4 ; Count down to restarting pattern +LineDotPatLSW # 4 ; Current state of pattern LSWord +LineDotPatMSW # 4 ; " " " " MSWord + +DotLineLength # 4 ; Dot Pattern repeat length as given in *FX163,242,n + +BBCcompatibleECFs # 4 ; 0 => BBC compatible, 1 => native + +SpAreaStart # 4 ; Start of sprite area +SpChooseName # 16 ; No comment says Richard +SpChoosePtr # 4 + +PointerHeights # 4 ; 4 x 1 byte +PointerActiveXs # 4 ; 4 x 1 byte +PointerActiveYs # 4 ; 4 x 1 byte +PointerShapeNumber # 4 ; only bottom byte used +PointerX # 4 ; co-ordinates of pointer (not always = mouse) +PointerY # 4 + +VIDCControlCopy # 4 ; Soft copy of VIDC control register +VertAdjust # 4 ; offset to add to vertical VIDC registers + +TeletextOffset # 4 ; Offset to current teletext flash bank + +TeletextCount # 4 ; Number of vsyncs till next teletext flash + +WrchNbit # 4 ; Pointer to char code for current mode + +BeepBlock # 8 ; OSWORD block for VDU 7 + +ScreenMemoryClaimed # 1 ; NZ => memory has been claimed or is unusable + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 ; Align workspace to 16 bytes + +TTXDoubleCounts # 25 ; Number of double height chars on each line + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 ; Align workspace to 16 bytes + +RAMMaskTb # 32*4 ; Copy of MaskTb for this mode (up to 32 words) + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 ; Align workspace to 16 bytes + +VduOutputCurrentState # 0 ; values of R0-R3 to return from SwitchOutputToSprite + ; or Mask; next 4 must be in this order +SpriteMaskSelect # 4 ; value of R0 to be given to SWI OS_SpriteOp to set up + ; current state +VduSpriteArea # 4 ; Pointer to sprite area containing VDU output sprite + ; (0 if output is to screen) +VduSprite # 4 ; Pointer to VDU output sprite (0 if output to screen) + +VduSaveAreaPtr # 4 ; Pointer to save area for VDU variables + + + [ AssemblingArthur + ! 0,"16,12 ":CC::STR:@ + ] + AlignSpace 16, 12 ; Make ClipBoxCoords a valid immediate, + ; with ClipBoxEnable immediately before it +ClipBoxInfo # 0 +ClipBoxEnable # 4 ; 0 => clip box disabled, 1 => enabled + +ClipBoxCoords # 0 ; Internal coords of modified area of screen +ClipBoxLCol # 4 +ClipBoxBRow # 4 +ClipBoxRCol # 4 +ClipBoxTRow # 4 + +FgPattern # 4*8 ; foreground pattern as defined by OS_SetColour +BgPattern # 4*8 ; background pattern as defined by OS_SetColour + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 ; Align workspace to 16 bytes + +TextExpand # 4*1024 ; Tim's massive text expansion table for whizzy WRCH +; TextPlain is now always hard against the end of TextExpand for this mode + +TTXSoftFonts * TextExpand + 2*1024 ; Soft fonts in teletext mode + + [ AssemblingArthur + ! 0,"64 ":CC::STR:@ + ] + AlignSpace 64 ; Align workspace to 64 bytes + +; Teletext map and copy/move buffer are overlaid + +TTXMapSize * 41*25*4 ; (&1004 bytes) +LargeCommon # TTXMapSize ; the largest area +TTXMap * LargeCommon + +ScrLoaSpriteCB * LargeCommon ; (size = SpriteCBsize + MaxSpritePaletteSize) +ScrLoaBuffer * LargeCommon ; (size = one pixel row) +ScrSavCommon * LargeCommon ; (size = SpriteAreaCBsize + SpriteCBsize + ; + MaxSpritePaletteSize) + +FldQueueSize * ScratchSpaceSize +FldQueueStart * ScratchSpace + + [ AssemblingArthur + ! 0,"64 ":CC::STR:@ + ] + AlignSpace 64 ; Align workspace to 64 bytes + +Font # &700 ; 7 pages of (soft) font + +SaveAreaSize * 12*1024-@ + +VduSaveArea # SaveAreaSize ; save area for switching output to sprites + +VDWSSize # 0 + + ASSERT VDWSSize <= 12 * 1024 + +; ***************************************************************************** +; Space in the first 32K is allocated below +; ***************************************************************************** +; Real workspace definition + +; Basic kernel space - defined locations for external modules + + ^ &100 +IRQ1V # 4 ; &100 + +ESC_Status # 1 ; &104 +LatchBSoftCopy # 1 ; &105 +IOCControlSoftCopy # 1 ; &106 +CannotReset # 1 ; &107 + +IRQsema # 4 ; &108 +MetroGnome # 4 ; &10C +MemorySpeed # 4 ; &110 + +MEMC_CR_SoftCopy # 4 ; &114 +ResetIndirection # 4 ; &118 + +; Now all internal definitions + +; Up to here is initialized on reset + +; Next come handler variables + +MemLimit # 4 +UndHan # 4 +PAbHan # 4 +DAbHan # 4 +AdXHan # 4 + +ErrHan # 4 +ErrBuf # 4 +ErrHan_ws # 4 + +CallAd_ws # 4 ; smart Rs ordering: +CallAd # 4 ; can do LDMIA of r12, pc +CallBf # 4 + +BrkAd_ws # 4 +BrkAd # 4 +BrkBf # 4 + +EscHan_ws # 4 +EscHan # 4 + +EvtHan_ws # 4 +EvtHan # 4 + +; The next lot of workspace is in the space vacated by the small soft CAM map area +; (256 words) which is no longer adequate, so we can reuse it + +JordanWS # 0 +VInitSoftCopy # 4 ; soft copy of VInit so we can set L bit correctly +VEndSoftCopy # 4 ; soft copy of VEnd ------------""--------------- +DAList # 4 ; Pointer to first node on dynamic area list + + AlignSpace 16 ; skipped bit must start on 16-byte boundary + +SkippedTables # 0 +PhysRamTable # 0 ; 6 pairs of words (physaddr, size) indicating + ; RAM present in machine (NB normally you would need at most 5 + ; on IOMD machines, but the extra one is if a soft-loaded ROM image + ; causes a bank to split +VideoPhysAddr # 4 ; Address of video RAM (in the case of DRAM-only machines, +VideoSize # 4 ; this is actually a chunk out of DRAM) +DRAMPhysAddrA # 4 ; Next the DRAM - note that any banks with no memory +DRAMSizeA # 4 ; in them will be omitted from this table, so that +DRAMPhysAddrB # 4 ; eg DRAMPhysAddrA corresponds to the first bank with +DRAMSizeB # 4 ; DRAM in it, not necessarily bank 0 +DRAMPhysAddrC # 4 ; If not all the slots are occupied, then +DRAMSizeC # 4 ; the remaining entries in this table have size fields +DRAMPhysAddrD # 4 ; of zero (and probably addresses of zero too) +DRAMSizeD # 4 +DRAMPhysAddrE # 4 +DRAMSizeE # 4 +PhysRamTableEnd # 0 + +VRAMSize # 4 ; Amount of VRAM (in bytes) (may be more than 2M) +VRAMWidth # 4 ; 0 => no VRAM, 1 => 32-bits wide, 2 => 64-bits wide +VideoBandwidth # 4 ; video bandwidth in bytes/sec +L2PTSize # 4 ; Amount of memory (in bytes) used for static L2PT + ; - this consists of fixed size first bit, plus variable size + ; bit for the free pool L2, which follows directly after it +SoftCamMapSize # 4 ; Amount of memory (in bytes) used for soft CAM map + ; (whole number of pages) +InitKbdWs # 12 ; Workspace for reset keyboard IRQ code + + AlignSpace 16 ; skipped bit must end on 16-byte boundary +SkippedTablesEnd # 0 + +CMOSRAMCache # 240 ; Cache for CMOS RAM +AppSpaceDANode # DANode_NodeSize ; Dummy area node for application space (not on list) +FreePoolDANode # DANode_NodeSize ; Area node for free pool +SysHeapDANode # DANode_NodeSize ; Area node for system heap +CDASemaphore # 4 ; Semaphore for OS_ChangeDynamicArea - non-zero => routine threaded +MMUControlSoftCopy # 4 ; Soft copy of ARM600/700 control register + +AplWorkSize * AppSpaceDANode + DANode_Size + +ProcVec_Start # 0 ; Start of processor vector table +ProcVec_Branch0 # 4 ; Branch through zero +ProcVec_UndInst # 4 ; Undefined instruction vector +ProcVec_SWI # 4 ; SWI vector +ProcVec_PrefAb # 4 ; Prefetch abort vector +ProcVec_DataAb # 4 ; Data abort vector +ProcVec_AddrEx # 4 ; Address exception vector (not useful on ARM600/700) +ProcVec_IRQ # 4 ; IRQ vector +ProcVec_End # 0 + +ProcVecPreVeneersSize * 4*4 ; Space for preveneers for loading handler addresses from 0 page. +ProcVecPreVeneers # ProcVecPreVeneersSize + + ASSERT @ <= &500 ; a convenient address to remember + # (&500-@) + +CamMapCorruptDebugBlock # &40 ; somewhere to dump registers in case of emergency + + ASSERT @ <= JordanWS+256*4 + # (JordanWS+256*4-@) ; pad out to original size + +CamEntriesPointer # 4 ; points to where CAM soft copy is + ; (CamEntries for machines up to 8MBytes, + ; CamEntriesForBigMachines for larger machines) + +MaxCamEntry # 4 ; maximum index into the cam map, ie + ; 511 for 16MByte machines, 383 for 12MBytes + ; 255 for 8MBytes, otherwise 127 + +RAMLIMIT # 4 + + # 4 ; dummy slot where AplWorkSize used to be + +HiServ_ws # 4 +HiServ # 4 +SExitA # 4 +SExitA_ws # 4 +UpCallHan_ws # 4 +UpCallHan # 4 + +ROMModuleChain # 4 ; pointer to head of ROM module chain + +; now a section that it's handy to have in simply loadable places + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 + +KeyWorkSpaceSize * &200 +KeyWorkSpace # KeyWorkSpaceSize + +; The following were reordered on 26-Jul-91. Old ordering was: +; GeneralMOSBuffer +; ModuleSWI_HashTab +; Module_List +; Curr_Active_Object +; VecPtrTab +; ExceptionDump + +ModuleSHT_Entries * 16 +ModuleSWI_HashTab # 4*ModuleSHT_Entries + +Module_List # 4 +Curr_Active_Object # 4 + +; Vector Claim & Release tables etc + +VecPtrTab # NVECTORS * 4 + +ExceptionDump # 4 + +; GeneralMOSBuffer: re-use with caution! +; Here's just some of the users: +; user use(s) +; default error handler error buffer (must be 246+4 bytes big) +; *If expression to be evaluated to control the *If +; Command line to be submited on the expression +; evaluating to non-zero (the THEN clause). +GeneralMOSBuffer # 256+4 + + [ AssemblingArthur + ! 0,"16 ":CC::STR:@ + ] + AlignSpace 16 ; Ensures we can MOV rn, #OsbyteVars if <=&1000 + +OsbyteVars # OSBYTEVarSize + ASSERT OsbyteVars < &10000 ; Must keep in first 64K so address can be read by + ; (and stored in) OS_Bytes &A6,&A7. SKS + +; These must be in first 4K +NBuffers * 10 +BuffInPtrs # 4 * NBuffers +BuffOutPtrs # 4 * NBuffers + +VariableList # 4 + +; Oscli stuff +OscliCBtopUID # 4 +OscliCBbotUID # 4 +OscliCBcurrend # 4 + +ReturnCode # 4 +RCLimit # 4 + +SpriteSize # 4 ; saved on startup for Sprite code and RAMFS +RAMDiscSize # 4 +FontCacheSize # 4 ; and font manager + +TickNodeChain # 4 + +; Workspace + +EnvTime # 5 +RedirectInHandle # 1 +RedirectOutHandle # 1 +MOShasFIQ # 1 +FIQclaim_interlock # 1 +CallBack_Flag # 1 +IRQ_CallBack_Flag * CallBack_Flag +IOSystemType # 1 ; 0 => old I/O subsystem, 1 => IOEB+82C710 system, 2..255 => ? +MonitorLeadType # 1 ; some function of the monitor lead inputs, as yet undetermined + + AlignSpace + +EnvString # 256 + + +DUMPER # 16 * 4 + +; more system workspace +Page_Size # 4 +PIRQ_Chain # 4 +PFIQasIRQ_Chain # 4 + +; !!!! Free space (752 bytes) left by old IRQ despatch (new IRQ despatch +; !!!! moved as it required more space). +OldIRQ1Vspace # 752 + + +CallBack_Vector # 4 + +; interruptible heap manager workspace + +HeapSavedReg_R0 # 4 +HeapSavedReg_R1 # 4 +HeapSavedReg_R2 # 4 +HeapSavedReg_R3 # 4 +HeapSavedReg_R4 # 4 +HeapSavedReg_R13 # 4 +HeapReturnedReg_R0 # 4 +HeapReturnedReg_R1 # 4 +HeapReturnedReg_R2 # 4 +HeapReturnedReg_R3 # 4 +HeapReturnedReg_R4 # 4 +HeapReturnedReg_R13 # 4 +HeapReturnedReg_PC # 4 ; also acts as interlock + +PrinterBufferAddr # 4 ; holds address of printer buffer +PrinterBufferSize # 4 ; size of printer buffer - not to be confused with PrintBuffSize + ; which is the (constant) default size for the MOS's smallish buffer +RawMachineID # 8 ; 64 bits for unique machine ID +KernelMessagesBlock # 20 ; 5 Words for messagetrans message block. +ErrorSemaphore # 1 ; Error semaphore to avoid looping on error translation. +PortableFlag # 1 ; Non-zero => got an error from Portable_Speed, so don't try it again + + AlignSpace + +MOSConvertBuffer # 12 ; Enough romm for 8 hex digits. +AbortIndirection # 4 ; Pointer to list of addresses and trap routines +PreVeneerRegDump # 17*4 ; room for r0-r15, spsr + + [ AssemblingArthur + ! 0, "low space free ":CC::STR:(&FEC-@) + ] + ASSERT @ < &FEC + +; Words for old tools of assorted varieties + ^ &FEC +; ECN 17-Feb-92 +; Added RISCOSLibWord and CLibWord. The ROM RISCOSLib and CLib must continue +; to work even when they are killed since ROM apps are hard linked to the +; ROM libraries. They cannot use the private word since the block pointed +; to by this will be freed. +RISCOSLibWord # 4 +CLibWord # 4 +FPEAnchor # 4 +DomainId # 4 ; SKS added for domain identification +Modula2_Private # 4 ; MICK has FFC and uses it it in USR mode + +VduDriverWorkSpace # VDWSSize + ASSERT (VduDriverWorkSpace :AND: 63) = 0 ; For Tim (VDU5) + + + [ AssemblingArthur + ! 0, "high space free ":CC::STR:(&4000-@) + ] + + ^ &4000 +ScratchSpaceSize * &4000 +ScratchSpace # ScratchSpaceSize + + ASSERT @ <= &8000 ; Start of apl + +; ***************************************************************************** +; Users of ScratchSpace declare yourself here: + +; NRaine: Filling a polygon uses ScratchSpace to flatten the path + +; DSeal: Draw module uses ScratchSpace on fill operations (this supercedes +; NRaine's declaration above). + +; SKS: HeapSort with (r1 & 0x80000000) & ~(r1 & 0x20000000) & (r5 <= 16K) +; uses ScratchSpace as a temp slot for data shuffling after sorting + +; TMD: Flood fill uses ScratchSpace for the flood queue. + +; Tidying the RMA uses ScratchSpace while all modules are dead + +; GSTRANS workspace: GSINIT puts state into the workspacem and GSREAD uses it. +; DO NOT do any operations between GSINIT/GSREAD SWIS. +; SWIs called: OSWord in time var code +; BinaryToDecimal, ReadUnsigned + +; LVR: ADFS uses scratch space to format floppies on 1772 based machines + +; DDV: ColourTrans uses scratch space to build palette tables when in +; ColourTrans_SelecTable/RetrunColourNumber and also whilst generating +; stipple pattterns. + +GSVarWSpace * ScratchSpace + + ^ 0 +GSNameBuff # &100 +GS_Stack # &200 +GS_StackPtr_Lim * &200 / 4 ; Number of words in stack. +GS_StackPtr # 4 + + ^ @ + ScratchSpace + +; Pointers for SubstituteArgs: no external calls. +; Ensure these don't overlap FileSwitch's buffers below! + +MacExStartPtrs # 44 +MacExEndPtrs # 44 + +; OS_CLI has a buffer for alias expansion: ReadVarVal and SubstituteArgs +; are called while the buffer is held. Also used for module prefixes: +; Module called twice in this case. + +AliasExpansionBuffer # 100 + +; *list/*type need an argument expansion buffer: ReadArgs called with it. + +ArgumentBuffer * AliasExpansionBuffer + +; EvaluateExpression space. Calls ReadUnsigned, BinaryToDecimal and ReadVarVal. + +ExprWSpace * @ + + ^ 0, R12 +ExprBuff # &100 +exprBracDif # 2 ; keep exprSTRACC aligned +tos_op # 2 ; 1 byte for use as STRACC-1 +ExprSVCstack # 4 +exprSTRACC * @ - ExprBuff + ExprWSpace + +ExprStackLimit * exprSTRACC + &100 +ExprStackStart * ScratchSpace + ScratchSpaceSize + + +; Tutu needs some for argument substitution + expansion for run/load types +; Only OS call during xform is XOS_SubstituteArgs and XOS_Heap(Claim,SysHeap) + + ^ 0 ; Offset from ScratchSpace +rav_substituted # 256 +rav_arglist # 256 + +TopOfPageZero # 0 + + ^ &8000 ; The actual top of Page Zero +EconetDebugSpace |#| &20 * 4 ; Thirty two words (&7F80) + + ASSERT @ > TopOfPageZero ; Make sure we don't clash + +; ***************************************************************************** +; *** Cursor, Sound DMA, SWI, and OSCLI workspace. *** +; *** Sits in the 32K above 31M, ie. &01F000000..&01F07FFF *** +; *** Has the physical address &02078000, ie. 32M + 512K - 32K *** +; ***************************************************************************** + +TopOfDMAPhysRAM * &80000 ; OFFSET in physram +TopOfDMAWorkSpace * CursorChunkAddress + 32*1024 +OffsetLogicalToPhysical * TopOfDMAPhysRAM - TopOfDMAWorkSpace + + ^ TopOfDMAWorkSpace ; Note we will be going down + +; Sound + +SoundWorkSpaceSize * &1000 +SoundDMABufferSize * &1000 +SoundEvtSize * &1000 +SoundDMABuffers |#| SoundDMABufferSize * 2 +SoundWorkSpace |#| SoundWorkSpaceSize + SoundEvtSize + +; Cursor + +CursorDataSize * &800 +CursorData |#| CursorDataSize +CursorSoundRAM * CursorData +CursorSoundPhysRAM * CursorSoundRAM + OffsetLogicalToPhysical + +; SWI despatcher + +BranchToSWIExit |#| 4 +SvcTable |#| &400 + ASSERT SvcTable = &01F033FC ; Required for SVC table pokers, 1.20 compatible +SWIDespatch_Size * 29*4 +SWIDespatch |#| SWIDespatch_Size + + +; Buffers + +KeyBuffSize * &100 +RS423InBuffSize * &100 +RS423OutBuffSize * &C0 +PrintBuffSize * &400 +Sound0BuffSize * 4 +Sound1BuffSize * 4 +Sound2BuffSize * 4 +Sound3BuffSize * 4 +SpeechBuffSize * 4 +MouseBuffSize * &40 +KeyBuff |#| KeyBuffSize +RS423InBuff |#| RS423InBuffSize +RS423OutBuff |#| RS423OutBuffSize +PrintBuff |#| PrintBuffSize +Sound0Buff |#| Sound0BuffSize +Sound1Buff |#| Sound1BuffSize +Sound2Buff |#| Sound2BuffSize +Sound3Buff |#| Sound3BuffSize +SpeechBuff |#| SpeechBuffSize +MouseBuff |#| MouseBuffSize + +; Oscli buffering + +OscliBuffSize * &100 +OscliNoBuffs * 16 +OscliCircBuffLimit |#| 0 +OscliCircBuffStart |#| OscliBuffSize * OscliNoBuffs +RedirectBuff |#| OscliBuffSize + +; Default IRQ despatch moved here as a result of IOMD having an extra +; 6 interrupts for I/O and sound DMA (this is really IOMD specific, not +; ARM600/700 specific but for the moment it is assumed that they are +; used on the same machines). +DefIRQ1Vspace * 12*4+12*23+2*256+64 ; for size checking in MOS +DefaultIRQ1V |#| DefIRQ1Vspace + + [ AssemblingArthur + ! 0, "Aligning IRQ stack from ":CC::STR:@ + ] + [ @-7*4 :AND: 15 <> 0 + |#| (@-7*4):AND:15 + ] +IRQSTK # 0 ; Overflow will give abort + [ AssemblingArthur + ! 0, "IRQ stack size ":CC::STR:(IRQSTK-CursorChunkAddress) + ] + + ASSERT @ > ( CursorChunkAddress + &1000 ) ; Check minimum stack + +; ***************************************************************************** +; High system workspace +; ***************************************************************************** + + ^ SysHeapChunkAddress + + # 8*1024 ; svcstk size. Overflow will give abort +SVCSTK # 0 +SysHeapStart # 0 + + + OPT OldOpt + END diff --git a/hdr/PublicWS b/hdr/PublicWS new file mode 100644 index 0000000000000000000000000000000000000000..de7f3c3d2534208c743857f9fe2f1e7395b171ab --- /dev/null +++ b/hdr/PublicWS @@ -0,0 +1,98 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + SUBT > Public Work Space + +OldOpt SETA {OPT} + OPT OptNoList+OptNoP1List + +; *********************************** +; *** C h a n g e L i s t *** +; *********************************** + +; Date Name Description +; ---- ---- ----------- +; 15-Jun-94 AMcC Created - holds values 'exported' from KernelWS +; Corresponds to Values previously set in VickySpace / NewSpace +; 03-Nov-94 AMcC Added ScreenBlankFlag and ScreenBlankDPMSState +; +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Memory map values: (in address order) + + ^ &00000104 +ESC_Status # 1 + + ^ &00000105 +LatchBSoftCopy # 1 + + ^ &00000107 +CannotReset # 1 + + ^ &00000108 +IRQsema # 4 + + ^ &00000114 +MEMC_CR_SoftCopy # 4 + + ^ &0000047C +ScreenBlankFlag # 1 ; 0 => unblanked, 1 => blanked + + ^ &0000047D +ScreenBlankDPMSState # 1 ; 0 => just blank video + ; 1 => blank to stand-by (hsync off) + ; 2 => blank to suspend (vsync off) + ; 3 => blank to off (H+V off) + ^ &00000480 +FgEcfOraEor # 4*16 ; Interleaved zgora & zgeor (from Vdu Driver Workspace) + + ^ &000004C0 +BgEcfOraEor # 4*16 ; Interleaved zgora & zgeor (from Vdu Driver Workspace) + + ^ &00000AE1 ; RedirectInHandle +RedirectInHandle # 1 + + ^ &00000AE2 ; RedirectOutHandle +RedirectOutHandle # 1 + + ^ &00000FF8 +DomainId # 4 ; domain identification + + ^ &00001000 +VduDriverWorkSpace # &3000 + + ^ &00004000 +ScratchSpace # &4000 + + ^ &01C02000 +SVCSTK # 0 + + ^ &01C02000 +SysHeapStart # 0 + + ^ &01F033FC +SvcTable # &400 + + ^ &01F037FC +BranchToSWIExit # 4 ; from SWI despatcher + + ^ &01F04000 +SoundWorkSpace # &2000 + +SoundDMABufferSize * &1000 + + ^ &01F06000 +SoundDMABuffers # SoundDMABufferSize * 2 + + OPT OldOpt + END diff --git a/hdr/Variables b/hdr/Variables new file mode 100644 index 0000000000000000000000000000000000000000..697ce82b5cbeb9436c8ea64c328d8d3263e390af --- /dev/null +++ b/hdr/Variables @@ -0,0 +1,27 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Hdr.Variables +; define variable types, as got by SWI ReadVarVal, etc. + +VarType_String * 0 +VarType_Number * 1 +VarType_Macro * 2 +VarType_Expanded * 3 ; given to Read, this always returns a string + ; given to Set, this means evaluate an expression +VarType_LiteralString * 4 ; Only valid for Set - sets the string as is (no + ; GSTrans) +VarType_Code * 16 + + END diff --git a/hdr/VduExt b/hdr/VduExt new file mode 100644 index 0000000000000000000000000000000000000000..793eb48dddd4abe741cb85c5ba09b7d83f8b2870 --- /dev/null +++ b/hdr/VduExt @@ -0,0 +1,123 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + SUBT VDU variable numbers => &.Hdr.VduExt + +OldOpt SETA {OPT} + OPT OptNoList+OptNoP1List + +; ************************************************************ +; *** C h a n g e L i s t (better late than never!) *** +; ************************************************************ + +; Date Name Description +; ---- ---- ----------- +; 27-Oct-89 TMD Added VIDCClockSpeed +; 05-Aug-91 DDV Added Flag_FullPalette +; 15-Jul-93 TMD Added NumModeVars + +; Sets up external symbols of the form VduExt_<var name> +; for use with SWI OS_ReadVDUVariables + + MACRO + NotRVVTBarWobblyBits $var, $base + [ "$base"<>"" +NotRVVTBarWobblyBitscounter SETA $base + ] +VduExt_$var * NotRVVTBarWobblyBitscounter +NotRVVTBarWobblyBitscounter SETA NotRVVTBarWobblyBitscounter +1 + MEND + + GBLA NotRVVTBarWobblyBitscounter +NotRVVTBarWobblyBitscounter SETA 0 + + NotRVVTBarWobblyBits ModeFlags, 0 + NotRVVTBarWobblyBits ScrRCol + NotRVVTBarWobblyBits ScrBRow + NotRVVTBarWobblyBits NColour + NotRVVTBarWobblyBits XEigFactor + NotRVVTBarWobblyBits YEigFactor + NotRVVTBarWobblyBits LineLength + NotRVVTBarWobblyBits ScreenSize + NotRVVTBarWobblyBits YShftFactor + NotRVVTBarWobblyBits Log2BPP + NotRVVTBarWobblyBits Log2BPC + NotRVVTBarWobblyBits XWindLimit + NotRVVTBarWobblyBits YWindLimit + +NumModeVars * NotRVVTBarWobblyBitscounter + + NotRVVTBarWobblyBits GWLCol, &80 + NotRVVTBarWobblyBits GWBRow + NotRVVTBarWobblyBits GWRCol + NotRVVTBarWobblyBits GWTRow + NotRVVTBarWobblyBits TWLCol + NotRVVTBarWobblyBits TWBRow + NotRVVTBarWobblyBits TWRCol + NotRVVTBarWobblyBits TWTRow + NotRVVTBarWobblyBits OrgX + NotRVVTBarWobblyBits OrgY + NotRVVTBarWobblyBits GCsX + NotRVVTBarWobblyBits GCsY + NotRVVTBarWobblyBits OlderCsX + NotRVVTBarWobblyBits OlderCsY + NotRVVTBarWobblyBits OldCsX + NotRVVTBarWobblyBits OldCsY + NotRVVTBarWobblyBits GCsIX + NotRVVTBarWobblyBits GCsIY + NotRVVTBarWobblyBits NewPtX + NotRVVTBarWobblyBits NewPtY + NotRVVTBarWobblyBits ScreenStart + NotRVVTBarWobblyBits DisplayStart + NotRVVTBarWobblyBits TotalScreenSize + NotRVVTBarWobblyBits GPLFMD + NotRVVTBarWobblyBits GPLBMD + NotRVVTBarWobblyBits GFCOL + NotRVVTBarWobblyBits GBCOL + NotRVVTBarWobblyBits TForeCol + NotRVVTBarWobblyBits TBackCol + NotRVVTBarWobblyBits GFTint + NotRVVTBarWobblyBits GBTint + NotRVVTBarWobblyBits TFTint + NotRVVTBarWobblyBits TBTint + NotRVVTBarWobblyBits MaxMode + NotRVVTBarWobblyBits GCharSizeX + NotRVVTBarWobblyBits GCharSizeY + NotRVVTBarWobblyBits GCharSpaceX + NotRVVTBarWobblyBits GCharSpaceY + NotRVVTBarWobblyBits HLineAddr + NotRVVTBarWobblyBits TCharSizeX + NotRVVTBarWobblyBits TCharSizeY + NotRVVTBarWobblyBits TCharSpaceX + NotRVVTBarWobblyBits TCharSpaceY + NotRVVTBarWobblyBits GcolOraEorAddr + NotRVVTBarWobblyBits VIDCClockSpeed + + NotRVVTBarWobblyBits WindowWidth, &100 + NotRVVTBarWobblyBits WindowHeight + +; Bits in ModeFlags + +Flag_NonGraphic * 1 +Flag_Teletext * 2 +Flag_GapMode * 4 +Flag_BBCGapMode * 8 +Flag_HiResMono * 16 +Flag_DoubleVertical * 32 +Flag_HardScrollDisabled * 64 ; set when outputting to a sprite +Flag_FullPalette * 128 ; set when palette is not brain damaged + + OPT OldOpt + + END diff --git a/s/ARM600 b/s/ARM600 new file mode 100644 index 0000000000000000000000000000000000000000..255fec8d6bcadda5993d703322d6fee109d0cb84 --- /dev/null +++ b/s/ARM600 @@ -0,0 +1,2646 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > ARM600 + + GBLL DebugAborts +DebugAborts SETL {FALSE} + + [ Simulator + ! 0, "**** Warning - IOMD Simulator debugging included - will crash on real thing! ****" + ] + +; MMU interface file - ARM600 version + +; Created by TMD 15-Jul-92 +; Comments updated by TMD 04-Aug-93 + +; Workspace needed for ARM600 work is as follows: +; +; * Level 2 page tables for a contiguous logical area starting at zero +; This consists of: +; a) a fixed size bit covering 0 to 192M (currently) +; b) a variable size bit covering the free pool - 192M to 192M + (memsize rounded up to 4M) +; Note that the 192M value is sufficient to cover all the fixed size areas at present. +; As more areas switch to new world, this limit will come down and down, but free pool must always +; start at the end of the fixed areas. +; (Level 2 for areas outside this region are allocated dynamically afterwards) +; +; * Level 1 page table (16K, stored in the middle of L2PT, where the I/O + ROM would be if it wasn't section mapped) +; +; * Undefined32 mode stack (8K) +; +; * Soft CAM map (variable size = memsize/4K*8, rounded up to 4K) +; +; In order to make the memory models for MEMC1 and IOMD harmonious, the MEMC1 system is considered as a section of +; video RAM starting at &02000000 size 480K, and an area of "non-video RAM" starting at &02078000, size (totalRAM-480K) +; IOMD has 1 area of video RAM and up to 4 areas of non-video RAM. +; +; (Note: when OS is soft-loaded, a 2 Mbyte chunk of DRAM is removed from the RAM map, therefore the model allows for +; 1 area of video RAM and up to 5 areas of non-video RAM) +; +; The fixed system pages (which include those described above) start at the base of the first bank of non-video RAM +; (on IOMD we allow this to be in any of the 4 RAM sites, ie you don't have to have RAM in any particular SIMM site) +; Consequently the base of the fixed system pages is not known at assembly time, so has to be passed in a register +; to the generic code. + +; Fixed page allocation is as follows + + ^ 0 +DRAMOffset_CursorChunk # 32*1024 ; ie on MEMC1 this is the last 32K of DAG-addressable memory +DRAMOffset_PageZero # 32*1024 ; 32K at location zero +DRAMOffset_SystemHeap # 32*1024 ; system heap/svc stack +DRAMOffset_L2PT # 0 ; static L2PT (variable size, with embedded L1PT) +DRAMOffset_L1PT * DRAMOffset_L2PT + 48*1024 + +; Undefined stack memory (size 8K) starts immediately after end of L2PT (which is variable size) +; Soft CAM map (variable size) starts immediately after end of UndStack + +StaticPagesSize * @ + +; Logical addresses are as follows + +L2PT * &02C00000 ; size 256K +L1PT * &02C0C000 ; in the middle of L2PT, where the mapping for 03000000 to 03FFFFFF would be + +FixedAreasL2Size * 96*1024 ; amount of L2 to cover fixed areas, excluding free pool + +UndStackSoftCamChunk * &01E00000 +UndStackSize * 8*1024 +CamEntriesForVicky * UndStackSoftCamChunk + &2000 +UNDSTK * CamEntriesForVicky ; points to end of stack +PhysSpace * &80000000 ; Map of MEMC/IOMD physical space (64M/512M in size) + + [ LateAborts +DefaultMMUControlRegister * MMUC_M + MMUC_C + MMUC_W + MMUC_P + MMUC_D + MMUC_L + MMUC_F + | +DefaultMMUControlRegister * MMUC_M + MMUC_C + MMUC_W + MMUC_P + MMUC_D + MMUC_F + ] + +OneMByte EQU (1024*1024) +SixteenMByte EQU (1024*1024 * 16) + + [ MEMC_Type = "IOMD" +; ***************************************************************************** +; +; SetDAG - Program DMA address generator R1 with physical address R0 +; NB on IOMD this is the true physical address, not just offset into VRAM or DRAM +; +; in: r0 = physical address +; r1 = index of DMA address generator to program, as defined in vdudecl +; +; out: All registers preserved, operation ignored if illegal +; + +SetDAG ENTRY "r0,r12" + MOV r12, #IOMD_Base + CMP r1, #1 + BEQ %FT10 + BHI %FT20 + +; Program VInit + +00 + ASSERT MEMCDAG_VInit = 0 + MOV r14, #0 + STR r0, [r14, #VInitSoftCopy] ; save VInit so that writes to VEnd can check + LDR r14, [r14, #VEndSoftCopy] + CMP r0, r14 ; if VInit >= VEnd then set L bit + ORRCS r0, r0, #IOMD_DMA_L_Bit + STR r0, [r12, #IOMD_VIDINIT] + EXIT + +; Program VStart + +10 + ASSERT MEMCDAG_VStart = 1 + STR r0, [r12, #IOMD_VIDSTART] + EXIT + +20 + CMP r1, #3 + EXIT HI + BEQ %FT30 + +; Program VEnd + + ASSERT MEMCDAG_VEnd = 2 + MOV r14, #0 + STR r0, [r14, #VEndSoftCopy] ; remember old VEnd value + LDR r14, [r14, #VInitSoftCopy] ; load old VInit + CMP r14, r0 ; if VInit >= VEnd + ORRCS r14, r14, #IOMD_DMA_L_Bit ; then set L bit + STR r14, [r12, #IOMD_VIDINIT] ; store VInit + STR r0, [r12, #IOMD_VIDEND] ; and VEnd + EXIT + +; Program CInit + +30 + ASSERT MEMCDAG_CInit = 3 + STR r0, [r12, #IOMD_CURSINIT] + EXIT + + | + +; DMA address generators - still controlled by MEMC1 currently + +VInit * &03600000 +VStart * &03620000 +VEnd * &03640000 +CInit * &03660000 + +; ***************************************************************************** +; +; SetDAG - Program DMA address generator R1 with physical address R0 +; +; in: r0 = physical address offset from 32M +; r1 = index of DMA address generator to program, as defined in vdudecl +; +; out: All registers preserved, operation ignored if illegal +; + +SetDAG ENTRY "r0" + CMP r1, #MEMCDAG_MaxReason + EXIT HI + ADR r14, DAGAddressTable + LDR r14, [r14, r1, LSL #2] ; load base address in MEMC1 + MOV r0, r0, LSR #4 ; bottom 4 bits irrelevant + CMP r0, #(1 :SHL: 15) ; ensure in range + ORRCC r14, r14, r0, LSL #2 + STRCC r14, [r14] ; any old data will do + EXIT + + GBLA DAGIndex +DAGIndex SETA 0 + + MACRO + DAGTab $reason, $address + ASSERT ($reason)=DAGIndex + & $address +DAGIndex SETA DAGIndex + 1 + MEND + +DAGAddressTable + DAGTab MEMCDAG_VInit, VInit + DAGTab MEMCDAG_VStart, VStart + DAGTab MEMCDAG_VEnd, VEnd + DAGTab MEMCDAG_CInit, CInit + ] + + +; **************** CAM manipulation utility routines *********************************** + +; ************************************************************************************** +; +; BangCamUpdate - Update CAM entry and soft copy +; +; This part of the routine has to do more work on ARM600 +; +; First look in the CamEntries table to find the logical address L this physical page is +; currently allocated to. Then check in the Level 2 page tables to see if page L is currently +; at page R2. If it is, then map page L to be inaccessible, otherwise leave page L alone. +; Then map logical page R3 to physical page R2. +; +; in: r2 = physical page number +; r3 = logical address (2nd copy if doubly mapped area) +; r9 = offset from 1st to 2nd copy of doubly mapped area (either source or dest, but not both) +; r11 = PPL + CB bits +; +; out: r0, r1, r4, r6 corrupted +; r2, r3, r5, r7-r12 preserved +; +; NB Use of stack is allowed in this routine + +BangCamUpdate ROUT + TST r11, #DynAreaFlags_DoublyMapped ; if moving page to doubly mapped area + SUBNE r3, r3, r9 ; then CAM soft copy holds ptr to 1st copy + + MOV r1, #0 + LDR r1, [r1, #CamEntriesPointer] + ADD r1, r1, r2, LSL #3 ; point at cam entry (logaddr, PPL) + LDMIA r1, {r0, r6} ; r0 = current logaddress, r6 = current PPL + STMIA r1, {r3, r11} ; store new address, PPL + Push "r0, r6" ; save old logical address, PPL + MOV r1, #PhysRamTable ; go through phys RAM table + MOV r6, r2 ; make copy of r2 (since that must be preserved) +10 + LDMIA r1!, {r0, r4} ; load next address, size + SUBS r6, r6, r4, LSR #12 ; subtract off that many pages + BCS %BT10 ; if more than that, go onto next bank + + ADD r6, r6, r4, LSR #12 ; put back the ones which were too many + ADD r0, r0, r6, LSL #12 ; move on address by the number of pages left + LDMFD r13, {r6} ; reload old logical address + +; now we have r6 = old logical address, r2 = physical page number, r0 = physical address + + TEQ r6, r3 ; TMD 19-Jan-94: if old logaddr = new logaddr, then + BEQ %FT20 ; don't remove page from where it is, to avoid window + ; where page is nowhere. + LDR r1, =L2PT + ADD r6, r1, r6, LSR #10 ; r6 -> L2PT entry for old log.addr + MOV r4, r6, LSR #12 ; r4 = word offset into L2 for address r6 + LDR r4, [r1, r4, LSL #2] ; r4 = L2PT entry for L2PT entry for old log.addr + TST r4, #3 ; if page not there + BEQ %FT20 ; then no point in trying to remove it + + LDR r4, [r6] ; r4 = L2PT entry for old log.addr + MOV r4, r4, LSR #12 ; r4 = physical address for old log.addr + TEQ r4, r0, LSR #12 ; if equal to physical address of page being moved + BNE %FT20 ; if not there, then just put in new page + + Push "r0, r3, r11, r14" ; save phys.addr, new log.addr, new PPL, lr + ADD r3, sp, #4*4 + LDMIA r3, {r3, r11} ; reload old logical address, old PPL + MOV r0, #0 ; cause translation fault + BL BangL2PT ; map page out + Pull "r0, r3, r11, r14" +20 + ADD sp, sp, #8 ; junk old logical address, PPL + B BangCamAltEntry ; and branch into BangCam code + +; ************************************************************************************** +; +; BangCam - Update CAM entry, but not soft copy +; +; This routine maps a physical page to a given logical address +; For ARM600, I assume that the physical page was previously not mapped +; anywhere else - on MEMC1 it would automatically unmap any logical +; address that the physical page was previously at, but on ARM600 it won't +; +; in: r2 = physical page number +; r3 = logical address (2nd copy if doubly mapped) +; r9 = offset from 1st to 2nd copy of doubly mapped area (either source or dest, but not both) +; r11 = PPL +; +; out: r0, r1, r4, r6 corrupted +; r2, r3, r5, r7-r12 preserved +; +; NB Can't use stack - there might not be one! +; +; NB Also - the physical page number MUST be in range. + +; This routine must work in 32-bit mode + + GBLL UsePPLCBBits +UsePPLCBBits SETL {TRUE} + +BangCam ROUT + TST r11, #DynAreaFlags_DoublyMapped ; if area doubly mapped + SUBNE r3, r3, r9 ; then move ptr to 1st copy + + MOV r1, #PhysRamTable ; go through phys RAM table + MOV r6, r2 ; make copy of r2 (since that must be preserved) +10 + LDMIA r1!, {r0, r4} ; load next address, size + SUBS r6, r6, r4, LSR #12 ; subtract off that many pages + BCS %BT10 ; if more than that, go onto next bank + + ADD r6, r6, r4, LSR #12 ; put back the ones which were too many + ADD r0, r0, r6, LSL #12 ; move on address by the number of pages left +BangCamAltEntry + ADR r1, PPLTrans + AND r4, r11, #3 ; first use PPL bits + LDR r1, [r1, r4, LSL #2] ; get PPL bits and SmallPage indicator + [ UsePPLCBBits + TST r11, #DynAreaFlags_NotCacheable + TSTEQ r11, #PageFlags_TempUncacheableBits + ORREQ r1, r1, #L2_C ; if cacheable (area bit CLEAR + temp count zero), then OR in C bit + TST r11, #DynAreaFlags_NotBufferable + ORREQ r1, r1, #L2_B ; if bufferable (area bit CLEAR), then OR in B bit + ] + ORR r0, r0, r1 + + LDR r1, =L2PT ; point to level 2 page tables + +BangL2PT ; internal entry point used only by BangCamUpdate + BICS r4, r3, #(3 :SHL: 10) ; ensure going to be on word boundary + [ {FALSE} ; this breaks too many things at the moment + BICEQ r0, r0, #&30 ; if logical page zero, then make 1st 1K no user access + ORREQ r0, r0, #&10 + ] + [ :LNOT: UsePPLCBBits + LDR r6, [r1, r4, LSR #10] ; read current contents + AND r6, r6, #L2_C :OR: L2_B ; preserve old CB bits (set up by soft loader) + ORR r0, r0, r6 ; but OR in new address and PPL bits + ] + STR r0, [r1, r4, LSR #10]! ; update level 2 page table (and update pointer so we can use bank-to-bank offset + TST r11, #DynAreaFlags_DoublyMapped ; if area doubly mapped + STRNE r0, [r1, r9, LSR #10] ; then store entry for 2nd copy as well + ADDNE r3, r3, r9 ; and point logical address back at 2nd copy + + SetCop r0, CR_IDCFlush ; flush cache + SetCop r0, CR_TLBFlush ; and TLB + MOV pc, lr + +PPLTrans + & (AP_Full * L2_APMult) + L2_SmallPage ; R any W any + & (AP_Read * L2_APMult) + L2_SmallPage ; R any W sup + & (AP_None * L2_APMult) + L2_SmallPage ; R sup W sup + & (AP_None * L2_APMult) + L2_SmallPage ; R sup W sup + +PageSizes + & 4*1024 ; 0 is 4K + & 8*1024 ; 4 is 8K + & 16*1024 ; 8 is 16 + & 32*1024 ; C is 32 + +PageShifts + = 12, 13, 0, 14 ; 1 2 3 4 + = 0, 0, 0, 15 ; 5 6 7 8 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_UpdateMEMC: Read/write MEMC1 control register + +SSETMEMC ROUT + + AND r10, r0, r1 + MOV r12, #0 + TEQP pc, #SVC_mode+I_bit+F_bit + LDR r0, [r12, #MEMC_CR_SoftCopy] ; return old value + BIC r11, r0, r1 + ORR r11, r11, R10 + BIC r11, r11, #&FF000000 + BIC r11, r11, #&00F00000 + ORR r11, r11, #MEMCADR + STR r11, [r12, #MEMC_CR_SoftCopy] + +; We now have to mimic the relevant bits of the MEMC1 control register +; +; bits 0,1 => unused +; bits 2,3 => page size, irrelevant since always 4K +; bits 4,5 => low ROM access time (mostly irrelevant but set it up anyway) +; bits 6,7 => hi ROM access time (definitely irrelevant but set it up anyway) +; bits 8,9 => DRAM refresh control +; bit 10 => Video/cursor DMA enable +; bit 11 => Sound DMA enable +; bit 12 => OS mode + + [ MEMC_Type = "IOMD" + MOV r12, #IOMD_Base + TST r11, #1 :SHL: 10 ; see if video DMA wants to be enabled + LDRB r11, [r12, #IOMD_VIDCR] + AND r11, r11, #(&7F :AND: :NOT: IOMD_VIDCR_Enable) ; knock out bit 7 and video DMA enable bit + ORRNE r11, r11, #IOMD_VIDCR_Enable + STRB r11, [r12, #IOMD_VIDCR] + | + +; Just change the page size to the real MEMC page size and leave other bits alone + + ORR r11, r11, #&0C ; force 32K page size + STR r11, [r11] ; any old data will do + ] + + TEQP pc, #SVC_mode+I_bit + ExitSWIHandler + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; ClearPhysRAM - Routine to clear "all" memory +; +; While this routine is running, keyboard IRQs may happen. For this reason +; it avoids LogRAM 0..31 (where hardware IRQ vector is) and PhysRAM +; 0..31 where the IRQ workspace is. +; +; We also have to avoid the L2PT (inc L1PT) and the PhysRamTable. +; The latter is also used to tell us which areas of memory we should clear. + +; We don't have to worry about trampling on the ROM image as it's +; already been excluded from PhysRamTable. + +; This routine must work in 32-bit mode. + +; in: r7 = memory speed +; r8 = page size +; r9 = MEMC control register +; r13 = total RAM size +; +; None of the above are actually used by this routine +; +; out: r7-r9, r13 preserved +; + +ClearPhysRAM ROUT + MOV r0, #0 + MOV r1, #0 + MOV r2, #0 + MOV r3, #0 + LDR r12, =PhysRamTable ; point to 5 lots of (physaddr,size) + ADR r6, RamSkipTable + ADD r4, r12, #PhysRamTableEnd-PhysRamTable ; r4 -> end of table +10 + LDR r5, [r6], #4 ; load first skip offset + + LDMIA r12!, {r10, r11} ; load next address, size + + ORR r10, r10, #PhysSpace ; point to logical representation of physical space + ADD r11, r11, r10 ; r11 -> end address of this area +15 + ADD r5, r5, r10 ; r5 -> skip address if any +20 + TEQ r10, r11 ; test for end of this area? + BEQ %FT30 + TEQ r10, r5 ; test for the start of a skipped region + STMNEIA r10!, {r0-r3} + BNE %BT20 + + LDR r5, [r6], #4 ; load skip amount + CMP r5, #0 ; if negative, then it's an offset from start of skipped bit + LDRLT r5, [r10, r5] ; to address of word holding skip amount + ADD r10, r10, r5 ; and skip it + LDR r5, [r6], #4 ; load next skip offset (NB relative to end of last skip) + B %BT15 + +30 + TEQ r12, r4 ; have we done all areas? + BNE %BT10 + + LDR r0, =OsbyteVars + :INDEX: LastBREAK + MOV r1, #&80 + STRB r1, [r0] ; flag the fact that RAM cleared + + MOV r0, #0 + LDR r1, =DefaultMMUControlRegister ; set up MMU soft copy + STR r1, [r0, #MMUControlSoftCopy] + + MOV pc, lr + + GBLA lastaddr +lastaddr SETA 0 + GBLA lastregion +lastregion SETA 0 + + MACRO + MakeSkipTable $region, $addr, $size + [ ($region)<>lastregion + & -1 +lastaddr SETA 0 + ] + & ($addr)-lastaddr, $size +lastaddr SETA ($addr)+($size) +lastregion SETA $region + MEND + + MACRO + EndSkipTables + WHILE lastregion < (PhysRamTableEnd-PhysRamTable)/8 + & -1 +lastregion SETA lastregion +1 + WEND + MEND + +; Note (TMD 04-Aug-93): Special bodge put in here to allow variable size skip for L2PT. +; If skip size field is negative, then it's an offset from the start of this skipped bit to a word holding +; the size of the skip. This relies on the L2PTSize being in page zero, which is at a lower physical address than +; the L2 itself. Also assumes that there are no more skips in the 1st DRAM chunk after the L2PT, since the offset +; to the next skip is relative to the end of the previous one, which isn't known at assembly time! + +; Tim says "Yuk, yuk, yuk!!" + +RamSkipTable + [ :LNOT: NewStyle_Screen + MakeSkipTable 0, 0, 32 ; in video RAM skip 1st 32 bytes (kbd workspace) + ] + MakeSkipTable 1, DRAMOffset_PageZero + 0, 32 ; skip 1st 32 bytes of LogRAM, so IRQs work! + MakeSkipTable 1, DRAMOffset_PageZero + SkippedTables, SkippedTablesEnd-SkippedTables + MakeSkipTable 1, DRAMOffset_L2PT, DRAMOffset_PageZero + L2PTSize - DRAMOffset_L2PT + EndSkipTables + + ASSERT DRAMOffset_PageZero + L2PTSize < DRAMOffset_L2PT + + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; InitMEMC - Initialise memory controller +; +; in: If ResetIndirection assembly flag set, then +; r1 = 0 if reset, 1 if break +; else +; r1 undefined +; endif + +InitMEMC ROUT + [ MEMC_Type = "IOMD" + +; Note: On IOMD, all accesses go to ROM until the first write cycle. + + MOV r12, #IOMD_Base + + [ MorrisSupport +; Perform a dummy write to IOMD (some harmless register) to get it out of ROM force mode. +; Reads from IOMD will return garbage before this has happened. If we're actually running out +; of 32-bit wide ROMs on MORRIS, a write will already have happened, to get ROMCR0 from +; 16 to 32-bit wide mode, but we can't yet determine for sure (by reading it back), so do it +; anyway. + + STRB r12, [r12, #IOMD_DMAREQ] ; writes to DMAREQ are ignored + + LDRB r0, [r12, #IOMD_ID0] + CMP r0, #&98 + LDRB r0, [r12, #IOMD_ID1] + CMPEQ r0, #&5B + ;MOVEQ r3, #xxxx + BNE MedusaInit ; NOT MORRIS assume Medusa hardware +; +; MORRIS contains IOMD equivalant circuitry. Due to lack of VRAM, presence of 16/32 bit support +; and a different ROM speed register, we program it slightly differently. +; + +; +; PSwindell wants all prescalers set to divide by 1 +; + MOV r0, #IOMD_CLKCTL_CpuclkNormal + IOMD_CLKCTL_MemclkNormal + IOMD_CLKCTL_IOclkNormal + STRB r0, [r12, #IOMD_CLKCTL] ; initialise all prescalers to div1 + +; +; Set ROM speed, take care to preserve 16-bit mode bit... +; +; According to RJKing on 6/5/94, Kryten will use burst mode roms: use 93nS burst, 156nS initial. +; +; We assume that the extension ROMs are the same access time and width as the main OS ROMS. +; + LDRB r0, [r12, #IOMD_ROMCR0] + AND r0, r0, #&40 ; clear all but 16-bit mode bit + [ NormalSpeedROMS + ;Normal code + ORR r0, r0, #IOMD_ROMCR_Normal + IOMD_ROMCR_156 + IOMD_ROMCR_Burst93 + ; initialise ROM speed to 156.25nS, 93.75nS burst + ; the fast EPROMS used for Kryten testing should be able to cope even though they aren't + ; burst devices + | + ;Slow ROM access for PSwindells test EPROMS. Paul requested 156nS (or slower), burst off. + ORR r0, r0, #IOMD_ROMCR_Normal + IOMD_ROMCR_187 + IOMD_ROMCR_BurstOff + + ! 0, "*** WARNING *** Slow ROM version ment for PSwindell" + ] + STRB r0, [r12, #IOMD_ROMCR0] + STRB r0, [r12, #IOMD_ROMCR1] ; and do the same for extension ROMs (just in case) +; +; MORRIS doesn't support VRAM. Kryten has same DRAM speed as Medusa +; + MOV r0, #IOMD_VREFCR_REF_16 ; select 16µs refresh + STRB r0, [r12, #IOMD_VREFCR] + + MOV r0, #IOMD_IOTCR_Network_TypeA :OR: IOMD_IOTCR_Combo_TypeB :OR: IOMD_IOTCR_Sound_TypeB :OR: IOMD_IOTCR_Sound_Word + STRB r0, [r12, #IOMD_IOTCR] + + MOV r0, #0 ; Podule manager wants TypeA setting by default for all podules + STRB r0, [r12, #IOMD_ECTCR] + + [ Select16BitSound +; All MORRIS based machines have 16bit 'Japanese' format sound DAC's + MOV r0, #2_10 + STRB r0, [r12, #IOMD_VIDMUX] + ] + B CommonInit + +MedusaInit + ] + + [ Simulator + MOV r0, #IOMD_ROMCR_62 + IOMD_ROMCR_BurstOff ; make faster for simulation (no point in burst mode, it's + ; no faster than the fastest initial speed) + | + [ RISCPCBurstMode + [ 1 = 1 + ReadCop r0, CR_ID + BIC r0, r0, #&F ;ignore 4 bit revision field + LDR r2, =&41007100 ;Test for early 710's + CMP r0, r2 ; + MOVEQ r0, #IOMD_ROMCR_156 + IOMD_ROMCR_BurstOff ;cos they can't work in burst mode! + MOVNE r0, #IOMD_ROMCR_156 + IOMD_ROMCR_Burst93 ;610's 710A's and beyond can + ! 0, "*** WARNING *** Burst mode enabled on RISC PC iff processor can cope" + | + MOV r0, #IOMD_ROMCR_156 + IOMD_ROMCR_Burst93 + ! 0, "*** WARNING *** Burst mode enabled on RISC PC" + ] + | + MOV r0, #IOMD_ROMCR_156 + IOMD_ROMCR_BurstOff ; initialise ROM speed to 156.25ns (changed from 187ns 21-Jan-94) + ] + ] + STRB r0, [r12, #IOMD_ROMCR0] + STRB r0, [r12, #IOMD_ROMCR1] ; and do the same for extension ROMs (just in case) + + MOV r0, #IOMD_VREFCR_VRAM_256Kx64 :OR: IOMD_VREFCR_REF_16 ; select 16µs refresh, assume 2 banks of VRAM + STRB r0, [r12, #IOMD_VREFCR] + + MOV r0, #IOMD_IOTCR_Network_TypeA :OR: IOMD_IOTCR_Combo_TypeB :OR: IOMD_IOTCR_Sound_TypeB :OR: IOMD_IOTCR_Sound_Word + STRB r0, [r12, #IOMD_IOTCR] + + MOV r0, #0 ; Podule manager wants TypeA setting by default for all podules + STRB r0, [r12, #IOMD_ECTCR] + + | + LDR R0, ResetMemC_Value + STR R0, [R0] ; set ROM access times, refresh on flyback, no DMA + ] +CommonInit +; On breaks (ie software resets) we have to turn the MMU off. +; This is slightly tricky if we've been soft-loaded! + + [ ResetIndirected + TEQ r1, #0 ; r1 = 0 if reset, 1 if break + BEQ %FT03 ; [it's a reset] + + SetMode SVC32_mode, r0 ; select 32-bit mode (we know we're in 32-bit config) + B %FT05 +03 + | +; We check for breaks by testing if we're in 32-bit configuration: +; - on reset we'll be put into 26-bit config, MMU off, 26-bit mode +; - on breaks we'll be left in 32-bit config, MMU on, 26-bit mode + +; In both cases we want to end up in 32-bit config with MMU off, in 32-bit mode + + SetMode SVC32_mode, r1, r0 ; try to select SVC32 mode + mrs AL, r2, CPSR_all ; read back PSR + AND r2, r2, #&1F ; extract mode bits from PSR we tried to modify + TEQ r2, #SVC32_mode ; and see if we made it into SVC32 + BEQ %FT05 ; [we made it so must be a Break] + ] + +; It's a reset, so select 32-bit config, MMU off + + [ LateAborts + MOV r2, #MMUC_P :OR: MMUC_D :OR: MMUC_L ; select 32-bit config, MMU off, late aborts + | + MOV r2, #MMUC_P :OR: MMUC_D ; select 32-bit config, MMU off + ] + SetCop r2, CR_Control + SetMode SVC32_mode, r1, r0 ; and re-select 32-bit mode (this time it'll work) + AND r0, r0, #&1F ; check original mode + TEQ r0, #SVC26_mode ; if we were in a 26-bit mode, + BICEQ lr, lr, #&FC000003 ; then knock off 26-bit style PSR bits from link register + ; don't knock them off otherwise, since we may be soft-loaded above 64M + MOV pc, lr ; and exit + +; It's a Break + +; The MMU is on and we want it off: whether we're executing out of ROM or RAM, we +; have to jump to the physical location of our image, which means paging it in at its +; own physical address. + +; On MEMC1 systems it's possible that the L1/L2 logical address is the same as the image's physical +; address, which causes a headache, so we'd best use the physical mapping of the page tables (this +; can't clash as IOMD only goes up to 2000 0000 and our physical mapping is above that). + +05 + MOV r0, #0 + LDR r0, [r0, #DRAMPhysAddrA] ; get address of 1st DRAM bank + LDR r1, =PhysSpace + DRAMOffset_L1PT ; offset to start of L1 + ADD r0, r0, r1 ; r0 -> L1 in physical mapped logical space + + LDR r1, [r0, #ROM :SHR: (20-2)] ; load L1 entry for 1st Mbyte of ROM + MOV r1, r1, LSR #20 ; knock off other bits + LDR r2, =(AP_None * L1_APMult) + L1_Section + ; (svc-only access) + ~ucb + section mapped + ORR r2, r2, r1, LSL #20 ; merge in address + STR r2, [r0, r1, LSL #2]! ; store in L1PT for 1st Mbyte + ADD r2, r2, #1 :SHL: 20 ; move on to 2nd Mbyte + STR r2, [r0, #4] ; and store in next entry + + SetCop r0, CR_TLBFlush ; flush TLB (data is ignored) + SetCop r0, CR_IDCFlush ; and flush cache as well + + MOV r0, r1, LSL #20 + SUB r0, r0, #ROM ; form RAM-ROM offset + ADD pc, pc, r0 ; jump to RAM code (when we get onto IOMD, we'll have to be in 32-bit mode) + NOP ; this instruction will be skipped + +; we're now in RAM, so it's safe to turn the MMU off, but leave us in 32-bit config (and 32-bit mode) + + BIC lr, lr, #&FC000003 ; knock out PSR bits from return address + ; (we know we were in 32-bit config, 26-bit mode on entry) + ADD lr, lr, r0 ; and add on offset - NB this may now be above 64MB (on IOMD) + [ LateAborts + MOV r0, #MMUC_P :OR: MMUC_D :OR: MMUC_L ; turn MMU off, but leave us in 32-bit config, late aborts + | + MOV r0, #MMUC_P :OR: MMUC_D ; turn MMU off, but leave us in 32-bit config + ] + SetCop r0, CR_Control + + MOV pc, lr ; return to caller, but in physical address space + +; -> MemSize + +; (non-destructive) algorithm to determine MEMC RAM configuration +; +; Dave Flynn and Alasdair Thomas +; 17-March-87 +; +; Spooling checkered by NRaine and SSwales ! +; 8MByte check bodged in by APT +; +; NOTE: Routines MemSize and TimeCPU are called by the power-on test software, +; so their specifications MUST not change. +; +; Set MEMC for 32-k page then analyse signature of possible +; external RAM configurations... +; The configurations are: +; +; Ram Size Page Size Configuration (Phys RAM) Signature +;-------------------------------------------------------------------- +; 16MByte 32k 4*32*1Mx1 A13,A20,A21,A22,A23,A23.5 distinct +; 16MByte 32k 16*8*256kx4 A13,A20,A21,A22,A23,A23.5 distinct +; +; 12MByte 32k 3*32*1Mx1 A13,A20,A21,A22,A23 OK, A23.5 fail +; 12MByte 32k 12*8*256kx4 A13,A20,A21,A22,A23 OK, A23.5 fail +; +; 8MByte 32k 2*32*1Mx1 A13,A20,A21,A22 distinct, A23 fail +; 8MByte 32k 8*8*256kx4 A13,A20,A21,A22 distinct, A23 fail +; +; 4Mbyte 32k 32*1Mx1 A13,A21,A20 distinct, A22,A23 fail +; 4Mbyte 32k 4*8*256kx4 A13,A21,A20 distinct, A22,A23 fail +; +; 2Mbyte 32k expandable 2*8*256kx4 A13,A20 distinct, A21 fails +; 2Mbyte ??? 16k fixed 2*8*256kx4 A13,A21 distinct, A20 fails +; +; 1Mbyte 8k 32*256kx1 A13,A20 fail, A19,A18,A12 distinct +; 1Mbyte 8k 8*256kx1 A13,A20 fail, A19,A18,A12 distinct +; 1Mbyte 8k 4*8*64kx4 A13,A20 fail, A19,A18,A12 distinct +; +; 512Kbyte 8k expandable 2*8*64kx4 A13,A20,A19 fail, A12,A18 distinct +; 512Kbyte 4k fixed 2*8*64kx4 A13,A20,A12 fail, A19,A18 distinct +; +; 256Kbyte 4K 8*64kx4 A13,A20,A12,A18 fail, A21,A19 ok +; 256Kbyte 4K 32*64kx1 A13,A20,A12,A18 fail, A21,A19 ok +; + +Z_Flag * &40000000 + +; MemSize routine... enter with 32K pagesize set +; R0 returns page size +; R1 returns memory size +; R2 returns value set in MEMC +; Can corrupt R3-R14 + +; Note that on a soft-loaded system, the 1st word of the image may be +; temporarily overwritten, but this is just the reset branch so it's OK. + +; MMU is always off at this point, so we must use the physical address of PhysRAM +; Also we are entered in 32-bit config, 32-bit mode, +; but we exit in 32-bit config, 26-bit mode + + [ MorrisSupport +funnypatterns + & &66CC9933 ; 0110 1100 1001 0011 + & &CC993366 ; 1100 1001 0011 0110 + ] + +MemSize ROUT + MOV r13, lr ;save in a register, cos we've got no stack + + [ MEMC_Type = "IOMD" + + MOV r12, #IOMD_Base + + [ MorrisSupport +; + LDRB r0, [r12, #IOMD_ID0] + CMP r0, #&98 + LDRB r0, [r12, #IOMD_ID1] + CMPEQ r0, #&5B + ;MOVEQ r3, #xxxx + BNE MemSizeIOMD ; NOT MORRIS assume Medusa hardware +; +; MemSize for Morris +; + MOV r11, #IOMD_DRAMWID_DRAM_32bit * &0F ;set all 4 banks to be 32bit initially + MOV r14, #IOMD_Base + STRB r11, [r14, #IOMD_DRAMWID] + [ 1 = 0 + MOV R10, #DRAM0PhysRam + MOV R11, #(2*OneMByte) + STMIA R10!, {R10, R11} + B AllocateTheRAM + ! 0, "*** WARNING *** Bodged RAM sizing version ment for PSwindell" + ] + MOV r10, #0 ;indicate no RAM found yet + MOV r9, #IOMD_DRAMWID_DRAM_16bit ;bit to OR into DRAMWID to set 16bit + MOV r0, #DRAM0PhysRam +; +; r0 DRAM address +; r9 IOMD_DRAMWID_DRAM_16bit for current DRAM bank +; r11 current IOMD_DRAMWID register contents +; +ExamineDRAMBank ;examine first/next DRAM bank +; + LDMIA r0, {r1, r2} ;Preserve the two locations that we widdle on + + ADR r3, funnypatterns ;We write different values to two locations + LDMIA r3, {r3, r4} ; incase bus capacitance holds our value + STMIA r0, {r3, r4} + LDMIA r0, {r5, r6} ;Reread test locations + EORS r5, r5, r3 ;Both locations should read correctly + EOR r6, r6, r4 ; if memory is 32bits wide + ;TEQ r5, #0 + TEQEQ r6, #0 + BEQ %FT1010 ;32bit wide memory + + TST r5, #&00FF ;If the bottom 16bits of each location + TSTEQ r5, #&FF00 ; are correct, the memory is 16bits wide + TSTEQ r6, #&00FF + TSTEQ r6, #&FF00 + BNE NoRamInBank ;No memory in this bank + + ORR r11, r11, r9 ;Bank is 16bits wide +1010 + STMIA r0, {r1, r2} ;Restore the two locations we widdled on + ;Must do BEFORE poking the DRAMWID register + MOV r14, #IOMD_Base ; + STRB r11, [r14, #IOMD_DRAMWID] ; +; +; minimum ram test +; + ADD r1, r0, #A18 + BL DistinctAddresses + BNE NoRamInBank ;Less than 512KBytes, so ignore this bank + + MOV r6, #0 ;Fragment address + MOV r7, #0 ;Fragment address + MOV r8, #A19 ; now go through address lines A19-A25 +1015 + ADD r1, r0, r8 ; see if this address line is unique + BL DistinctAddresses + BNE %FT1020 ; if we've failed then r8 is true size, so exit + MOV r8, r8, LSL #1 ; else shift up to next + TEQ r8, #A26 ; only test up to A25 + BNE %BT1015 + BEQ %FT1035 ;Bank fully occupied, DON'T test for higher fragments +1020 +; +; Found some DRAM, at address r0, size r8. +; There may be one or two higher address lines connected, so scan upto A25 looking for +; extra DRAM chunks. +; + MOV r1, r8 +1025 + TEQ r1, #A25 + BEQ %FT1035 ;No higher active address lines found ie one lump of DRAM + ADD r1, r0, r1,LSL #1 + BL DistinctAddresses + SUB r1, r1, r0 ;Recover bit value + BNE %BT1025 +; +; Got a 2nd fragment, at address r1 (also of size r8) +; + MOV r6, r1 +1030 + TEQ r1, #A25 + BEQ %FT1035 ;No higher active address lines found ie two lumps of DRAM + ADD r1, r0, r1,LSL #1 + BL DistinctAddresses + SUB r1, r1, r0 ;Recover bit value + BNE %BT1030 +; +; Got another active address line (ie total four fragments) +; + MOV r7, r1 +; +1035 +; +; Found 1, 2 or 4 lumps of DRAM +; + [ 1 = 1 +; +; New code which relies on reflection to merge fragments into larger blocks +; + TEQ r10, #0 ;Need some ram to dump block/fragment data + MOVEQ r10, r0 ; + + TEQ r6, #0 ;Do we have one fragment? + MOVEQ r1, r0 ;EQ: First and only fragment in this bank + MOVEQ r2, r8 ;EQ: so save actual address and size + ADDNE r1, r0, r6 ;NE: Use reflection to make 1st fragment appear + SUBNE r1, r1, r8 ;NE: to start just below 2nd fragment + MOVNE r2, r8, LSL #1 ;NE: treat as one double size fragment + + STMIA r10!, {r1, r2} ; {address, size} + + TEQ r7, #0 ;Do 3rd and 4th fragments exist + ADDNE r1, r1, r7 ;NE: yes, merge 3 and 4 together + STMNEIA r10!, {r1, r2} ; {address, size} + | +; +; Old code which enters each fragment as found +; + TEQ r10, #0 ;Need some ram to dump block/fragment data + MOVEQ r10, r0 ; + + STMIA r10!, {r0, r8} ;First fragment + + TEQ r6, #0 + ADDNE r1, r0, r6 + STMNEIA r10!, {r1, r8} ;Second fragment + + TEQ r7, #0 + ADDNE r1, r0, r7 + STMNEIA r10!, {r1, r8} ;Third + ADDNE r1, r1, r6 + STMNEIA r10!, {r1, r8} ;and fourth fragments + ] + [ Simulator + TubeString r2, r3, r4, "Address Size" + TubeDumpNoStack r0, r2, r3, r4 + TubeDumpNoStack r8, r2, r3, r4 + TubeNewlNoStack r3, r4 + + TEQ R7, #0 + BEQ skip1 + TubeString r2, r3, r4, "Fragment (1): " + TubeDumpNoStack r7, r2, r3, r4 + TubeNewlNoStack r3, r4 +skip1 + TEQ R6, #0 + BEQ skip2 + TubeString r2, r3, r4, "Fragment (2): " + TubeDumpNoStack r6, r2, r3, r4 + TubeNewlNoStack r3, r4 +skip2 + ] + + + +NoRamInBank + ADD r0, r0, #DRAM1PhysRam-DRAM0PhysRam ; move onto next bank + MOV r9, r9, LSL #1 ; shunt up position in DRAMWID + CMP r9, #&0010 ; if more banks to do + BLT ExamineDRAMBank ; then loop + + TEQ r10, #0 ; have we got any DRAM? +;NoDRAMPanic + BEQ NoDRAMPanic ; we'd better stop now + +; +; Having dumped our block/fragment data to the first bit of DRAM that we found. +; We now go back through it, allocating some for the screen, and some for 'PageZero'. +; The data has been dumped into RAM that we now allocate as screen ram, so it needs +; to be copied into 'PageZero'. +; +; r10 -> byte after last fragment(address, size) pair +; +AllocateTheRAM + AND r7, r10, #DRAMBaseAddressMask ;point to first fragment data + MOV r2, #0 ;MOS workspace not yet allocated + + LDMIA r7!, {r4, r5} ;first fragment address & size + CMP r10, r7 ;is there only 1 fragment + [ 1 = 1 +; +; New - requested by Tim Dobson +; + MOVHI r1, r5 ;if >1 fragments, take first fragment for the screen + SUBLS r1, r5, #OneMByte ;if this is the only fragment, take all but 1MByte of it + MOV r0, r4 ;screen starts at beginning of fragment + [ 1 = 1 +; +; New - also requested by Tim Dobson +; + CMP r1, #SixteenMByte ;Limit our claim to 16Mbyte + MOVGT r1, #SixteenMByte + ] + | + MOVHI r1, r5 ;if >1 fragments, consider taking first fragment for the screen + MOVLS r1, r5, LSR #1 ;if this is the only fragment, try for half of it + MOV r0, r4 ;screen starts at beginning of fragment + + CMP r1, #OneMByte ;Limit our claim to 1Mbyte + MOVGT r1, #OneMByte + ] + ADD r4, r4, r1 ;adjust fragment for amount claimed by screen + SUBS r5, r5, r1 + BEQ %FT1065 ;EQ whole fragment used + ;NE part of fragment remains to be allocated +1060 + TEQ r2, #0 ;allocate MOS workspace if not already done so + LDREQ r2, =DRAMOffset_PageZero + DRAMPhysAddrA + ADDEQ r2, r2, r4 + MOVEQ r3, r2 + + STMIA r3!, {r4, r5} ;write fragment data to correct place in PageZero +1065 + CMP r10, r7 ;any more fragment (address, size) pairs? + LDMHIIA r7!, {r4, r5} ;HI, yes so load next fragment pair (size + BHI %BT1060 ;HI, mustbe non-zero) and loop back + + STMDB r2!, {r0, r1} ;write VideoPhysAddr, VideoSize +; +; r2 -> start of PhysRamTable +; r3 -> byte after last used entry in PhysRamTable +; + MOV r7, r2 + ;MOV r2, r2 ; r2 -> start of PhysRamTable + MOV r10, r3 + ;MOV r3, r3 ; r3 -> byte after last used entry in PhysRamTable + + +; +; r0 screen start address +; r1 screen size +; r2 -> start of PhysRamTable +; r3 -> byte after last used entry in PhysRamTable + + MOV r4, #0 ;Morris cannot support VRAM, so... + STR r4, [r2, #VRAMWidth-PhysRamTable] ; store width of VRAM (0,1 or 2) + STR r4, [r2, #VRAMSize-PhysRamTable] ; and size of VRAM (fixes DForth's bug of 6/3/95) + + MOV r14, #IOMD_Base + + MOV r4, #IOMD_VIDCR_DRAMMode :OR: &10 ; if no VRAM, then turn on DRAM mode, and set increment to &10 + STRB r4, [r14, #IOMD_VIDCR] + STR r0, [r14, #IOMD_VIDCUR] ; set up VIDCUR to start of video RAM + STR r0, [r14, #IOMD_VIDSTART] ; do same for VIDSTART + STR r0, [r14, #IOMD_VIDINIT] ; and for VIDINIT + ; so we don't get a mess when we turn video DMA on later + + LDR r4, =46500000 ; if no VRAM, then 46.5E6 bytes/sec bandwidth + STR r4, [r2, #VideoBandwidth-PhysRamTable] ; store video bandwidth + + ADD r4, r0, r1 ;form VIDEND (will be on mult. of SAM) + SUB r4, r4, #4096 + STR r4, [r14, #IOMD_VIDEND] ;this instruction put in on 6/3/95 after inspection of RPC code +; +; +; + MOV r7, r2 + MOV r10, r3 + + B MemSizeTotalRAM + +MemSizeIOMD + ] + +; Right, let's find out where our memory is + +; First, we check out the VRAM. This is so that if there's no VRAM, we know to take out the 1st Mbyte of DRAM +; that we find. + +; Don't bother checking for more than 2M of VRAM, because we don't know what the 1/2 SAM length is for larger sizes + + MOV r2, #IOMD_VREFCR_VRAM_256Kx64 :OR: IOMD_VREFCR_REF_16 ; assume 2 banks of VRAM by default + STRB r2, [r12, #IOMD_VREFCR] + + MOV r0, #VideoPhysRam ; point at VRAM + ADD r1, r0, #A2 ; test A2 + BL DistinctAddresses + MOVEQ r6, #2 ; we've got 2M of VRAM + BEQ %FT08 + + MOV r2, #IOMD_VREFCR_VRAM_256Kx32 :OR: IOMD_VREFCR_REF_16 + STRB r2, [r12, #IOMD_VREFCR] + ADD r1, r0, #A2 ; check for any VRAM at all + BL DistinctAddresses + MOVEQ r6, #1 ; we've got 1M of VRAM + MOVNE r6, #0 ; no VRAM +08 + [ IgnoreVRAM + MOV r6, #0 ; pretend there's no VRAM + ] + MOVS r12, r6 ; if no VRAM, then video RAM has yet to be found + MOVNE r12, r0 ; else point at VRAM + +; Now, we have to find a bank of DRAM, so we've got somewhere to store our results! + + MOV r11, #IOMD_DRAMCR_DRAM_Large * &55 ; set all banks to be large initially + MOV r14, #IOMD_Base + STRB r11, [r14, #IOMD_DRAMCR] + + MOV r10, #0 ; indicate no RAM found yet + MOV r9, #IOMD_DRAMCR_DRAM_Small ; bit to OR into DRAMCR + MOV r0, #DRAM0PhysRam +10 + ADD r1, r0, #A10 ; this should be OK for both configurations + BL DistinctAddresses + BNE %FT25 ; [no RAM in this bank at all] + + ADD r1, r0, #A11 ; test for 256K DRAM + BL DistinctAddresses + ORRNE r11, r11, r9 ; it is, so select small multiplexing + MOVNE r14, #IOMD_Base + STRNEB r11, [r14, #IOMD_DRAMCR] ; store new value of DRAMCR, so we can use memory immediately + MOVNE r8, #1024*1024 ; must be 1Mbyte at this address + BNE %FT20 + +; it's bigger than 256K words, so test address lines A21-A25 in sequence +; we assume that the size of each bank is a power of 2 + + MOV r8, #A21 ; now go through address lines A21-A25 +15 + ADD r1, r0, r8 ; see if this address line is unique + BL DistinctAddresses + BNE %FT20 ; if we've failed then r8 is true size, so exit + MOV r8, r8, LSL #1 ; else shift up to next + TEQ r8, #A26 ; only test up to A25 + BNE %BT15 +20 + TEQ r12, #0 ; have we found any video RAM yet? + BNE %FT22 ; yes, so no worries + + MOV r12, r0 ; no, so use this as video RAM + ADD r0, r0, #1024*1024 ; advance RAM pointer by 1M + SUBS r8, r8, #1024*1024 ; take 1 Mbyte off the size + BEQ %FT25 ; if that's all there was, then go look for the next bank +22 + TEQ r10, #0 ; is this the first lot we've found? + LDREQ r10, =DRAMOffset_PageZero + DRAMPhysAddrA + ADDEQ r10, r10, r0 ; then point r10 at DRAM part of PhysRamTable + MOVEQ r7, r10 ; points to beginning of table + STMIA r10!, {r0, r8} ; store address, size +25 + AND r0, r0, #DRAMBaseAddressMask ; move back to start of DRAM bank (in case we stole some video DRAM) + ADD r0, r0, #DRAM1PhysRam-DRAM0PhysRam ; move onto next bank + MOV r9, r9, LSL #2 ; shunt up position in DRAMCR + CMP r9, #&100 ; if more banks to do + BCC %BT10 ; then loop + + TEQ r10, #0 ; have we got any DRAM? +NoDRAMPanic + BEQ NoDRAMPanic ; we'd better stop now + +; Now go back and put the VRAM information in, and also program VIDCR and VIDCUR + + STR r6, [r7, #VRAMWidth-DRAMPhysAddrA] ; store width of VRAM (0,1 or 2) + CMP r6, #1 + MOVCC r2, #IOMD_VIDCR_DRAMMode :OR: &10 ; if no VRAM, then turn on DRAM mode, and set increment to &10 + MOVEQ r2, #SAMLength/2/256 ; if 1M VRAM, then use VRAM mode, and set increment for 1/2 SAM + MOVHI r2, #SAMLength/2/256*2 ; if 2M VRAM, then use VRAM mode, and set increment for 2*1/2 SAM + LDRCC r3, =46500000 ; if no VRAM, then 46.5E6 bytes/sec bandwidth + LDREQ r3, =80000000 ; if 1M VRAM, then 80E6 ---------""-------- + LDRHI r3, =160000000 ; if 2M VRAM, then 160E6 ---------""-------- + MOV r14, #IOMD_Base + STRB r2, [r14, #IOMD_VIDCR] + STR r12, [r14, #IOMD_VIDCUR] ; set up VIDCUR to start of video RAM + STR r12, [r14, #IOMD_VIDSTART] ; do same for VIDSTART + STR r12, [r14, #IOMD_VIDINIT] ; and for VIDINIT + ; so we don't get a mess when we turn video DMA on later + STR r3, [r7, #VideoBandwidth-DRAMPhysAddrA] ; store video bandwidth + + ADD r3, r12, #1024*1024-4096 ; add on a bit to form VIDEND (will be on mult. of SAM) + STR r3, [r14, #IOMD_VIDEND] ; yes I know it's a bit of a bodge + + MOVS r14, r6, LSL #20 ; convert amount of VRAM to bytes + STR r14, [r7, #VRAMSize-DRAMPhysAddrA] ; and store + + MOVEQ r14, #1024*1024 ; if no VRAM, then video RAM size is 1M + STMDB r7!, {r12, r14} ; store video information + + MOV r2, r7 ; r2 -> start of PhysRamTable + MOV r3, r10 ; r3 -> byte after last used entry in PhysRamTable +MemSizeTotalRAM +; Now we have to work out the total RAM size + + [ Simulator + TubeString r4, r5, r6, "Address Size" + ] + MOV r1, #0 +26 + LDMIA r7!, {r4, r5} ; get address, size + ADD r1, r1, r5 ; add on size + [ Simulator + TubeDumpNoStack r4, r6, r8, r9 + TubeDumpNoStack r5, r6, r8, r9 + TubeNewlNoStack r6, r8 + ] + TEQ r7, r10 + BNE %BT26 + + MOV r0, #Page4K ; something to put in MEMC CR soft copy + ; (it's probably irrelevant) + | + +; MEMC based memory sizing + + MOV r0, #PhysRamPhys + + ADD r1, r0, #A13 + BL DistinctAddresses + BNE %05 + ADD r1, r0, #A21 + BL DistinctAddresses + MOVNE r0, #Page32K + MOVNE r1, #2048*1024 + BNE MemSizeDone + + ADD r1, r0, #4*1024*1024 + BL DistinctAddresses + MOVNE r0, #Page32K + MOVNE r1, #4*1024*1024 + BNE MemSizeDone + + ADD r1, r0, #8*1024*1024 + BL DistinctAddresses + MOVNE r0, #Page32K + MOVNE r1, #8*1024*1024 + BNE MemSizeDone + + ADD r1, r0, #12*1024*1024 + BL DistinctAddresses + MOV r0, #Page32K + MOVNE r1, #12*1024*1024 + MOVEQ r1, #16*1024*1024 + B MemSizeDone + +05 + ADD r1, r0, #A20 + BL DistinctAddresses + BNE %10 + MOV r0, #Page16K + MOV r1, #2048*1024 + B MemSizeDone + +10 + ADD r1, r0, #A19 + BL DistinctAddresses + BEQ %15 + MOV r0, #Page8K + MOV r1, #512*1024 + B MemSizeDone + +15 + ADD r1, r0, #A18 + BL DistinctAddresses + BEQ %20 + MOV r0, #Page4K + MOV r1, #256*1024 + B MemSizeDone + +20 + ADD r1, r0, #A12 + BL DistinctAddresses + BEQ %25 + MOV r0, #Page4K + MOV r1, #512*1024 + B MemSizeDone + +25 + MOV r0, #Page8K + MOV r1, #1024*1024 + +MemSizeDone + LDR r3, =PhysRamPhys ; Base of "video RAM" + MOV r4, #480*1024 ; 480K of "video RAM" + ADD r5, r3, r4 ; Base of "1st bank of DRAM" + SUB r6, r1, r4 ; Size of "1st bank of DRAM" + + LDR r2, =DRAMOffset_PageZero + PhysRamTable + ADD r2, r5, r2 ; physical address of table of physical RAM addresses/sizes + STMIA r2, {r3-r6} + + ADD r3, r2, #4*4 ; indicate just 2 areas + + LDR r4, =38400000 ; indicate 38.4E6 bytes/sec video bandwidth + STR r4, [r2, #VideoBandwidth-PhysRamTable] + ] + + ADRL r4, ROM ; use PC-relative addressing to get to start of image + TEQ r4, #PhysROM ; then see if it's the normal ROM address + BEQ %FT55 ; if so, then we're OK + + SUB r1, r1, #OSROM_ImageSize*1024 ; if we've been soft-loaded, then we have ?M less than we thought + ADD r5, r4, #OSROM_ImageSize*1024 ; point r5 at end of ROM + +; now go through the declared RAM areas looking for our image (we assume it's not split across two banks) + + MOV r6, r2 ; make copy of start pointer +30 + TEQ r6, r3 + BEQ %FT55 + LDMIA r6!, {r7,r8} ; load address, size + ADD r8, r8, r7 ; r8 -> end + SUBS r9, r8, r5 + SUBCSS r10, r4, r7 ; test for r4>=r7 and r5<=r8 + BCC %BT30 + +; we've found where the ROM is + + BNE %FT40 ; if NE from last comparison then r4<>r7 ie start(ROM)<>start(region) + ; else start(ROM)=start(region), so modify region to be end(ROM)..end(region) + TEQ r9, #0 ; test if region completely removed + STMNEDB r6, {r5, r9} ; if region not completely removed, store updated (address, size) + BNE %FT55 + +; region completely removed, so shunt down remaining ones + +35 + TEQ r6, r3 ; if not got to end + LDMNEIA r6, {r7, r8} ; then load next pair + STMNEDB r6, {r7, r8} ; and store in last + ADD r6, r6, #8 ; advance pointer + BNE %BT35 + SUB r3, r3, #8 ; move back end pointer + B %FT55 + +; there is a lump at the start + +40 + STMDB r6, {r7, r10} ; reduce start bit + TEQ r9, #0 ; is there an end bit? + BEQ %FT55 ; [no, so we've finished] + +; now shunt up all remaining areas, to make room for new one + + MOV r8, r3 +45 + TEQ r8, r6 + LDMNEDB r8, {r7, r10} + STMNEIA r8, {r7, r10} + SUBNE r8, r8, #8 + BNE %BT45 + STMIA r8, {r5, r9} ; store end lump + ADD r3, r3, #8 ; advance end pointer + +; now store zeros to fill out table + +55 + ADD r5, r2, #PhysRamTableEnd-PhysRamTable + MOV r6, #0 + MOV r7, #0 +57 + CMP r3, r5 + STMCCIA r3!, {r6, r7} + BCC %BT57 + +; Now set up L1 + L2 +; - first work out how big static L2 needs to be +; - then zero L1 + L2 (L1 is actually inside L2) + + MOV r3, r1, LSR #22 ; r3 = memsize / 4M + TEQ r1, r3, LSL #22 ; if any remainder + ADDNE r3, r3, #1 ; then round up (r3 is now how many pages of L2 needed for free pool) + MOV r3, r3, LSL #12 ; convert to bytes + ADD r3, r3, #FixedAreasL2Size ; add on size of L2 for other fixed areas + STR r3, [r2, #L2PTSize-PhysRamTable] ; save away for future reference + + LDR r2, [r2, #DRAMPhysAddrA-PhysRamTable] ; get address of 1st DRAM bank + LDR r5, =DRAMOffset_L2PT + ADD r2, r2, r5 ; make r2 -> L2PT + MOV r5, #0 ; value to initialise L1 and L2 to (translation faults) + MOV r6, r5 + MOV r7, r5 + MOV r8, r5 + MOV r9, r5 + MOV r10, r5 + MOV r11, r5 + MOV r12, r5 + [ :LNOT: Simulator ; don't bother zeroing L1/2 for Mark + ADD r2, r2, r3 ; start at end and work back +60 + STMDB r2!, {r5-r12} + SUBS r3, r3, #8*4 + BNE %BT60 + ] + +; r2 ends up pointing at L2 + + ADD r3, r2, #DRAMOffset_L1PT-DRAMOffset_L2PT ; r3 -> L1Phys + +; now initialise all the L1 for the area covered by the static L2, as if it were all page mapped +; - the section mapped stuff will be overwritten when we go thru MemInitTable shortly + + ORR r5, r2, #L1_Page + L1_U ; take phys base of L2, and or in other bits to form an L1 entry + LDR r6, =L2PTSize+DRAMOffset_PageZero-DRAMOffset_L2PT + LDR r10, [r2, r6] ; r10 = size of L2 (used after this loop, too) + ADD r6, r5, r10 ; r6 = value in r5 when we've finished + MOV r7, r3 ; r7 -> where we're storing L1 entries +61 + STR r5, [r7], #4 ; store L1 entry + ADD r5, r5, #1024 ; advance L2 pointer + TEQ r5, r6 + BNE %BT61 + +; now go through memory initialisation table, setting up entries + + ADR r5, MemInitTable +65 + LDMIA r5!, {r6-r8} ; load size, logaddr, indicator + TEQ r6, #0 ; if size field is zero + BEQ %FT90 ; then we've finished going through table + + TST r8, #1 ; if bit 0 of indicator is set, then it's page mapped + BNE %FT75 + + TST r8, #2 ; is it abort? + BNE %FT68 ; [no] + +; it's a section abort (r8=0) + +66 + STR r8, [r3, r7, LSR #20-2] ; store zero in L1 table + ADD r7, r7, #&00100000 ; increment logical address by 1M + SUBS r6, r6, #&00100000 ; and decrement size by 1M + BNE %BT66 ; loop until done + B %BT65 + + +68 +; it's section mapped + + TST r8, #ROMbit ; is it a ROM image offset + ADDNE r8, r8, r4 ; if so, then add in image offset + BICNE r8, r8, #ROMbit ; and knock out the dodgy bit + + TST r8, #Vidbit ; is it a video memory offset + LDRNE r9, =VideoPhysAddr+DRAMOffset_PageZero-DRAMOffset_L2PT + LDRNE r9, [r2, r9] ; get physical address of video RAM + ADDNE r8, r8, r9 ; add on offset + BICNE r8, r8, #Vidbit ; and knock out the dodgy bit +70 + STR r8, [r3, r7, LSR #20-2] ; store entry in L1 table (assumes bits 18, 19 are clear!) + ADD r7, r7, #&00100000 ; increment logical address by 1M + ADD r8, r8, #&00100000 ; and physical address by 1M + SUBS r6, r6, #&00100000 ; and decrement size by 1M + BNE %BT70 ; if we've not finished then loop + B %BT65 ; else go back to main loop + +; explicit L2 setup + +75 + CMP r6, #-1 ; if size <> -1 + BNE %FT80 ; then normal + +; size = -1 => this is the chunk with the soft CAM map in it, +; so we must work out a suitable size (and store it in SoftCamMapSize) +; we also have to work out the correct offset in the DRAM bank, since this is +; after variable size L2PT + + MOV r6, r1, LSR #24-3 ; number of pages for cam map + CMP r1, r6, LSL #24-3 ; if bits dropped off + ADDNE r6, r6, #1 ; then need one more page + MOV r6, r6, LSL #12 + LDR r9, =DRAMOffset_PageZero-DRAMOffset_L2PT+SoftCamMapSize + STR r6, [r2, r9] ; store size used + ADD r6, r6, #UndStackSize ; chunk also includes undstack + ADD r9, r10, #DRAMOffset_L2PT ; undstack/cammap starts at offset L2PT + L2PTSize + ORR r8, r8, r9 ; OR in other misc bits from table +80 + LDR r9, =DRAMOffset_PageZero-DRAMOffset_L2PT+DRAMPhysAddrA + ; offset from L2 to word containing physical address of 1st DRAM bank + LDR r9, [r2, r9] ; r9 = address of 1st DRAM bank + ADD r8, r8, r9 ; convert offset to address + EOR r8, r8, #L2_SmallPage :EOR: 1 ; make bottom 2 bits correct for L2 + ADD r9, r2, r7, LSR #10 ; r9 -> L2 for this page +85 + STR r8, [r9], #4 ; store entry in L2 + ADD r8, r8, #4*1024 ; advance physical page address + SUBS r6, r6, #4*1024 ; one less page to do + BNE %BT85 + B %BT65 + +; L1 is now set up correctly, and L2 has the correct CB bits, but no accessible pages +; Put in the L2 entries for the logical area we are going to access the L2 (and L1) at +; r10 still holds L2PT size + +90 + ADD r5, r2, #(L2PT :SHR: 10) ; r5 -> start of L2PT for L2 logical address + LDR r6, =(AP_None * L2_APMult) + L2_SmallPage ; r6 = other gubbins to put in L2 entries (not C or B) + ORR r6, r6, r2 ; OR in physical address of L2 + MOV r7, r10 ; amount to put in (L2PTSize) +95 + STR r6, [r5], #4 ; store entry + ADD r6, r6, #4096 ; move onto next page + SUBS r7, r7, #4096 ; one less page to do + BNE %BT95 ; loop until done + +; But before we turn on, we have to temporarily make the addresses we are currently executing out of +; into a section mapped area straight through, so we don't crash before we can jump up into ROM area + + ASSERT ((CritStart :EOR: CritEnd) :AND: &FFF00000)=0 ; make sure start and end are in the same MB chunk + + ADR r5, CritStart ; point at critical region start + MOV r5, r5, LSR #20 ; divide by 1MB + LDR r6, [r3, r5, LSL #2] ; get current L1 entry to put back later + MOV r7, r5, LSL #20 ; r7 = physical address of base of section + ORR r7, r7, #(AP_None * L1_APMult) + ORR r7, r7, #L1_Section + STR r7, [r3, r5, LSL #2] ; store replacment entry in L1 (not U,C or B) + + SetCop r3, CR_TTabBase ; set up MMU pointer to L1 + ADD r3, r3, #PhysSpace ; when we put L1 entry back later, we need to use the copy in PhysSpace area + + MOV r7, #1 + SetCop r7, CR_Domains ; only use domain 0 + + SetCop r7, CR_IDCFlush ; flush cache + TLB just in case + SetCop r7, CR_TLBFlush ; (data written is irrelevant) + + LDR r7, =DefaultMMUControlRegister ; turn on MMU, cache + write-buffer and select 32-bit configuration +CritStart + SetCop r7, CR_Control + +; now we can jump into the ROM space (if we're not already there) + + RSB r4, r4, #ROM ; make offset from current address to ROM + ADD pc, pc, r4 ; jump up into ROM area + NOP ; this instruction will be skipped + +; now put back the L1 entry we messed up + + STR r6, [r3, r5, LSL #2] +CritEnd ; 2 words after we go up into ROM + SetCop r7, CR_TLBFlush ; flush TLB (no need to flush cache, as there's nothing in it) + + SetMode UND32_mode, r7 + LDR r13_undef, =UNDSTK ; set up undefined mode stack pointer + + SetMode SVC26_mode, r7 ; switch into 26-bit mode + ADD r13, r13, r4 ; adjust return address + + LDR r2, ResetMemC_Value + BIC r2, r2, #&C + ORR r2, r2, r0 + [ MEMC_Type <> "IOMD" + STR r2, [r2] ; set MEMC to right state + ] + MOV r0, #4*1024 ; r0 = true page size (now split off + ; from MEMC control register) + [ MEMC_Type = "IOMD" + [ Simulator + TubeString r4, r5, r6, "Got through all of MemSize, and we're still here!" + TubeChar r4, r5, "MOV r5, #4", NoStack + ] + ] + MOV pc, r13 + +; Memory map initialisation table +; Consists of word triplets (size,logaddr,type) +; where size is size in bytes of area (size=0 terminates list) +; logaddr is the base logical address of area +; type is one of 5 formats: +; a) a standard section-mapped L1 entry (physical address gets incremented for each MB in size) +; b) like a section-mapped L1 entry, but with bit 12 set (address field holds base offset from "ROM" image) +; c) like a section-mapped L1 entry, but with bit 13 set (address field holds base offset from start of video RAM) +; d) like a page-mapped L1 entry, which indicates a page-mapped area to fill in +; the L2 for. In this case the other bits are as follows:- +; Bits 3,2 - CB respectively +; Bits (11,10),(9,8),(7,6),(5,4) - access privileges +; Bits 31-12 - offset in 1st DRAM bank to start of these pages (in units of pages) +; If the size field contains -1, then it is the SoftCAMMap, and the appropriate size should be worked out, +; and stored in SoftCamMapSize. Also, since the size of the L2 is variable the offset into the DRAM bank +; of the SoftCamMap is unknown at assembly time, so the offset bits in table are zero. +; e) zero - indicating that this area should abort (only necessary for section mapped bits in 48M-64M, cause they +; have no level 2, therefore section must abort) - used for VIDC1 emulation area. +; Note in case d), the L1 is not actually touched (it should have already been set up to point to the right L2) +; + +ROMbit * 1 :SHL: 12 +Vidbit * 1 :SHL: 13 +PSS * PhysSpaceSize :SHR: 20 ; Number of megabytes in physical space (used in table generation) + + MACRO + MemInitSection $size, $U, $C, $B, $logaddr, $ap, $physaddr + & ($size)*&00100000 + & $logaddr + & (($U)*L1_U):OR:(($C)*L1_C):OR:(($B)*L1_B):OR:(($ap)*L1_APMult):OR:$physaddr:OR:L1_Section + MEND + + MACRO + MemInitROMs $size, $U, $C, $B, $logaddr, $ap + & ($size)*&00100000 + & $logaddr + & (($U)*L1_U):OR:(($C)*L1_C):OR:(($B)*L1_B):OR:(($ap)*L1_APMult):OR:ROMbit:OR:L1_Section + MEND + + MACRO + MemInitVideo $size, $U, $C, $B, $logaddr, $ap + & ($size)*&00100000 + & $logaddr + & (($U)*L1_U):OR:(($C)*L1_C):OR:(($B)*L1_B):OR:(($ap)*L1_APMult):OR:Vidbit:OR:L1_Section + MEND + + MACRO + MemInitAbort $size, $logaddr + & ($size)*&00100000 + & $logaddr + & 0 + MEND + + MACRO + MemInitPagesL2 $size, $C, $B, $logaddr, $ap, $dramoffset + & ($size) + & $logaddr + & (($C)*L1_C):OR:(($B)*L1_B):OR:(($ap)*L2_APMult):OR:$dramoffset:OR:L1_Page + MEND + +MemInitTable ; sz, U, C, B, logaddr, (ap, (physaddr)) + MemInitSection 4, 1, 0, 0, &03000000, AP_None, &03000000 ; I/O + + MemInitAbort 1, &03400000 ; VIDC1 emulation zone + MemInitSection 1, 1, 0, 0, &03500000, AP_None, &03400000 ; VIDC20 space + MemInitSection 2, 1, 0, 0, &03600000, AP_None, &03600000 ; LAGs + + + [ OSROM_ImageSize = 4096 + MemInitROMs 4, 1, 1, 1, &03800000, AP_Read ; ROM + MemInitROMs 4, 1, 1, 1, &03C00000, AP_Read ; ROM + | + MemInitROMs 2, 1, 1, 1, &03800000, AP_Read ; ROM + MemInitROMs 2, 1, 1, 1, &03A00000, AP_Read ; ROM + MemInitROMs 2, 1, 1, 1, &03C00000, AP_Read ; ROM + MemInitROMs 2, 1, 1, 1, &03E00000, AP_Read ; ROM + ] + + [ :LNOT: NewStyle_Screen + MemInitVideo 16, 1, 0, 1, &05000000, AP_None ; real screen (section-mapped) + ] + MemInitSection PSS, 1, 0, 0, PhysSpace, AP_None, &00000000 ; map of physical space + + MemInitROMs 2, 1, 1, 1, &FF800000, AP_Read ; ROM + MemInitROMs 2, 1, 1, 1, &FFA00000, AP_Read ; ROM + MemInitROMs 2, 1, 1, 1, &FFC00000, AP_Read ; ROM + MemInitROMs 2, 1, 1, 1, &FFE00000, AP_Read ; ROM + +; Now explicit initialisation of L2 for static pages + + MemInitPagesL2 &8000, 0, 0, CursorChunkAddress, AP_Read, DRAMOffset_CursorChunk + MemInitPagesL2 &8000, 1, 1, &00000000, AP_Full, DRAMOffset_PageZero + MemInitPagesL2 &8000, 1, 1, SysHeapChunkAddress, AP_Full, DRAMOffset_SystemHeap + MemInitPagesL2 -1, 1, 1, UndStackSoftCamChunk, AP_Full, 0 ; variable offset and size + + & 0, 0, 0 ; terminate table + + +; DistinctAddresses routine... +; r0,r1 are the addresses to check +; uses r2-5 +; writes interleaved patterns (to prevent dynamic storage...) +; checks writing every bit low and high... +; return Z-flag set if distinct + +; This routine must work in 32-bit mode + +DistinctAddresses ROUT + LDR r2, [r0] ; preserve + LDR r3, [r1] + LDR r4, Pattern + STR r4, [r0] ; mark first + MOV r5, r4, ROR #16 + STR r5, [r1] ; mark second + LDR r5, [r0] + CMP r5, r4 ; check first + BNE %10 ; exit with Z clear + LDR r5, [r1] ; check second + CMP r5, r4, ROR #16 ; clear Z if not same + BNE %10 +; now check inverse bit writes + STR r4, [r1] ; mark second + MOV r5, r4, ROR #16 + STR r5, [r0] ; mark first + LDR r5, [r1] + CMP r5, r4 ; check second + BNE %10 ; exit with Z clear + LDR r5, [r0] ; check first + CMP r5, r4, ROR #16 ; clear Z if not same +10 STR r3, [r1] ; restore + STR r2, [r0] + MOV pc, lr ; Z flag is already set up, and other flags don't matter + +Pattern + & &AAFF5500 ; shiftable bit check pattern + +; init state with masked out page size + +ResetMemC_Value + & &E010C :OR: MEMCADR ; slugged ROMs + flyback refresh only + 32K page + +; Constants +; +A0 * 1 :SHL: 00 +A1 * 1 :SHL: 01 +A2 * 1 :SHL: 02 +A3 * 1 :SHL: 03 +A4 * 1 :SHL: 04 +A5 * 1 :SHL: 05 +A6 * 1 :SHL: 06 +A7 * 1 :SHL: 07 +A8 * 1 :SHL: 08 +A9 * 1 :SHL: 09 +A10 * 1 :SHL: 10 +A11 * 1 :SHL: 11 +A12 * 1 :SHL: 12 +A13 * 1 :SHL: 13 +A14 * 1 :SHL: 14 +A15 * 1 :SHL: 15 +A16 * 1 :SHL: 16 +A17 * 1 :SHL: 17 +A18 * 1 :SHL: 18 +A19 * 1 :SHL: 19 +A20 * 1 :SHL: 20 +A21 * 1 :SHL: 21 +A22 * 1 :SHL: 22 +A23 * 1 :SHL: 23 +A24 * 1 :SHL: 24 +A25 * 1 :SHL: 25 +A26 * 1 :SHL: 26 +A27 * 1 :SHL: 27 +A28 * 1 :SHL: 28 +A29 * 1 :SHL: 29 +A30 * 1 :SHL: 30 +A31 * 1 :SHL: 31 + +Page32K * &C ; in MEMC control reg patterns... +Page16K * &8 +Page8K * &4 +Page4K * &0 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r0-r6 trashable +; r9 = Current MEMC CR (true MEMC value, not fudged to look like 4K page size) + +; Out r9 MEMC value with slowest ROM speed, correct pagesize +; r7 processor speed in kHz, bit 16 => can do STM to I/O (ie MEMC1a, MEMC2), bit 17 => MEMC2 + +; This routine must work in 32-bit mode + +ncpuloops * 1024 ; don't go longer than 4ms without refresh ! +nmulloops * 128 + +TimeCPU ROUT + [ MEMC_Type = "IOMD" + LDR r7, =(1 :SHL: 16) :OR: 16000 ; indicate 16MHz RAM + | + BIC r9, r9, #3 :SHL: 8 + STR r9, [r9] ; turn off refresh for a bit + +; Time CPU/Memory speed + + LDR r1, =&7FFE ; 32K @ 2MHz = ~16ms limit + MOV r3, #IOC + + MOV r0, r1, LSR #8 + STRB r1, [r3, #Timer1LL] + STRB r0, [r3, #Timer1LH] + LDR r0, =ncpuloops + STRB r0, [r3, #Timer1GO] ; start the timer NOW + B %FT10 ; Looks superfluous, but is required + ; to get ncpuloops pipeline breaks + +10 + SUBS r0, r0, #1 ; 1S + BNE %BT10 ; 1N + 2S + + STRB r0, [r3, #Timer1LR] ; latch count NOW + LDRB r2, [r3, #Timer1CL] + LDRB r0, [r3, #Timer1CH] + ADD r2, r2, r0, LSL #8 ; count after looping is ... + + SUB r2, r1, r2 ; decrements ! + MOV r2, r2, LSR #1 ; IOC clock decrements at 2MHz + +; Time CPU/MEMC Multiply time + + MOV r4, #-1 ; Gives worst case MUL + + MOV r0, r1, LSR #8 + STRB r1, [r3, #Timer1LL] + STRB r0, [r3, #Timer1LH] + LDR r0, =nmulloops + STRB r0, [r3, #Timer1GO] ; start the timer NOW + B %FT20 ; Looks superfluous, but is required + ; to get nmulloops pipeline breaks + +20 + MUL r5, r4, r4 ; 1S + 16I + MUL r5, r4, r4 ; 1S + 16I + SUBS r0, r0, #1 ; 1S + BNE %BT20 ; 1N + 2S + + STRB r0, [r3, #Timer1LR] ; latch count NOW + LDRB r4, [r3, #Timer1CL] + LDRB r0, [r3, #Timer1CH] + ADD r4, r4, r0, LSL #8 ; count after looping is ... + + SUB r4, r1, r4 ; decrements ! + MOV r4, r4, LSR #1 ; IOC clock decrements at 2MHz + + ORR r9, r9, #1 :SHL: 8 ; set refresh on flyback + STR r9, [r9] ; restore MEMC state a.s.a.p. + +; In ROM - each cpu loop took 4R cycles @ 8/f*500ns/cycle + + LDR r0, =4*(8*500/1000)*ncpuloops*1000 + DivRem r7, r0, r2, r1 ; r2 preserved + MOV r0, #&80 ; At 8 MHz and below, run fast ROMs + LDR r1, =8050 ; Over 8 MHz, need medium ROMs + CMP r7, r1 + MOVHI r0, #&40 + LDR r1, =13000 ; Over 13 MHz, need slowest ROMs + CMP r7, r1 + MOVHI r0, #&00 + ORR r9, r9, r0 + STR r9, [r9] ; Set ROM speed appropriately + + ASSERT ncpuloops = 8*nmulloops ; for given ratio cutoff <------------ + + MOV r4, r4, LSL #10 ; *1024 to get resolution on divide + DivRem r0, r4, r2, r1 + LDR r1, =1100 ; Cutoff point; MEMC1 longer than this + CMP r0, r1 + ORRLO r7, r7, #1 :SHL: 16 ; Note MEMC1a prescence + ] + MOV pc, lr + +; Typical figures give (in ROM at 8MHz): + +; MEMC1 2048 CPU, 2432 MEMC -> MUL ratio 1216 +; MEMC1a 2048 864 432 + + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; SWI OS_MMUControl +; +; in: r0 = 0 (reason code for modify control register) +; r1 = EOR mask +; r2 = AND mask +; +; new control = ((old control AND r2) EOR r1) +; +; out: r1 = old value +; r2 = new value + + ^ 0 +MMUCReason_ModifyControl # 1 +MMUCReason_Unknown # 0 + +MMUControlSWI ENTRY + BL MMUControlSub + PullEnv + ORRVS lr, lr, #V_bit + ExitSWIHandler + +MMUControlSub + CMP r0, #MMUCReason_Unknown + ADDCC pc, pc, r0, LSL #2 + B MMUControl_Unknown + B MMUControl_ModifyControl + +MMUControl_Unknown + ADRL r0, ErrorBlock_HeapBadReason + [ International + Push lr + BL TranslateError + Pull lr + ] + SETV + MOV pc, lr + +MMUControl_ModifyControl ENTRY "r3, r4" + MOV r4, pc + ORR lr, r4, #I_bit + TEQP lr, #0 ; disable IRQs while we modify soft copy + MOV r3, #0 + LDR lr, [r3, #MMUControlSoftCopy] + AND r2, r2, lr + EOR r2, r2, r1 + MOV r1, lr + STR r2, [r3, #MMUControlSoftCopy] + + BIC lr, r2, r1 ; lr = bits going from 0->1 + TST lr, #MMUC_C ; if cache turning on + SetCop r0, CR_IDCFlush, NE ; then flush cache before we do it + + SetCop r2, CR_Control ; write to control register + + BIC lr, r1, r2 ; lr = bits going from 1->0 + TST lr, #MMUC_C ; if cache turning off + SetCop r0, CR_IDCFlush, NE ; then flush cache afterwards + + TEQP r4, #0 ; restore IRQ state + EXIT + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; Exception veneers + +; Undefined instruction trap pre-veneer +; in: r13_undef -> a FD stack +; r14_undef -> undefined instruction +4 +; psr_undef = PSR at time of undef'd instruction + +UndPreVeneer ROUT + +; entered in undef32, and we've branched up to &FF80xxxx, so we need to jump +; back to normal ROM space + + BIC pc, pc, #&FC000000 ; remove silly bits from pc + NOP ; (this instruction skipped) + + Push "r0-r7,r14" ; push r0-r7 on undef stack, and make room for return address + MOV r0, r13_undef + +; for the time being just merge lr and psr + + mrs AL, r1, SPSR_all ; r1 = saved PSR + AND r2, r1, #&F0000003 ; get saved NZCV and 26 bit modes + ORR lr_undef, lr_undef, r2 + AND r2, r1, #I32_bit + F32_bit ; extract I and F from new place + ORR r1, lr_undef, r2, LSL #IF32_26Shift ; r1 = combined lr and psr + + mrs AL, r2, CPSR_all ; now switch into SVC26 + BIC r3, r2, #&1F + ORR r3, r3, #SVC26_mode + msr AL, SPSR_all, r3 ; set SPSR_undef to be CPSR but with SVC26 + msr AL, CPSR_all, r3 ; and select this mode now + + MOV lr_svc, r1 ; lr_svc = PC + PSR from exception + + msr AL, CPSR_all, r2 ; go back into undef mode + + LDR r1, =UndHan ; work out address of undefined instruction handler + LDR r1, [r1] + STR r1, [r0, #8*4] ; and store it as return address + Pull "r0-r7, pc",,^ ; exit to handler, restoring sp_undef and entering SVC26 mode + +; Instruction fetch abort pre-veneer + +PAbPreVeneer ROUT + +; entered in abort32, and we've branched up to &FF80xxxx, so we need to jump +; back to normal ROM space + + BIC pc, pc, #&FC000000 ; remove silly bits from pc + NOP ; (this instruction skipped) + LDR r13_abort, =PreVeneerRegDump + STMIA r13_abort, {r0-r7} + MOV r0, r13_abort + +; for the time being just merge lr and psr + + mrs AL, r1, SPSR_all ; r1 = saved PSR + AND r2, r1, #&F0000003 ; get saved NZCV and 26 bit modes + ORR lr_abort, lr_abort, r2 + AND r2, r1, #I32_bit + F32_bit ; extract I and F from new place + ORR r1, lr_abort, r2, LSL #IF32_26Shift ; r1 = combined lr and psr + + mrs AL, r2, CPSR_all ; now switch into SVC26 + BIC r2, r2, #&1F + ORR r2, r2, #SVC26_mode + msr AL, CPSR_all, r2 + + MOV lr_svc, r1 ; lr_svc = PC + PSR from exception + LDR r1, =PAbHan + LDR r1, [r1] + STR r1, [r0, #8*4] + LDMIA r0, {r0-r7, pc} ; jump to prefetch abort handler + +; Preliminary layout of abort indirection nodes + + ^ 0 +AI_Link # 4 +AI_Low # 4 +AI_High # 4 +AI_WS # 4 +AI_Addr # 4 + +DAbPreVeneer ROUT + +; entered in abort32, and we've branched up to &FF80xxxx, so we need to jump +; back to normal ROM space + + BIC pc, pc, #&FC000000 ; remove silly bits from pc + NOP ; (this instruction skipped) + LDR r13_abort, =PreVeneerRegDump + STMIA r13_abort, {r0-r7} ; save unbanked registers anyway + STR lr_abort, [r13_abort, #15*4] ; save old PC, ie instruction address + + mrs AL, r0, SPSR_all ; r0 = PSR when we aborted + mrs AL, r1, CPSR_all ; r1 = CPSR + ADD r2, r13_abort, #8*4 ; r2 -> saved register bank for r8 onwards + + MOV r4, lr_abort ; move address of aborting instruction into an unbanked register + BIC r1, r1, #&1F ; knock out current mode bits + ANDS r3, r0, #&1F ; extract old mode bits (and test for USR26_mode (=0)) + TEQNE r3, #USR32_mode ; if usr26 or usr32 then use ^ to store registers + STMEQIA r2, {r8-r14}^ + BEQ %FT05 + + ORR r3, r3, r1 ; and put in user's + msr AL, CPSR_all, r3 ; switch to user's mode + + STMIA r2, {r8-r14} ; save the banked registers + + mrs AL, r5, SPSR_all ; get the SPSR for the aborter's mode + STR r5, [r2, #8*4] ; and store away in the spare slot on the end + ; (this is needed for LDM with PC and ^) +05 + ORR r1, r1, #SVC26_mode + msr AL, CPSR_all, r1 ; then switch to SVC26 for the rest of this + + Push "r0, lr_svc" ; save SPSR_abort and lr_svc + SUB sp_svc, sp_svc, #8*4 ; make room for r8_usr to r14_usr and PC + STMIA sp_svc, {r8-r15}^ ; save USR bank in case STM ^, and also so we can corrupt them + + SUB r11, r2, #8*4 ; r11 -> register bank + STR r4, [sp_svc, #7*4] ; store aborter's PC in user register bank + + LDR r10, [r4, #-8]! ; r10 = actual instruction that aborted, and r4 points to it + AND r9, r10, #&0E000000 + TEQ r9, #&08000000 ; test for LDM/STM + BNE %FT50 ; if not LDM/STM, then it's an "easy" LDR/STR + +; Write "It's an LDM/STM" + + [ DebugAborts + DLINE "It's an LDM/STM" + ] + +; First count the number of transferred registers, and undo any writeback + + MOV r9, #0 ; r9 = no. of registers in list + MOVS r8, r10, LSL #16 + BEQ %FT20 +10 + MOVS r8, r8, LSL #1 + ADDCS r9, r9, #1 + BNE %BT10 +20 + MOV r8, r10, LSR #16 + AND r8, r8, #&0F ; base register number + LDR r7, [r11, r8, LSL #2] ; ------""----- value + + TST r10, #1 :SHL: 23 ; test up/down + SUBNE r6, r7, r9, LSL #2 ; if up then subtract offset + ADDEQ r6, r7, r9, LSL #2 ; else add it + + TST r10, #1 :SHL: 21 ; test if write-back bit set + TEQNE r8, #15 ; (if base is PC then write-back not allowed) + MOVEQ r6, r7 ; if not wb, original base register is OK + + MOV r1, sp ; r1 -> end of stack frame, and start of user-mode register bank + SUB sp, sp, r9, LSL #2 ; make stack frame for registers + TST r10, #1 :SHL: 20 ; if its an STM, we have to load up the stack frame + BNE %FT30 ; but if it's an LDM, we call trap routine first + + STR r6, [r11, r8, LSL #2] ; store original base in register list, to be overwritten after 1st transfer + +; now go through registers, storing them into frame + + MOV r5, sp ; pointer to position in stack frame + MOV lr, r10, LSL #16 ; extract bottom 16 bits + MOVS lr, lr, LSR #16 ; ie bitmask of which registers r0-r15 stored + BEQ %FT30 ; this shouldn't happen (it's illegal) + + MOV r3, r11 ; current pointer into register bank +21 + TST r10, #1 :SHL: 22 ; is it STM with ^ + ANDNE lr, lr, #&FF ; if so then extract bottom 8 bits (r0-r7 on 1st pass, r8-r15 on 2nd) +22 + MOVS lr, lr, LSR #1 ; shift bit into carry + LDRCS r2, [r3], #4 ; if set bit then transfer word from register bank + STRCS r2, [r5], #4 ; into stack frame + STRCS r7, [r11, r8, LSL #2] ; and after 1st transfer, store updated base into register bank + ADDCC r3, r3, #4 ; else just increment register bank pointer + BNE %BT22 ; if more bits to do, then loop + + TEQ r5, r1 ; have we done all registers? + MOVNE lr, r10, LSR #8 ; no, then must have been doing STM with ^, and have some user-bank regs to store + MOVNE r3, r1 ; so point r3 at user-mode register bank + BNE %BT21 ; and go back into loop + +30 + +; now work out address of 1st transfer + + ANDS r5, r10, #(3 :SHL: 23) ; bit 24 set => pre, bit 23 set => inc + SUBEQ r2, r6, r9, LSL #2 ; if post-dec, then 1st address = initial-nregs*4+4 + ADDEQ r2, r2, #4 + BEQ %FT32 + + CMP r5, #2 :SHL: 23 + MOVCC r2, r6 ; CC => post-inc, so 1st address = initial + SUBEQ r2, r6, r9, LSL #2 ; EQ => pre-dec, so 1st address = initial-nregs*4 + ADDHI r2, r6, #4 ; HI => pre-inc, so 1st address = initial+4 +32 + ANDS r0, r10, #1 :SHL: 20 ; r0 = 0 => STM + MOVNE r0, #1 ; = 1 => LDM + LDR r1, [r1, #8*4] ; get SPSR_abort + TST r1, #3 ; test if transfer took place in USR mode + ORRNE r0, r0, #2 ; if not then set bit 1 of flags word in r0 + MOV r1, sp ; block to transfer from/into + BIC r2, r2, #3 ; LDM/STM always present word-aligned address + MOV r3, r9, LSL #2 ; length of transfer in bytes, and r4 still points to aborting instruction + BL ProcessTransfer + ADDVS sp, sp, r9, LSL #2 ; if invalid transfer then junk stack frame + BVS %FT90 ; and generate an exception + +; we transferred successfully, so now check if LDM and load up register bank from block + + TST r10, #1 :SHL: 20 + ADDEQ sp, sp, r9, LSL #2 ; it's an STM, so junk stack frame and tidy up + BEQ %FT70 + +; now go through registers, loading them from frame + + ADD r1, sp, r9, LSL #2 ; r1 -> end of stack frame, and start of user-mode bank registers + MOV r5, sp ; pointer to position in stack frame + MOV r4, r10, LSL #16 ; extract bottom 16 bits + MOVS r4, r4, LSR #16 ; ie bitmask of which registers r0-r15 stored + BEQ %FT40 ; this shouldn't happen (it's illegal) + + SUB r3, r1, #8*4 ; r3 -> notional start of user bank, if it began at r0 (it actually starts at r8) + MOV r0, #0 ; assume no user registers by default + TST r10, #1 :SHL: 15 ; is PC in list + BNE %FT34 ; then can't be LDM of user bank + TST r10, #1 :SHL: 22 ; is it LDM with ^ + BEQ %FT34 ; no, then use main bank for all registers + LDR r2, [r1, #8*4] ; get SPSR + ANDS r2, r2, #3 ; get bottom 2 bits of mode (EQ => USR26 or USR32) + BEQ %FT34 ; if USR mode then use main bank for all + TEQ r2, #FIQ26_mode ; if FIQ mode then put r8-r14 in user bank + LDREQ lr, =&7F00 ; then put r8-r14 in user bank + LDRNE lr, =&6000 ; else put r13,r14 in user bank + AND r0, r4, lr ; r0 = mask of registers to put into user bank + BIC r4, r4, lr ; r4 = mask of registers to put into main bank + MOV lr, #0 +34 + MOVS r4, r4, LSR #1 ; shift bit into carry + LDRCS r2, [r5], #4 ; if set bit then transfer word from stack frame + STRCS r2, [r11, lr, LSL #2] ; into main register bank + MOVS r0, r0, LSR #1 ; shift bit into carry + LDRCS r2, [r5], #4 ; if set bit then transfer word from stack frame + STRCS r2, [r3, lr, LSL #2] ; into user register bank + ADD lr, lr, #1 + ORRS r6, r0, r4 ; have we finished both banks? + BNE %BT34 ; no, then loop + +; If LDM with PC in list, then add 4 to it, so the exit procedure is the same as if PC not loaded +; Also, if it was an LDM with PC and ^, then we have to update the stacked SPSR + +40 + MOV sp, r1 ; junk frame + + TST r10, #1 :SHL: 15 ; check PC in list + ADDNE r2, r2, #4 ; since PC is last, r2 will still hold the value loaded + STRNE r2, [r11, #15*4] ; store back into main register bank + TSTNE r10, #1 :SHL: 22 ; now check LDM ^ + BEQ %FT70 ; [not LDM with PC in list] + + LDR r9, [sp, #8*4] ; get SPSR_abort + AND r8, r9, #&1F ; r8 = aborter's mode + TEQ r8, #USR32_mode ; if in USR32 + BEQ %FT70 ; then the ^ has no effect (actually uses CPSR) + TST r8, #&10 ; if 32-bit mode + LDRNE r7, [r11, #16*4] ; then use SPSR for the aborter's mode else use updated r15 in r2 (26-bit format) + ANDEQ r7, r2, #&F0000003 ; flag and mode bits in same place + ANDEQ r2, r2, #&0C000000 ; but I and F have to move to bits 7 and 6 + ORREQ r7, r7, r2, LSR #(26-6) + +; r7 is now desired PSR (in 32-bit format) to update to +; now check which bits can actually be updated + + TEQ r8, #USR26_mode + BICEQ r9, r9, #&F0000000 ; if USR26 then we can only update NZCV + ANDEQ r7, r7, #&F0000000 + ORREQ r9, r9, r7 + MOVNE r9, r7 ; else can update all bits + STR r9, [sp, #8*4] ; store back updated SPSR_abort (to become CPSR) + B %FT70 ; now tidy up + +50 + +; it's an LDR/STR - first work out offset + + [ DebugAborts + DLINE "It's an LDR/STR" + ] + + TST r10, #1 :SHL: 25 ; if immediate + MOVEQ r9, r10, LSL #(31-11) ; then extract bottom 12 bits + MOVEQ r9, r9, LSR #(31-11) + BEQ %FT60 + + AND r8, r10, #&0F ; register to shift + LDR r9, [r11, r8, LSL #2] ; get actual value of register + + MOV r8, r10, LSR #7 ; extract shift amount + ANDS r8, r8, #&1F ; (bits 7..11) + MOVEQ r8, #32 ; if zero then make 32 + + ANDS r7, r10, #&60 + ANDEQ r8, r8, #&1F ; LSL 0 is really zero + MOVEQ r9, r9, LSL r8 + TEQ r7, #&20 + MOVEQ r9, r9, LSR r8 + TEQ r7, #&40 + MOVEQ r9, r9, ASR r8 + TEQ r7, #&60 + MOVEQ r9, r9, ROR r8 ; if 32 then we haven't spoilt it! + TEQEQ r8, #32 ; if ROR #32 then really RRX + BNE %FT60 + LDR r7, [sp, #8*4] ; get SPSR + AND r7, r7, #C_bit + CMP r7, #1 ; set carry from original user + MOV r9, r9, RRX +60 + TST r10, #1 :SHL: 23 ; test for up/down + RSBEQ r9, r9, #0 ; if down then negate + + [ LateAborts + TST r10, #1 :SHL: 21 ; if write-back + MOVNE r8, #0 ; then no post-inc + RSBEQ r8, r9, #0 ; else post-inc = - pre-inc + ADD r0, r8, r9 ; amount to subtract off base register for correction + + TST r10, #1 :SHL: 24 ; however, if we're doing post-increment + MOVEQ r8, r9 ; then post-inc = what was pre-inc + MOVEQ r0, r9 ; and adjustment is what was added on + RSB r9, r8, #0 ; and pre-inc = -post-inc + | + TST r10, #1 :SHL: 21 ; if write-back + MOVNE r8, #0 ; then no post-inc + RSBEQ r8, r9, #0 ; else post-inc = - pre-inc + + TST r10, #1 :SHL: 24 ; however, if we're doing post-increment + MOVEQ r8, r9 ; then post-inc = what was pre-inc + MOVEQ r9, #0 ; and pre-inc = 0 + ] + + MOV r7, r10, LSL #31-19 + MOV r7, r7, LSR #28 ; r7 = base register number + LDR r6, [r11, r7, LSL #2] ; r6 = base register value + + [ LateAborts + SUB r0, r6, r0 ; compute adjusted base register + STR r0, [r11, r7, LSL #2] ; and store back in case we decide to abort after all + ] + +; no need to clear PSR bits out of R15, because PSR is separate + + ADD r9, r9, r6 ; r2 = offset+base = illegal address + + [ DebugAborts + DREG r9, "Aborting address = " + DREG r8, "Post-increment = " + DREG r4, "Instruction where abort happened = " + ] + + ANDS r0, r10, #1 :SHL: 20 ; if an LDR then bit 20 set + MOVNE r0, #1 ; so make 1 + SUBNE sp, sp, #4 ; then just create 1 word stack frame + BNE %FT65 + + MOV r5, r10, LSR #12 ; else it's an STR (r0 = 0) + AND r5, r5, #&0F ; r5 = source register number + LDR r5, [r11, r5, LSL #2] ; r5 = value of source register + [ DebugAborts + DREG r5, "Data value to store = " + ] + Push "r5" ; create stack frame with this value in it +65 + LDR r1, [sp, #(1+8)*4] ; get SPSR_abort + TST r1, #3 ; test if transfer took place in USR mode + ORRNE r0, r0, #2 ; if not then set bit 1 of flags word in r0 + + MOV r1, sp ; r1 -> data block + TST r10, #1 :SHL: 22 ; if byte transfer + MOVNE r3, #1 ; then length of transfer = 1 + MOVNE r2, r9 ; and use unmolested address + MOVEQ r3, #4 ; else length = 4 + BICEQ r2, r9, #3 ; and mask out bottom 2 bits of address + + BL ProcessTransfer + ADDVS sp, sp, #4 ; if illegal transfer, junk stack frame + BVS %FT90 ; and cause exception + + ADD r6, r9, r8 ; update base register with offset + STR r6, [r11, r7, LSL #2] ; and store back (NB if LDR and dest=base, the load overwrites the updated base) + + TST r10, #1 :SHL: 20 ; if it's STR (not LDR) + ADDEQ sp, sp, #4 ; then junk stack frame + BEQ %FT70 ; and tidy up + + Pull "r6" ; LDR/LDRB, so get value to load into register + TST r10, #1 :SHL: 22 ; if LDRB + ANDNE r6, r6, #&FF ; then put zero in top 3 bytes of word + ANDEQ r9, r9, #3 ; else rotate word to correct position - r9 = bottom 2 bits of address + MOVEQ r9, r9, LSL #3 ; multiply by 8 to get rotation factor + MOVEQ r6, r6, ROR r9 ; rotate to correct position in register + + MOV r5, r10, LSR #12 ; test for LDR PC + AND r5, r5, #&0F ; r5 = dest register number + TEQ r5, #15 ; if PC + ADDEQ r6, r6, #4 ; then adjust for abort exit + STR r6, [r11, r5, LSL #2] ; store into register bank + +70 + +; Tidy up routine, common to LDR/STR and LDM/STM + + ADD r2, r11, #8*4 ; point r2 at 2nd half of main register bank + LDMIA sp, {r8-r14}^ ; reload user bank registers + NOP ; don't access banked registers after LDM^ + ADD sp, sp, #8*4 ; junk user bank stack frame + + Pull "r0, lr" ; r0 = (possibly updated) SPSR_abort, restore lr_svc + + SetMode ABT32_mode, r1 ; leaves r1 = current PSR + + mrs AL, r6, SPSR_all ; get original SPSR, with aborter's original mode + AND r7, r6, #&1F + TEQ r7, #USR26_mode + TEQNE r7, #USR32_mode ; test also for USR32 + LDMEQIA r2, {r8-r14}^ ; if user mode then just use ^ to reload registers + NOP + BEQ %FT80 + + ORR r6, r6, #I32_bit ; use aborter's flags and mode but set I + msr AL, CPSR_all, r6 ; switch to aborter's mode + LDMIA r2, {r8-r14} ; reload banked registers + msr AL, CPSR_all, r1 ; switch back to ABT32 + +80 + LDR lr_abort, [r13_abort, #15*4] ; get PC to return to + msr AL, SPSR_all, r0 ; set up new SPSR (may have changed for LDM {PC}^) + + LDMIA r13_abort, {r0-r7} ; reload r0-r7 + SUBS pc, lr_abort, #4 ; go back 8 to adjust for PC being 2 words out, + ; then forward 4 to skip instruction we've just executed + +; Call normal exception handler + +90 + +; for the time being just merge lr and psr + + LDR r0, [sp, #8*4] ; r0 = original SPSR (can't have been modified) + + LDR lr, [r11, #15*4] ; get PC of aborter + AND r1, r0, #&F0000000 ; get saved NZCV + ORR lr, lr, r1 + AND r1, r0, #I32_bit + F32_bit ; extract I and F from new place + ORR lr, lr, r1, LSL #IF32_26Shift ; and merge + AND r1, r0, #3 ; get old mode bits (have to assume a 26-bit mode!) + ORR lr, lr, r1 ; lr = combined lr and psr + STR lr, [sp, #9*4] ; overwrite stacked lr_svc + TEQ r1, #SVC26_mode ; if aborter was in SVC mode + STREQ lr, [r11, #14*4] ; then also overwrite r14 in aborter's register bank + + BIC r0, r0, #&1F ; clear mode bits in SPSR + ORR r0, r0, #SVC26_mode :OR: I32_bit ; and force SVC26 with I set + [ DebugAborts + DLINE "Going to call data abort handler" + DREG lr, "lr_svc will be " + DREG r0, "PSR going to exit with = " + ] + STR r0, [sp, #8*4] ; overwrite stacked SPSR + + [ NewStyle_All + MOV r0, #0 ; we're going to call abort handler + STR r0, [r0, #CDASemaphore] ; so allow recovery if we were in CDA + ] + + CMP r2, #&20 ; if aborting address <&20 + ADRCCL r0, ABORTD ; then use MOS's default abort handler + LDRCS r0, =DAbHan ; else use current handler + LDRCS r0, [r0] ; get address of data abort handler + [ DebugAborts + DREG r0, "Handler address = " + ] + ADD r0, r0, #4 ; add on 4 to adjust for abort exit + STR r0, [r11, #15*4] ; and store in pc in register bank + B %BT70 ; then junk to normal tidy-up routine + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; ProcessTransfer - Process an abort transfer +; +; in: r0 = flags +; bit 0 = 0 => Store to memory +; 1 => Load from memory +; bit 1 = 0 => Transfer executed in user mode +; 1 => Transfer executed in non-user mode +; r1 = block of data to transfer from/into +; r2 = illegal address +; r3 = length of transfer in bytes +; r4 -> instruction which aborted +; SVC26 mode +; +; out: V=0 => transfer accomplished +; V=1 => transfer not accomplished +; All registers preserved +; + +SectionSizeShift * 20 +SectionSize * 1 :SHL: SectionSizeShift + +LargePageSizeShift * 16 +LargePageSize * 1 :SHL: LargePageSizeShift + +SmallPageSizeShift * 12 +SmallPageSize * 1 :SHL: SmallPageSizeShift + +ProcessTransfer ENTRY "r1-r7,r12" + + [ DebugAborts + DLINE "ProcessTransfer entered" + DREG r2, "Illegal address = " + DREG r3, "Length of transfer = " + DREG r4, "Abort happened at address " + DREG r0, "Flags = " + DLINE "Data = ",cc + + MOV r5, r3 + MOV r6, r1 +01 + LDR r7, [r6], #4 + DREG r7," ",cc + SUBS r5, r5, #4 + BHI %BT01 + DLINE "" + ] + + +; First identify if start address should have aborted + +10 + LDR r7, =L1PT + MOV lr, r2, LSR #SectionSizeShift ; r2 as a multiple of 1Mb + EOR r5, r2, lr, LSL #SectionSizeShift ; r5 = offset within section + SUB r5, r2, r5 ; r5 -> start of section containing r2 + ADD r5, r5, #SectionSize ; r5 -> start of section after r2 + + LDR lr, [r7, lr, LSL #2] ; get L1PT entry + ANDS r7, lr, #3 ; 00 => trans.fault, 01 => page, 10 => section, 11 => reserved (fault) + TEQNE r7, #3 + BEQ Fault + TEQ r7, #1 + BEQ CheckPage + +; it's section mapped - check section access privileges + +15 + ANDS r7, lr, #3 :SHL: 10 ; extract ap + BEQ Fault ; 00 => no access for anyone (at the moment) + TST r0, #2 ; test for non-usr access + BNE %FT20 ; if non-usr then OK to access here + CMP r7, #2 :SHL: 10 + BCC Fault ; 01 => no usr access + BHI %FT20 ; 11 => full user access, so OK + TST r0, #1 + BEQ Fault ; 10 => usr read-only, so stores not allowed + +; access OK, so copy up to end of section/sub-page + +20 + TST r0, #1 ; if load from memory + BNE %FT60 ; then skip + +; it's a store to memory (may be a vector write) +; do it in words if >= 4 bytes, so word writes to VIDC work for example + +25 + [ {TRUE} + CMP r2, #&1C ; if in abort area (but allow any access to &1C) + | + CMP r2, #&20 ; if in abort area + ] + CMPCC r4, #ROM ; and executing out of RAM + MOVCC r5, #&20 ; then set end-of-section = 32 + BCC Fault ; and check user list + + SetMode SVC32_mode, lr ; go into SVC32 so we can poke vector area +30 + TEQ r2, r5 ; have we gone onto a new block? + BEQ %FT50 ; if so then exit if finished else go back to outer loop + SUBS r3, r3, #4 ; have we got at least a word to do? + LDRCS lr, [r1], #4 ; if so then copy word + STRCS lr, [r2], #4 + BHI %BT30 ; and if not all done then loop + BEQ %FT50 ; if all done then switch back to SVC26 and exit + + ADDS r3, r3, #4 +40 + LDRB lr, [r1], #1 ; read byte from register bank + STRB lr, [r2], #1 ; and store to memory + SUBS r3, r3, #1 ; decrement byte count + BEQ %FT50 ; if finished then switch back to SVC26 and exit + TEQ r2, r5 ; have we gone onto a new block? + BNE %BT40 ; no, then loop + +50 + SetMode SVC26_mode, lr + CMP r3, #0 + BNE %BT10 + EXIT ; exit (VC from CMP) + +; it's a load from memory + +60 + LDRB lr, [r2], #1 ; read byte from memory + STRB lr, [r1], #1 ; and store to memory bank + SUBS r3, r3, #1 ; decrement byte count + EXIT EQ ; if finished then exit (VC from SUBS) + TEQ r2, r5 ; have we gone onto a new block? + BNE %BT60 ; no, then loop + B %BT10 ; yes, then go back to start + +; it's page mapped, so check L2PT +; lr = L1 table entry +; We use the logical copy of physical space here, in order to access the entry pointed to by the L1 entry + +CheckPage + MOV r5, r2, LSR #SmallPageSizeShift ; r2 as a multiple of 4K + MOV r5, r5, LSL #SmallPageSizeShift + ADD r5, r5, #SmallPageSize ; if translation fault, then it applies to small page + + MOV lr, lr, LSR #10 ; remove domain and U bits + MOV lr, lr, LSL #10 + ORR lr, lr, #PhysSpace ; now physical address is converted to a logical one (in physspace) + AND r7, r2, #&000FF000 ; extract bits which are to form L2 offset + + LDR lr, [lr, r7, LSR #10] ; lr = L2PT entry + ANDS r7, lr, #3 ; 00 => trans.fault, 01 => large page + ; 10 => small page, 11 => reserved (fault) + TEQNE r7, #3 + BEQ Fault + TEQ r7, #2 ; if small page + MOVEQ r7, #SmallPageSizeShift-2 ; then sub-page size = 1<<10 + MOVNE r7, #LargePageSizeShift-2 ; else sub-page size = 1<<14 + + MOV r5, r2, LSR r7 ; round down to start of sub-page + MOV r5, r5, LSL r7 + MOV r6, #1 + ADD r5, r5, r6, LSL r7 ; then move on to start of next sub-page + + MOV r7, r2, LSR r7 ; put sub-page number in bits 1,2 + AND r7, r7, #3 ; and junk other bits + RSB r7, r7, #3 ; invert sub-page ordering + MOV r7, r7, LSL #1 ; and double it + MOV lr, lr, LSL r7 ; then shift up access privileges so that correct ones appear in bits 10,11 + B %BT15 ; re-use code to check access privileges + +Fault + SUB r5, r5, r2 ; r5 = number of bytes we can do in this section/page/sub-page + Push "r3" ; save number of bytes to do + CMP r3, r5 ; if more bytes than there are in this block + MOVHI r3, r5 + +; Now scan list of user abort addresses + + MOV r6, #0 + LDR r6, [r6, #AbortIndirection] + TEQ r6, #0 + BEQ %FT85 ; address not in any abort node +75 + LDR r5, [r6, #AI_Low] + CMP r2, r5 + BCC %FT80 + LDR r5, [r6, #AI_High] + CMP r2, r5 + BCS %FT80 + + Push "r3" ; save number of bytes we can do in this section/page/sub-page + SUB r5, r5, r2 ; number of bytes we can do for this node + CMP r3, r5 ; if bigger than the size of this node + MOVHI r3, r5 ; then restrict number of bytes + + ADD r5, r6, #AI_WS + MOV lr, pc + LDMIA r5, {r12, pc} + +; returns to here + + ADDVS sp, sp, #8 ; if user abort failed, then junk both pushed r3's + EXIT VS ; and exit + + ADD r1, r1, r3 ; advance register block + ADD r2, r2, r3 ; and illegal address pointer + + LDR r5, [sp, #4] ; subtract amount done from stacked total amount to do + SUBS r5, r5, r3 + STR r5, [sp, #4] ; and store back + + Pull "r5" + SUBS r3, r5, r3 ; is there more to do in this section/page/sub-page? + BEQ %FT90 ; no then skip +80 + LDR r6, [r6, #AI_Link] ; else try next node + TEQ r6, #0 + BNE %BT75 +85 + ADD sp, sp, #4 ; junk pushed r3 + SETV ; indicate access invalid + EXIT ; and exit + +90 + Pull "r3" ; restore total amount left to do + TEQ r3, #0 + BNE %BT10 ; yes, then loop + EXIT ; no, then exit (V=0 from SUBS) + + [ DebugAborts + InsertDebugRoutines + ] + END diff --git a/s/Arthur2 b/s/Arthur2 new file mode 100644 index 0000000000000000000000000000000000000000..922ae00728edc1a7899301be1cb07d362fe70cac --- /dev/null +++ b/s/Arthur2 @@ -0,0 +1,2253 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + TTL => Arthur2 + +; GET $.Hdr.Variables - got at start + + MACRO +$l GSVarGetWSpace +$l LDR R12, =GSVarWSpace + MEND + + GBLL LongVars +LongVars SETL {TRUE} ; Long system variables (>255 chars) + + GBLL QuickIndex +QuickIndex SETL {TRUE} ; Quick index to binary chop on lookup + + GBLL DebugSysVars +DebugSysVars SETL {FALSE} + + + +;----------------------------------------------------------------------------------- +; +; This file covers: +; System variables: +; InitVariables +; OS_ReadVarVal +; OS_SetVarVal +; GSTrans: +; OS_GSInit +; OS_GSRead +; OS_GSTrans +; OS_BinaryToDecimal +; These have been grouped because GSTrans makes direct use of the system variables' +; structures and OS_BinaryToDecimal is used by readvarval. +; +; The system variables are stored as a one way sorted alphabetically linked list hanging +; off the zero-page location VariableList: +; + [ QuickIndex +; VariableList---->sorted table of pointers to variable blocks + | +; VariableList---->1st variable--->2nd variable--....-->last variable--->|| + ] +; +; The end is indicated by the link having the value 0. +; +; Each variable is stored in one block in the system heap. The format of each block is: +; +; Bytes Use + [ :LNOT: QuickIndex +; 4 Link. Points to next variable in the list. 0 indicates no more. + ] +; N+1 Variable's name (length N with terminator). +; 1 Variable's type: +; 0 string +; 1 number +; 2 macro +; 3 expanded (not valid within sysvar structure) +; 16 code +; M data - depends on the variable's type +; +; The structure of the data is as follows: +; +; Type 0 - string +; Bytes Use +; 1 Length (N) +; N the bytes of the string - may contain any characters +; +; Type 1 - number +; Bytes Use +; 4 its value (not necessarily word aligned) +; +; Type 2 - macro +; Bytes Use +; 1 Length (N) +; N the bytes of the string - must be a valid GSTransable string +; including terminator +; +; Type 16 - code +; Bytes Use +; x Sufficient to word align... +; 4 Write entry +; 4 Read entry +; N The rest of the code + +InitVariables ROUT + Push "lr" + + ; Blank the sysvar list + MOV R0, #0 + LDR R12, =VariableList + STR R0, [R12] + + ; Set up the preset system variables + ADR R0, SystemVarList ; R0 pointer to name +01 MOV R1, R0 + LDRB R2, [R1], #1 + CMP R2, #0 + Pull "PC", EQ +02 LDRB R3, [R1], #1 + CMP R3, #0 + BNE %BT02 + LDRB R4, [R1], #1 ; get type + ADD R1, R1, #3 + BIC R1, R1, #3 + LDR R2, [R1], #4 + SWI XOS_SetVarVal + ADD R0, R1, R2 + B %BT01 + + LTORG + +; System vars have Thunks : +; read thunk returns R0 ptr to string, R2 length. R1 corruptible +; set thunk takes R1 ptr to value, R2 length. Value is always a string. +; Can corrupt R1, R2, R4, R10-12 + +; The list of nodes to copy into RAM : +; name, 0 , type, ALIGN, size of value, value + +SystemVarList ROUT + = "Sys$$Time", 0, VarType_Code + ALIGN + & sv2-.-4 + LDR PC, %FT01 + LDR PC, %FT02 +01 + & SetTimeVar +02 + & ReadTimeVar + +sv2 = "Sys$$Year", 0, VarType_Code + ALIGN + & sv3-.-4 + LDR PC, %FT03 + LDR PC, %FT04 +03 + & SetYear +04 + & ReadYear + +sv3 = "Sys$$Date", 0, VarType_Code + ALIGN + & sv4-.-4 + LDR PC, %FT05 + LDR PC, %FT06 +05 + & SetDate +06 + & ReadClock + +sv4 = "Sys$$ReturnCode", 0, VarType_Code + ALIGN + & sv5-.-4 + LDR PC, %FT07 + LDR PC, %FT08 +07 + & SetRC +08 + & ReadRC + +sv5 = "Sys$$RCLimit", 0, VarType_Code + ALIGN + & sv6-.-4 + LDR PC, %FT09 + LDR PC, %FT10 +09 + & SetRCL +10 + & ReadRCL + +sv6 = "Alias$.", 0, VarType_String + ALIGN + & sv7-.-4 + = "Cat ", 10 + +sv7 = "Sys$$DateFormat", 0, VarType_String + ALIGN + & sv8-.-4 + + [ {TRUE} + = "%24:%mi:%se %dy-%m3-%ce%yr", 10 + | + = "%w3,%dy %m3 %ce%yr.%24:%mi:%se", 10 + ] + +sv8 = 0 + + ALIGN + +; Now the code for our system variables. + +ReadTimeVar + Push "lr" ; Subr to read hh:mm:ss from clock + BL ReadClock + ADD R0, R0, #16 + MOV R2, #8 + Pull "PC" +SetTimeVar ROUT + Push "R0, lr" + GSVarGetWSpace + ADD R12, R12, #GSNameBuff + MOV R11, #8 + STRB R11, [R12], #1 + MOV R10, #7 +01 LDRB R11, [R1, R10] + STRB R11, [R12, R10] + SUBS R10, R10, #1 + BPL %BT01 + SUB R1, R12, #1 + MOV R0, #15 + SWI XOS_Word + Pull "R0, PC" + +ReadYear + Push "lr" ; Subr to read yyyy from clock + BL ReadClock + ADD R0, R0, #11 + MOV R2, #4 + Pull "PC" +SetYear ROUT + MOV R2, #3 ; no chars -1 + MOV R4, #11 ; offset -1 +SetYD Push "R0-R2, lr" + BL ReadClock + MOV R10, #15 + STRB R10, [R0, #-1] + ADD R0, R0, R4 + LDR R1, [stack, #4] + LDR R2, [stack, #8] +01 LDRB R10, [R1, R2] + STRB R10, [R0, R2] + SUBS R2, R2, #1 + BPL %BT01 + SUB R1, R0, R4 + SUB R1, R1, #1 + MOV R0, #15 + SWI XOS_Word + Pull "R0-R2, PC" + +ReadClock + Push "lr" + GSVarGetWSpace ; Subr to read ddd, nn mmm from clock + ADD R1, R12, #GSNameBuff+1 + MOV R0, #0 + STRB R0, [R1] + MOV R0, #14 + SWI XOS_Word + MOV R0, R1 + MOV R2, #10 ; no. of chars. + Pull "PC" +SetDate MOV R2, #9 + MOV R4, #0 + B SetYD + +ReadRC ROUT + MOV R0, #0 + LDR R0, [R0, #ReturnCode] + B ReadNumSysVar +SetRC Push "lr" + BL SetNumSysVar + LDR R4, =ReturnCode + STR R2, [R4] + LDR R4, =RCLimit + LDR R4, [R4] + CMP R2, R4 + Pull "lr", LS + BICLSS PC, lr, #V_bit + ADRGT R0, ErrorBlock_RCExc + ADRLT R0, ErrorBlock_RCNegative + [ International + BL TranslateError + | + SETV + ] + Pull "PC" + MakeErrorBlock RCExc + MakeErrorBlock RCNegative + +ReadRCL MOV R0, #0 + LDR R0, [R0, #RCLimit] +ReadNumSysVar + Push "lr" + GSVarGetWSpace + ADD R1, R12, #GSNameBuff + MOV R2, #256 + SWI XOS_BinaryToDecimal + MOV R0, R1 + Pull "PC" +SetRCL Push "lr" + BL SetNumSysVar + LDR R4, =RCLimit + CMP R2, #0 ; can't set -ve RCLimit + RSBMIS R2, R2, #0 + MOVMI R2, #0 ; BIC of MININT + STR R2, [R4] + Pull "PC" + + LTORG + +SetNumSysVar ROUT ; R1 ptr to string, R2 string length + Push "lr" + SUBS R2, R2, #1 + ADDMI R2, R2, #1 ; give 0 in R2 for bad length. + Pull "PC", MI + LDR R12, =GSNameBuff+GSVarWSpace +03 LDRB R10, [R1], #1 ; copy into a buffer so we can terminate it. + STRB R10, [R12], #1 + SUBS R2, R2, #1 + BPL %BT03 + MOV R10, #13 + STRB R10, [R12], #1 + LDR R1, =GSNameBuff+GSVarWSpace + LDRB R10, [R1] + MOV R12, #0 + CMP R10, #"-" + MOVEQ R12, #-1 + CMPNE R10, #"+" + ADDEQ R1, R1, #1 + MOV R0, #0 + SWI XOS_ReadUnsigned + CMP R12, #0 + RSBMI R2, R2, #0 + Pull "PC" + + +;***************************************************************************** +; GSINIT, GSREAD, GSTRANS + +; To enable GSTrans nesting to stand a chance of working don't flatten the +; stack every FSINIT. Instead, pick up the stack pointer (any value is OK) +; and wrap at 255. Stack overflow occurs if you increment the pointer to +; where it started for this GSINIT, and stack underflow occurs if you +; decrement the pointer when it is currently equal to stack limit. +; The stack limit is held in the environment value, R2. +; The stack is empty ascending. + GBLL GS_BufferNotStack +GS_BufferNotStack SETL {TRUE} + +; some semi-arbitrary flags +GS_NoQuoteMess * 1 :SHL: 31 ; flags passed in from user +GS_NoVBarStuff * 1 :SHL: 30 +GS_Spc_term * 1 :SHL: 29 ; clear if user requested terminate on space +GS_In_String * 1 :SHL: 28 ; set if waiting for closing " +GS_ReadingString * 1 :SHL: 27 ; set if reading chars from a string var. +GS_Macroing * 1 :SHL: 26 ; set if reading chars from a macro + [ GS_BufferNotStack + ASSERT GS_StackPtr_Lim = &80 +GS_StackLimitBits * 7 +GS_StackLimitPos * 19 ; The bit position of the LSB of the byte + ; which holds the stack limit +; bits 0-18 hold the string length for string transfers + | +; bits 24-25 are unused +; bits 0-23 hold the string length for string transfers + ] + +; After GSINIT, R2 has these flags, and if expanding a count in the low byte + +GSINIT ROUT +; In : R0 pointer to string to expand +; R2 has flags : +; Bit 29 set means space is a terminator +; Bit 30 set means | characters will not be molested +; Bit 31 set means don't mess with quotes + +; Out : R0, R2 are values to pass back in to GSREAD +; R1 is the first non-blank character +; EQ means char is CR or LF, i.e. string is empty. + + ; Enable interupts as we've no right to have them disabled here + TEQP pc, #SVC_mode + + [ GS_BufferNotStack + AND R2, R2, #GS_NoQuoteMess :OR: GS_NoVBarStuff :OR: GS_Spc_term + ; get caller's flags + ] + +; If no tokens to expand then don't reset evaluation stack +; This prevents conflict with modules opening messages files at lower levels + + Push "r0" +10 LDRB r1, [r0], #1 + CMP r1, #13 + CMPNE r1, #10 + CMPNE r1, #0 + Pull "r0",EQ + BEQ %FT20 ; Jump if end of string, nothing to expand + + TEQ r1, #"<" ; Possibly something to expand? + BNE %BT10 ; No then try next + Pull "r0" + +; Expansion may be necessary so flatten evaluation stack + + [ GS_BufferNotStack + GSVarGetWSpace + LDRB R1, [R12, #GS_StackPtr] + AND R1, R1, #(GS_StackPtr_Lim-1) ; Ensure we remain in range + STRB R1, [R12, #GS_StackPtr] + ORR R2, R2, R1, LSL #GS_StackLimitPos + | + MOV R1, #0 + GSVarGetWSpace + STRB R1, [R12, #GS_StackPtr] ; no stacked R0s + ] + +20 + [ GS_BufferNotStack + | + AND R2, R2, #GS_NoQuoteMess :OR: GS_NoVBarStuff :OR: GS_Spc_term + ; get caller's flags + ] + EOR R2, R2, #GS_Spc_term ; and invert for convenience + +01 LDRB R1, [R0], #1 + CMP R1, #" " + BEQ %BT01 + TST R2, #GS_NoQuoteMess + CMPEQ R1, #"""" + SUBNE R0, R0, #1 ; dec if went too far + ORREQ R2, R2, #GS_In_String ; set flag if in string + CMP R1, #13 + CMPNE R1, #10 + CMPNE R1, #0 + ORREQ lr, lr, #Z_bit ; and move EQ/NE to return pc + BICNE lr, lr, #Z_bit + ExitSWIHandler + +; ----------------------------------------------------------------------------- + + +GSREAD ROUT +; In : R0, R2 from last GSREAD/GSINIT +; Out : R1 character, R0, R2 updated. +; VS => "Bad String" error +; CS => string ended (in which case R1 = terminator) + + ; enable interupts as (a) they'll get enabled by a <thing> entry + ; and (b) GSREAD may take some time + TEQP pc, #SVC_mode + + BIC lr, lr, #C_bit + MOV R10, #0 + TST R2, #GS_ReadingString + BNE GSREAD_RStringGetNextByte ; take byte from stringvar + +GSREAD_XPandGetNextByte + LDRB R1, [R0], #1 + CMP R1, #13 + CMPNE R1, #10 + CMPNE R1, #0 + BEQ GSREAD_XPandGotToEnd + CMP R1, #" " + BEQ GSREAD_XPandGotSpace + BLT GSREAD_BadStringError ; bad string : control code in string + CMP R1, #"""" + BEQ GSREAD_XPandGotQuote + CMP R1, #"|" + TSTEQ R2, #GS_NoVBarStuff + BEQ GSREAD_WorkOutBarChar + CMP R1, #"<" + BNE GSREAD_ReturnWithChar ; OS_Exit with valid character + +; got to try and get a variable value. + Push "R0, R2, lr" + LDRB R1, [R0] + CMP R1, #">" + CMPNE R1, #" " + BEQ GSREAD_AngleBraDaftSoIsnt ; <> and < > are silly. + + ; Copy angle bracketed thing checking for correct termination + GSVarGetWSpace + ADD R12, R12, #GSNameBuff + MOV R11, #0 +20 LDRB R1, [R0], #1 + STRB R1, [R12], #1 + ADD R11, R11, #1 + CMP R11, #255 + CMPNE R1, #13 + CMPNE R1, #10 + CMPNE R1, #0 + BEQ GSREAD_AngleBraDaftSoIsnt + CMP R1, #">" + BNE %BT20 + + ; Check for number first + MOV R1, #0 + STRB R1, [R12, #-1] ; terminate it + SUB R1, R12, R11 ; pointer to name or number + Push "R0" + SWI XOS_ReadUnsigned ; check for number + Pull "R0" + BVS GSREAD_AngledThingAintNumber ; silly - has to be name + LDRB R1, [R1] ; check terminated by the null + CMP R1, #0 + BNE GSREAD_AngledThingAintNumber + MOV R1, R2 ; character value + ADD stack, stack, #4 ; discard old R0 value. + Pull "R2, lr" + B GSREAD_ReturnWithChar ; exit-R1's the char value. + +GSREAD_AngledThingAintNumber + ; R0, R2, lr on stack + Push "R0, R3, R4, R10" ; corrupted by VarFindIt + MOV R3, #0 ; context ptr + SUB R0, R12, R11 ; name ptr + BL VarFindIt + Pull "R0, R3, R4, R10", EQ ; not found mate + BEQ GSREAD_AngledThingNotThere ; return null expansion +; well, we've found it - better stack old R0 + Pull "R0" + GSVarGetWSpace + [ GS_BufferNotStack + LDRB r1, [r12, #GS_StackPtr] + LDR r2, [sp, #4*4] ; r3,r4,r10,r0,r2,lr on stack, hence r2 retrieved + MOV r2, r2, ASL #32-(GS_StackLimitPos+GS_StackLimitBits) + SUB r2, r2, #1:SHL:(32-GS_StackLimitBits) + TEQ r1, r2, LSR #32-GS_StackLimitBits + BEQ GSREAD_CantNestMore + | + LDRB R1, [R12, #GS_StackPtr] + CMP R1, #GS_StackPtr_Lim + BHS GSREAD_CantNestMore + ] + ADD R12, R12, #GS_Stack + STR R0, [R12, R1, LSL #2] + ADD R1, R1, #1 + [ GS_BufferNotStack + AND R1, R1, #(GS_StackPtr_Lim-1) + ] + STRB R1, [R12, #GS_StackPtr-GS_Stack] + MOV R0, R4 + LDRB R1, [R0], #1 ; type + CMP R1, #VarType_Code + BEQ GSREAD_CallCodeVar + CMP R1, #VarType_Number + LDRB R1, [R0], #1 + + [ LongVars + LDRB R3, [R0], #1 + ORR R1, R1, R3, LSL #8 + LDRB R3, [R0], #1 + ORR R1, R1, R3, LSL #16 + + BLO GSREAD_GotVarAsString + BHI GSREAD_GotMacroVar + | + BLO GSREAD_GotVarAsString + BHI GSREAD_GotMacroVar + + ; Got number var + LDRB R3, [R0], #1 ; number - build value + ORR R1, R1, R3, LSL #8 + LDRB R3, [R0], #1 + ORR R1, R1, R3, LSL #16 + ] + LDRB R3, [R0], #1 + ORR R1, R1, R3, LSL #24 + MOV R0, R1 + ADD R1, R12, #GSNameBuff-GS_Stack + MOV R2, #256 + SWI XOS_BinaryToDecimal + MOV R0, R1 + MOV R1, R2 + +; it's a string variable, by now. +GSREAD_GotVarAsString + Pull "R3, R4, R10" + ADD stack, stack, #4 ; discard that R0 + Pull "R2, lr" + CMP R1, #0 + BEQ ZeroLengthVar + ORR R2, R2, R1 ; old flags+new count + ORR R2, R2, #GS_ReadingString + LDRB R1, [R0], #1 + B GSREAD_ReturnWithChar + +GSREAD_GotMacroVar + ; Macro - R0 is now the ptr to the macro value. + Pull "R3, R4, R10" + ADD stack, stack, #4 + Pull "R2, lr" + ORR R2, R2, #GS_Macroing + B GSREAD_XPandGetNextByte ; loop, transforming chars. + +GSREAD_CantNestMore + Pull "R3, R4, R10" ; no room to stack pointer, so don't expand +GSREAD_AngledThingNotThere + ADD stack, stack, #4 ; skip R0 - return null string + Pull "R2, lr" + B GSREAD_XPandGetNextByte ; get next char + +GSREAD_AngleBraDaftSoIsnt + Pull "R0, R2, lr" + MOV R1, #"<" + B GSREAD_ReturnWithChar ; failed to get sensible variable + +GSREAD_XPandGotToEnd + TST R2, #GS_In_String ; got CR or LF + BNE GSREAD_BadStringError ; bad string + TST R2, #GS_Macroing +GSREAD_GotToAnEnd + ORREQ lr, lr, #C_bit ; got terminator + ExitSWIHandler EQ + + ; Nest out by one level + GSVarGetWSpace + LDRB R11, [R12, #GS_StackPtr] + [ GS_BufferNotStack + SUB R11, R11, #1 + AND R11, R11, #(GS_StackPtr_Lim-1) + MOV r2, r2, ROR #GS_StackLimitPos+GS_StackLimitBits + TEQ r11, r2, LSR #32-GS_StackLimitBits + MOV r2, r2, ROR #32-(GS_StackLimitPos+GS_StackLimitBits) + | + SUBS R11, R11, #1 + ] + BICEQ R2, R2, #GS_Macroing + STRB R11, [R12, #GS_StackPtr] + ADD R12, R12, #GS_Stack + LDR R0, [R12, R11, LSL #2] + B GSREAD_XPandGetNextByte ; return to prevstring + +GSREAD_XPandGotSpace + TST R2, #(GS_In_String :OR: GS_Spc_term :OR: GS_Macroing) + ; got space : check termination + BEQ GSREAD_GotToAnEnd ; terminates + +GSREAD_ReturnWithChar + ORR R1, R1, R10 ; valid character + ExitSWIHandler + +GSREAD_XPandGotQuote + TST R2, #GS_In_String + BEQ GSREAD_ReturnWithChar ; if not in string, " is valid. + LDRB R1, [R0], #1 + CMP R1, #"""" ; "" in string? + BEQ GSREAD_ReturnWithChar ; yup + + [ Fix16 + +; TMD 25-Sep-89: Fix termination here + +10 + CMP R1, #" " + LDREQB R1, [R0], #1 + BEQ %BT10 + SUB R0, R0, #1 + | + +10 LDRB R1, [R0], #1 + CMP R1, #" " + BEQ %BT10 + ] + ORR lr, lr, #C_bit ; got terminator (second ") + ExitSWIHandler ; and out + +GSREAD_WorkOutBarChar + LDRB R1, [R0], #1 ; got |, do traditional escaping + CMP R1, #"|" + CMPNE R1, #"""" + CMPNE R1, #"<" + BEQ GSREAD_ReturnWithChar ; || gives |, |" gives ", |< gives < + CMP R1, #"?" + MOVEQ R1, #&7F ; delete + BEQ GSREAD_ReturnWithChar ; valid ch + CMP R1, #"!" + MOVEQ R10, #&80 + BEQ GSREAD_XPandGetNextByte ; tbs char + CMP R1, #" " + BLT GSREAD_BadStringError ; OS_Control character is naff + CMP R1, #&7F ; CTRL-delete is delete + EORGT R1, R1, #&20 ; softkey + BGE GSREAD_ReturnWithChar ; now valid ch + CMP R1, #"`" ; CTRL-` = CTRL-_ + MOVEQ R1, #"_" + CMP R1, #"@" + ANDGE R1, R1, #&1F ; transform if @<=ch<delete + B GSREAD_ReturnWithChar + +GSREAD_RStringGetNextByte + SUB R2, R2, #1 ; we're reading a string + [ LongVars + [ GS_BufferNotStack + MOVS R12, R2, ASL #32-GS_StackLimitPos + | + ANDS r12, r2, #&00ffffff + ] + | + TST R2, #&FF + ] + LDRNEB R1, [R0], #1 ; and this is already expanded + ExitSWIHandler NE ; so finished +ZeroLengthVar + GSVarGetWSpace + LDRB R0, [R12, #GS_StackPtr] ; pull an R0 from our stack + SUB R0, R0, #1 + [ GS_BufferNotStack + AND R0, R0, #(GS_StackPtr_Lim-1) + ] + STRB R0, [R12, #GS_StackPtr] + ADD R12, R12, #GS_Stack + LDR R0, [R12, R0, LSL #2] + BIC R2, R2, #GS_ReadingString + B GSREAD_XPandGetNextByte + +GSREAD_BadStringError + ADR R0, BadStrErr + [ International + Push "lr" + BL TranslateError + Pull "lr" + ] + ORR lr, lr, #V_bit :OR: C_bit + ExitSWIHandler + +BadStrErr + MakeErrorBlock BadString + +GSREAD_CallCodeVar + ADD R0, R0, #3 + 4 ; 3 to ALIGN, 4 to get to read entry + MOV lr, PC ; get link + BIC PC, R0, #3 ; call entrypoint to Read Thunk + MOV R1, R2 + B GSREAD_GotVarAsString + +; --------------------------------------------------------------------------- + + +GSTRANS ROUT ; enables interrupts +; In : R0 ptr to input string + ; R1 ptr to Out buffer + ; R2 max number of chars, with flags at top. + +; Out : R0 points at terminator + ; R1 unchanged + ; R2 Number of chars got, + ; C set if too many chars + ; V set if bad string. + + BIC lr, lr, #C_bit + Push "R1, R3-R5, lr" + TEQP PC, #SVC_mode ; enable ints. + + MOV R3, R1 + MOV R4, R1 ; two copies of start ptr + BIC R5, R2, #&E0000000 + ADD R5, R5, R1 ; 1st byte we can't write to. + SWI XOS_GSInit +01 CMP R3, R5 + BGE %FT03 ; no rheum for byte. + SWI XOS_GSRead + BVS %FT02 ; bad string + STRB R1, [R3], #1 + BCC %BT01 +04 SUB R2, R3, R4 ; no chars got + SUB R2, R2, #1 + Pull "R1, R3-R5, lr" + ExitSWIHandler + +02 SUB R2, R3, R4 + Pull "R1, R3-R5, lr" + B SLVK_SetV ; bad string: error set by GSRead + +03 SUB R2, R3, R4 + Pull "R1, R3-R5, lr" + ORR lr, lr, #C_bit ; buffer overflow + ExitSWIHandler + +;**************************************************************************** +; Read/Write variables +; Also the binary->decimal SWI. +; All the var SWIs enable interrupts - they all take quite a while. + +; Variable storage format is dead simple - linear list! +; It's not even ordered in any fashion. +; List has fixed section of system vars that cannot die. + +; Node format : Link, Name bytes, 0 terminator (so Write0able), type byte, +; then 4 bytes for numeric +; or length byte, value bytes for string/macro. +; then a CR if it's a macro variable. + + [ QuickIndex +VNameOff * 0 + | +VarLink * 0 +VNameOff * 4 + ] + +; First the lookup SWI, ReadVarValue +; In: +; R0 -> name; maybe wildcarded (* and #) +; R1 -> buffer +; R2 = buffer max length +; R3 = 0 or pointer to name returned from previous ReadVarVal +; R4 = VarType_Expanded or something else + +; Out: +; Not found: +; R0 -> VarCantFind error +; R1 unaltered +; R2 = 0 +; R3,r4 trashed +; VSet +; Found, r2 < 0 and r4 <> VarType_Expanded on entry: +; R0, R1 unaltered +; R2 = NOT length of value +; R3 -> name of variable (0-terminated) +; R4 = type of result +; Found, r2 < 0 and r4 = VarType_Expanded on entry: +; R0, R1 unaltered +; R2 = -ve +; R3 -> name of variable (0-terminated) +; R4 = type of result +; Found, r2 >= 0 on entry: +; R0, R1 unaltered +; R2 no chars got +; R3 -> name of variable. Can be passed to this SWI to continue enumeration +; of wildcard. +; R4 type of result (VarType_String, VarType_Number, VarType_Macro) +; VSet if buffer overflowed (R0->error block) + +ReadVarValue ROUT + TEQP PC, #SVC_mode ; enable interupts (mode remains unchanged) + Entry "r0,r1" + + MOV r11, r4 + + BL VarFindIt ; name=r0,context=r3 -> name found in node=r3,r4=after namein,r12=prev + BEQ RVVNotFound + + ; Regardless of expanded or not - always call the code to get value + LDRB lr, [r4], #1 + TEQ lr, #VarType_Code + BEQ ReadVarVal_CallCode + + ; Check whether expanded value wanted and pick up found variable's type + TEQ r11, #VarType_Expanded + MOV r11, r4 + MOV r4, lr + BEQ ReadVarVal_ExpandedWanted + + ; Unexpanded value wanted.... + + ; If number then want 4 bytes, else however many there are in the varval + TEQ r4, #VarType_Number + MOVEQ r10, #4 + +ReadVarVal_CopyStringVarToUserBuffer + ; R1 -> user buffer + ; R2 = user buffer size + ; R3 -> name of sysvar found + ; R4 = sysvar type to return + ; R10 = length to transfer to user buffer (EQ only) + ; R11 -> length byte(s) of sysvar (NE only) + ; -> bytes string to transfer (EQ only) + [ LongVars + LDRNEB r10, [r11], #1 + LDRNEB lr, [r11], #1 + ORRNE r10, r10, lr, ASL #8 + LDRNEB lr, [r11], #1 + ORRNE r10, r10, lr, ASL #16 + | + LDRNEB r10, [r11], #1 + ] + +ReadVarVal_CopyR10BytesToUserBuffer + ; R1 -> user buffer + ; R2 = user buffer size + ; R3 -> name of sysvar found + ; R4 = type byte to be returned + ; R10 = bytes to be copied + ; R11 -> bytes to be copied + + CMP R10, R2 + BGT ReadVarVal_BufWillOFlow + +VarNoOFlo + ; Guaranteed the the buffer won't overflow now + MOV R2, R10 ; bytes he's gonna get +; now copy R10 bytes into buffer +02 SUBS R10, R10, #1 + LDRPLB R12, [R11, R10] + STRPLB R12, [R1, R10] + BPL %BT02 + +ReadVarVal_OKExit + PullEnv + ExitSWIHandler + +ReadVarVal_BufWillOFlow + ; Have determined that the buffer will overflow, so generate an error + ; and shorten down to the buffer's size + ADR r0, BufferOFloError + [ International + BL TranslateError + ] + STR r0, [stack, #Proc_LocalStack + 0*4] + LDR lr, [stack, #Proc_LocalStack + 2*4] + ORR lr, lr, #V_bit ; set for return + STR lr, [stack, #Proc_LocalStack + 2*4] + + ; ensure NOT length returned in r2 when returning with r2<0 on entry + CMP r2, #0 + MVNMI r10, r10 + MOVPL r10, r2 + B VarNoOFlo + +BufferOFloError + MakeErrorBlock BuffOverflow + +ReadVarVal_CallCode + Push "r0-r2" ; read sysvar : r4 points after type + ADD r11, r4, #3 + 4 ; 3 to align and 4 to get to read entry + MOV lr, pc ; construct link + BIC pc, r11, #3 ; call read code in var + MOV r11, r0 ; ptr to value + MOV r10, r2 ; no of chars. + Pull "r0-r2" + + ; error may be returned from reading the var val + MOVVS r0, r11 + BVS ReadVarVal_TestVExit + + MOV r4, #VarType_String + B ReadVarVal_CopyR10BytesToUserBuffer + +ReadVarVal_ExpandedWanted + ; Request for expanded value.... + + ; Check for number, string or macro + CMP R4, #VarType_Number + BLT ReadVarVal_CopyStringVarToUserBuffer + BEQ ReadVarVal_FoundNumber + +; macro - gstrans it. R1 buffer ptr, r2 max chars, R11+1 ptr to value. +; Macros have a terminator after their value, to allow GSTRANS. + + CMP r2, #0 ; if negative, then don't call GSTrans because bits 29..31 have + MVNMI r10, r2 ; return r2 out by this method + BMI ReadVarVal_BufWillOFlow ; a special meaning - just branch back to the normal overflow code + + [ LongVars + ADD r0, r11, #3 ; skip length + | + ADD r0, r11, #1 ; skip length + ] + SWI XOS_GSTrans + BVS ReadVarVal_TestVExit + BCC ReadVarVal_OKExit + + ADR R0, BufferOFloError + [ International + BL TranslateError + ] + B ReadVarVal_SetVExit + + +ReadVarVal_FoundNumber + ; Found a number - extract its value and convert to string + LDRB R0, [R11], #1 ; number - convert to string. + LDRB R12, [R11], #1 + ORR R0, R0, R12, LSL #8 + LDRB R12, [R11], #1 + ORR R0, R0, R12, LSL #16 + LDRB R12, [R11] + ORR R0, R0, R12, LSL #24 + + ; got number in R0, buffptr in R1, max chars in R2 + SWI XOS_BinaryToDecimal + + MOV r4, #VarType_String + +ReadVarVal_TestVExit + STRVS r0, [stack, #Proc_LocalStack + 0*4] + PullEnv + B SLVK_TestV + +RVVNotFound + [ International + MOV r4, r0 + ADR r0, RVVNFError + BL TranslateError_UseR4 + | + ADR R0, RVVNFError + ] + MOV r2, #0 ; indicate not found. + +ReadVarVal_SetVExit + STR r0, [stack, #Proc_LocalStack + 0*4] + PullEnv + B SLVK_SetV ; general error return + +RVVNFError + MakeErrorBlock VarCantFind + +;*************************************************************************** + +; The convert number to string SWI +; In : R0 signed 32-bit integer +; R1 pointer to buffer +; R2 max buffer length +; Out : R0, R1 unmodified +; R2 actual chars given +; V Set if buffer overflow + +; Format : - if negative, leading zeros stripped. + +CvtToDecimal ROUT + Push "R0, R3-R5" + MOV R12, R2 + MOV R2, #0 + CMP R0, #0 + BPL %FT01 + SUBS R12, R12, #1 + BMI %FT10 + MOV R11, #"-" + STRB R11, [R1] + MOV R2, #1 + RSB R0, R0, #0 + +; now do digits. + +01 RSB R0, R0, #0 ; get negative so minint works. + ADR R3, TenTimesTable + MOV R10, #9 ; max entry + MOV R4, #0 ; non-0 had flag +02 LDR R11, [R3, R10, LSL #2] + MOV R5, #-1 ; digit value +03 ADDS R0, R0, R11 + ADD R5, R5, #1 + BLE %BT03 + SUB R0, R0, R11 + CMP R5, #0 + CMPEQ R4, #0 + BNE %FT04 ; put digit +05 SUBS R10, R10, #1 + BPL %BT02 ; next digit + CMP R4, #0 + BEQ %FT04 ; R5 must be 0 + Pull "R0, R3-R5" + ExitSWIHandler + +04 SUBS R12, R12, #1 + BMI %FT10 ; naff Exit + ADD R5, R5, #"0" + MOV R4, #-1 + STRB R5, [R1, R2] + ADD R2, R2, #1 + B %BT05 +10 + ADR R0, BufferOFloError + [ International + Push "lr" + BL TranslateError + Pull "lr" + ] + Pull "R3" ; discard R0 in + Pull "R3-R5" + B SLVK_SetV + +TenTimesTable + & 1 + & 10 + & 100 + & 1000 + & 10000 + & 100000 + & 1000000 + & 10000000 + & 100000000 + & 1000000000 + +; ***************************************************************************** +; SWI OS_SetVarVal : create/update/destroy a variable. + +; In: R0 pointer to name (can be wildcarded for update/delete) +; ctrl/char or space terminated +; R1 pointer to value. String values must be CR or LF terminated. +; R2 negative means destroy the variable. +ve is update/create +; R3 name pointer or 0 +; R4 type. +; +; Evaluation of value : this depends on the type. +; VarType_String : GSTRANS the given value +; VarType_Number : Value is a 4 byte (signed) integer +; VarType_Macro : Copy value (may be GSTRANSed on use) +; VarType_Expanded : the value is a string which should be evaluated as an +; expression. Variable is then numeric or string +; VarType_LiteralString : Copy the given value as a string +; +; VarType_Code : R2 is the length of the code to copy in, including +; padding to align the code. +; Can only delete sysvars if R4 = VarType_Code + +; Out: R3 new name pointer (so can delete all occurrences of f*, etc. +; slightly more efficiently). +; R4 type created for expressions +; V set for : +; 1) bad name (creation of wildcarded names is banned) +; 2) Bad string from GSTRANS +; 3) Bad macro value (control codes not allowed) +; 4) Bad expression from ReadExpression +; 5) Can't find (for deletion) +; 6) Not enough room to create/update it (system heap full) +; 7) Value too long (variables are limited to 256 bytes in length) +; 8) Bad type (update/create) + + + [ LongVars + [ DebugSysVars +SysVar_Write0 Entry "r0,r1" + MOV r1, r0 +10 + LDRB r0, [r1], #1 + CMP r0, #" " + EXIT LO + SWI XOS_WriteC + B %BT10 + + ] + +SetVarValue + ; enable IRQs + TEQP pc, #SVC_mode + + Entry "r0,r1,r2,r4,r5,r6,r9" + + [ DebugSysVars + SWI XOS_WriteS + = "SetVarVal ",0 + BL SysVar_Write0 + SWI XOS_NewLine + ] + + MOV r9, stack + MOV r10, r4 + + CMP r2, #0 + BMI SetVarVal_DeleteIt + + ; Range check type + CMP r10, #VarType_Code + CMPNE r10, #VarType_LiteralString + ADRHIL r0, ErrorBlock_BadVarType + BHI SetVarValBadExit_Translate + + ; Always expand a VarType_Expanded: + TEQ r10, #VarType_Expanded + BNE SetVarVal_AintExpanded + + ; Process VarType_Expanded + SUB stack, stack, #256 + + MOV r0, r1 ; ptr to expression + MOV r1, stack + MOV r2, #256 + SWI XOS_EvaluateExpression + BVS SetVarVal_TestVExit + TEQ r1, #0 ; integer? + MOVNE r10, #VarType_LiteralString + MOVEQ r10, #VarType_Number + STREQ r2, [stack] + MOVEQ r2, #4 + STR r10, [r9, #3*4] ; r4 out + MOV r1, stack + LDR r0, [r9, #0*4] + +SetVarVal_AintExpanded + + ; Setting a variable + BL VarFindIt + BNE SetVarVal_NodeAlreadyExists + + ; Node missing.... + + ; Check variable name has no wildcards + SUB r4, r0, #1 +05 + LDRB lr, [r4, #1]! + CMP lr, #"#" + CMPNE lr, #"*" + CMPNE lr, #" " + BHI %BT05 + CMP lr, #"#" + CMPNE lr, #"*" + CMPNE r4, r0 + ADREQL r0, ErrorBlock_BadVarNam + BEQ SetVarValBadExit_Translate ; error no. 1) + + [ QuickIndex + ; R12 index of 1st entry in QuickIndex >= the entry we're interested in + | + ; Variable name OK, find where in list we want to insert it + + LDR r12, =VariableList + LDR r11, [r12] + CMP r11, #0 + B %FT08 + +06 + MOV r3, r0 + ADD r4, r11, #VNameOff +07 + LDRB r5, [r3], #1 + LDRB r6, [r4], #1 + CMP r5, r6 ; can't hit terminator : + BEQ %BT07 ; not same as any on list + MOVHI r12, r11 + LDRHI r11, [r12, #VarLink] + CMPHI r11, #0 +08 + BHI %BT06 + + ; r12 now ready as pointer to prev + ] + MOV r3, #0 ; To indicate absence of current + B SetVarVal_CreateNode + +SetVarVal_NodeAlreadyExists + MOV r0, r3 ; If already there use that's name in case supplied name wildcarded + LDRB lr, [r4] + TEQ lr, #VarType_Code + BNE SetVarVal_CreateNode + TEQ r10, #VarType_Code + BEQ SetVarVal_CreateNode + + ; Assign non code value to code node + CMP r10, #VarType_Number + BHI SetVarVal_AssignToCodeDoIt + + ; For both string and number give ourselves a stack frame + SUB stack, stack, #256 + MOV r2, #256 + + BLO SetVarVal_AssignStringToCode + + ; Assign a number to the code variable + LDRB r0, [r1], #1 + LDRB lr, [r1], #1 + ORR r0, r0, lr, LSL #8 + LDRB lr, [r1], #1 + ORR r0, r0, lr, LSL #16 + LDRB lr, [r1], #1 + ORR r0, r0, lr, LSL #24 + MOV r1, stack + SWI XOS_BinaryToDecimal + + B SetVarVal_AssignToCodeDoIt + +SetVarVal_AssignStringToCode + + ; Expand string to stack frame then do it + MOV r0, r1 + MOV r1, stack + SWI XOS_GSTrans + BVS SetVarVal_TestVExit + ADRCSL r0, ErrorBlock_VarTooLong + BCS SetVarValBadExit_Translate + +SetVarVal_AssignToCodeDoIt + + ADDS r4, r4, #3 + 1 ; skip type, add 3 for ALIGN , clear V + MOV lr, PC + BIC PC, R4, #3 ; complete align and call + + B SetVarVal_TestVExit + + +SetVarVal_CreateNode + ; Create a node + ; + ; r0 -> name (already confirmed non-wildcarded) + ; r1 -> value + ; r2 = length (where appropriate) + ; r3 = this or 0 + ; r10 = type + [ QuickIndex + ; r12 = insertion point + | + ; r12 = prev + ] + + MOV r5, r1 + MOV r6, r3 + + ; first work out the length of those things we can work the length of + + ; Header and name... + MOV r3, #VNameOff + 1 ; Add one for the type byte + MOV r1, r0 +10 + LDRB lr, [r1], #1 + ADD r3, r3, #1 + CMP lr, #" " + BHI %BT10 + + ; Deal with number and string type + CMP r10, #VarType_Number + ADDLO r3, r3, #50 ; only an initial guess for the string type + ADDEQ r3, r3, #4 + MOVEQ r2, #4 + BLS SetVarVal_GotInitialLength + + CMP r10, #VarType_Code + ADDEQ r3, r3, #3 ; ALIGN + BICEQ r3, r3, #3 + ADDEQ r3, r3, r2 ; code + BEQ SetVarVal_GotInitialLength + + TEQ r10, #VarType_LiteralString + BEQ %FT20 + + ; Macro - strlen and check the value is vaguely OK + MOV r2, r5 +15 + LDRB lr, [r2], #1 + CMP lr, #" " + BHS %BT15 + TEQ lr, #0 ; must terminate with NUL, CR or LF + TEQNE lr, #10 + TEQNE lr, #13 + ADRNE r0, ErrorBlock_BadMacVal + BNE SetVarValBadExit_Translate + SUB r2, r2, r5 +20 + ADD r3, r3, r2 + ADD r3, r3, #3 ; for the length bytes + +SetVarVal_GotInitialLength + ; r0 -> node's name + ; r2 = value length (Number, Macro and Code) + ; r3 = node length needed (maybe initial guess for Strings) + ; r5 -> value (r1 in) + ; r6 -> name of node to be replaced (0 if no node being replaced) + ; r10 = value's type (String, Number, Macro or Code) + [ QuickIndex + ; r12 -> insertion point + | + ; r12 -> prev node + ] + + Push "r0,r2" + BL ClaimSysHeapNode + BVS SetVarVal_VarNoRoom + Pull "r0,r1" + + ; Got a heap block - fill it in + + ; Copy name + ADD r4, r2, #VNameOff +25 + LDRB lr, [r0], #1 + CMP lr, #" " + MOVLS lr, #0 + STRB lr, [r4], #1 + BHI %BT25 + + ; Variable's type + TEQ r10, #VarType_LiteralString + MOVEQ lr, #VarType_String + MOVNE lr, r10 + STRB lr, [r4], #1 + + TEQ r10, #VarType_String + BEQ SetVarVal_FillInString + + TEQ r10, #VarType_Code + ADDEQ r4, r4, #3 + BICEQ r4, r4, #3 + TEQNE r10, #VarType_Number + BEQ SetVarVal_CopyR1BytesToR4 + + ; For macro type fill in a length + TEQ r10, #VarType_Macro + SUBEQ r1, r1, #1 ; ghastly fudge to avoid display of terminator + STRB r1, [r4], #1 + MOV r1, r1, ROR #8 + STRB r1, [r4], #1 + MOV r1, r1, ROR #8 + STRB r1, [r4], #1 + MOV r1, r1, ROR #16 + ADDEQ r1, r1, #1 ; undo ghastly fudge + +SetVarVal_CopyR1BytesToR4 + B %FT35 +30 + LDRB lr, [r5], #1 + STRB lr, [r4], #1 +35 + SUBS r1, r1, #1 + BHS %BT30 + + B SetVarVal_NewNodeReady + +SetVarVal_FillInString + ; Here's the real smart bit of code + + ; The idea is this: + ; Instead of GSTransing, we GSInit and GSRead ourselves. When the + ; block gets full expand it and carry on. At the end the block is shrunk to fit. + + ADD r4, r4, #3 ; for the length bytes + MOV r11, r4 ; preserve location of string start for when we've done + MOV r0, r5 ; r1 in + MOV r5, r2 + MOV r2, #0 + SWI XOS_GSInit + BVS SetVarVal_DisasterExpandingString + B %FT45 + +40 + SWI XOS_GSRead + BVS SetVarVal_DisasterExpandingBadString + BCS SetVarVal_StringFinishedExpanding + STRB r1, [r4], #1 + CMP r4, r3 + BLO %BT40 + + ; Run out of room in this block - stretch it + Push "r0-r2" + MOV r0, #HeapReason_ExtendBlock + MOV r2, r5 + MOV r3, #64 + BL DoSysHeapOpWithExtension + STRVS r0, [sp] + SUBVC lr, r2, r5 + ADDVC r4, r4, lr + ADDVC r11, r11, lr + MOVVC r5, r2 + Pull "r0-r2" + BVS SetVarVal_DisasterExpandingString + +45 + LDR r3, [r5, #-4] ; The heap block's size + SUB r3, r3, #4 ; the amount we're allowed to use + ADD r3, r3, r5 ; the block's end + B %BT40 + +SetVarVal_StringFinishedExpanding + + ; Shorten block to required size + MOV r0, #HeapReason_ExtendBlock + SUB r3, r4, r3 + MOV r2, r5 + BL DoSysHeapOpWithExtension + BVS SetVarVal_DisasterExpandingString + + ; Relocate pointers + SUB lr, r2, r5 + ADD r4, r4, lr + ADD r11, r11, lr + + ; Work out ultimate size and store it + SUB lr, r4, r11 + STRB lr, [r11, #-3] + MOV lr, lr, LSR #8 + STRB lr, [r11, #-2] + MOV lr, lr, LSR #8 + STRB lr, [r11, #-1] + +SetVarVal_NewNodeReady + ; r2 -> new node + ; r6 -> old node's name (or is 0 if no old node) + [ QuickIndex + ; r12 = insertion point + | + ; r12 -> prevP + ] + + [ DebugSysVars + Push "r0,r1,r2" + SUB sp, sp, #12 + MOV r0, r2 + MOV r1, sp + MOV r2, #12 + SWI XOS_ConvertHex8 + SWI XOS_Write0 + SWI XOS_WriteI+" " + MOV r0, r6 + MOV r1, sp + MOV r2, #12 + SWI XOS_ConvertHex8 + SWI XOS_Write0 + SWI XOS_WriteI+" " + MOV r0, r12 + MOV r1, sp + MOV r2, #12 + SWI XOS_ConvertHex8 + SWI XOS_Write0 + SWI XOS_WriteI+" " + ADD sp, sp, #12 + Pull "r0,r1,r2" + ] + [ QuickIndex + LDR r11, =VariableList + LDR r10, [r11] + MOV r5, r2 + TEQ r6, #0 + BEQ SetVarVal_Insertion + + [ DebugSysVars + SWI XOS_WriteS + = "-straight replace-",0 + ] + + SUB r2, r6, #VNameOff + BL FreeSysHeapNode + B SetVarVal_Replace + +SetVarVal_Insertion + [ DebugSysVars + SWI XOS_WriteS + = "-insert-",0 + ] + TEQ r10, #0 + BNE SetVarVal_PossibleExtend + + [ DebugSysVars + SWI XOS_WriteS + = "-create index-",0 + ] + MOV r3, #44 ; 10 nodes and 1 for the count + BL ClaimSysHeapNode + BVS SetVarVal_NoRoomForIndex + MOV r10, r2 + MOV r4, #0 + B SetVarVal_DoInsertNewBlock + +SetVarVal_PossibleExtend + [ DebugSysVars + SWI XOS_WriteS + = "-extend index-",0 + ] + LDR r4, [r10] + LDR lr, [r10, #-4] ; Block length + SUB lr, lr, #4+4 ; 4 for heap adjustment and 4 for entry count word + CMP lr, r4, ASL #2 + BHI SetVarVal_DoInsert ; we've got room with this block + + [ DebugSysVars + SWI XOS_WriteS + = "-do extend-",0 + ] + + MOV r0, #HeapReason_ExtendBlock + MOV r2, r10 + MOV r3, #40 ; room for 10 more nodes + BL DoSysHeapOpWithExtension + BVS SetVarVal_NoRoomForIndex + + MOV r10, r2 + +SetVarVal_DoInsertNewBlock + STR r10, [r11] +SetVarVal_DoInsert + [ DebugSysVars + SWI XOS_WriteS + = "-doinsert-",0 + ] + ADD r0, r10, r12, ASL #2 ; insertion point + ADD r1, r10, r4, ASL #2 ; rover + B SetVarVal_DoInsertEnd + +SetVarVal_DoInsertStart + LDR lr, [r1], #-4 + STR lr, [r1, #8] + +SetVarVal_DoInsertEnd + CMP r1, r0 + BHS SetVarVal_DoInsertStart + + ADD r4, r4, #1 + STR r4, [r10] + +SetVarVal_Replace + [ DebugSysVars + SWI XOS_WriteS + = "-doreplace-",0 + ] + STR r5, [r10, r12, ASL #2] + [ DebugSysVars + SWI XOS_WriteS + = "-done-",0 + ] + | + ; Remove old node and place new node in its place + TEQ r6, #0 + LDRNE lr, [r6, #-VNameOff] + LDREQ lr, [r12] + STR lr, [r2] + STR r2, [r12] + + ; If old node present then junk it + SUBNE r2, r6, #VNameOff + BLNE FreeSysHeapNode + ] + + ; All done + B SetVarVal_TestVExit + +SetVarVal_DeleteIt + BL VarFindIt + + ; Error if not found + ADREQL r0, ErrorBlock_VarCantFind ; V set no. 1) + BEQ SetVarValBadExit_Translate + + ; Check if found vartype code that the supplied vartype was code too + LDRB lr, [r4] + TEQ lr, #VarType_Code + BNE %FT80 + + TEQ r10, #VarType_Code + BNE SetVarVal_TestVExit +80 + [ QuickIndex + LDR r11, =VariableList + LDR r10, [r11] + LDR r4, [r10] + ADD r0, r10, r12, ASL #2 ; rover + ADD r1, r10, r4, ASL #2 ; end + B SetVarVal_DoRemoveEnd +SetVarVal_DoRemoveStart + LDR lr, [r0, #4]! + STR lr, [r0, #-4] +SetVarVal_DoRemoveEnd + CMP r0, r1 + BLO SetVarVal_DoRemoveStart + SUB r2, r3, #VNameOff + BL FreeSysHeapNode + + ; Reduce number of nodes + SUB r4, r4, #1 + STR r4, [r10] + + ; Construct best guess context ptr to be prev node (if present) + TEQ r12, #1 + SUBHI r12, r12, #1 + ASSERT VNameOff = 0 + LDRHI r3, [r10, r12, ASL #2] + MOVLS r3, #0 + + | + ; Unlink node from chain + SUB r3, r3, #VNameOff + LDR r11, [r3, #VarLink] + STR r11, [r12, #VarLink] + MOV R2, R3 ; node ptr. + BL FreeSysHeapNode + ADD R3, R12, #VNameOff ; our best guess at a context ptr + ] + +SetVarVal_TestVExit + MOV stack, r9 + STRVS r0, [stack] + PullEnv + B SLVK_TestV + +SetVarValBadExit_Translate + BL TranslateError + SETV + B SetVarVal_TestVExit + +SetVarVal_DisasterExpandingString +SetVarVal_NoRoomForIndex + MOV r2, r5 + BL FreeSysHeapNode +SetVarVal_VarNoRoom + ADR r0, ErrorBlock_VarNoRoom + B SetVarValBadExit_Translate + +SetVarVal_DisasterExpandingBadString + Push "r0" ; Save bad string error + MOV r2, r5 + BL FreeSysHeapNode + Pull "r0" + SETV + B SetVarVal_TestVExit + + MakeErrorBlock BadVarType + MakeErrorBlock BadVarNam + MakeErrorBlock VarTooLong + MakeErrorBlock BadMacVal + MakeErrorBlock VarNoRoom + + | +SetVarValue ROUT + + Push "R1, R2, R4, lr" + CheckSpaceOnStack 512, SVStackFull, r12 + SUB stack, stack, #256 ; buffer space + + CMP R2, #0 + BMI SetVarVal_GotValueToBuffer ; deletion + +; now range check type + CMP R4, #VarType_Code + BEQ SetVarVal_GotValueToBuffer + CMP R4, #VarType_Expanded + BGT SetVarVal_TypeNaff + +; now get the value, before destroying anything + BEQ SetVarVal_AssignExpanded ; evaluate an expression + CMP R4, #VarType_Number + MOVEQ R2, #3 ; numbers use type byte as one byte. + BEQ SetVarVal_GotValueToBuffer + BGT SetVarVal_ValidateMacroValue +; string : GSTRANS it. + Push "R0" + MOV R0, R1 ; source ptr. + ADD R1, stack, #4 + MOV R2, #255 + SWI XOS_GSTrans + BVS VarBadStrErr + Pull "R0" + BCC SetVarVal_GotValueToBuffer + +SetVarVal_GotValueToBufferButItsTooLong + LDR lr, [Stack, #4*3+256] ; V set no. 3): value too long + ORR lr, lr, #V_bit ; Poke V into stacked lr! + STR lr, [Stack, #4*3+256] + +SetVarVal_GotValueToBuffer +; now got R1 pointer to value, R2 = value length + BL VarFindIt + BEQ SetVarVal_NodeNotFound + + ; Check whether we're assigning a Code value to a Code variable + LDRB R10, [R4] ; get type + CMP R10, #VarType_Code + BNE %FT30 + LDR R10, [Stack, #4*2+256] + CMP R10, #VarType_Code + BNE SetVarVal_AssignNonCodeToCode + +30 + ; We are assigning a code value to a code variable + ; OR any value to a non-code variable + + ; deleting? + CMP R2, #0 + BMI SetVarVal_GotToJunkOldNode ; just delete it. + + ; Assigning.... + LDR R11, [R3, #-(VNameOff+4)] ; real no of bytes in heap node + SUB R11, R11, #VNameOff+4+2 + ADD R11, R11, R3 + SUB R11, R11, R4 ; take off bytes in name + CMP R11, R2 + BGT SetVarVal_NodeReadyToCopyInValue +; let's copy the name, in case orig source wildcarded. + LDR R0, =GSVarWSpace+GSNameBuff + MOV R10, R3 +15 LDRB R11, [R10], #1 + STRB R11, [R0], #1 + CMP R11, #0 + BNE %BT15 + LDR R0, =GSVarWSpace+GSNameBuff + +SetVarVal_GotToJunkOldNode +; got to delete old node (too small). R12 previous, R3-VNameOff is this. + SUB R3, R3, #VNameOff + LDR R11, [R3, #VarLink] + STR R11, [R12, #VarLink] ; chain updated + Push "R0-R2" + MOV R2, R3 ; node ptr. + BL FreeSysHeapNode + Pull "R0-R2" ; node gone + ADD R3, R12, #VNameOff ; our best guess at a context ptr + CMP R2, #0 ; delete? + BMI SetVarValueTestExit ; yup - exit. + +SetVarVal_MakeNewNode +; here, R2 is value length, R0 ptr to name. Validate name while finding length + MOV R10, #0 +16 LDRB R11, [R0, R10] + ADD R10, R10, #1 + CMP R11, #"#" + CMPNE R11, #"*" + BEQ SetVarVal_BadVarName ; error no. 1) + CMP R11, #32 + BGT %BT16 + CMP R10, #1 + BEQ SetVarVal_BadVarName ; 0 char name also naff +; now got R10 name length. Calculate node size + ADD R11, R10, R2 + ADD R11, R11, #VNameOff+2 ; link+name terminator+type + Push "R0-R3" + MOV R3, R11 + BL ClaimSysHeapNode ; corrupts R12 + MOV R4, R2 + Pull "R0-R3" + BVS SetVarSysHeapFull +; now need to find correct alphabetic position on chain. + LDR R12, =VariableList + LDR R11, [R12] +; R4 node to insert, R12 prevnode, R11 nextnode + Push "R5, R6" +31 CMP R11, #0 + BEQ %FT33 + ADD R11, R11, #VNameOff + MOV R10, #-1 +32 ADD R10, R10, #1 + LDRB R5, [R0, R10] + LDRB R6, [R11, R10] + CMP R5, R6 ; can't hit terminator : + BEQ %BT32 ; not same as any on list + SUB R11, R11, #VNameOff + MOVGT R12, R11 + LDRGT R11, [R12, #VarLink] + BGT %BT31 + +33 + ; Link node into list + STR R11, [R4, #VarLink] + STR R4, [R12, #VarLink] ; new entry in + Pull "R5, R6" + + ; Copy name to node + ADD R4, R4, #VNameOff +18 LDRB R11, [R0], #1 + STRB R11, [R4], #1 + CMP R11, #32 + BGT %BT18 + MOV R11, #0 + STRB R11, [R4, #-1] + +SetVarVal_NodeReadyToCopyInValue +; now easy: just copy new value in. R2 bytes, from (R1).R4 points to type + + LDR R10, [stack, #2*4+256] ; get original type back + STRB R10, [R4], #1 ; put type in + CMP R10, #VarType_Macro + SUBEQ R2, R2, #1 ; fudge macro terminators + CMP R10, #VarType_Code + ADDEQ R4, R4, #3 ; align for code. + BICEQ R4, R4, #3 + CMP R10, #VarType_Number + MOVEQ R2, #4 + CMPNE R10, #VarType_Code ; no length for numbers, sysvars + STRNEB R2, [R4], #1 + CMP R10, #VarType_Macro + ADDEQ R2, R2, #1 +05 SUBS R2, R2, #1 + BMI SetVarValueTestExit ; finished + LDRB R10, [R1, R2] + STRB R10, [R4, R2] + B %BT05 + +SetVarSysHeapFull + ADR r0, ErrorBlock_VarNoRoom ; VS no. 2) + B SetVarValueBadExit_256Translate + + MakeErrorBlock VarNoRoom + +SetVarVal_ValidateMacroValue + MOV R2, #0 +13 CMP R2, #255 + BGT SetVarVal_GotValueToBufferButItsTooLong + LDRB R10, [R1, R2] ; it's a macro: check for bad chars. + ADD R2, R2, #1 + CMP R10, #31 + BGT %BT13 + CMP R10, #13 + CMPNE R10, #10 + CMPNE R10, #0 + BEQ SetVarVal_GotValueToBuffer + + ADR r0, ErrorBlock_BadMacVal + B SetVarValueBadExit_256Translate + + MakeErrorBlock BadMacVal + +SetVarVal_BadVarName + ADR r0, ErrorBlock_BadVarNam ; VS no. 2) + B SetVarValueBadExit_256Translate + + MakeErrorBlock BadVarNam + +SetVarVal_NodeNotFound + CMP R2, #0 ; no node for it, test whether deletion + BPL SetVarVal_MakeNewNode + + ADRL r0, ErrorBlock_VarCantFind ; V set no. 1) + B SetVarValueBadExit_256Translate + + +SetVarVal_AssignNonCodeToCode + CMP R2, #0 + BMI SetVarValueTestExit ; deletion's a NOP, when wrong type given + LDR R10, [stack, #2*4+256] ; get original type back + CMP R10, #VarType_Number + BNE %FT25 + MOV R10, R0 + LDRB R0, [R1], #1 + LDRB R2, [R1], #1 + ORR R0, R0, R2, LSL #8 + LDRB R2, [R1], #1 + ORR R0, R0, R2, LSL #16 + LDRB R2, [R1], #1 + ORR R0, R0, R2, LSL #24 + ADD R1, stack, #0 + MOV R2, #256 + SWI XOS_BinaryToDecimal + MOV R0, R10 ; force string value. +25 ADDS R4, R4, #4 ; skip type, add 3 , clear V + MOV lr, PC + BIC PC, R4, #3 ; complete align and call + +; set thunk must take R1 ptr to value, R2 value length + + BVS SetVarValueBadExit_256 + +SetVarValueTestExit + ADD stack, stack, #256 + Pull "R1, R2, R4, lr" + TST lr, #V_bit + ADRNE R0, ErrorBlock_VarTooLong + [ International + Push "lr",NE + BLNE TranslateError + Pull "lr",NE + ] + ExitSWIHandler + + MakeErrorBlock VarTooLong + +SetVarVal_AssignExpanded + Push "R0" + MOV R0, R1 ; ptr to expression + ADD R1, stack, #4 + MOV R2, #256 + SWI XOS_EvaluateExpression + BVS NarffExpression + CMP R1, #0 ; integer? + MOVEQ R4, #VarType_Number + MOVNE R4, #VarType_String + BNE %FT40 + ADD R1, stack, #8 + STR R2, [R1] + MOV R2, #3 +40 + Pull "R0" + STR R4, [stack, #2*4+256] ; update original type + B SetVarVal_GotValueToBuffer + + +NarffExpression + ADD stack, stack, #256+4 ; discard an r0 and buffer + Pull "R1, R2, r4, lr" + B SLVK_SetV + +SetVarVal_TypeNaff + + ADR R0, ErrorBlock_BadVarType ; V set no. 4) + B SetVarValueBadExit_256Translate + + MakeErrorBlock BadVarType + +VarBadStrErr + Pull "R1" + +SetVarValueBadExit_256Translate + BL TranslateError + +SetVarValueBadExit_256 + ADD stack, stack, #256 + B SetVarValueBadExit + +SVStackFull + ADRL r0, ErrorBlock_StackFull + BL TranslateError + +SetVarValueBadExit + Pull "R1, R2, R4, lr" + B SLVK_SetV + ] + +; ***************************************************************************** +; Utility routines. + +; ----------------------------------------------------------------------------- +; +; VarFindIt +; +; In +; r0 -> (wildcard) name of varibale to find +; r3 = context pointer +; +; Out +; r3 = name pointer +; r4 = pointer after name terminator + [ QuickIndex +; r12 = insertion point (1st node >= this node) + | +; r12 = address of previous node + ] +; NE if found, EQ if not found +; + [ QuickIndex +VarFindIt Entry "r0,r1,r2,r5,r6,r7,r8,r9,r10,r11" + +; validate R3 by looking down the list to see if we find it. +; Crude, but effective! + + [ DebugSysVars + SWI XOS_WriteS + = "VarFindIt(",0 + BL SysVar_Write0 + ] + + LDR r9, =VariableList + LDR r9, [r9] + TEQ r9, #0 + LDRNE r8, [r9] + MOVEQ r8, #0 + TEQ r3, #0 + BEQ %FT20 + + [ DebugSysVars + SWI XOS_WriteS + = "-scan-",0 + ] + ; r3 non-zero - scan list for entry + ADD r12, r8, #1 + B %FT10 +05 + LDR lr, [r9, r12, ASL #2] + CMP lr, r3 + BEQ %FT70 ; continue scan down list +10 + SUBS r12, r12, #1 + BHI %BT05 + +20 + [ DebugSysVars + SWI XOS_WriteS + = "-wildcheck-",0 + ] + ; not found in scan - check for name being wildcarded + MOV r10, r0 +25 + LDRB lr, [r10], #1 + TEQ lr, #"*" + TEQNE lr, #"#" + BEQ %FT65 + CMP lr, #" " + BHI %BT25 + + [ DebugSysVars + SWI XOS_WriteS + = "-bchop-",0 + ] + + ; Name not wildcarded - do binary chop search + ORRS r7, r8, r8, LSR #1 + ORR r7, r7, r7, LSR #2 + ORR r7, r7, r7, LSR #4 + ORR r7, r7, r7, LSR #8 + ORR r7, r7, r7, LSR #16 + BICS r7, r7, r7, LSR #1 ; least 2^n <= number of entries + MOV r6, #0 + + B %FT60 +40 + ADD r5, r6, r7 + CMP r5, r8 + BHI %FT55 + + MOV r1, r0 + LDR r4, [r9, r5, ASL #2] + +45 + LDRB r2, [r1], #1 + CMP r2, #" " + MOVLS r2, #0 + LDRB r3, [r4], #1 + CMP r3, #" " + MOVLS r3, #0 + UpperCase R2,LR + UpperCase R3,LR + CMP r3, r2 + BNE %FT50 + CMP r3, #0 + BNE %BT45 +50 + MOVHS r10, pc ; preserve last HS result we got + MOVHS r11, r4 + MOVLO r6, r5 +55 + MOVS r7, r7, LSR #1 +60 + BNE %BT40 + + ; We always want the element above. + ; If r6<r8 then we want the preserved result + ; else we want the result HI + ADD r6, r6, #1 + CMP r6, r8 + LDRLS r3, [r9, r6, ASL #2] + MOVLS r4, r11 + MOVHI r3, #0 + TEQLSP pc, r10 + + [ DebugSysVars + SWI XOS_WriteS + = "-complete-",0 + SWI XOS_NewLine + ] + MOV r12, r6 + MOV lr, pc + TEQP lr, #Z_bit + EXIT + +65 + [ DebugSysVars + SWI XOS_WriteS + = "-listscan-",0 + SWI XOS_NewLine + ] + ; Scan down list looking for wildmatch + MOV r12, #0 +70 + ADD r12, r12, #1 + CMP r12, r8 + BHI %FT90 ; end of list reached + LDR r4, [r9, r12, ASL #2] + BL WildMatch ; trashes r10,r11 + BNE %BT70 + +80 + [ DebugSysVars + SWI XOS_WriteS + = "-complete-",0 + SWI XOS_NewLine + ] + ; Found + ; r4->name end + ; r12 = entry number + LDR r3, [r9, r12, ASL #2] + ASSERT VNameOff = 0 + MOVS r12, r12 ; set NE + EXIT + +90 + ; Not found + [ DebugSysVars + SWI XOS_WriteS + = "-not found-",0 + SWI XOS_NewLine + ] + MOV r12, #1 + MOVS r3, #0 + EXIT + | +VarFindIt Entry "r10,r11" + +; validate R3 by looking down the chain to see if we find it. +; Crude, but effective! + + CMP R3, #0 + BEQ %FT03 + SUB R3, R3, #VNameOff ; step back to chain ptr + LDR R11, =VariableList + LDR R11, [R11] +02 CMP R11, #0 + CMPNE R11, R3 + LDRNE R11, [R11, #VarLink] + BNE %BT02 + CMP R11, #0 +03 LDREQ R3, =VariableList +01 MOV R12, R3 ; keep previous for creation + LDR R3, [R3, #VarLink] ; step on + CMP R3, #0 + EXIT EQ ; failed + ADD R4, R3, #VNameOff + BL WildMatch ; trashes r10,r11 + BNE %BT01 + ADDS R3, R3, #VNameOff ; get node ptr and set NE + EXIT ; and back with got. + ] + + +WildMatch ROUT +; In : R0 is wildcard spec ptr, R4 is name ptr. +; Wild Terminators are any ch <=" ", name terminator 0 +; Wildcards are *, # +; Out : EQ/NE for match (EQ if matches) +; R4 points after name terminator for found +; R0 preserved, R10, 11 corrupted + + Push "R0-R3" + MOV R11, #0 ; this is the wild backtrack pointer + MOV R3, #0 ; and this is the name backtrack ptr. +01 LDRB R1, [R0], #1 ; nextwild + CMP R1, #"*" + BEQ %FT02 ; IF nextwild = "*" + LDRB R2, [R4], #1 ; nextname + CMP R2, #0 + BEQ %FT03 + UpperCase R1, R10 + UpperCase R2, R10 + CMP R1, R2 ; IF nextwild=nextname + CMPNE R1, #"#" ; OR nextwild = # (terminator checked already) + BEQ %BT01 ; THEN LOOP (stepped already) + MOV R0, R11 ; try backtrack + MOVS R4, R3 ; if * had at all + BNE %FT02 + CMP PC, #0 ; set NE +04 Pull "R0-R3" ; return NE (failed) + MOV PC, lr + +03 CMP R1, #" " ; name terminated : has wildcard? + BHI %BA04 ; note HI has NE set. + CMP R1, R1 ; set EQ + Pull "R0-R3" + MOV PC, lr + +02 MOV R11, R0 ; wild backtrack ptr is char after * + LDRB R1, [R0], #1 ; step wild + CMP R1, #"*" + BEQ %BT02 ; fujj ** + UpperCase R1, R10 +05 LDRB R2, [R4], #1 ; step name + CMP R2, #0 ; terminator? + BEQ %BT03 + UpperCase R2, R10 + CMP R1, R2 + CMPNE R1, #"#" ; match if # + BNE %BT05 + MOV R3, R4 ; name backtrack ptr is char after match + B %BT01 ; LOOP + + LTORG + + END diff --git a/s/Arthur3 b/s/Arthur3 new file mode 100644 index 0000000000000000000000000000000000000000..18e31635a826e1d3223c4510a9e44c30d69aa5c5 --- /dev/null +++ b/s/Arthur3 @@ -0,0 +1,2454 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + TTL => Arthur3 + +; the IF command + +IF_Code ROUT + Push "R2, lr" + LDR R2, =GeneralMOSBuffer +01 + LDRB R1, [R0], #1 + STRB R1, [R2], #1 + CMP R1, #10 + CMPNE R1, #13 + CMPNE R1, #0 + BEQ NoTHEN + CMP R1, #" " + BNE %BT01 + LDRB R1, [R0] + CMP R1, #"t" + CMPNE R1, #"T" + BNE %BT01 + LDRB R1, [R0, #1] + CMP R1, #"h" + CMPNE R1, #"H" + BNE %BT01 + LDRB R1, [R0, #2] + CMP R1, #"e" + CMPNE R1, #"E" + BNE %BT01 + LDRB R1, [R0, #3] + CMP R1, #"n" + CMPNE R1, #"N" + BNE %BT01 + LDRB R1, [R0, #4] + CMP R1, #" " + CMPNE R1, #13 + CMPNE R1, #10 + CMPNE R1, #0 + BNE %BT01 + MOV R1, #13 + STRB R1, [R2, #-1] + ADD R0, R0, #4 ; skip THEN + Push "R0" + LDR R0, =GeneralMOSBuffer + MOV R2, #-1 ; integers only mate + SWI XOS_EvaluateExpression + BVS WantInteger + Pull "R1" + CMP R2, #0 + BEQ %FT02 ; false + LDR R2, =GeneralMOSBuffer +03 + LDRB R0, [R1], #1 + STRB R0, [R2], #1 + CMP R0, #10 + CMPNE R0, #13 + CMPNE R0, #0 + BEQ %FT04 + CMP R0, #" " + BLEQ %FT05 + BNE %BT03 +04 + MOV R0, #13 + STRB R0, [R2, #-1] + LDR R0, =GeneralMOSBuffer +07 + SWI XOS_CLI +06 + Pull "R2, PC" + +05 + LDRB R0, [R1] + CMP R0, #"e" + CMPNE R0, #"E" + MOVNE PC, lr + LDRB R0, [R1, #1] + CMP R0, #"l" + CMPNE R0, #"L" + MOVNE PC, lr + LDRB R0, [R1, #2] + CMP R0, #"s" + CMPNE R0, #"S" + MOVNE PC, lr + LDRB R0, [R1, #3] + CMP R0, #"e" + CMPNE R0, #"E" + MOVNE PC, lr + LDRB R0, [R1, #4] + CMP R0, #" " + CMPNE R1, #13 + CMPNE R1, #10 + CMPNE R1, #0 + MOV PC, lr + +02 + LDRB R0, [R1], #1 + CMP R0, #10 + CMPNE R0, #13 + CMPNE R0, #0 + BEQ %BT06 + CMP R0, #" " + BLEQ %BT05 + BNE %BT02 + ADD R0, R1, #4 + B %BT07 + +NoTHEN ROUT + ADR R0, %FT01 + [ International + BL TranslateError + ] +IfError + Pull "R2, lr" + ORRS PC, lr, #V_bit +01 + & ErrorNumber_Syntax + = "NoThen:There is no THEN", 0 + ALIGN + +WantInteger ROUT + CMP R1, #0 + Pull "R1" + Pull "R2, lr", EQ ; integer returned, so leave expranal error there + ORREQS PC, lr, #V_bit + ADR R0, %FT01 + [ International + BL TranslateError + ] + B IfError +01 + & ErrorNumber_Syntax + = "IsString:Expression is a string", 0 + ALIGN + +;************************************************************************ +; the expression analysis SWI + +; truth values +Expr_True * -1 +Expr_False * 0 + +; Type symbols + +type_Integer * 0 +type_String * 1 +type_Operator * 2 + +; operators : +; single char syms have their ascii value +op_Bra * "(" ; 40 +op_Ket * ")" ; 41 +op_Times * "*" ; 42 +op_Plus * "+" ; 43 +op_Minus * "-" ; 45 +op_Divide * "/" ; 47 +op_LT * "<" ; 60 +op_EQ * "=" ; 61 +op_GT * ">" ; 62 + +; now fill in some gaps + +op_NE * 44 ; <> +op_STR * 46 ; STR +op_GE * 48 ; >= +op_LE * 49 ; <= +op_RShift * 50 ; >> +op_LShift * 51 ; << +op_AND * 52 ; AND +op_OR * 53 ; OR +op_EOR * 54 ; EOR +op_NOT * 55 ; NOT +op_Right * 56 ; RIGHT +op_Left * 57 ; LEFT +op_MOD * 58 ; MOD +op_Bottom * 59 +op_VAL * 63 ; VAL +op_LRShift * 64 ; >>> +op_LEN * 65 ; LEN + +; TMD 12-Sep-89 - add separate tokens for monadic versions of + and - + +op_UnaryPlus * 66 ; unary plus +op_UnaryMinus * 67 ; unary minus + +; so 40-67 inclusive is filled. + + MACRO +$label ePush $reglist +$label STMFD R11!, {$reglist} + CMP R11, R10 + BLE StackOFloErr + MEND + + MACRO +$label ePull $reglist, $writeback, $cc + [ "$writeback" = "" + LDM$cc.FD R11!, {$reglist} + | + LDM$cc.FD R11, {$reglist} + ] + MEND + +;************************************************************************* +; SWI EvalExp. +; In : R0 -> string +; R1 -> buffer +; R2 maxchars +; Out : R0 unchanged. +; IF R1 = 0, R2 is an integer +; IF R1<>0, buffer has a string, length in R2. +; V set if bad expression, buffer overflow +;************************************************************************* + +ExprBuffOFlo ROUT + ADRL R0, ErrorBlock_BuffOverflow + [ International + BL TranslateError + ] + STR R0, [stack] + Pull "R0-R4, lr" + B SLVK_SetV + +ReadExpression ROUT + Push "R0-R4, lr" + TEQP PC, #SVC_mode ; interrupts on, ta. + LDR R12, =ExprWSpace + STR R13, ExprSVCstack + ADR R1, ExprBuff + MOV R2, #256 + ORR R2, R2, #(1 :SHL: 30) :OR: (1 :SHL: 31) + SWI XOS_GSTrans ; No | transformation, no " or space termination. + ; so can never go wrong! + BCS ExprBuffOFlo + MOV R0, #13 + STRB R0, [R1, R2] + + LDR R11, =ExprStackStart + LDR R10, =ExprStackLimit + MOV R0, #0 + STRB R0, exprBracDif + MOV R0, #type_Operator + MOV R2, #op_Bottom + STRB R2, tos_op + STMFD R11!, {R0, R2} ; push "bottom" + +; All set : now chug round items. + +01 + BL GetFactor + CMP R0, #type_Operator + BNE %BT01 + + CMP R2, #op_Ket + BNE %FT02 + LDRB R3, exprBracDif + [ {TRUE} ; TMD 11-Sep-89 - save an instruction + SUBS R3, R3, #1 + BCC BadBraErr + | + CMP R3, #0 + BEQ BadBraErr + SUB R3, R3, #1 + ] + STRB R3, exprBracDif + +03 + LDRB R3, tos_op + CMP R3, #op_Bra + BLNE compile_top_op + BNE %BT03 + + ePull "R0, R2" + CMP R0, #type_Operator + BEQ MissingOpErr + CMP R0, #type_String + BLEQ Pull_String + Push "R0, R2" + ePull "R0, R2" + CMP R0, #type_Operator + BNE MissingOrErr ; discard "(" + ePull "R0, R2", No + CMP R0, #type_Operator + BNE MissingOrErr + STRB R2, tos_op ; reset tosop + Pull "R0, R2" + CMP R0, #type_String + BLEQ Push_String + ePush "R0, R2" ; move temp result down. + B %BT01 + +02 + CMP R2, #op_Bra + LDREQB R3, exprBracDif + ADDEQ R3, R3, #1 + STREQB R3, exprBracDif ; bracdif +:= 1 + +; TMD 12-Sep-89 - now check for unary plus or minus + + CMP R2, #op_Plus ; if EQ then CS + TEQNE R2, #(op_Minus :SHL: 2),2 ; if EQ then CC + ePull "R0, R4", No, EQ ; if +/- and top item is op + TEQEQ R0, #type_Operator, 0 ; then it's unary plus/minus + BNE %FT10 ; else normal + + MOVCS R2, #op_UnaryPlus ; CS => unary plus + MOVCC R2, #op_UnaryMinus ; CC => unary minus +10 + +; WHILE lp (tos.op) > rp (itemtype) DO compile.top.op () + + ADR R4, rightprectab-op_Bra + LDRB R4, [R4, R2] +04 + ADR R0, leftprectab-op_Bra + LDRB R3, tos_op + LDRB R0, [R0, R3] + CMP R0, R4 + BLGT compile_top_op + BGT %BT04 + + MOV R0, #type_Operator + ePush "R0, R2" ; push (operator) + STRB R2, tos_op + CMP R2, #op_Bottom + BNE %BT01 + +; check proper expr, return it. +; should have bum/result/bum on stack. + + ePull "R0, R2" ; this one's forced to be bottom + ePull "R0, R2" + CMP R0, #type_Operator + BEQ MissingOpErr + CMP R0, #type_String + BLEQ Pull_String + Push "R0, R2" + ePull "R0, R2" + CMP R0, #type_Operator ; if an op's there, it has to be bottom + Pull "R1, R2" + BNE MissingOpErr + + Pull "R0, R3, R4" ; original R1, R2 -> R3, R4 + CMP R1, #type_Integer + Pull "R3, R4, lr", EQ + ExitSWIHandler EQ + CMP R4, R2 + BGE ExprBuffOK + MOV R2, R4 ; no chars to move. + ADRL R0, BufferOFloError + LDR lr, [stack, #4*2] + ORR lr, lr, #V_bit + STR lr, [stack, #4*2] +ExprBuffOK + MOV R1, R3 + LDR R4, =exprSTRACC ; get ptr to it. + Push "R2" +06 + SUBS R2, R2, #1 + LDRPLB R3, [R4, R2] + STRPLB R3, [R1, R2] + BPL %BT06 + Pull "R2-R4, lr" + ExitSWIHandler + +leftprectab +; Bra Ket Time Plus NE Minu STR Divi GE LE RShi LShift + = 2, 1, 8, 7, 6, 7, 9, 8, 6, 6, 6, 6 +; AND OR EOR NOT Righ Left MOD Bott LT EQ GT VAL LRSh + = 5, 4, 4, 9, 9, 9, 8, 1, 6, 6, 6, 9, 6 +; LEN Un+ Un- + = 9, 9, 9 + +rightprectab +; Bra Ket Time Plus NE Minu STR Divi GE LE RShi LShift + = 11, 0, 7, 6, 5, 6, 10, 7, 5, 5, 5, 5 +; AND OR EOR NOT Righ Left MOD Bott LT EQ GT VAL LRSh + = 4, 3, 3, 10, 10, 10, 7, 1, 5, 5, 5, 10, 5 +; LEN Un+ Un- + = 10, 10, 10 + + ALIGN + +;***************************************************************************** + +compile_top_op ROUT +; preserves the flags + Push "R2-R4, lr" + ePull "R0, R2" + CMP R0, #type_Operator + BEQ MissingOpErr ; everybody needs a rhs op + CMP R0, #type_String + BLEQ Pull_String + ePull "R3, R4" ; must be tosop + CMP R3, #type_Operator + BNE MissingOrErr + + SUB R4, R4, #op_Bra + ADR R3, Operator_Dispatch + LDR R4, [R3, R4, LSL #2] + ADD PC, R3, R4 + +DispatchReturn + ePull "R3, R4", No ; pull with no writeback + CMP R3, #type_Operator + BNE MissingOrErr + STRB R4, tos_op + CMP R0, #type_String + BLEQ Push_String + ePush "R0, R2" ; temp val -> stack + + GRABS "R2-R4, PC" + +; the routines in this table are entered with one operand popped, +; any other op on stack ready to pop. +; Return with temp val set up (R0, R2 and maybe exprSTRACC) +; Can use R0, R2-R4 as reqd + +Operator_Dispatch + & Bra_Code - Operator_Dispatch + & 0 ; Ket_Code - Operator_Dispatch - can't happen + & Times_Code - Operator_Dispatch + & Plus_Code - Operator_Dispatch + & NE_Code - Operator_Dispatch + & Minus_Code - Operator_Dispatch + & STR_Code - Operator_Dispatch + & Divide_Code - Operator_Dispatch + & GE_Code - Operator_Dispatch + & LE_Code - Operator_Dispatch + & RShift_Code - Operator_Dispatch + & LShift_Code - Operator_Dispatch + & AND_Code - Operator_Dispatch + & OR_Code - Operator_Dispatch + & EOR_Code - Operator_Dispatch + & NOT_Code - Operator_Dispatch + & Right_Code - Operator_Dispatch + & Left_Code - Operator_Dispatch + & MOD_Code - Operator_Dispatch + & 0 ; Bottom_Code - Operator_Dispatch - can't happen + & LT_Code - Operator_Dispatch + & EQ_Code - Operator_Dispatch + & GT_Code - Operator_Dispatch + & VAL_Code - Operator_Dispatch + & LRShift_Code- Operator_Dispatch + & LEN_Code- Operator_Dispatch + & UnPlus_Code- Operator_Dispatch + & UnMinus_Code- Operator_Dispatch + +;************************************************************************** +; dispatch routines + +;-------------------------------------------------------------------------- +; monadic operators + +VAL_Code ROUT ; VAL string (VAL integer is NOP) +UnPlus_Code ROUT ; + integer (same code as VAL) + CMP R0, #type_String + BLEQ StringToInteger + B DispatchReturn + +STR_Code ROUT ; STR integer (STR string is NOP) + CMP R0, #type_Integer + BLEQ IntegerToString + B DispatchReturn + +LEN_Code ROUT ; LEN string + CMP R0, #type_Integer + BLEQ IntegerToString + MOV R0, #type_Integer ; and R2 is length! + B DispatchReturn + +NOT_Code ROUT ; NOT integer + CMP R0, #type_String + BLEQ StringToInteger + MVN R2, R2 + B DispatchReturn + +UnMinus_Code ROUT ; - integer + CMP R0, #type_String + BLEQ StringToInteger + RSB R2, R2, #0 + B DispatchReturn + +;-------------------------------------------------------------------------- +; diadic plus + +Plus_Code ROUT ; integer+integer ; string+string + ePull "R3, R4" +; CMP R3, #type_Operator ; can't be operator as unary plus +; BEQ %FT01 ; is separately dispatched now + CMP R0, #type_String + BEQ %FT02 + CMP R3, #type_String + BLEQ PullStringToInteger ; in R4 + ADD R2, R2, R4 + B DispatchReturn + +02 + CMP R3, #type_String + BEQ %FT03 + BL StringToInteger + ADD R2, R2, R4 + B DispatchReturn + +03 + ADD R0, R2, R4 + CMP R0, #255 + BGT StrOFloErr + LDR R3, =exprSTRACC + Push "R0" ; new length + ADD R0, R3, R0 + ADD R3, R3, R2 + ; copy R2 bytes from --(R3) to --(R0) +04 + SUBS R2, R2, #1 + LDRGEB R4, [R3, #-1]! + STRGEB R4, [R0, #-1]! + BGE %BT04 +; R0-exprSTRACC is no of chars in stacked string + LDR R3, =exprSTRACC + SUB R0, R0, R3 +05 + SUBS R0, R0, #1 + LDRGEB R2, [R11], #1 + STRGEB R2, [R3], #1 + BGE %BT05 + ADD R11, R11, #3 + BIC R11, R11, #3 ; realign stack + Pull "R2" + MOV R0, #type_String + B DispatchReturn + +Minus_Code ROUT ; integer-integer +; ePull "R3, R4", No ; can't be unary minus - this is +; CMP R3, #type_Operator ; separately dispatched now +; BEQ %FT01 + BL TwoIntegers + SUB R2, R4, R2 + B DispatchReturn + +;--------------------------------------------------------------------------- +; integer pair only : maths + +Times_Code ROUT ; integer*integer + BL TwoIntegers + MOV R3, R2 + MULTIPLY R2, R3, R4 ; get R3*R4->R2 + B DispatchReturn + +MOD_Code ROUT ; integer MOD integer + Push "R5" + MOV R5, #&80000000 + B DivModCommon + +Divide_Code ROUT ; integer/integer + Push "R5" + MOV R5, #0 +DivModCommon + BL TwoIntegers ; want R4/R2 + CMP R2, #0 + Pull "R5", EQ + BEQ DivZeroErr + RSBMI R2, R2, #0 + EORMIS R5, R5, #1 + EORMI R5, R5, #1 ; oops-wanted MOD, ignore this sign + CMP R4, #0 + EORMI R5, R5, #1 + RSBMI R4, R4, #0 + DivRem R3, R4, R2, R0 ; R3 := R4 DIV R2; R4 := R4 REM R2 + MOVS R5, R5, LSL #1 ; CS if MOD, NE if -ve + MOVCS R2, R4 + MOVCC R2, R3 + RSBNE R2, R2, #0 + MOV R0, #type_Integer + Pull "R5" + B DispatchReturn + +;--------------------------------------------------------------------------- +; integer pair only : logical + +AND_Code ROUT ; integer AND integer + BL TwoIntegers + AND R2, R2, R4 + B DispatchReturn + +OR_Code ROUT ; integer OR integer + BL TwoIntegers + ORR R2, R2, R4 + B DispatchReturn + +EOR_Code ROUT ; integer EOR integer + BL TwoIntegers + EOR R2, R2, R4 + B DispatchReturn + +;---------------------------------------------------------------------------- +; mixed operands + +Right_Code ROUT ; string RIGHT integer + CMP R0, #type_Integer + BLNE StringToInteger + MOV R4, R2 + ePull "R0, R2" + CMP R0, #type_String + BNE %FT01 + BL Pull_String +02 ; string in stracc, R2 chars available, R4 chars wanted. + CMP R2, R4 + BLO DispatchReturn ; ignore if R4 -ve or bigger than available + LDR R0, =exprSTRACC + ADD R3, R0, R2 + SUB R3, R3, R4 ; mov from R3 to R0, R4 bytes +03 + LDRB R2, [R3], #1 + SUBS R4, R4, #1 + STRGEB R2, [R0], #1 + BGE %BT03 + LDR R2, =exprSTRACC + SUB R2, R0, R2 ; get length back. + MOV R0, #type_String + B DispatchReturn + +01 + CMP R0, #type_Operator + BEQ MissingOpErr + BL IntegerToString + B %BT02 + +Left_Code ROUT ; string LEFT integer + CMP R0, #type_Integer + BLNE StringToInteger + MOV R4, R2 + ePull "R0, R2" + CMP R0, #type_String + BNE %FT01 + BL Pull_String +02 + CMP R4, R2 + MOVLO R2, R4 ; only use new length if +ve and < current length + B DispatchReturn + +01 + CMP R0, #type_Operator + BEQ MissingOpErr + BL IntegerToString + B %BT02 + +;----------------------------------------------------------------------- +; relational operators + +EQ_Code ROUT ; integer = integer ; string = string + BL Comparison + MOVEQ R2, #Expr_True + MOVNE R2, #Expr_False + B DispatchReturn + +NE_Code ROUT ; integer<>integer ; string<>string + BL Comparison + MOVNE R2, #Expr_True + MOVEQ R2, #Expr_False + B DispatchReturn + +GT_Code ROUT ; integer > integer ; string>string + BL Comparison + MOVGT R2, #Expr_True + MOVLE R2, #Expr_False + B DispatchReturn + +LT_Code ROUT ; integer < integer ; string<string + BL Comparison + MOVLT R2, #Expr_True + MOVGE R2, #Expr_False + B DispatchReturn + +GE_Code ROUT ; integer >= integer ; string>=string + BL Comparison + MOVGE R2, #Expr_True + MOVLT R2, #Expr_False + B DispatchReturn + +LE_Code ROUT ; integer <= integer ; string<=string + BL Comparison + MOVLE R2, #Expr_True + MOVGT R2, #Expr_False + B DispatchReturn + +;-------------------------------------------------------------------------- +; shift operators + +RShift_Code ROUT ; integer >> integer + BL TwoIntegers + CMP R2, #0 + RSBLT R2, R2, #0 + BLT NegRShift +NegLShift + CMP R2, #32 + MOVGE R2, R4, ASR #31 ; sign extend all through + MOVLT R2, R4, ASR R2 + B DispatchReturn + +LRShift_Code ROUT ; integer >>> integer + BL TwoIntegers + CMP R2, #0 + RSBLT R2, R2, #0 + BLT NegRShift + CMP R2, #32 + MOVGE R2, #0 + MOVLT R2, R4, LSR R2 + B DispatchReturn + +LShift_Code ROUT ; integer << integer + BL TwoIntegers + CMP R2, #0 + RSBLT R2, R2, #0 + BLT NegLShift +NegRShift + CMP R2, #32 + MOVGE R2, #0 + MOVLT R2, R4, LSL R2 + B DispatchReturn + +;--------------------------------------------------------------------------- +; Support routines : + +TwoIntegers ROUT + Push "lr" + CMP R0, #type_String + BLEQ StringToInteger + ePull "R3, R4" + CMP R3, #type_Operator + BEQ MissingOpErr + CMP R3, #type_String + BLEQ PullStringToInteger + Pull "PC" + +Comparison ROUT + Push "lr" + ePull "R3, R4" + CMP R3, #type_Operator + BEQ MissingOpErr + CMP R0, #type_String + BEQ %FT01 + CMP R3, #type_String + BLEQ PullStringToInteger + CMP R4, R2 + Pull "PC" + +01 + CMP R3, #type_String + BEQ %FT02 + BL StringToInteger + CMP R4, R2 + Pull "PC" + +02 + MOV R3, R11 + ADD R11, R11, R4 + ADD R11, R11, #3 + BIC R11, R11, #3 +; $R3, length R4 against $exprSTRACC, length R2 + Push "R1, R2, R4, R5" + CMP R2, R4 + MOVGT R2, R4 ; minm length -> R2 + LDR R0, =exprSTRACC +03 + SUBS R2, R2, #1 + BLT %FT04 + LDRB R1, [R0], #1 + LDRB R5, [R3], #1 + CMP R5, R1 + BEQ %BT03 + MOV R0, #type_Integer + Pull "R1, R2, R4, R5, PC" + +04 + Pull "R1, R2, R4, R5" + CMP R4, R2 + MOV R0, #type_Integer + Pull "PC" + +StringToInteger ROUT + Push "R1, R3, R4, lr" + LDR R1, =exprSTRACC + ADD R3, R1, R2 ; end pointer to check all string used. + MOV R0, #13 + STRB R0, [R1, R2] ; force terminator in +01 + LDRB R0, [R1], #1 + CMP R0, #" " + BEQ %BT01 + MOV R4, #0 + CMP R0, #"-" + MOVEQ R4, #-1 + CMPNE R0, #"+" + SUBNE R1, R1, #1 + MOV R0, #10 + SWI XOS_ReadUnsigned +02 + LDRB R0, [R1], #1 + CMP R0, #" " + BEQ %BT02 + SUB R1, R1, #1 + CMP R1, R3 + BNE BadIntegerErr + MOV R0, #type_Integer + CMP R4, #0 + RSBNE R2, R2, #0 + Pull "R1, R3, R4, PC" + +IntegerToString ROUT + Push "R1, lr" + MOV R0, R2 + LDR R1, =exprSTRACC + MOV R2, #255 + SWI XOS_BinaryToDecimal + MOV R0, #type_String + Pull "R1, PC" + +PullStringToInteger ROUT ; corrupts exprSTRACC + Push "R0, R2, lr" + MOV R2, R4 + BL Pull_String + BL StringToInteger + MOV R4, R2 + MOV R3, #type_Integer + Pull "R0, R2, PC" + +;****************************************************************************** + +GetFactor ROUT +; return type in R0 +; if operator, R2 has op_xxx +; if integer/string, it has been pushed +; R1 updated, R2 corrupted. + +10 + LDRB R0, [R1], #1 + CMP R0, #" " + BEQ %BT10 + + CMP R0, #13 + BNE %FT11 + MOV R2, #op_Bottom + MOV R0, #type_Operator + MOV PC, lr + +31 + CMP R0, #"@"-1 ; chars >= "@" are OK + BGT %FT32 + CMP R0, #" " ; chars <= " " always terminate + MOVLE PC, lr + Push "R2, R3" + ADR R2, terminatename_map-"!" + LDRB R3, [R2, R0] ; termination map for " " < char < "@" + CMP R3, #0 + Pull "R2, R3" + MOVEQ PC, lr +32 + STRB R0, [R3], #1 + MOV PC, lr ; return with GT for OK, LE for naff + +terminatename_map ; 1 means character allowed + ; ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? + = 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1 + ALIGN + +11 + CMP R0, #"&" ; hex number? + CMPNE R0, #"0" + RSBGTS R2, R0, #"9" + BGE %FT03 ; got to get a number. + + CMP R0, #"""" + BEQ %FT04 ; string. + + ; look for operator + Push "R3" + ADR R2, operator_table +20 + LDRB R3, [R2], #1 + CMP R3, #0 ; end of table? + BEQ %FT30 + CMP R0, R3 + BEQ %FT21 +22 + LDRB R3, [R2], #1 + CMP R3, #0 + BNE %BT22 + ADD R2, R2, #1 ; skip op_xxx + B %BT20 +21 + Push "R1" +24 + LDRB R3, [R2], #1 + CMP R3, #0 + BEQ %FT23 + LDRB R0, [R1], #1 + CMP R0, R3 + BEQ %BT24 + Pull "R1" + LDRB R0, [R1, #-1] + B %BT22 +23 + Pull "R3" ; junk R1 + Pull "R3" + LDRB R2, [R2] + MOV R0, #type_Operator + MOV PC, lr ; got an operator. + +30 + LDR R3, =exprSTRACC + ; assume variable name : try and read it. + Push "lr" + BL %BT31 ; check R0 for allowed in name, insert. + BLE NaffItemErr +33 + LDRB R0, [R1], #1 + BL %BT31 + BGT %BT33 + SUB R1, R1, #1 + MOV R0, #13 + STRB R0, [R3], #1 + ; potential name in exprSTRACC + Push "R1, R4" + LDR R0, =exprSTRACC + MOV R2, #-1 ; just test for existence first + MOV R3, #0 + MOV R4, #0 ; no expansion + SWI XOS_ReadVarVal + CMP R2, #0 + BEQ NaffItemErr + LDR R1, =exprSTRACC ; overwrite name with value + MOV R0, R1 ; overwritten by VSet return + MOV R2, #255 + MOV R3, #0 + CMP R4, #VarType_Macro + MOVEQ R4, #VarType_Expanded + SWI XOS_ReadVarVal + BVS StrOFloErr + CMP R4, #VarType_Number + LDREQ R2, [R1] + MOVEQ R0, #type_Integer + BLNE Push_String + MOVNE R0, #type_String + ePush "R0, R2" + Pull "R1, R4, lr" + Pull "R3" + MOV PC, lr + +operator_table + = "(" , 0, op_Bra + = ")" , 0, op_Ket + = "+" , 0, op_Plus + = "-" , 0, op_Minus + = "*" , 0, op_Times + = "/" , 0, op_Divide + = "=" , 0, op_EQ + = "<>" , 0, op_NE + = "<=" , 0, op_LE + = "<<" , 0, op_LShift + = "<" , 0, op_LT + = ">=" , 0, op_GE + = ">>>" , 0, op_LRShift + = ">>" , 0, op_RShift + = ">" , 0, op_GT + = "AND" , 0, op_AND + = "OR" , 0, op_OR + = "EOR" , 0, op_EOR + = "NOT" , 0, op_NOT + = "RIGHT", 0, op_Right + = "LEFT" , 0, op_Left + = "MOD" , 0, op_MOD + = "STR" , 0, op_STR + = "VAL" , 0, op_VAL + = "LEN" , 0, op_LEN + = 0 + ALIGN + +03 + SUB R1, R1, #1 ; point at string start + Push "lr" + MOV R0, #10 + SWI XOS_ReadUnsigned + LDRVS R13, ExprSVCstack + BVS BumNumber2 ; already messagetransed, so don't do it again MED-01583 + MOV R0, #type_Integer + ePush "R0, R2" + Pull "PC" + +ExprErrCommon +BumNumber + LDR R13, ExprSVCstack + [ International + BL TranslateError + ] +BumNumber2 + STR R0, [stack] + Pull "R0-R4, lr" + MOV R1, #0 ; haven't put anything in buffer + B SLVK_SetV +BadStringErr + ADRL R0, ErrorBlock_BadString + B ExprErrCommon +Bra_Code +BadBraErr + ADR R0, ErrorBlock_BadBra + B ExprErrCommon + MakeErrorBlock BadBra +StackOFloErr + ADR R0, ErrorBlock_StkOFlo + B ExprErrCommon + MakeErrorBlock StkOFlo +MissingOpErr + ADR R0, ErrorBlock_MissOpn + B ExprErrCommon + MakeErrorBlock MissOpn +MissingOrErr + ADR R0, ErrorBlock_MissOpr + B ExprErrCommon + MakeErrorBlock MissOpr +BadIntegerErr + ADR R0, ErrorBlock_BadInt + B ExprErrCommon + MakeErrorBlock BadInt +StrOFloErr + ADR R0, ErrorBlock_StrOFlo + B ExprErrCommon + MakeErrorBlock StrOFlo +NaffItemErr + ADR R0, ErrorBlock_NaffItm + B ExprErrCommon + MakeErrorBlock NaffItm +DivZeroErr + ADR R0, ErrorBlock_DivZero + B ExprErrCommon + MakeErrorBlock DivZero + +04 + LDR R2, =exprSTRACC +05 + LDRB R0, [R1], #1 + CMP R0, #13 + CMPNE R0, #10 + CMPNE R0, #0 + BEQ BadStringErr + CMP R0, #"""" + BEQ %FT06 +07 + STRB R0, [R2], #1 ; can't overflow - comes from buffer + B %BT05 + +06 + LDRB R0, [R1], #1 + CMP R0, #"""" + BEQ %BT07 + SUB R1, R1, #1 + LDR R0, =exprSTRACC + SUB R2, R2, R0 ; length to R2 + Push "lr" + BL Push_String + ePush "R0, R2" + Pull "PC" + +Push_String ROUT + Push "R2, R3" + SUBS R2, R2, #1 + BMI %FT02 + BIC R2, R2, #3 + LDR R0, =exprSTRACC +01 + LDR R3, [R0, R2] + ePush "R3" + SUBS R2, R2, #4 + BGE %BT01 +02 + Pull "R2, R3" + MOV R0, #type_String + MOV PC, lr + +Pull_String ROUT + CMP R2, #0 + MOVEQ PC, lr + Push "R0, R2, R3" + LDR R0, =exprSTRACC +01 + ePull "R3" + STR R3, [R0], #4 + SUBS R2, R2, #4 + BGT %BT01 + Pull "R0, R2, R3" + MOV PC, lr + + LTORG + +;***************************************************************************** + +; Configure and Status + +; The configuration table : some types and macros first. + +ConType_NoParm * 1 +ConType_Field * 2 +ConType_Special * 3 +ConType_Size * 4 + +; Type Special has another table : +; code to set it +; code to show it +; string to print for Configure listing. +; Keep table position as offset from table entry + + MACRO + Config_Special $name + = ConType_Special, "$name", 0 + ALIGN + & Config_$name._table - . + MEND + +; Table offset : +Config_Special_SetCode * 0 +Config_Special_ShowCode * 4 +Config_Special_String * 8 + +; Type NoParm : *con. name +; put $value into bits $bitoff to $bitoff+$fwidth in byte $byteoff + + MACRO + Config_NoParm $name, $bitoff, $fwidth, $bytoff, $value + = ConType_NoParm, "$name", 0 + ALIGN + = $bitoff, $fwidth, $bytoff, $value + MEND + +; Type Field : *con. name number +; read value & put into bits $bitoff to $bitoff+$fwidth in byte $byteoff + + MACRO + Config_Field $name, $bitoff, $fwidth, $bytoff + = ConType_Field, "$name", 0 + ALIGN + = $bitoff, $fwidth, $bytoff, 0 + MEND + +; Type Size : *con. name number|nK +; read value & put into bits $bitoff to $bitoff+$fwidth in byte $byteoff + + MACRO +$l Config_Size $name, $bitoff, $fwidth, $bytoff + = ConType_Size, "$name", 0 + ALIGN +$l = $bitoff, $fwidth, $bytoff, 0 + MEND + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; now the table + +Config_Table + Config_Special Baud +AlternateBoot + Config_NoParm Boot, 4, 0, DBTBCMOS, 1 +AlternateNoBoot + Config_NoParm NoBoot, 4, 0, DBTBCMOS, 0 +AlternateCaps + Config_NoParm Caps, 3, 2, StartCMOS, 4 +AlternateNoCaps + Config_NoParm NoCaps, 3, 2, StartCMOS, 2 +ExpandShCaps + Config_NoParm ShCaps, 3, 2, StartCMOS, 1 +EndListCapsFrig + Config_Field Data, 5, 2, DBTBCMOS + Config_Field Delay, 0, 7, KeyDelCMOS +ExpandDir + Config_NoParm Dir, 6, 0, StartCMOS, 0 +ExpandNoDir + Config_NoParm NoDir, 6, 0, StartCMOS, 1 + Config_Field DumpFormat, 0, 4, TutuCMOS + Config_Size FontSize, 0, 7, FontCMOS +FontSizeFrig + Config_Special Ignore + Config_Field Language, 0, 7, LanguageCMOS +AlternateLoud + Config_NoParm Loud, 1, 0, DBTBCMOS, 1 + Config_Special Mode + Config_Special MonitorType + Config_Special MouseStep + [ AssemblePointerV + Config_Special MouseType + ] + Config_Field Print, 5, 2, PSITCMOS + [ :LNOT: DriversInKernel + Config_Size PrinterBufferSize, 0, 7, PrinterBufferCMOS +PrinterBufferFrig + ] +AlternateQuiet + Config_NoParm Quiet, 1, 0, DBTBCMOS, 0 + Config_Size RamFsSize, 0, 6, RAMDiscCMOS + Config_Field Repeat, 0, 7, KeyRepCMOS + Config_Size RMASize, 0, 6, RMASizeCMOS + Config_Size ScreenSize, 0, 6, ScreenSizeCMOS +ScreenSizeFrig +AlternateScroll + Config_NoParm Scroll, 3, 0, DBTBCMOS, 0 +AlternateNoScroll + Config_NoParm NoScroll, 3, 0, DBTBCMOS, 1 + Config_Size SpriteSize, 0, 6, SpriteSizeCMOS + Config_Special Sync + Config_Size SystemSize, 0, 5, SysHeapCMOS + Config_Special TV + Config_Special WimpMode + = 0 + +NoDirString = "No" +DirString = "Directory", 0 +ShCapsString = "ShiftCaps", 0 + + ALIGN + +ExpandFrig * 8 ; see code that shows NoParm options. +ExpandTab + & ExpandDir - ExpandFrig-. + & DirString - .-1 ; another printing fudge! + & ExpandNoDir - ExpandFrig-. + & NoDirString - .-1 + & ExpandShCaps - ExpandFrig-. + & ShCapsString - .-1 + & 0 + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + MACRO + Config_Special_Table $name, $text +Config_$name._table + B Config_$name._setcode + B Config_$name._showcode + = "$text", 0 + ALIGN + MEND + + ALIGN + Config_Special_Table Baud, "<D>" + Config_Special_Table TV, "[<D> [[,] <D>]]" + Config_Special_Table Mode, "<D> | Auto" + Config_Special_Table Ignore, "[<D>]" + Config_Special_Table MouseStep, "<D>" + [ AssemblePointerV + Config_Special_Table MouseType, "<D>" + ] + Config_Special_Table MonitorType, "<D> | Auto" + Config_Special_Table Sync, "<D> | Auto" + Config_Special_Table WimpMode, "<D> | Auto" + +;***************************************************************************** +; Lookup : R0 -> option +; Exit : R2 -> table entry, EQ for not found +; R0 stepped on + +FindOption ENTRY "r1, r3-r5" + ADRL r2, Config_Table+1 +04 + MOV r1, #0 ; offset +01 + LDRB r3, [r0, r1] + LDRB r4, [r2, r1] + CMP r3, #32 + CMPLE r4, #32 + BLE %FT02 + UpperCase r3, r5 + UpperCase r4, r5 + CMP r3, r4 + ADDEQ r1, r1, #1 + BEQ %BT01 + CMP r3, #"." + MOV r3, #Z_bit + TEQP r3, pc ; invert EQ/NE + CMPNE r1, #0 + ADDNE r1, r1, #1 ; skip . + BNE %FT02 +03 + LDRB r1, [r2], #1 + CMP r1, #0 + BNE %BT03 + ADD r2, r2, #7 ; skip infoword + BIC r2, r2, #3 + LDRB r1, [r2], #1 + CMP r1, #0 + BNE %BT04 + EXIT ; failure exit + +02 + ADD r0, r0, r1 ; point at char after option + SUBS r2, r2, #1 + EXIT ; return with success + +;**************************************************************************** +; +; Configure +; IF noparms OR parm=. THEN list options : issue service call : finish listing +; ELSE lookup parm1 : doit +; IF notfound THEN issue service + +Configure_Help ROUT + Push "r0, lr" + ADR r0, %FT01 + MOV r1, #Status_Keyword_Flag + B KeyHelpCommon +01 + DCB "HUTMCON", 0 + ALIGN + +Configure_Code ROUT + Push "lr" + CMP r1, #0 ; noparms? + MOVEQ r3, #0 + BEQ ListAll ; go listem. + BL FindOption + BEQ %FT01 + LDRB r4, [r2], #1 +03 + LDRB r1, [r2], #1 + CMP r1, #0 + BNE %BT03 + ADD r2, r2, #3 + BIC r2, r2, #3 + LDR r1, [r2] + CMP r4, #ConType_Size + BEQ ReadSizeParm + + CMP r4, #ConType_Field + ASSERT ConType_Special > ConType_Field +; if special dispatch it + ADDGT r1, r1, r2 ; point at node + ADDGT pc, r1, #Config_Special_SetCode ; call it +; if noparm get value + MOVLT r2, r1, LSR #24 + BLEQ ReadNumParm + BVS BadConParm +BaudEntry + BL ConfigCheckEOL + Pull "pc", VS +IgnoreEntry + MOV r0, r1 ; info word + BL ReadByte ; current byte into R1 + + MOV r3, r0, LSR #8 + AND r3, r3, #&FF ; get fwidth + MOV r4, #2 + MOV r4, r4, LSL r3 + SUB r4, r4, #1 ; get mask/maximum value + CMP r2, r4 + BHI ConParmTooBig + + AND r3, r0, #&FF ; get bitoff + BIC r1, r1, r4, LSL r3 ; clear bits in correct position + ORR r2, r1, r2, LSL r3 ; OR in new bits + + MOV r1, r0, LSR #16 ; get bytoff + AND r1, r1, #&FF + MOV r0, #WriteCMOS + SWI XOS_Byte ; and set it. Assume this clears V! + + Pull "pc" + +BadConParm + MOV r0, #1 + B ConfigGenErr +BadConParmError + & ErrorNumber_Syntax + = "NotNumeric:Numeric parameter needed", 0 + ALIGN + +ConParmTooBig + MOV r0, #2 + B ConfigGenErr +ConParmTooBigError + & ErrorNumber_Syntax + = "ConParmTooBig:Configure parameter too big", 0 + ALIGN +01 + MOV r12, #Module_List +conoptloop + LDR r12, [r12] + CMP r12, #0 + BEQ conoptservice + LDR r1, [r12, #Module_code_pointer] + LDR r2, [r1, #Module_HC_Table] + CMP r2, #0 + BEQ conoptloop + MOV r4, #Status_Keyword_Flag + BL FindItem + BCC conoptloop ; next module + ADD r0, r0, r3 ; point at commtail + LDR r12, [r12, #Module_incarnation_list] ; preferred life + ADDS r12, r12, #Incarnation_Workspace ; clear V + Push "r1-r6" + +StKey_SkipSpaces + LDRB r4, [r0], #1 + CMP r4, #" " + BEQ StKey_SkipSpaces + SUB r0, r0, #1 + + MOV lr, pc + ADD pc, r1, r5 ; call im + Pull "r1-r6" + Pull "pc", VC +ConfigGenErr + CMP r0, #3 + BHI ExitConfig + ADREQL r0, Config2manyparms + CMP r0, #2 + ADREQ r0, ConParmTooBigError + CMP r0, #1 + ADRLO r0, BadConOptError + ADREQ r0, BadConParmError + [ International + BL TranslateError + ] +ExitConfig + Pull "lr" + ORRS pc, lr, #V_bit + +conoptservice + MOV r1, #Service_UKConfig + BL Issue_Service + CMP r1, #0 + BNE BadConOpt + CMP r0, #0 + BGE ConfigGenErr + Pull "pc" ; TBS means OK: note CMP has cleared V + +BadConOpt + MOV r0, #0 + B ConfigGenErr +BadConOptError + & ErrorNumber_Syntax + = "BadConOpt:Bad configure option", 0 + ALIGN + +ReadNumParm ENTRY "r1" +10 + LDRB r2, [r0], #1 + CMP r2, #" " + BEQ %BT10 + SUB r1, r0, #1 + SWI XOS_ReadUnsigned + EXIT VS + MOV r0, r1 + LDRB r1, [r0] + CMP r1, #" " + SETV GT + EXIT + +; read a number or Auto +; returns R2 = number or -1 for Auto +; R0 -> terminator + +ReadNumAuto ENTRY "r1,r3,r4" +10 + LDRB r2, [r0], #1 + CMP r2, #" " + BEQ %BT10 + SUB r1, r0, #1 + ADR r3, AutoString ; string to match against + MOV r4, #0 ; no other terminators for $R1 + BL Module_StrCmp ; out: EQ => match, r1 -> terminator + ; NE => no match, r1 preserved + ; r3 corrupted in both cases + MOVEQ r2, #-1 + BEQ %FT20 + SWI XOS_ReadUnsigned + EXIT VS +20 + MOV r0, r1 + LDRB r1, [r0] + CMP r1, #" " + SETV GT + EXIT + +AutoString + = "Auto", 0 + ALIGN + +ReadSizeParm ROUT + Push "r1, r8" + MOV r8, r2 +02 + LDRB r2, [r0], #1 + CMP r2, #" " + BEQ %BT02 + SUB r1, r0, #1 + SWI XOS_ReadUnsigned + Pull "r1, r8", VS + BVS BadConParm + MOV r0, r1 + LDRB r1, [r0] + CMP r1, #" " + BLE %FT01 + CMP r1, #"k" + CMPNE r1, #"K" + Pull "r1, r8", NE + BNE BadConParm + [ :LNOT: DriversInKernel + ADRL r14, PrinterBufferFrig-4 + TEQ r8, r14 ; if printer buffer size + TEQEQ r2, #1 ; and 1K + MOVEQ r2, #0 ; then use zero (default) + ] + ADRL r14, FontSizeFrig-4 ; point at info word for fontsize + TEQ r8, r14 ; if fontsize + MOVEQ r8, #4*1024 ; then use 4K (lucky it's a pagesize!) + MOVNE r8, #0 ; else use pagesize units + LDRNE r8, [r8, #Page_Size] + ADRL r14, PageShifts-1 + LDRB r14, [r14, r8, LSR #12] + SUB r14, r14, #10 ; *1024 + MOV r8, r8, LSR #10 ; /1024 + SUB r8, r8, #1 + ADD r2, r2, r8 + BIC r2, r2, r8 ; round up to nearest pagesize + MOV r2, r2, LSR r14 ; divide parm by pagesize + ADD r0, r0, #1 ; point past "K" for EOL checking +01 + Pull "r1, r8" + B BaudEntry + +;***************************************************************************** +; Status +; list all options matched : allow . and <terminator> to match all +; issue service + +Status_Code ROUT + Push "lr" + CMP r1, #0 ; noparms? + MOVEQ r3, #1 + BEQ ListAll ; go listemall + CMP r1, #1 + BNE %FT01 + BL FindOption + BEQ %FT01 + MOV r3, #2 + BL ListOneConfig + Pull "pc" + +01 + MOV r6, #Module_List +statoptloop + LDR r6, [r6] + CMP r6, #0 + BEQ statoptservice + LDR r1, [r6, #Module_code_pointer] + LDR r2, [r1, #Module_HC_Table] + CMP r2, #0 + BEQ statoptloop + MOV r4, #Status_Keyword_Flag + BL FindItem + BCC statoptloop ; next module + MOV r0, #1 + LDR r12, [r6, #Module_incarnation_list] + ADD r12, r12, #Incarnation_Workspace + Push "r0-r6" + MOV lr, pc + ADD pc, r1, r5 ; call im + STRVS r0, [sp] + Pull "r0-r6, pc" + +statoptservice + MOV r1, #Service_UKStatus + BL Issue_Service + CMP r1, #0 + Pull "pc", EQ + ADR r0, %FT03 + [ International + BL TranslateError + ] + Pull "lr" + ORRS pc, lr, #V_bit +03 + & ErrorNumber_Syntax + = "BadStat:Bad status option", 0 + ALIGN + +;***************************************************************************** + +; routine to list everything : on entry R3 = 0 means entered from configure +; = 1 " " " status +; lr stacked for return + +ListAll ROUT + MOV r0, #117 ; Read current VDU status + SWI XOS_Byte ; Won't fail + Push "r1" + + [ International + SWI XOS_WriteI+14 + BL WriteS_Translated + = "Config:Configuration",0 + ALIGN + SWIVC XOS_WriteI+" " + | + SWI XOS_WriteS + = 14, "Configuration ", 0 ; paged mode on. + ALIGN + ] + Pull "r1, pc", VS ; Wrch can fail + CMP r3, #0 + ADREQ r0, %FT06 + ADRNE r0, %FT08 + [ International + BL Write0_Translated + | + SWI XOS_Write0 + ] + SWIVC XOS_NewLine + SWIVC XOS_NewLine + Pull "r1, pc", VS + + ADRL r2, Config_Table +02 + ADRL r4, AlternateCaps + CMP r4, r2 + CMPEQ r3, #1 + BEQ FrigCapsList + LDRB r4, [r2] + CMP r4, #0 + BLNE ListOneConfig + Pull "r1, pc", VS + BNE %BT02 + +10 + ADRL r0, dotstring ; match all + Push "r3, r7" + MOV r7, #Module_List +listallmloop + LDR r7, [r7] + CMP r7, #0 + BEQ listallservice + LDR r1, [r7, #Module_code_pointer] + LDR r2, [r1, #Module_HC_Table] + CMP r2, #0 + BEQ listallmloop +listalltryfind + MOV r4, #Status_Keyword_Flag + BL FindItem + BCC listallmloop ; next module + LDR r0, [stack] ; pick up r3 + LDR r12, [r7, #Module_incarnation_list] + ADD r12, r12, #Incarnation_Workspace + Push "r0-r6" + MOV lr, pc + ADD pc, r1, r5 ; call im + Pull "r0-r6" + ADD r2, r2, #16 ; step to next field + ADRL r0, dotstring + B listalltryfind + + [ International +06 + = "Options:options:",0 +08 + = "Status:status:",0 + | +06 + = "options:",0 +08 + = "status:",0 + ] + ALIGN + +listallservice + Pull "r3, r7" + CMP r3, #0 + MOVEQ r1, #Service_UKConfig + MOVNE r1, #Service_UKStatus + MOV r0, #0 ; indicate list wanted + BL Issue_Service + CMP r3, #0 + [ International + BEQ %FT20 + BL GSWriteS_Translated + = "STail:|J|MUse *Configure to set the options.|J|M",0 + ALIGN + B %FT30 +20 + BL GSWriteS_Translated + = "CTail1:|J|MWhere:|J|MD is a decimal number, a hexadecimal number preceded by &,|J|M" + = "or the base followed by underscore, followed|J|M",0 + ALIGN + BL GSWriteS_Translated + = "CTail2:by digits in the given base.|J|MItems within [ ] are optional.|J|M" + = "Use *Status to display the current settings.|J|M",0 + ALIGN +30 + | + ADRNE r0, statuslastline + ADREQ r0, configlastline + SWI XOS_Write0 + ] + Pull "r1" + Pull "pc", VS ; return error if set + TST r1, #5 + SWIEQ XOS_WriteI+15 ; paged mode off + Pull "pc" + + [ :LNOT: International +statuslastline + = 10,13, "Use *Configure to set the options.", 10,13,0 +configlastline + = 10,13, "Where:", 10,13 + = "D is a decimal number, " ;, 10,13 + = "a hexadecimal number preceded by &, ", 10,13 + = "or the base followed by underscore, followed", 10,13 + = "by digits in the given base.", 10,13 + = "Items within [ ] are optional.", 10,13 + = "Use *Status to display the current settings.", 10,13, 0 + ALIGN + ] + +FrigCapsList + MOV r3, #2 + BL ListOneConfig + Pull "r1, pc", VS + MOV r3, #1 + ADRL r2, EndListCapsFrig + B %BT02 + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +; routine to list one item : +; R3 = 0 means entered from configure +; = 1 " " " status +; = 2 " " " status <item> +; R2 points at the item, stepped to next on exit +; Preserves flags + +ListOneConfig ROUT + Push "lr" + LDRB r4, [r2] + CMP r4, #ConType_Field + CMPNE r4, #ConType_Size + CMPNE r3, #0 + BNE %FT20 + + ADD r0, r2, #1 + SWI XOS_Write0 + BVS ExitShow + SUB r1, r0, r2 ; get length + ADD r2, r0, #3 ; skip terminator + BIC r2, r2, #3 ; and align + + CMP r4, #ConType_NoParm + BEQ %FT07 +04 + SWI XOS_WriteI+" " + BVS ExitShow + ADD r1, r1, #1 + CMP r1, #12 + BLS %BT04 + + CMP r3, #0 + BNE %FT30 + + CMP r4, #ConType_Size + ADREQ r0, %FT42 + BEQ %FT43 + + CMP r4, #ConType_Field + ASSERT ConType_Special > ConType_Field + ADREQ r0, %FT05 + LDRGT r0, [r2] + ADDGT r0, r0, r2 ; point at node + ADDGT r0, r0, #Config_Special_String ; point at string +43 + SWI XOS_Write0 +07 + ADD r2, r2, #4 +ExitShow + SWIVC XOS_NewLine +11 + Pull "lr" + BICVCS pc, lr, #V_bit + ORRS pc, lr, #V_bit +05 + = "<D>", 0 +42 + = "<D>[K]", 0 + +; status bits : + +20 + ADD r0, r2, #1 ; got to do *status on a NoParm or Special +21 + LDRB r1, [r0], #1 + CMP r1, #0 ; step past name + BNE %BT21 + ADD r0, r0, #3 + BIC r0, r0, #3 ; align + LDR r1, [r0] ; get info word. + CMP r4, #ConType_Special + ADDEQ r1, r1, r0 ; point at node + ADDEQ pc, r1, #Config_Special_ShowCode + +; if CRbytevalue = infowordvalue then print something + + MOV r4, r0 ; hang on to it + MOV r0, r1 + BL GetValue + MOV r1, r1, LSR #24 ; value. + CMP r0, r1 + BNE %FT10 ; check for *Status <Item> + +; first see if expansion needed + + ADRL r0, ExpandTab +22 + LDR r1, [r0], #8 + CMP r1, #0 + BEQ %FT23 + ADD r1, r1, r0 ; get real address + CMP r1, r2 + BNE %BT22 + LDR r2, [r0, #-4]! +14 + ADD r2, r2, r0 ; new string +23 + ADD r2, r2, #1 + +; now write chars with space between lowercase then upper + + MOV r1, #1 ; indicate uppercase last +24 + LDRB r0, [r2], #1 + CMP r0, #0 + BEQ %FT25 + CMP r0, #"Z" ; uppercase if LE + CMPLE r1, #0 + SWILE XOS_WriteI+" " + BVS ExitShow + CMP r0, #"Z" + MOVLE r1, #1 + MOVGT r1, #0 + SWI XOS_WriteC + BVC %BT24 + +25 + ADDVC r2, r4, #4 + B ExitShow + +30 + LDR r0, [r2], #4 ; got to do *status for Field + CMP r4, #ConType_Size + MOV r4, r2 + BL GetValue + BEQ %FT31 + BL PrintR0 + B ExitShow +31 + Push "r8, r9" + ADRL r8, FontSizeFrig + CMP r4, r8 + MOVNE r8, #0 + LDRNE r8, [r8, #Page_Size] + MOVEQ r8, #4*1024 + ADRL r9, PageShifts-1 + LDRB r9, [r9, r8, LSR #12] + SUB r9, r9, #10 + MOVS r0, r0, LSL r9 ; size in K + BNE %FT35 + [ :LNOT: DriversInKernel + ADRL r8, PrinterBufferFrig ; if zero and PrinterBufferSize, then 1K + TEQ r8, r2 + MOVEQ r0, #1 + BEQ %FT35 + ] + ADRL r8, ScreenSizeFrig ; if zero and it's ScreenSize, then call OS_ReadSysInfo to find appropriate amount + TEQ r8, r2 + SWIEQ XOS_ReadSysInfo ; proper screen size (r0=0) on entry + MOVEQ r0, r0, LSR #10 +35 + Pull "r8, r9" + BL PrintR0 + SWIVC XOS_WriteI+"K" + B ExitShow + +10 + CMP r3, #2 + ADDNE r2, r4, #4 + BNE %BT11 + +; R0 is the value set : can corrupt R3 as this is the do-one entry + + MOV r3, r0 + ADRL r0, AlternateTab ; look for option really set +12 + LDR r1, [r0], #8 ; better find a match! + ADD r1, r1, r0 ; get real address + CMP r1, r2 + BNE %BT12 + LDR r2, [r0, #-4]! + ADD r2, r2, r0 ; translation table + LDR r0, [r2, r3, LSL #2] + B %BT14 ; go printit + +AlternateTab + & AlternateBoot - ExpandFrig-. + & %FT91 -. + & AlternateNoBoot - ExpandFrig-. + & %FT91 -. + & AlternateCaps - ExpandFrig-. + & %FT92 -. + & AlternateNoCaps - ExpandFrig-. + & %FT92 -. + & ExpandShCaps - ExpandFrig-. + & %FT92 -. + & ExpandDir - ExpandFrig-. + & %FT93 -. + & ExpandNoDir - ExpandFrig-. + & %FT93 -. + & AlternateLoud - ExpandFrig-. + & %FT95 -. + & AlternateQuiet - ExpandFrig-. + & %FT95 -. + & AlternateScroll - ExpandFrig-. + & %FT96 -. + & AlternateNoScroll - ExpandFrig-. + & %FT96 -. + +91 + & AlternateNoBoot -%BT91 + & AlternateBoot -%BT91 +92 + & ShCapsString -%BT92-1 + & ShCapsString -%BT92-1 + & AlternateNoCaps -%BT92 + & AlternateNoCaps -%BT92 + & AlternateCaps -%BT92 + & AlternateCaps -%BT92 + & AlternateCaps -%BT92 + & AlternateCaps -%BT92 +93 + & DirString -%BT93-1 + & NoDirString -%BT93-1 +95 + & AlternateQuiet -%BT95 + & AlternateLoud -%BT95 +96 + & AlternateScroll -%BT96 + & AlternateNoScroll -%BT96 + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +; read byte from CMOS RAM : info word in R0, byte -> R1 + +ReadByte ENTRY "r0, r2" + MOV r1, r0, LSR #16 ; get bytoff + AND r1, r1, #&FF + MOV r0, #ReadCMOS + SWI XOS_Byte + MOV r1, r2 + EXIT + +; take infoword in R0, return value in R0 + +GetValue ENTRY "r1" + BL ReadByte ; now extract the value + AND r14, r0, #&FF ; get bitoff + MOV r1, r1, LSR r14 ; throw away low bits + MOV r0, r0, LSR #8 + AND r0, r0, #&FF ; get fwidth + RSB r0, r0, #31 ; number of positions to shift up to remove unwanted bits + MOV r1, r1, LSL r0 ; shift up... + MOV r0, r1, LSR r0 ; ...then down again + EXITS + +PrintR0 ENTRY "r1, r2" + CMP r0, #-1 + BNE %FT10 + ADRL r0, AutoString + SWI XOS_Write0 + EXIT +10 + SUB sp, sp, #32 + MOV r1, sp + MOV r2, #32 + SWI XOS_ConvertInteger4 + SWIVC XOS_Write0 + ADD sp, sp, #32 + EXIT + +NoString = "No ", 0 + ALIGN + +ConfigCheckEOL ROUT + LDRB r3, [r0], #1 + CMP r3, #" " + BEQ ConfigCheckEOL + CMP r3, #13 + CMPNE r3, #10 + CMPNE r3, #0 + MOVEQ pc, lr + ADR R0, Config2manyparms + [ International + Push "lr" + BL TranslateError + Pull "lr" + | + SETV + ] + MOV pc, lr + +Config2manyparms + & ErrorNumber_Syntax + = "Config2manyparms:Too many parameters" + +;************************************************************************* + +IgnoreBitoff * 1 + +Config_TV_setcode ROUT + LDRB r2, [r0], #1 + CMP r2, #" " + BEQ Config_TV_setcode + SUB r1, r0, #1 + SWI XOS_ReadUnsigned + BVS %FT01 + CMP r2, #3 + SUBGT r0, r2, #252 + CMPGT r0, #3 + BHI BadConOpt + CMP r2, #3 + ANDGT r2, r2, #7 ; top bit set in field means 252-255 + Push "r2" + MOV r0, #0 +03 + LDRB r2, [r1], #1 + CMP r2, #" " + BEQ %BT03 + CMP r2, #"," + CMPEQ r0, #0 + MOVEQ r0, #"," + BEQ %BT03 + SUB r1, r1, #1 + Push "r0" + MOV r0, #10 + SWI XOS_ReadUnsigned + Pull "r0" + BVC %FT04 + CMP r0, #0 + Pull "r0", NE + BNE BadConOpt +04 + CMP r2, #1 + Pull "r0" + BHI ConParmTooBig + ORR r2, r2, r0, LSL #1 +01 + MOV r0, r1 + LDR r1, %FT02 + B BaudEntry +02 + = 4, 3, MODETVCMOS, 0 + +Config_TV_showcode + MOV r4, r0 + SWI XOS_WriteS + = "TV ", 0 + ALIGN + MOVVC r0, #ReadCMOS + MOVVC r1, #MODETVCMOS + SWIVC XOS_Byte + MOVVC r2, r2, LSL #24 + MOVVC r0, r2, ASR #29 ; get signed TV shift + ANDVC r0, r0, #&FF + BLVC PrintR0 + SWIVC XOS_WriteI+"," + MOVVC r0, r2, LSR #28 + ANDVC r0, r0, #1 ; interlace bit + BLVC PrintR0 + ADD r2, r4, #4 + B ExitShow + +Config_Ignore_setcode ROUT + LDRB r2, [r0], #1 + CMP r2, #" " + BEQ Config_Ignore_setcode + SUB r1, r0, #1 + SWI XOS_ReadUnsigned + MOV r0, r1 + Push "r2" + ADR lr, %FT03 + Push lr ; return reg for BaudEntry + MOVVS r2, #1 + MOVVC r2, #0 ; if number had clear noignore + LDR r1, %FT01 + B BaudEntry ; pseudo-BL +03 + Pull "r2" ; set to 0 if noignore, but we don't care! + LDR r1, %FT02 + B IgnoreEntry +01 + = IgnoreBitoff, 0, PSITCMOS, 0 +02 + = 0, 7, PigCMOS, 0 + +Config_Ignore_showcode + MOV r4, r0 + MOV r0, #ReadCMOS + MOV r1, #PSITCMOS + SWI XOS_Byte + TST r2, # 1 :SHL: IgnoreBitoff + ADRNE r0, NoString + SWINE XOS_Write0 + BVS ExitShow + SWI XOS_WriteS + = "Ignore", 0 + ALIGN + BVS ExitShow + ADDNE r2, r4, #4 + BNE ExitShow + MOV r1, #PigCMOS + SWI XOS_Byte + SWI XOS_WriteS + = " ", 0 + ALIGN + MOV r1, #PigCMOS + SWIVC XOS_Byte + MOVVC r0, r2 + BLVC PrintR0 + ADD r2, r4, #4 + B ExitShow + +Config_Mode_setcode ROUT +Config_WimpMode_setcode ROUT + ADR r1, ModeCMOSTable +ConfigMultiField ROUT + BL ReadNumAuto + BVS BadConParm + CMP r2, #-1 + LDR r14, [r1], #4 ; get auto number + MOVEQ r2, r14 ; if auto number then replace by auto value + LDR r14, [r1], #4 ; get maximum value + CMPNE r2, r14 ; if not auto then check maximum value + BHI ConParmTooBig + BL ConfigCheckEOL + BVS ExitConfig + MOV r0, r1 + BL WriteMultiField + Pull "pc" ; was already stacked by *Configure + +ModeCMOSTable + & 256 ; Auto value + & 255 ; maximum valid number +; address, mask from bit 0, shift to 1st bit in value, shift to 1st bit in CMOS + [ {TRUE} ; mode = wimpmode + = WimpModeCMOS, &FF, 0, 0 ; normal bits here + = Mode2CMOS, &01, 8, 4 ; mode auto bit + ASSERT WimpModeAutoBit = 16 + | + = MODETVCMOS, &0F, 0, 0 ; bits 0 to 3 here + = VduCMOS, &01, 4, 1 ; bit 4 here + = Mode2CMOS, &0F, 5, 0 ; bits 5 to 7, and auto bit here + ] + = 0 + ALIGN + +; Write a number of CMOS RAM bit fields from a value + +; in: r0 -> table +; r2 -> value to split +; +; out: - + +WriteMultiField ENTRY "r0-r5" + MOV r3, r0 ; pointer to where we're at in table + MOV r4, r2 ; value +10 + LDRB r1, [r3], #1 + TEQ r1, #0 + EXIT EQ + MOV r0, #ReadCMOS + SWI XOS_Byte + LDRB r0, [r3], #1 ; r0 = mask + LDRB r5, [r3], #1 ; r5 = shift to 1st bit in value + LDRB r14, [r3], #1 ; r14 = shift to 1st bit in CMOS + BIC r2, r2, r0, LSL r14 ; knock out previous bits + AND r5, r0, r4, LSR r5 ; get new bits, at bottom of byte + ORR r2, r2, r5, LSL r14 ; form new CMOS value + MOV r0, #WriteCMOS + SWI XOS_Byte + B %BT10 + +; Read a value formed by merging a number of CMOS RAM bit fields + +; in: r0 -> table +; out: r0 = value + +ReadMultiField ENTRY "r1-r6" + LDR r6, [r0, #4] ; get maximum value allowed + ADD r3, r0, #2*4 ; pointer to where we're at in table (skip auto, max) + MOV r4, #0 ; cumulative value +10 + LDRB r1, [r3], #1 + TEQ r1, #0 + BEQ %FT20 + MOV r0, #ReadCMOS + SWI XOS_Byte + LDRB r0, [r3], #1 ; r0 = mask + LDRB r5, [r3], #1 ; r5 = shift to 1st bit in value + LDRB r14, [r3], #1 ; r14 = shift to 1st bit in CMOS + AND r2, r0, r2, LSR r14 ; get relevant bits in bottom of byte + ORR r4, r4, r2, LSL r5 ; merge new bits with value + B %BT10 +20 + CMP r4, r6 ; if within range + MOVLS r0, r4 ; then return that value + MOVHI r0, #-1 ; else return -1 indicating Auto + EXIT + +Config_Mode_showcode ROUT + MOV r4, r0 + ADR r0, ModeSpacedString +ModeWimpModeShowCode + SWI XOS_Write0 + BVS %FT10 + BL Read_Configd_Mode + BL PrintR0 +10 + ADD r2, r4, #4 + B ExitShow + +ModeSpacedString + = "Mode ", 0 +WimpModeSpacedString + = "WimpMode ", 0 + ALIGN + +Config_WimpMode_showcode ROUT + MOV r4, r0 + ADR r0, WimpModeSpacedString + B ModeWimpModeShowCode + +Read_Configd_Mode ENTRY + ADR r0, ModeCMOSTable + BL ReadMultiField + EXIT + +Config_Baud_setcode ROUT + BL ReadNumParm + BVS BadConParm + CMP r2, #8 + BGT ConParmTooBig + SUBS r2, r2, #1 + MOVMI r2, #6 + LDR r1, %FT01 ; set up info word + B BaudEntry +01 + = 2, 2, PSITCMOS, 0 + +Config_Baud_showcode + MOV r4, r0 + SWI XOS_WriteS + = "Baud ", 0 + ALIGN + LDRVC r0, %BT01 ; get infoword + BLVC GetValue + ADDVC r0, r0, #1 + BLVC PrintR0 + ADD r2, r4, #4 + B ExitShow + +Config_MouseStep_setcode ROUT + LDRB r2, [r0], #1 + CMP r2, #" " + BEQ Config_MouseStep_setcode + CMP r2, #"-" + Push "r2" + SUBNE r1, r0, #1 + SWI XOS_ReadUnsigned + Pull "r0" + BVS BadConParm + CMP r0, #"-" + RSBEQ r2, r2, #0 + CMP r2, #0 + BEQ BadConOpt + CMP r2, #-128 + BLT BadConOpt + CMP r2, #127 + BGT ConParmTooBig + MOV r0, r1 + LDR r1, %FT02 + B BaudEntry +02 + = 0, 7, MouseStepCMOS, 0 + +Config_MouseStep_showcode ROUT + MOV r4, r0 + SWI XOS_WriteS + = "MouseStep ", 0 + ALIGN + MOVVC r0, #ReadCMOS + MOVVC r1, #MouseStepCMOS + SWIVC XOS_Byte + BVS %FT01 + MOVS r2, r2, LSL #24 + MOVNE r0, r2, ASR #24 ; get sign extended byte + MOVEQ r0, #1 + BL PrintR0 +01 ADD r2, r4, #4 + B ExitShow + +Config_MouseType_setcode ROUT + LDRB r2, [r0], #1 + CMP r2, #" " + BEQ Config_MouseType_setcode + SUB r1, r0, #1 + SWI XOS_ReadUnsigned + BVS BadConParm + CMP r2, #&100 + BCS ConParmTooBig + MOV r4, r1 + MOV r0, #1 + MOV r1, r2 + SWI XOS_Pointer + MOV r0, r4 + LDR r1, %FT01 + B BaudEntry +01 + = 0, 7, MouseCMOS, 0 + +Config_MouseType_showcode + MOV r4, r0 + SWI XOS_WriteS + = "MouseType ", 0 + ALIGN + LDRVC r0, %BT01 + BLVC GetValue + BLVC PrintR0 + ADD r2, r4, #4 + B ExitShow + +Config_MonitorType_setcode + [ ModeSelectors + ADR r1, MonitorTypeCMOSTable + BL ReadNumAuto + BVS BadConParm + MOV r4, r2 ; save value to store in current monitortype + CMP r2, #-1 + LDR r14, [r1], #4 ; get auto number + MOVEQ r2, r14 ; if auto number then replace by auto value + LDR r14, [r1], #4 ; get maximum value + CMPNE r2, r14 ; if not auto then check maximum value + BHI ConParmTooBig + BL ConfigCheckEOL + BVS ExitConfig + + LDR r0, =VduDriverWorkSpace+CurrentMonitorType + STR r4, [r0] ; update current value + + MOV r0, r1 + BL WriteMultiField + Pull "pc" ; was already stacked by *Configure + | + ADR r1, MonitorTypeCMOSTable + B ConfigMultiField + ] + +MonitorTypeCMOSTable + & MonitorTypeAuto :SHR: MonitorTypeShift ; Auto value + & MonitorTypeF :SHR: MonitorTypeShift ; maximum valid number +; address, mask from bit 0, shift to 1st bit in value, shift to 1st bit in CMOS + = VduCMOS, MonitorTypeBits :SHR: MonitorTypeShift, 0, MonitorTypeShift + = 0 + ALIGN + +Config_MonitorType_showcode ROUT + MOV r4, r0 + SWI XOS_WriteS + = "MonitorType ", 0 + ALIGN + BVS %FT10 + BL Read_Configd_MonitorType + BL PrintR0 +10 + ADD r2, r4, #4 + B ExitShow + +Read_Configd_MonitorType ENTRY + ADR r0, MonitorTypeCMOSTable + BL ReadMultiField + EXIT + +Config_Sync_setcode + ADR r1, SyncCMOSTable + B ConfigMultiField + +SyncCMOSTable + & 3 ; Auto value + & 1 ; maximum valid number +; address, mask from bit 0, shift to 1st bit in value, shift to 1st bit in CMOS + = VduCMOS, 1, 0, 0 + = VduCMOS, 1, 1, 7 + = 0 + ALIGN + +Config_Sync_showcode ROUT + MOV r4, r0 + SWI XOS_WriteS + = "Sync ", 0 + ALIGN + BVS %FT10 + BL Read_Configd_Sync + BL PrintR0 +10 + ADD r2, r4, #4 + B ExitShow + +Read_Configd_Sync ENTRY + ADR r0, SyncCMOSTable + BL ReadMultiField + EXIT + + [ :LNOT: DriversInKernel +SetUpPrinterBuffer ENTRY "r1-r3" + MOV r0, #PrinterBufferCMOS + BL Read + MOV r2, #0 + LDR r2, [r2, #Page_Size] + MULS r3, r2, r0 + BEQ %FT10 ; if zero, then use default area & size + + BL ClaimSysHeapNode ; else claim space from system heap + BVC %FT20 ; if no error then OK, else use default +10 + LDR r2, =PrintBuff ; use default buffer + MOV r3, #PrintBuffSize +20 + MOV r0, #0 + STR r2, [r0, #PrinterBufferAddr] + STR r3, [r0, #PrinterBufferSize] + EXIT + ] + + END diff --git a/s/ArthurSWIs b/s/ArthurSWIs new file mode 100644 index 0000000000000000000000000000000000000000..9c9a8dee9785e679545e0abc16b80c31808b7e4b --- /dev/null +++ b/s/ArthurSWIs @@ -0,0 +1,1080 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + TTL => ArthurSWIs - ReadUnsigned, Vectors, Bits + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; ReadUnsigned. +; ============ +; +; Read an unsigned number from a string in decimal (no prefix), hex (&) +; or given base (nn_). Leading spaces are stripped. +; 'Bad base for number' is given if a base is not in 02..10_36 +; 'Bad number' is given if +; (i) No valid number was +; or (ii) a '<base>_' or '&' has no following valid number +; 'Number too big' is given if the result overflowed a 32-bit word + +; In r1 -> string +; r0 = base to read number in (0 means any based number allowed) +; bit 31 set -> check term chars for ok-ness +; bit 30 set -> restrict range to 00..FF +; bit 29 set -> restrict range to 0..R2 (inclusive) +; (overrides bit 30) + +; Out VC : r1 -> first unused char, r2 = number +; VS : r1 unchanged, r2 = 0, current error block set + +ReadUnsigned_Routine ENTRY "r0-r1, r3-r4, r9" + + TEQP PC, #SVC_mode + +; first set range limit + MOV r9, r2 ; limit value + TST r0, #3 :SHL: 29 + MOVEQ r9, #-1 ; used unsigned; allows anything + TSTNE r0, #1 :SHL: 30 + MOVNE r9, #&FF + + MOV r11, r0 ; Remember the input flags + BIC r12, r0, #(2_111 :SHL: 29) ; r12 := base + CMP r12, #2 ; If base nonsensical, default to 10 + RSBGES r14, r12, #36 ; ie. try to match most generally + MOVLT r12, #10 + +01 LDRB r0, [r1], #1 ; Skip spaces for Bruce + TEQ r0, #" " + BEQ %BT01 + SUB r10, r1, #1 ; Keep ptr to start of string after spaces + + TEQ r0, #"&" ; '&' always forces hex read + BNE %FT20 + MOV r4, #16 + BL ReadNumberInBase + BVS %FT95 + +10 STR r1, [sp, #4] ; Update string^ + TST r11, #(1 :SHL: 31) ; Was the termcheck flag set ? + BEQ %FT15 + LDRB r0, [r1] ; What was the term char ? + CMP r0, #" " ; CtrlChar + space all ok + BGT %FT85 ; For bad term errors + +15 CMP r2, r9 + BHI %FT80 + PullEnv + ExitSWIHandler ; VClear already in lr + + +20 SUB r1, r1, #1 ; Skip back to first char of string + MOV r4, #10 ; Try reading a decimal number + BL ReadNumberInBase + MOVVS r4, r12 ; If we failed to read a decimal number + BVS %FT30 ; then use the one supplied (r12). r1 ok + LDRB r0, [r1] ; Is it base_number ? + CMP r0, #"_" ; If not based, use supplied base + MOVNE r1, r10 ; to read from given start of string (spaces !) + MOVNE r4, r12 ; restore supplied base! + ADDEQ r1, r1, #1 ; Skip the '_' + MOVEQ r4, r2 ; Use this as new base + +; Reading number in base r4 + +30 CMP r4, #2 ; Is base valid (2..36) ? + RSBGES r0, r4, #36 ; LT -> invalid + BLT %FT90 + BL ReadNumberInBase ; Read rest of number + BVS %FT95 + B %BT10 + + +80 ADR r2, ErrorBlock_NumbTooBig + [ International + B %FT94 + | + B %FT95 + ] + +85 ADR r2, ErrorBlock_BadNumb + [ International + B %FT94 + | + B %FT95 + ] + +90 ADR r2, ErrorBlock_BadBase + + [ International +94 + Push "r0,lr" + MOV r0,r2 + BL TranslateError + MOV r2,r0 + Pull "r0,lr" + ] + +95 + STR r2, [stack] ; Go set the current error + PullEnv + MOV r2, #0 ; Defined to return 0 on error + B SLVK_SetV + + MakeErrorBlock BadBase + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; ReadNumberInBase +; ================ + +; In r1 -> string, r4 = base (valid) + +; Out VC : Number read in r2, r1 updated. r3 = number of chars used +; VS : r1 preserved, r2 -> error block + +ReadNumberInBase ENTRY "r0, r1, r12" + + MOV r2, #0 ; Result + MOV r3, #0 ; Number of valid digits read + +10 BL GetCharForReadNumber + BNE %FT50 ; Finished ? + MOV r12, r4 + + MOV r14, #0 ; Multiply by repeated addition. Base <> 0 ! +20 ADDS r14, r14, r2 + BCS %FT90 ; Now checks for overflow ! + SUBS r12, r12, #1 ; result *:= base + BNE %BT20 + ADDS r2, r14, r0 ; result +:= digit + BCC %BT10 + B %FT90 ; Now checks for overflow here too! + +50 CMP r3, #0 ; Read any chars at all ? VClear + STRNE r1, [sp, #4] ; Update string^ + EXIT NE ; Resultis r2 + + [ International + Push "r0" + ADR r0, ErrorBlock_BadNumb + BL TranslateError + MOV r2,r0 + Pull "r0" + | + ADR r2, ErrorBlock_BadNumb + SETV + ] + EXIT + MakeErrorBlock BadNumb + +90 + [ International + Push "r0" + ADR r0, ErrorBlock_NumbTooBig + BL TranslateError + MOV r2,r0 + Pull "r0" + | + ADR r2, ErrorBlock_NumbTooBig + SETV + ] + EXIT + MakeErrorBlock NumbTooBig + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; GetCharForReadNumber +; ==================== +; +; Read a digit and validate for reading in current base. Bases 2..36 are valid + +; In r1 -> string, r4 = base for number input + +; Out EQ -> r0 = valid number in [0..base-1], r1++ +; NE -> r0 invalid, r1 same + +GetCharForReadNumber ENTRY + + LDRB r0, [r1] + CMP r0, #"0" + BLO %FT95 + CMP r0, #"9" + BLS %FT50 + UpperCase r0, r14 + CMP r0, #"A" ; Always hex it, even if reading in decimal + RSBGES r14, r0, #"Z" ; Inverse compare as nicked from UpperCase + BLT %FT95 ; GE -> in range A..Z + SUB r0, r0, #"A"-("0"+10) +50 SUB r0, r0, #"0" + CMP r0, r4 ; digit in [0..base-1] ? + BHS %FT95 + ADD r1, r1, #1 ; r1++ + ADD r3, r3, #1 ; Valid digit has been read + CMP r0, r0 ; EQ + EXIT + +95 CMP r0, #-1 ; NE + EXIT + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Initialise_vectors() +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + ^ 0 +TailPtr # 4 ; order very carefully chosen! +VecWSpace # 4 +Address # 4 +VecNodeSize # 0 + +InitVectors + +; for vec:=0 to NVECTORS-1 do vectab!(vec*4):= defaultvectab+8*vec + + MOV R0, #NVECTORS + ADR R1, defaultvectab ; Point at the default vector table + LDR R2, =VecPtrTab ; Point at table of head pointers + +VecInitLoop + STR R1, [R2], #4 + ADD R1, R1, #VecNodeSize ; defaultvectab+vns*vec + SUBS R0, R0, #1 ; Next vec + BGT VecInitLoop + + MOV PC, link + LTORG + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Call_vector (n) +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In: r10 = vector number +; lr contains return address + flags/int state to set up before calling + +; Out: r10, r12, lr corrupted + +CallVector ROUT + + CMP r10, #NVECTORS + MOVCSS pc, lr ; return - silly value + + Push lr ; claimed return goes back to caller + TEQP lr, #0 ; put back caller's flags + int state + + LDR r14, =VecPtrTab ; Point at table of head pointers + LDR r10, [r14, r10, LSL #2] ; nextblock:=vecptrtab!(n*4) + +CallVecLoop + MOV lr, pc ; Set up the return address + LDMIA r10, {r10, r12, pc} ; CALL the vectored routine, step chain + +; NB. It is the responsibility of vector code NOT to corrupt flags that are +; part of the input conditions if they are going to pass the call on, eg. INSV +; must not do CMP as C,V are needed by old handler + + TEQ r10, #0 ; until nextblock points to zero + BNE CallVecLoop + + Pull pc,,^ ; we don't expect to get to here + ; (should always be claimed), + ; but return to caller, restoring flags + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +;Add_To_vector(n, Addressess) +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Add_ToVector_SWICode ROUT + + CMP R0, #NVECTORS + BCS BadClaimNumber + Push "R0-R4, link" + B GoForAddToVec + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +;Claim_vector(n, Addressess) +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +ClaimVector_SWICode ROUT + ; On Entry : R0 = Vector number, R1 = Address, R2 = workspace reqd + + CMP R0, #NVECTORS + BCS BadClaimNumber + + Push "R0-R4, link" + + [ IrqsInClaimRelease + MOV R4, #I_bit + TST R4, PC ; is I_bit set ? + TEQEQP R4, PC ; No, then set it, save changed bits + MOVNE R4, #0 ; Else no changed bits + + MOV R3, #0 ; List of de-linked nodes is empty + LDR R11, =VecPtrTab ; Get ptr to table of head pointers + LDR R10, [R11, R0, LSL #2]! ; R10 "nextblock" := *oldptr, R11= root ptr +01 BL FindAndDelinkNode ; R10,R11->R10,R11,R12 + STRVC R3, [R12, #TailPtr] ; Attach de-linked nodes onto this node + MOVVC R3, R12 ; New head of de-linked nodes + BVC %BT01 ; Repeat until all nodes de-linked + + TEQP R4, PC ; Restore IRQ state + +; Free the list of de-linked nodes, pointed to by R3, enter with VS + +02 LDRVC R3, [R3, #TailPtr] ; Update head of de-linked nodes + BLVC FreeNode ; Free the node pointed to by R12 + SUBS R12, R3, #0 ; Any more nodes to free? + BNE %BT02 ; Yes then jump + | + TEQP PC, #SVC_mode+I_bit ; IRQs off while holding context. + LDR R11, =VecPtrTab ; Point at table of head pointers + LDR R10, [R11, R0, LSL #2]! ; R10 "nextblock" := !oldptr, + ; point R11 at the table entry "oldptr" +01 BL FreeLink + BVC %BT01 ; loop with chain pointers still set + ] +GoForAddToVec + LDR R11, =VecPtrTab ; Point at table of head pointers + + ADD R11, R11, R0, LSL #2 + MOV R10, R1 ; Address + MOV R4, R2 ; TailPtr pointer is "nextblock" + + MOV R3, #VecNodeSize ; Ask for this number of bytes + BL ClaimSysHeapNode ; The result is in R2 : R12 corrupted + BVS BadClaimVector ; Failed : Exit + + TEQP PC, #SVC_mode+I_bit ; force noirq + LDR R3, [R11] ; "nextblock" :=vecptrtab!(n*4) + STMIA R2, {R3, R4, R10} ; Atomic Operation thus links in the new + ; routine + STR R2, [R11] ; vectab!(n*4) := "thisblock" +BadClaimVector + STRVS R0, [stack] + Pull "R0-R4, link" + B SLVK_TestV + +BadClaimNumber + ADR R0, ErrorBlock_BadClaimNum + [ International + Push "lr" + BL TranslateError + Pull "lr" + ] + B SLVK_SetV + + MakeErrorBlock BadClaimNum + +;Release_vector(n, Addressess) +;+++++++++++++++++++++++++ + +ReleaseVector_SWICode + ; On Entry : R0 = vector number, R1 = Address, R2 = workspace, SVC mode + + CMP R0, #NVECTORS + SETV CS + BVS BadVectorRelease + + [ IrqsInClaimRelease + Push "R0-R2,R9,link" + + MOV R9, #I_bit + TST R9, PC ; is I_bit set ? + TEQEQP R9, PC ; No, then set it, R9 = changed bits + MOVNE R9, #0 ; Else R9=0 for no change + + LDR R11, =VecPtrTab ; Get ptr to table of head pointers + LDR R10, [R11, R0, LSL #2]! ; R10 "nextblock" := *oldptr, R11= root ptr + BL FindAndDelinkNode ; R10,R11->R10,R11,R12 + TEQP R9, PC ; Restore IRQ state + BLVC FreeNode ; If found, free the node in R12 + + Pull "R0-R2,R9,link" + | + Push "R0-R2, link" + + TEQP PC, #SVC_mode+I_bit ; IRQs off while holding context. + LDR R11, =VecPtrTab ; Point at table of head pointers + LDR R10, [R11, R0, LSL #2]! ; R10 "nextblock" := !oldptr, + ; point R11 at the table entry "oldptr" + BL FreeLink + Pull "R0-R2, link" + ] + +BadVectorRelease + ADRVS R0, ErrorBlock_NaffRelease + [ International + Push "lr",VS + BLVS TranslateError + Pull "lr",VS + ] + B SLVK_TestV + + MakeErrorBlock NaffRelease + + [ IrqsInClaimRelease +; Find a node and de-link it from the vector chain +; In: +; R1 = code address +; R2 = workspace address +; R10 -> Node +; R11 -> Root ptr +; Out: +; VC: +; R10 -> Node following found +; R11 -> New root ptr +; R12 -> Node de-linked +; VS: +; R10,11,12 trashed - node not found + +10 ADD R11, R10, #TailPtr ; oldptr := thisblock+TailPtr + LDR R10, [R11] ; nextblock:=thisblock!TailPtr + +FindAndDelinkNode + CMP R10, #0 ; End of chain? + ORREQS PC, lr, #V_bit ; Yes, return error + + LDR R12, [R10, #VecWSpace] + CMP R12, R2 ; Workspace matches? + LDREQ R12, [R10, #Address] + CMPEQ R12, R1 ; And code address matches? + BNE %BT10 ; No then jump, try next node + +; Remove node from vector chain + + MOV R12, R10 ; R12-> node to de-link + LDR R10, [R12, #TailPtr] ; Get link to next node + STR R10, [R11] ; Previous node's link -> next node + BICS PC, lr, #V_bit ; Return no error + +; Return node to heap space +; In: +; R12-> node to release + +FreeNode + Push "R0-R2, lr" + MOV R2, R12 + BL FreeSysHeapNode + STRVS R0, [stack] + Pull "R0-R2, PC" ; returns Vset if sysheap poo'd. + | +FreeLink ; find given vector entry from R10 currptr, R11 prevptr + CMP R10, #0 + ORREQS PC, lr, #V_bit + +ReleaseWLoop + LDR R12, [R10, #VecWSpace] + CMP R12, R2 + LDREQ R12, [R10, #Address] + CMPEQ R12, R1 + BEQ FoundRelease ; IF thisblock!Address=OneWanted THEN do it + ADD R11, R10, #TailPtr ; oldptr := thisblock+TailPtr + LDR R10, [R11] ; nextblock:=thisblock!TailPtr + CMP R10, #0 ; IF thisblock!TailPtr = 0 THEN naff + BNE ReleaseWLoop + ORRS PC, lr, #V_bit ; entry not found + +FoundRelease ; else !oldptr := nextblock!TailPtr : release_block(nextblock) + + LDR R12, [R10, #TailPtr] + STR R12, [R11] + + Push "R0-R2, lr" + MOV R2, R10 + MOV R10, R12 ; keep updated thisblk + BL FreeSysHeapNode + STRVS R0, [stack] + Pull "R0-R2, PC" ; returns Vset if sysheap poo'd. + ] + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + LTORG + +defaultvectab + & 0, 0, NaffVector ; UserV * &00 + & 0, 0, ErrHandler ; ErrorV * &01 + & 0, 0, NOIRQ ; IrqV * &02 + & 0, OsbyteVars, PMFWrch ; WrchV * &03 + + & 0, 0, NewRdch ; RdchV * &04 - start of VecNo=SWINo section + & 0, 0, VecOsCli + & 0, OsbyteVars, OsByte + & 0, OsbyteVars, OsWord + & 0, 0, NaffVector ; filev + & 0, 0, NaffVector ; argsv + & 0, 0, NaffVector ; bgetv + & 0, 0, NaffVector ; bputv + & 0, 0, NaffVector ; gbpbv + & 0, 0, NaffVector ; findv + & 0, OsbyteVars, VecRdLine ; ReadlineV * &0E - end of VecNo=SWINo + + & 0, 0, NaffVector ; fscv + + & 0, EvtHan_ws, DefEvent ; EventV * &10 + + & 0, 0, NaffVector ; UPTV * &11 + & 0, 0, NaffVector ; NETV * &12 + + [ AssembleKEYV + & 0, 0, KeyVector ; KEYV * &13 + | + & 0, 0, NaffVector ; KEYV * &13 + ] + + & 0, BuffParms+0, NewInsV ; INSV * &14 + & 0, BuffParms+0, NewRemV ; REMV * &15 + & 0, BuffParms+4, NewCnpV ; CNPV * &16 ; Count/Purge Buffer V + + & 0, 0, NaffVector ; UKVDU23V * &17 ; ---| VDU23 (decimal) + + & 0, HiServ_ws, HighSWI ; UKSWIV * &18 ; ---| Unknown SWI numbers + + & 0, 0, NaffVector ; UKPLOTV * &19 ; ---| VDU25 (decimal) + + & 0, 0, ReadMouse ; MouseV * &1A + + & 0, 0, NaffVector ; VDUXV * &1B + & 0, 0, Def_100HZ ; TickerV * &1C + + & 0, UpCallHan_ws, CallUpcallHandler + ; UpCallV * &1D + & 0, 0, AdjustOurSet ; ChangeEnvironment * &1E + + & 0, VduDriverWorkSpace, SpriteVecHandler ; SpriteV * &1F + & 0, 0, NaffVector ; DrawV * &20 + & 0, 0, NaffVector ; EconetV * &21 + & 0, 0, NaffVector ; ColourV * &22 + & 0, VduDriverWorkSpace, MOSPaletteV ; PaletteV * &23 + & 0, 0, NaffVector ; SerialV * &24 + + & 0, 0, NaffVector ; FontV * &25 + + & 0, 0, NaffVector ; PointerV * &26 + + ; the spares + & 0, 0, NaffVector ; &27 + & 0, 0, NaffVector ; &28 + & 0, 0, NaffVector ; &29 + & 0, 0, NaffVector ; &2a + & 0, 0, NaffVector ; &2b + & 0, 0, NaffVector ; &2c + & 0, 0, NaffVector ; &2d + & 0, 0, NaffVector ; &2e + & 0, 0, NaffVector ; &2f + + assert (.-defaultvectab) = NVECTORS*VecNodeSize + +NaffVector ROUT +Def_100HZ + Pull lr ; Claim vector, do nowt + BICS pc, lr, #V_bit + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWIs to save any vector entries pointing into application workspace +; +; Delink SWI: +; R0 pointer to buffer +; R1 buffer size +; Returns R1 bytes left in buffer +; V set if buffer not large enough + +Application_Delink ROUT + Push "R0, R2-R4, lr" + + CMP R1, #4 + BLT %FT99 ; invalid buffer size + + MOV R3, #NVECTORS-1 + LDR R4, [R3, #AplWorkSize-(NVECTORS-1)] + TEQP PC, #SVC_mode+I_bit ; IRQs off while holding context. + +03 LDR R11, =VecPtrTab ; Point at table of head pointers + ADD R10, R11, R3, LSL #2 +04 MOV R11, R10 ; step chain + LDR R10, [R11] +05 CMP R10, #0 + BNE %FT02 + SUBS R3, R3, #1 + BPL %BT03 ; next vector + MOV R3, #-1 + STR R3, [R0] + SUB R1, R1, #4 + Pull "R0, R2-R4, lr" + ExitSWIHandler + +02 LDR R12, [R10, #Address] + CMP R12, R4 + BGT %BT04 + CMP R12, #UserMemStart + BLT %BT04 + +; appl entry found: put in buffer, free it + CMP R1, #12+4 + BLT %FT99 ; no rheum + LDR R14, [R10, #VecWSpace] + STMIA R0!, {R3, R12, R14} + SUB R1, R1, #12 ; buffer entry added + + LDR R12, [R10, #TailPtr] + STR R12, [R11] ; vector delinked + + Push "R0-R2" + MOV R2, R10 + MOV R10, R12 ; keep updated thisblk + BL FreeSysHeapNode + MOVVS lr, R0 + Pull "R0-R2" + BVC %BT05 + +98 STR lr, [stack] + MOV R3, #-1 ; terminate buffer even if error + CMP r1, #4 + STRGE R3, [R0] + SUB R1, R1, #4 + Pull "R0, R2-R4, lr" + B SLVK_SetV + +99 + [ International + Push "r0" + ADRL r0, ErrorBlock_BuffOverflow + BL TranslateError + MOV lr,r0 + Pull "r0" + | + ADRL lr, ErrorBlock_BuffOverflow + ] + B %BT98 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Relink SWI: +; R0 pointer to buffer as set by Delink +; Returns V set if can't relink all + +Application_Relink ROUT + Push "R0-R2, lr" + MOV R10, R0 +02 LDR R0, [R10], #4 + CMP R0, #-1 + Pull "R0-R2, lr", EQ + ExitSWIHandler EQ + + LDMIA R10!, {R1, R2} + SWI XOS_AddToVector + BVC %BT02 + STR R0, [stack] + Pull "R0-R2, lr" + B SLVK_SetV + +;******************************************************************** +; Now the stuff that issues service calls; also deals with the MOS +; being default default FIQ owner, and wanting to see application +; startup. +;******************************************************************** + + GBLL FIQDebug +FIQDebug SETL {FALSE} + + GBLL DebugNeil +DebugNeil SETL {FALSE} ; if TRUE, check R7-R11 preserved over services + +Issue_Service ROUT ; R1 is service number, R2 may be a parameter + ; registers preserved. + Push "R9-R12, lr" + + CMP R1, #Service_ClaimFIQ + CMPNE R1, #Service_ClaimFIQinBackground + BEQ FIQclaim + CMP R1, #Service_ReleaseFIQ + BEQ test_FIQclaim_in_progress + + CMP r1, #Service_NewApplication + BEQ checkmoshandlers + +05 MOV R10, #Module_List +03 LDR R10, [R10, #Module_chain_Link] + CMP R10, #0 + BEQ %FT01 + LDR R9, [R10, #Module_code_pointer] + LDR R11, [R9, #Module_Service] + CMP R11, #0 + BEQ %BT03 + ADD R9, R9, R11 + ADD R11, R10, #Module_incarnation_list - Incarnation_Link +04 LDR R11, [R11, #Incarnation_Link] + CMP R11, #0 + BEQ %BT03 + + [ DebugNeil + Push "R7-R11" + ] + + ADD R12, R11, #Incarnation_Workspace + MOV lr, pc ; link inc. PSR, mode + MOV pc, R9 + + [ DebugNeil + ! 0, "Debug code included to check R7-R11 are preserved over services" + MOV lr, sp + Push "R1-R5" + LDMIA lr, {R1-R5} + TEQ R1, R7 + TEQEQ R2, R8 + TEQEQ R3, R9 + TEQEQ R4, R10 + TEQEQ R5, R11 + MOVNE PC, #0 + Pull "R1-R5" + ADD sp, sp, #5*4 + ] + + CMP R1, #Service_Serviced + BNE %BT04 + Pull "R9-R12, PC" + +01 CMP R1, #Service_ReleaseFIQ + Pull "R9-R12, PC",NE + STRB R1, [R1, #MOShasFIQ-Service_ReleaseFIQ] + + [ FIQDebug + TubeChar r0, r1, "MOV r1, #""D""" + ] + + assert (Service_ReleaseFIQ :AND: &FF) <> 0 + ; MOS is default owner if nobody +06 MOV R1, #Service_Serviced ; else wants it. + Pull "R9-R12, PC" + +FIQclaim + MOV R10, #0 + + [ FIQDebug + TubeChar r0, r1, "MOV r1, #""C""" + ] + + ; first refuse request if a claim is currently in action + + LDRB R9, [R10, #FIQclaim_interlock] + CMP R9, #0 + Pull "R9-R12, PC",NE ; no can do + +; have to issue a genuine FIQ claim call: set interlock to prevent another +; one passing round at an awkward moment. + + MOV r9, #1 + STRB r9, [r10, #FIQclaim_interlock] + + [ FIQDebug + TubeChar r0, r1, "MOV r1, #""I""" + ] + +; now safe to inspect our FIQ state + + LDRB R9, [R10, #MOShasFIQ] + CMP R9, #0 + + [ FIQDebug + BEQ sam001 + TubeChar r0, r1, "MOV r1, #""M""" + CMP r9, #0 +sam001 + ] + + STRNEB R10, [R10, #MOShasFIQ] + MOVNE r1, #Service_Serviced +fakeservicecall + Push PC, EQ ; return address + SUBEQ stack, stack, #4*4 ; pseudo- r9-r12 + BEQ %BT05 ; wacky pseudo-BL! + MOV r10, #0 + LDRB r9, [r10, #FIQclaim_interlock] + STRB r10, [r10, #FIQclaim_interlock] + + [ FIQDebug + TubeChar r0, r1, "MOV r1, #""i""" + ] + + CMP r9, #1 ; test for background release + + [ FIQDebug + BEQ sam002 + TubeChar r0, r1, "MOV r1, #""B""" + CMP r9, #1 +sam002 + ] + +; if background release happened, there are 3 possibilities: +; foreground claim; this is defined to have succeeded. Discard release +; background claim, that succeeded: releaser gave it away anyway. Discard +; " " " failed; we are holding a giveaway of FIQ, therefore +; claim service call! +; therefore, if background release happened, always claim the service. + + MOVNE r1, #Service_Serviced + Pull "r9-r12, PC" ; all done + +test_FIQclaim_in_progress + + [ FIQDebug + TubeChar r0, r1, "MOV r1, #""R""" + ] + + MOV r10, #0 + LDRB r9, [r10, #FIQclaim_interlock] + CMP r9, #0 + + [ {TRUE} + MOVEQ r9, #1 + STREQB r9, [r10, #FIQclaim_interlock] ; lock out background calls + BEQ fakeservicecall ; issue call, clear flag + | + BEQ %BT05 ; issue call + ] + + MOV r9, #2 ; mark release as occurring + + [ FIQDebug + TubeChar r0, r1, "MOV r1, #""b""" + ] + + STRB r9, [r10, #FIQclaim_interlock] + Pull "r9-r12, PC" + +; r9-r12, lr corruptible +checkmoshandlers + LDR r9, [r1, #SExitA-Service_NewApplication] + ADRL r10, CLIEXIT + CMP r9, r10 + BNE %BT05 + Push "r0-r7" + BL DEFHAN + BL DEFHN2 + Pull "r0-r7" + B %BT05 + +;************************************************ +; SWI to call a vector +;************************************************ +CallAVector_SWI ; R9 is the vector number (!!) + Push "lr" + MOV R10, R9 + ORR R14, R14, #SVC_mode + TEQP PC, R14 ; restore caller CCs + BL CallVector + MOV R10, PC, LSR #28 ; restore CCs + Pull "lr" + BIC lr, lr, #&F0000000 + ORR lr, lr, R10, LSL #28 + ExitSWIHandler + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +; Now some bits for the dynamic areas + +DoSysHeapOpWithExtension + Push "R0, lr" + B IntoSysHeapOp + +ClaimSysHeapNode ROUT ; size in R3 + MOV R0, #HeapReason_Get + Push "R0, lr" +IntoSysHeapOp + LDR R1, =SysHeapStart + SWI XOS_Heap + Pull "R0, PC", VC + + LDR r14, [r0] ; look at error number + TEQ r14, #ErrorNumber_HeapFail_Alloc + STRNE r0, [stack] + Pull "r0, r3, PC", NE ; can only retry if ran out of room + + Push r3 ; in case extension + LDR r1, [stack, #4] + CMP r1, #HeapReason_ExtendBlock + BNE notsysheapextendblock + + Push "r5, r6" + LDR r5, =SysHeapStart + LDR r6, [r5, #:INDEX:hpdbase] + ADD r6, r6, r5 ; free space + LDR r1, [r2, #-4] ; pick up block size + ADD r5, r1, r2 ; block end +4 + SUB r5, r5, #4 ; TMD 02-Aug-93: block size includes size field (optimisation was never taken) + CMP r5, r6 ; does block butt against end? + ADDNE r3, r3, r1 ; max poss size needed + Pull "r5, r6" + + ; note that this doesn't cope well with a block at the end preceded by a + ; free block, but tough. + +notsysheapextendblock + LDR r1, =SysHeapStart + LDR R0, hpdbase + LDR R1, hpdend + SUB R1, R1, R0 ; size left in heap + SUB R1, R3, R1 ; size needed + Pull r3 + ADD R1, R1, #8 ; plus safety space. + MOV R0, #0 + SWI XOS_ChangeDynamicArea + LDRVC R0, [stack] ; and retry. + LDRVC R1, =SysHeapStart + SWIVC XOS_Heap + Pull "R0, PC", VC +SysClaimFail + ADD stack, stack, #4 + ADR R0, ErrorBlock_SysHeapFull + [ International + BL TranslateError + ] + Pull "PC" + MakeErrorBlock SysHeapFull + +;************************************************************************** +; +; FreeSysHeapNode - Free a node in system heap +; +; in: R2 -> node to free +; +; out: R0 = HeapReason_Free or pointer to error if V=1 +; R1 = SysHeapStart +; + +FreeSysHeapNode ENTRY + MOV R0, #HeapReason_Free + LDR R1, =SysHeapStart + SWI XOS_Heap + EXIT + +;************************************************************************** + +; ValidateAddress_Code +; R0, R1 are limits of address range to check +; return CC for OK, CS for naff + +ValidateAddress_Code ROUT + Push "R1, lr" + CMP R0, R1 + SUBNE R1, R1, #1 ; cope with zero length range sensibly + MOV R10, #0 + + MOV R11, #0 + LDR R12, [R10, #AplWorkSize] + BL RangeCheck + + [ :LNOT: NewStyle_Screen + VDWS R11 + MOV R12, #ScreenEndAdr + LDR R11, [R11, #TotalScreenSize] + ADD R12, R12, R11 + SUB R11, R12, R11, LSL #1 + BL RangeCheck + ] + + [ NewStyle_SysHeap + MOV r11, #SysHeapChunkAddress ; need to still check 1st 8K + ADD r12, r11, #SysHeapStart-SysHeapChunkAddress + BL RangeCheck + | + LDR R11, =SysHeapStart + LDR R12, [R11, #:INDEX: hpdend] + ADD R12, R11, R12 + MOV R11, #SysHeapChunkAddress + BL RangeCheck + ] + + [ :LNOT: NewStyle_RMA + MOV R11, #RMAAddress + LDR R12, [R11, #:INDEX: hpdend] + ADD R12, R11, R12 + BL RangeCheck + ] + + [ :LNOT: NewStyle_SpriteArea + LDR R12, [R10, #SpriteSize] + ADD R12, R12, #SpriteSpaceAddress + MOV R11, #SpriteSpaceAddress + BL RangeCheck + ] + + [ :LNOT: NewStyle_RAMDisc + LDR R12, [R10, #RAMDiscSize] + ADD R12, R12, #RAMDiscAddress + MOV R11, #RAMDiscAddress + BL RangeCheck + ] + + [ :LNOT: NewStyle_FontArea + LDR R12, [R10, #FontCacheSize] + ADD R12, R12, #FontCacheAddress + MOV R11, #FontCacheAddress + BL RangeCheck + ] + + MOV R11, #CursorChunkAddress + ADD R12, R11, #32*1024 + BL RangeCheck + + [ NewCDA +; not in one of those ranges, so check against dynamic area list + MOV r10, #DAList +10 + LDR r10, [r10, #DANode_Link] + TEQ r10, #0 ; end of list + BEQ %FT20 + LDR r11, [r10, #DANode_Base] + LDR r12, [r10, #DANode_Flags] + TST r12, #DynAreaFlags_DoublyMapped + LDR r12, [r10, #DANode_Size] + SUBNE r11, r11, r12 ; if doubly mapped, move base back by size + MOVNE r12, r12, LSL #1 ; and double size + ADD r12, r12, r11 ; make r12 point at end (exclusive) + CMP r0, r12 ; if start >= end (excl) + BCS %BT10 ; then go onto next node + + CMP r0, r11 ; if range starts below this area + BCC %FT20 ; then not totally within this area + CMP r1, r12 ; else if range ends before end+1 of this area + BCC AddressIsValid ; then it's valid +20 + ] + +; not in one of those ranges, so issue service so modules can add other valid areas + + Push "R2, R3" + MOV R2, R0 ; pass parameters to service in R2 and R3 + LDR R3, [stack, #2*4] ; reload stacked R1 into R3 + MOV R1, #Service_ValidateAddress + BL Issue_Service + TEQ R1, #0 ; EQ => service claimed, so OK + Pull "R2, R3" + Pull "R1, lr" + ORRNE lr, lr, #C_bit ; return CS if invalid + BICEQ lr, lr, #C_bit ; return CC if valid + ExitSWIHandler + +RangeCheck ; check R0 - R1 lies totally within R11 - (r12-1) + + SUB R12, R12, #1 + CMP R0, R11 + CMPCS R12, R0 + CMPCS R1, R11 + CMPCS R12, R1 + MOVCC PC, lr ; failed +AddressIsValid + Pull "R1, lr" + BIC lr, lr, #C_bit + ExitSWIHandler + + LTORG + + END diff --git a/s/ChangeDyn b/s/ChangeDyn new file mode 100644 index 0000000000000000000000000000000000000000..9dc4632f7d7556470586fec73781dbed63eeabc1 --- /dev/null +++ b/s/ChangeDyn @@ -0,0 +1,4260 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + TTL => ChangeDyn + +;****************************************************************************** +; ChangeDynamic SWI +; In : R0 = 0 => System Heap, +; 1 => RMA +; 2 => Screen +; 3 => Sprite area +; 4 => Font cache +; 5 => RAM disc +; 6 => Free pool +; R1 = no of bytes to change by +; +; Out : V set if CAO in AplWork or couldn't move all the bytes requested. +; R1 set to bytes moved. +;****************************************************************************** + +; The following flag controls the operation of ReadCMOSAndConfigure and FudgeConfigureRMA +; +; If false, then no memory is in the free pool to start off, and these routines just allocate pages +; starting at page R2, and update this on exit. +; +; If true, then routine InitDynamicAreas initially moves all non-static free memory into the free pool, +; and then the above routines just take pages off the end of that. + + GBLL GetPagesFromFreePool ; whether ReadCMOSAndConfigure extract pages from the free pool +GetPagesFromFreePool SETL NewCDA :LAND: {TRUE} + + [ ExpandedCamMap +AP_AppSpace * 0 ; user r/w, CB +AP_SysHeap * 0 ; user r/w, CB +AP_RMA * 0 ; user r/w, CB + [ NewStyle_Screen + [ DAF_SpecifyBit +AP_Screen * 0 :OR: DynAreaFlags_NotCacheable :OR: DynAreaFlags_DoublyMapped :OR: DynAreaFlags_NeedsSpecificPages + | +AP_Screen * 0 :OR: DynAreaFlags_NotCacheable :OR: DynAreaFlags_DoublyMapped + ] + | +AP_Screen * 0 :OR: DynAreaFlags_NotCacheable ; user r/w, ~CB + ] +AP_Sprites * 0 ; user r/w, CB +AP_FontArea * 2 ; user none, CB +AP_RAMDisc * 2 :OR: DynAreaFlags_NotCacheable ; user none, ~CB +AP_Duff * 2 :OR: DynAreaFlags_NotCacheable :OR: DynAreaFlags_NotBufferable ; user none, ~C~B + [ UseFreePool +AP_FreePool * 2 :OR: DynAreaFlags_NotCacheable ; user none, ~CB + ] +AP_CursorChunk * 1 :OR: DynAreaFlags_NotCacheable :OR: DynAreaFlags_NotBufferable :OR: PageFlags_Unavailable +AP_PageZero * 0 + [ MEMM_Type = "ARM600" +AP_L2PT * 2 :OR: DynAreaFlags_NotCacheable :OR: DynAreaFlags_NotBufferable ; user none, ~C~B +AP_L1PT * AP_L2PT :OR: PageFlags_Unavailable +AP_UndStackSoftCam * PageFlags_Unavailable + ] + | +AP_AppSpace * 0 ; user r/w +AP_SysHeap * 0 ; user r/w +AP_RMA * 0 ; user r/w +AP_Screen * 0 ; user r/w +AP_Sprites * 0 ; user r/w +AP_FontArea * 2 ; user none +AP_RAMDisc * 2 ; user none +AP_Duff * 2 + [ UseFreePool +AP_FreePool * 2 ; user none + ] +AP_CursorChunk * 1 ; user r-o +AP_PageZero * 0 ; user r/w + ] + +ChangeDyn_FreeAndApl * -2 ; special reason code for when we're sucking out of free pool and apl space +ChangeDyn_AplSpace * -1 +ChangeDyn_SysHeap * 0 +ChangeDyn_RMA * 1 +ChangeDyn_Screen * 2 +ChangeDyn_SpriteArea * 3 +ChangeDyn_FontArea * 4 +ChangeDyn_RamFS * 5 +ChangeDyn_FreePool * 6 + [ UseFreePool +ChangeDyn_MaxArea * 6 + | +ChangeDyn_MaxArea * 5 + ] + +; Area handler reason codes + +DAHandler_PreGrow * 0 +DAHandler_PostGrow * 1 +DAHandler_PreShrink * 2 +DAHandler_PostShrink * 3 + +; Number of entries in page block on stack + +NumPageBlockEntries * 32 +PageBlockSize * NumPageBlockEntries * 12 +PageBlockChunk * NumPageBlockEntries * 4096 + + InsertDebugRoutines + +; *** Start of old style code *** + + [ :LNOT: NewStyle_All + +ChangeDynamicSWI ROUT + Push "r0, r2-r9, r10, lr" ; r10 is workspace + + [ NewCDA2 + B CheckForNewArea +IsOldArea + ] + + CMP r0, #ChangeDyn_MaxArea + MOVLS r10, #0 + LDRLS r10, [r10, #IRQsema] + CMPLS r10, #0 + BHI failure_IRQgoing + + [ DebugCDA + DLINE "Entering OS_ChangeDynamicArea" + DREG r0, "r0 = " + DREG r1, "r1 = " + ] + + [ :LNOT: NewStyle_RAMDisc + CMP r0, #ChangeDyn_RamFS + BEQ CheckRAMFSChangeOK +AllowRAMFSChange + ] + + MOV r6, #0 + LDR r6, [r6, #Page_Size] + SUB r12, r6, #1 + ADD r1, r1, r12 + BICS r1, r1, r12 ; round up to nearest page. + MOVEQ r11, r0 ; area + MOVEQ r10, #0 ; amount moved + BEQ CDS_PostService ; zero pages! + +; Now form source (r11) and destination (r12) registers + + [ UseFreePool + + CMP r0, #ChangeDyn_FreePool ; if specified area is free pool + MOVEQ r11, #ChangeDyn_AplSpace ; then "other" area is aplspace + MOVNE r11, #ChangeDyn_FreePool ; else other area is free pool + + CMP r1, #0 ; if growing area + MOVPL r12, r0 ; then dest is specified area, and src is other + MOVMI r12, r11 ; else dest is other + MOVMI r11, r0 ; and src is specified + RSBMI r1, r1, #0 ; and make change positive + | + MOVMI r12, #ChangeDyn_AplSpace ; dest := ApplWork + MOVMI r11, r0 ; source := R0 + MOVPL r12, r0 ; dest := R0 + MOVPL r11, #ChangeDyn_AplSpace ; source := ApplWork + RSBMI r1, r1, #0 + ] + + [ DebugCDA + DREG r11, "Initially, src = " + DREG r12, "and dest = " + ] + +; amount movable = current size(source) - shrink limit(source) + + [ :LNOT: NewStyle_SpriteArea + CMP r11, #ChangeDyn_SpriteArea + LDREQ r10, [r11, #SpriteSize-ChangeDyn_SpriteArea] + TEQEQ r10, #0 ; May have no sprite area ... + MOVEQ r5, #0 ; Shrink limit := 0 + BEQ gotsizeandshrink + ] + +; need to lock the heap if we are shrinking the SysHeap or the RMA +; lock by setting the heap end to be the same as the current base; +; this ensures that no claims will use memory about to disappear + + ADRL r10, Current_Size+4 + LDR r10, [r10, r11, LSL #2] ; get pointer to current size of area + + [ NewStyle_RMA :LAND: NewStyle_SysHeap ; if both new + LDR r10, [r10] ; then just get current size + | + [ NewStyle_SysHeap ; if sys heap new + CMP r11, #ChangeDyn_RMA ; then RMA must be old + | + CMP r11, #ChangeDyn_SysHeap ; else sys heap is old + [ :LNOT: NewStyle_RMA + CMPNE r11, #ChangeDyn_RMA ; and if RMA old as well, do 2 CMPs + ] + ] + LDRNE r10, [r10] + BNE CDA_GotSize + +; its a heap, so munge it to prevent anyone stealing memory while we are + + MOV lr, pc ; save I_bit + TEQP pc, #SVC_mode + I_bit ; disable IRQs round this bit + LDR r5, [r10] ; current size + LDR r2, [r10, #hpdbase-hpdend] ; remove all of the contiguous free chunk from the heap + STR r2, [r10] ; so that noone can steal any of it under IRQs + MOV r10, r5 + STR r10, [stack, #4*9] ; but save the old size on stack to restore later + TEQP lr, #0 ; restore state + +CDA_GotSize + ] + [ :LNOT: NewStyle_FontArea + CMP r11, #ChangeDyn_FontArea + BNE %FT04 ; source not font area + + MOV r5, r1 + MOV r1, #-1 + MOV r2, #0 ; in case font manager dead + SWI XFont_ChangeArea + MOV r1, r5 ; preserve r1 + MOV r5, r2 + B %FT05 +04 + ] + ADR r5, Shrink_Limits+4 ; now see how much we can remove from src + LDR r5, [r5, r11, LSL #2] ; load shrink limit address + LDR r5, [r5] ; and contents +05 + [ :LNOT: NewStyle_SpriteArea + CMP r11, #ChangeDyn_SpriteArea + CMPEQ r5, #saExten ; if no sprites defined, can delete hdr + MOVEQ r5, #0 + ] + +gotsizeandshrink + SUB r10, r10, r5 ; amount removable from source +06 + ADR r5, Grow_LimitsPtrs+4 + LDR r5, [r5, r12, LSL #2] ; get ptr to maximum size of destination area + LDR r5, [r5] ; maximum size of dest area + + [ MEMC_Type = "IOMD" + CMP r12, #ChangeDyn_Screen ; if screen + MOVEQ r5, #0 + LDREQ r5, [r5, #VideoSize] ; then maximum size depends on how much video RAM there is + ] + + ADRL r4, Current_Size+4 + LDR r4, [r4, r12, LSL #2] ; pointer to destination current size + LDR r4, [r4] ; current size of dest + SUB r5, r5, r4 ; maximum amount we can add to destination + +; r10 = amount removable from src, r5 = amount addable to dest + + MOV r2, r10 ; save amount removable from src, in case we need it again + CMP r10, r5 + MOVHI r10, r5 ; min(max removable from src, max addable to dest) + +; r10 is now the amount we can move +; IF removing from ApplWork AND amount moveable < size requested +; Then Error NotAllMoved + + CMP r10, r1 + BCS %FT10 ; can move all reqd (TMD 15-Oct-91; was GE) + +; we can't move all that is required - there are two cases to be considered +; a) if (src = AplSpace) and (dest <> FreePool) then give error (this can only happen in old world) +; b) if (src = FreePool) AND (dest <> AplSpace) then check if adding aplspace would allow us to succeed - +; if it does then adjust registers, else give error + + CMP r11, #ChangeDyn_AplSpace ; if src = aplspace + BNE %FT08 ; [not, so skip] + CMP r12, #ChangeDyn_FreePool ; and dest <> freepool + BNE failure_IRQgoing ; then fail (case (a)) +08 + [ UseFreePool + CMP r11, #ChangeDyn_FreePool ; if src = FreePool + BNE %FT10 ; [skip if not] + CMP r12, #ChangeDyn_AplSpace ; and dest <> AplSpace + BEQ %FT10 ; [skip if not] + +; now see if we would have enough if we had aplspace as well (r2 = amount we could remove from free pool) + + [ DebugCDA + DLINE "Not enough in just free pool" + ] + + LDR r4, Current_Size+4+(ChangeDyn_AplSpace :SHL: 2) + LDR r4, [r4] ; r4 = current apl size + LDR lr, Shrink_Limits+4+(ChangeDyn_AplSpace :SHL: 2) + LDR lr, [lr] ; lr = shrink limit for aplspace + SUB r4, r4, lr ; r4 = amount we could remove from aplspace + + ADD r10, r2, r4 ; add on to amount we could remove from free pool + CMP r10, r5 ; if more than amount area can grow + MOVHI r10, r5 ; then limit to that + + CMP r10, r1 ; if still can't do it now + BCC failure_IRQgoing ; then give error + + TEQ r2, #0 ; else check to see if there was any at all in free pool + MOVEQ r11, #ChangeDyn_AplSpace ; if not then just take from aplspace + MOVEQ r5, r10 ; and do all + + MOVNE r11, #ChangeDyn_FreeAndApl ; else make src indicator reflect that we need both + MOVNE r5, r2 ; but save amount we are taking from freepool + B %FT10 + ] + + [ (:LNOT: NewStyle_SysHeap) :LOR: (:LNOT: NewStyle_RMA) +testrestoreheapend + [ NewStyle_SysHeap ; if sys heap new + CMP r11, #ChangeDyn_RMA ; then RMA must be old + | + CMP r11, #ChangeDyn_SysHeap ; else sys heap is old + [ :LNOT: NewStyle_RMA + CMPNE r11, #ChangeDyn_RMA ; and if RMA old as well, do 2 CMPs + ] + ] + LDREQ r2, [stack, #4*9] + ADREQL r3, Current_Size + 4 + LDREQ r3, [r3, r11, LSL #2] + STREQ r2, [r3] + MOV pc, lr + ] + +UserMemStartAddr & UserMemStart + +Shrink_Limits ; locations to look at + & UserMemStartAddr ; AplWork - unfudged + [ NewStyle_SysHeap + & &FE000000 ; cause abort + | + & SysHeapStart + :INDEX: hpdbase ; SysHeap + ] + [ NewStyle_RMA + & &FE000000 ; cause abort + | + & RMAAddress + :INDEX: hpdbase ; RMA + ] + & VduDriverWorkSpace + ScreenSize ; Screen + [ NewStyle_SpriteArea + & &FE000000 ; cause abort + | + & SpriteSpaceAddress + saFree ; Sprites + ] + [ NewStyle_FontArea + & &FE000000 ; cause abort + | + & 0 ; Fonts not needed + ] + [ NewStyle_RAMDisc + & &FE000000 ; cause abort + | + & MinRamFSSize ; RAMFS + ] + & MinFreePoolSize ; Free pool + + [ :LNOT: NewStyle_RAMDisc +MinRamFSSize + ] +MinFreePoolSize + & 0 + + + +Grow_LimitsPtrs + [ NewCDA + & AppSpaceDANode + DANode_MaxSize ; AplWork + | + & AppSpaceMaxSizePtr + ] + [ NewStyle_SysHeap + & &FE000000 ; cause abort + | + & SysHeapMaxSizePtr ; SysHeap + ] + [ NewStyle_RMA + & &FE000000 ; cause abort + | + & RMAMaxSizePtr ; RMA + ] + & ScreenMaxSizePtr ; Screen + [ NewStyle_SpriteArea + & &FE000000 ; cause abort + | + & SpriteSpaceMaxSizePtr ; Sprites + ] + [ NewStyle_FontArea + & &FE000000 ; cause abort + | + & FontCacheMaxSizePtr ; Fonts + ] + [ NewStyle_RAMDisc + & &FE000000 ; cause abort + | + & RAMDiscMaxSizePtr ; RAMFS + ] + [ UseFreePool + & FreePoolDANode + DANode_MaxSize ; Free pool + ] + +; The following will eventually become redundant as more and more areas become new ones +; Ultimately the whole lot can be removed when no old areas exist (perhaps in my grandson's lifetime!) + + [ :LNOT: NewStyle_SysHeap +SysHeapMaxSizePtr & SysHeapMaxSize + ] + [ :LNOT: NewStyle_RMA +RMAMaxSizePtr & RMAMaxSize + ] +ScreenMaxSizePtr & ScreenMaxSize + [ :LNOT: NewStyle_SpriteArea +SpriteSpaceMaxSizePtr & SpriteSpaceMaxSize + ] + [ :LNOT: NewStyle_FontArea +FontCacheMaxSizePtr & FontCacheMaxSize + ] + [ :LNOT: NewStyle_RAMDisc +RAMDiscMaxSizePtr & RAMDiscMaxSize + ] + [ :LNOT: NewCDA +AppSpaceMaxSizePtr & AplWorkMaxSize + ] + + +Access_Rights + & AP_AppSpace + & AP_SysHeap + & AP_RMA + & AP_Screen + & AP_Sprites + & AP_FontArea + & AP_RAMDisc + [ UseFreePool + & AP_FreePool + ] + +10 + CMP r10, r1 ; if can move more than asked for + MOVHI r10, r1 ; then move requested amount (TMD 15-Oct-91; was GT) + BCS %FT15 ; (TMD 15-Oct-91); was GE) + +; moving less than asked for: set up an error for exit + ADR r0, ErrorBlock_ChDynamNotAllMoved + STR r0, [stack] + LDR r0, [stack, #4*10] + ORR r0, r0, #V_bit + STR r0, [stack, #4*10] + SUB r0, r6, #1 ; and make amount moveable + BICS r10, r10, r0 ; a pagesize multiple + BEQ CDS_PostServiceWithRestore + +; IF CAO in ApplWork AND UpCall not claimed THEN Error ChDynamCAO + +15 + [ UseFreePool + MOV r1, #0 ; default value if apl space not involved + CMP r11, #ChangeDyn_AplSpace ; if source = aplspace + RSBEQ r1, r10, #0 ; then make amount -ve + CMP r11, #ChangeDyn_FreeAndApl ; if source = free and apl + SUBEQ r1, r5, r10 ; then make it -(amount removing from apl space) + MOVNE r5, r10 ; else set up r5 to be total amount (wasn't set up above) + CMP r12, #ChangeDyn_AplSpace ; if dest = aplspace + MOVEQ r1, r10 ; then make amount +ve + + TEQ r1, #0 ; if none of the above + BEQ %FT25 ; then skip this + | + MOV r5, r10 ; r5 = total amount moving (since no split removes) + CMP r11, #ChangeDyn_AplSpace ; old code - if src = apl + RSBEQ r1, r10, #0 ; then -ve + MOVNE r1, r10 ; else +ve + ] + + [ DebugCDA + DREG r11, "After checking, src = " + DREG r12, "and dest = " + DREG r10, "Amount moving (total) = " + DREG r5, "Amount moving (partial) = " + + DLINE "Consulting application about change" + ] + + MOV r2, #0 + LDR r3, [r2, #AplWorkSize] + LDR r2, [r2, #Curr_Active_Object] + CMP r2, r3 ; check if CAO outside application space + BHI %FT20 ; [it is so issue Service not UpCall] + +; CAO in application space, so issue UpCall to check it's OK + + MOV r0, #UpCall_MovingMemory :AND: &FF + ORR r0, r0, #UpCall_MovingMemory :AND: &FFFFFF00 + TEQ r1, #0 + RSBMI r1, r1, #0 ; r1 passed in is always +ve (probably a bug, but should be compat.) + + SWI XOS_UpCall ; r1 already set up above + CMP r0, #UpCall_Claimed + BEQ %FT25 + + ADRL r0, ErrorBlock_ChDynamCAO + B ChangeDynamic_Error + +; IF service call claimed Then Error AplWSpaceInUse + +20 + MOV r0, r1 ; amount removing from aplspace + MOV r1, #Service_Memory + BL Issue_Service + CMP r1, #Service_Serviced + BNE %FT25 + + ADRL r0, ErrorBlock_AplWSpaceInUse + B ChangeDynamic_Error + +; Right! r10 is amount of memory we will move +; (if moving from free pool + apl space then r5 is amount removing from free pool) +; r11 is the source +; r12 is the destination + +25 + [ DebugCDA + DLINE "Change is going ahead" + ] + [ :LNOT: NewStyle_FontArea + CMP r11, #ChangeDyn_FontArea + LDREQ r1, [r11, #FontCacheSize-ChangeDyn_FontArea] + SUBEQ r1, r1, r10 ; new size + SWIEQ XFont_ChangeArea + ] + +; remove the cursors if screen moving: might flash during modechange wrch + + CMP r11, #ChangeDyn_Screen + CMPNE r12, #ChangeDyn_Screen + SWIEQ XOS_RemoveCursors + + CMP r11, #ChangeDyn_Screen + RSBEQ r0, r10, #0 + + MOV r9, pc + TEQEQP pc, #SVC_mode+I_bit+Z_bit + NOP + ; disable interrupts while sorting out the screen, in case (e.g) screen + ; start address is being reprogrammed under interrupt + + BLEQ RemovePages + + TEQP pc, r9 ; restore interrupt state + +; calculate addresses of blocks + + MOV r9, #0 + LDR r9, [r9, #MEMC_CR_SoftCopy] + + MOV r3, r11 + BL GetBlockEndSource + MOV r0, r3 ; R0 := blockend(source) + + CMP r12, #ChangeDyn_Screen + BEQ ExtendScreen ; dest=screen: perversion needed + + MOV r3, r12 + BL GetBlockEnd ; R3 := blockend(dest) + +; move memory: r5 bytes from r0 backwards to r3 forwards + MOV r1, #0 +30 + SUB r0, r0, r6 + Push "r5,r11" + ADR r11, Access_Rights+4 + LDR r11, [r11, r12, LSL #2] ; get access privs (+ CB bits in new world) + [ DebugCDA + DREG r0, "Moving page at ", cc + DREG r3, " to ", cc + DREG r11, " with PPL " + ] + BL MoveCAMatR0toR3 + Pull "r5,r11" + BVS cambust + ADD r1, r1, r6 + ADD r3, r3, r6 + + CMP r1, r5 ; have we done all (of this lot at least)? + BNE %BT30 ; [no, so loop] + + CMP r5, r10 ; have we done all of both lots? + BEQ %FT33 ; yes, so finished + + Push "r1,r3" + MOV r3, #ChangeDyn_AplSpace ; else we have more to do, from aplspace + BL GetBlockEnd ; so get apl block end + MOV r0, r3 ; and put into src register + Pull "r1,r3" + MOV r5, r10 + B %BT30 + +33 + CMP r11, #ChangeDyn_Screen + BNE %FT40 + +; source=screen: need to shuffle rest of screen down. + + VDWS r5 + LDR r5, [r5, #TotalScreenSize] + MOV r3, #ScreenEndAdr +35 + SUB r0, r0, r6 + SUB r3, r3, r6 + Push "r5" + MOV r11, #AP_Screen + BL MoveCAMatR0toR3 + Pull "r5" + BVS cambust + SUBS r5, r5, r6 + BGT %BT35 + MOV r11, #ChangeDyn_Screen + +40 +; now need to restore sizes if we have locked a heap + + [ (:LNOT: NewStyle_SysHeap) :LOR: (:LNOT: NewStyle_RMA) + BL testrestoreheapend + ] + +; update object sizes: current size(dest) +:= r10 +; current size(source) -:= r10 + + MOV r4, #0 ; remember for later + LDR r4, [r4, #SpriteSize] + + CMP r11, #ChangeDyn_FreeAndApl + BNE %FT41 + LDR r2, Current_Size+4+(ChangeDyn_FreePool :SHL: 2) ; r2 -> old size of free pool + LDR lr, [r2] ; lr = old size + LDR r3, Shrink_Limits+4+(ChangeDyn_FreePool :SHL: 2) ; r3 -> shrink limit of free pool + LDR r3, [r3] ; r3 = shrink limit + SUB lr, lr, r3 ; how much we took out of it + STR r3, [r2] ; put shrink limit into current size + + LDR r2, Current_Size+4+(ChangeDyn_AplSpace :SHL: 2) ; r2 -> old size of apl space + LDR r3, [r2] ; r3 = old size of apl space + SUB r3, r3, r10 ; how much we would have taken out of it + ADD r3, r3, lr ; but don't take out the stuff which came out of free + STR r3, [r2] + ADR r0, Current_Size+4 + B %FT42 + +41 + ADR r0, Current_Size+4 + CMP r11, #ChangeDyn_Screen ; don't update TotalScreenSize + LDRNE r2, [r0, r11, LSL #2] + LDRNE r3, [r2] + SUBNE r3, r3, r10 + STRNE r3, [r2] +42 + CMP r12, #ChangeDyn_Screen ; don't update TotalScreenSize + LDRNE r2, [r0, r12, LSL #2] + LDRNE r3, [r2] + ADDNE r3, r3, r10 + STRNE r3, [r2] + + [ :LNOT: NewStyle_SpriteArea + CMP r11, #ChangeDyn_SpriteArea ; watch out for sprite area creation + CMPNE r12, #ChangeDyn_SpriteArea ; or deletion + BNE %FT45 + + MOV r1, #0 ; used later also!! + LDR r3, [r1, #SpriteSize] + CMP r3, #0 ; if sprite area deleted + LDRNE r3, =SpriteSpaceAddress ; tell the vdu drivers + MOV r14, #VduDriverWorkSpace + STR r3, [r14, #SpAreaStart] + BEQ %FT45 ; and don't touch non-existent memory + + CMP r4, #0 ; if area was null, + LDMNEIB r3, {r4-r6} ; (skip size) + MOVEQ r4, #0 ; initialise variables if was null + MOVEQ r5, #saExten + MOVEQ r6, #saExten + LDR r0, [r1, #SpriteSize] ; set up earlier + STMIA r3, {r0,r4-r6} ; stash new set of variables +45 + ] + [ UseFreePool + CMP r11, #ChangeDyn_AplSpace ; if apl space involved in transfer + CMPNE r11, #ChangeDyn_FreeAndApl + CMPNE r12, #ChangeDyn_AplSpace + MOVEQ r0, #0 + LDREQ r2, [r0, #AplWorkSize] ; then reset memlimit to aplworksize + STREQ r2, [r0, #MemLimit] ; MemLimit := AplWorkSize + | + MOV r0, #0 + LDR r2, [r0, #AplWorkSize] + STR r2, [r0, #MemLimit] ; MemLimit := AplWorkSize + ] + + CMP r12, #ChangeDyn_Screen + MOVEQ r0, r10 + + MOV r9, pc + TEQEQP pc, #SVC_mode+I_bit+Z_bit + ; disable interrupts while sorting out the screen, in case (e.g) screen + ; start address is being reprogrammed under interrupt + + BLEQ InsertPages + + TEQP pc, r9 ; restore interrupt state + + CMP r11, #ChangeDyn_Screen + CMPNE r12, #ChangeDyn_Screen + SWIEQ XOS_RestoreCursors + + [ :LNOT: NewStyle_FontArea + CMP r12, #ChangeDyn_FontArea + LDREQ r1, [r12, #FontCacheSize-ChangeDyn_FontArea] + SWIEQ XFont_ChangeArea + ] + + [ :LNOT: NewStyle_RAMDisc + CMP r11, #ChangeDyn_RamFS + CMPNE r12, #ChangeDyn_RamFS + BEQ reinitialise_RAMFS + ] + B CDS_PostService + +Current_Size + & AplWorkSize ; AplWork + [ NewStyle_SysHeap + & &FE000000 ; cause abort + | + & SysHeapStart + :INDEX: hpdend ; SysHeap + ] + [ NewStyle_RMA + & &FE000000 ; cause abort + | + & RMAAddress + :INDEX: hpdend ; RMA + ] + & VduDriverWorkSpace + TotalScreenSize ; Screen + [ NewStyle_SpriteArea + & &FE000000 ; cause abort + | + & SpriteSize ; sprites + ] + [ NewStyle_FontArea + & &FE000000 ; cause abort + | + & FontCacheSize ; fonts + ] + [ NewStyle_RAMDisc + & &FE000000 ; cause abort + | + & RAMDiscSize ; RAMFS + ] + [ UseFreePool + & FreePoolDANode + DANode_Size ; Free pool + ] + +GetBlockEndSource + CMP r3, #ChangeDyn_FreeAndApl ; if removing from free + apl + MOVEQ r3, #ChangeDyn_FreePool ; then start by removing from free pool + [ (:LNOT: NewStyle_RMA) :LOR: (:LNOT: NewStyle_SysHeap) ; none of this needed if both sysheap+RMA new + [ NewStyle_SysHeap ; if sys heap new + CMP r3, #ChangeDyn_RMA ; then RMA must be old + | + CMP r3, #ChangeDyn_SysHeap ; else sys heap is old + [ :LNOT: NewStyle_RMA + CMPNE r3, #ChangeDyn_RMA ; and if RMA old as well, do 2 CMPs + ] + ] + BNE GetBlockEnd + ADR r4, StartAddrs+4 + LDR r3, [r4, r3, LSL #2] + LDR r4, [stack, #4*9] + ADD r3, r3, r4 ; start + size = end + MOV pc, lr + ] + +GetBlockEnd ; R3 is area to get end of: return address in R3 + MOV r1, r3 + ADR r4, StartAddrs+4 + LDR r3, [r4, r3, LSL #2] + CMP r1, #ChangeDyn_Screen ; screen ? + MOVEQ pc, lr + ADR r4, Current_Size+4 + LDR r4, [r4, r1, LSL #2] + LDR r4, [r4] + ADD r3, r3, r4 ; start + size = end + MOV pc, lr + +StartAddrs + & 0 ; AplWork + [ NewStyle_SysHeap + & &FE000000 ; cause abort + | + & SysHeapStart ; SysHeap + ] + [ NewStyle_RMA + & &FE000000 ; cause abort + | + & RMAAddress ; RMA + ] + & ScreenEndAdr ; Screen + [ NewStyle_SpriteArea + & &FE000000 ; cause abort + | + & SpriteSpaceAddress ; sprites + ] + [ NewStyle_FontArea + & &FE000000 ; cause abort + | + & FontCacheAddress ; fonts + ] + [ NewStyle_RAMDisc + & &FE000000 ; cause abort + | + & RAMDiscAddress ; RAMFS + ] + [ UseFreePool + & FreePoolAddress ; Free pool + ] + +; ExtendScreen - move memory into screen area +; +; in: r0 -> logical address of end of first source area (either free pool or aplspace) +; r5 = amount of memory being moved from first source area +; r6 = page size +; r9 = MEMC CR +; r10 = total amount of memory being moved +; r11 = number of source area +; r12 = number of dest area + + +ExtendScreen + +; screenpos -:= r10 (move all current blocks down) + + Push "r5,r11" ; save partial amount and src area number + MOV r2, #0 + VDWS r5 + LDR r5, [r5, #TotalScreenSize] + RSB r3, r5, #ScreenEndAdr + SUB r3, r3, r10 ; where new screen start is +50 + MOV r11, #AP_Screen ; access privileges for screen (includes CB bits in new world) + BL Call_CAM_Mapping + ADD r2, r2, #1 + ADD r3, r3, r6 + SUBS r5, r5, r6 + BNE %BT50 + Pull "r5,r11" + + ADD r5, r3, r5 ; logaddr of end of first part (if split) or both otherwise + +; r0 -> end of the source (AplSpace or FreePool) + Push "r7, r8, r10-r12" +55 + Push "r2, r3, r5, pc" ; save flags, etc. too + ADRL r3, PageShifts-1 + LDRB r3, [r3, r6, LSR #12] + MOV r3, r2, LSL r3 ; r3 = pagesize*r2 + ADD r3, r3, #ScreenEndAdr ; physram addr of next screen block + + SUB r0, r0, r6 ; address of last src block + + MOV r1, #Service_ClaimFIQ ; we may be moving FIQ workspace + BL Issue_Service + ADD r1, r0, r6 ; end marker + + TEQP pc, #SVC_mode+I_bit ; disable IRQs as we may be moving + NOP ; IRQ workspace + +; copy R6 bytes from nextscreenblock to last src block; the last +; src block MUST NOT be doubly mapped. + +60 + LDMIA r3!, {r2, r4, r5, r7, r8, r10, r11, r12} + STMIA r0!, {r2, r4, r5, r7, r8, r10, r11, r12} + CMP r0, r1 + BLT %BT60 + + LDR r2, [stack] + SUB r0, r0, r6 + MOV r3, #0 + LDR r3, [r3, #CamEntriesPointer] ; get address of soft CAM copy + [ ExpandedCamMap + ADD r3, r3, r2, LSL #3 ; point at (address, PPL) for this page + LDMIA r3, {r3, r11} ; and load them + | + LDR r3, [r3, r2, LSL #2] ; curr addr of next screen block + MOV r11, r3, LSR #28 ; protection level + BIC r3, r3, #&F0000000 + ] + + [ UseFreePool + BL MoveCAMatR0toR3issuingPagesSafe + | + BL MoveCAMatR0toR3 ; last aplblock := nextscreenblock + ] + + Pull "r2, r3, r5, r7" ; r7 has IRQ state to restore + BVS cambust2 + ; entry no in r2, logaddr in r3 + MOV r11, #AP_Screen + BL Call_CAM_Mapping ; nextscreenblock moves into place + + TEQP pc, r7 ; restore IRQ state + NOP + + MOV r1, #Service_ReleaseFIQ + BL Issue_Service + ADD r3, r3, r6 + ADD r2, r2, #1 + + CMP r3, r5 ; have we got to end of this part + BNE %BT55 ; [no, so loop] + + CMP r3, #ScreenEndAdr + BEQ %FT65 + + MOV r3, #ChangeDyn_AplSpace + BL GetBlockEnd ; get end of aplspace + MOV r0, r3 ; r0 -> end of aplspace + MOV r3, r5 ; continue dest where we left off + MOV r5, #ScreenEndAdr ; finish only at end this time + B %BT55 + +65 + Pull "r7, r8, r10-r12" + B %BT40 + +cambust2 + Pull "r7, r8, r10-r12" +cambust + STR r0, [stack] + Pull "r0, r2-r6, r9, r10, lr" + B SLVK_SetV + + ] + +; *** End of old style code *** + +; Exit from ChangeDynamicArea with error Not all moved + + [ NewStyle_All +failure_IRQgoingClearSemaphore + MOV r0, #0 + STR r0, [r0, #CDASemaphore] + ] +failure_IRQgoing + ADR r0, ErrorBlock_ChDynamNotAllMoved +ChangeDynamic_Error + MOV r10, #0 + STR r0, [stack] + LDR lr, [stack, #4*10] + ORR lr, lr, #V_bit + STR lr, [stack, #4*10] +CDS_PostServiceWithRestore + [ (:LNOT: NewStyle_SysHeap) :LOR: (:LNOT: NewStyle_RMA) + BL testrestoreheapend + ] + [ International + LDR r0, [stack] + BL TranslateError + STR r0, [stack] + ] + +; and drop thru to ... + +CDS_PostService + MOV r1, #Service_MemoryMoved + MOV r0, r10 ; amount moved + MOVS r2, r11 ; which way was transfer? + BMI %FT47 ; [definitely a grow] + CMP r11, #ChangeDyn_FreePool + BNE %FT48 ; [definitely a shrink] + CMP r12, #ChangeDyn_AplSpace + BEQ %FT48 ; [a shrink] +47 + RSB r0, r0, #0 ; APLwork or free was source + MOV r2, r12 ; r2 = area indicator +48 + BL Issue_Service + + MOV r1, r10 ; amount moved + + [ International + Pull "r0" + LDR lr, [sp, #9*4] + TST lr, #V_bit + BLNE TranslateError + Pull "r2-r9, r10, lr" + | + Pull "r0, r2-r9, r10, lr" + ] + ExitSWIHandler + + MakeErrorBlock ChDynamNotAllMoved + + [ MEMM_Type = "ARM600" + [ 1 = 1 +; in: r0 = logical address where page is now + +GetPageFlagsForR0IntoR6 ENTRY "R0-R2, R4-R5, R7" +; +; code from MoveCAMatR0toR3 +; + LDR r5, =L2PT + ADD r4, r5, r0, LSR #10 ; r4 -> L2PT for log addr r0 + MOV r2, r4, LSR #12 + LDR r2, [r5, r2, LSL #2] ; r2 = L2PT entry for r4 + TST r2, #3 ; if no page there + BEQ %FT90 ; then cam corrupt + + LDR r4, [r4] ; r4 = L2PT entry for r0 + TST r4, #3 ; check entry is valid too + BEQ %FT91 + MOV r4, r4, LSR #12 ; r4 = phys addr >> 12 + + MOV r2, #0 + LDR r6, [r2, #MaxCamEntry] + MOV r5, #PhysRamTable +10 + CMP r2, r6 ; if page we've got to is > max + BHI %FT92 ; then corrupt + LDMIA r5!, {r7, lr} ; get phys.addr, size + SUB r7, r4, r7, LSR #12 ; number of pages into this bank + CMP r7, lr, LSR #12 ; if too many + ADDCS r2, r2, lr, LSR #12 ; then advance physical page no. + BCS %BT10 ; and loop + + ADD r2, r2, r7 ; add on number of pages within bank +; +; code from BangCamUpdate +; + MOV r1, #0 + LDR r1, [r1, #CamEntriesPointer] + ADD r1, r1, r2, LSL #3 ; point at cam entry (logaddr, PPL) + LDMIA r1, {r0, r6} ; r0 = current logaddress, r6 = current PPL + EXIT + +90 + ADR lr, NoL2ForPageBeingRemovedError ; NB don't corrupt r0 yet - we need that in block as evidence +95 + STR lr, [sp] ; update returned r0 + BL StoreDebugRegs + PullEnv ; seriously broken memory + SETV + MOV pc, lr + +91 + ADR lr, PageBeingRemovedNotPresentError + B %BT95 + +92 + ADR lr, PhysicalAddressNotFoundError + B %BT95 + + + ] + ] + +; MoveCAMatR0toR3 +; in: r0 = old logaddr +; r3 = new logaddr +; r9 = MEMC CR +; r11 = page protection level +; +; out: r2 = physical page number of page moved, unless there was a serious error +; r0,r1,r3,r6-r12 preserved +; r4,r5 corrupted + + [ MEMM_Type = "ARM600" +MoveCAMatR0toR3 ENTRY "r0,r1,r6,r7" + LDR r5, =L2PT + ADD r4, r5, r0, LSR #10 ; r4 -> L2PT for log addr r0 + MOV r2, r4, LSR #12 + LDR r2, [r5, r2, LSL #2] ; r2 = L2PT entry for r4 + TST r2, #3 ; if no page there + BEQ %FT90 ; then cam corrupt + + LDR r4, [r4] ; r4 = L2PT entry for r0 + TST r4, #3 ; check entry is valid too + BEQ %FT91 + MOV r4, r4, LSR #12 ; r4 = phys addr >> 12 + + MOV r2, #0 + LDR r6, [r2, #MaxCamEntry] + MOV r5, #PhysRamTable +10 + CMP r2, r6 ; if page we've got to is > max + BHI %FT92 ; then corrupt + LDMIA r5!, {r7, lr} ; get phys.addr, size + SUB r7, r4, r7, LSR #12 ; number of pages into this bank + CMP r7, lr, LSR #12 ; if too many + ADDCS r2, r2, lr, LSR #12 ; then advance physical page no. + BCS %BT10 ; and loop + + ADD r2, r2, r7 ; add on number of pages within bank + BL BangCamUpdate + CLRV + EXIT + +90 + ADR lr, NoL2ForPageBeingRemovedError ; NB don't corrupt r0 yet - we need that in block as evidence +95 + STR lr, [sp] ; update returned r0 + BL StoreDebugRegs + PullEnv ; seriously broken memory + SETV + MOV pc, lr + +91 + ADR lr, PageBeingRemovedNotPresentError + B %BT95 + +92 + ADR lr, PhysicalAddressNotFoundError + B %BT95 + +StoreDebugRegs + Push "lr" + MOV lr, #CamMapCorruptDebugBlock + STMIA lr, {r0-lr} + LDR r0, [sp, #1*4] ; reload stacked r0 (error pointer) + STR r0, [lr, #15*4] ; store in stacked PC position + Pull "pc" + +NoL2ForPageBeingRemovedError + & 0 + = "Memory Corrupt: No L2PT for page being removed", 0 + ALIGN + +PageBeingRemovedNotPresentError + & 0 + = "Memory Corrupt: Page being removed was not present", 0 + ALIGN + +PhysicalAddressNotFoundError + & 0 + = "Memory Corrupt: Physical address not found", 0 + ALIGN + | + +MoveCAMatR0toR3 ROUT + MOV r2, #0 + LDR r4, [r2, #CamEntriesPointer] + LDR r2, [r2, #MaxCamEntry] +10 + [ ExpandedCamMap + LDR r5, [r4, r2, LSL #3] + | + LDR r5, [r4, r2, LSL #2] + BIC r5, r5, #&F0000000 + ] + CMP r5, r0 + BEQ Call_CAM_Mapping + SUBS r2, r2, #1 + BGE %BT10 + + ADR r0, CamMapBroke + ORRS pc, lr, #V_bit + ] + +CamMapBroke + & 0 + = "!!!! CAM Map Corrupt !!!!", 0 + ALIGN +Call_CAM_Mapping + Push "r0, r1, r4, r6, lr" + BL BangCamUpdate + Pull "r0, r1, r4, r6, pc" + + [ UseFreePool :LAND: :LNOT: NewStyle_All + +; MoveCAMatR0toR3issuingPagesSafe +; in: r0 = old logaddr +; r2 = old physical page number +; r3 = new logaddr +; r9 = MEMC CR +; r11 = page protection level +; +; out: r0,r1,r3,r6-r12 preserved +; r2,r4,r5 corrupted +; +; Note: this still needs some serious work done to it to cope with doubly-mapped areas + +MoveCAMatR0toR3issuingPagesSafe ENTRY "r0,r1,r3,r6,r7,r12", 6*4 + STR r2, [sp, #0*4] ; store old page number at offset 0 in frame + LDR r5, =L2PT + ADD r4, r5, r0, LSR #10 ; r4 -> L2PT for log addr r0 + MOV r2, r4, LSR #12 + LDR r2, [r5, r2, LSL #2] ; r2 = L2PT entry for r4 + TST r2, #3 ; if no page there + BEQ %FT90 ; then cam corrupt + + LDR r4, [r4] ; r4 = L2PT entry for r0 + TST r4, #3 ; check entry OK too + BEQ %FT91 + MOV r12, r4, LSR #12 ; r12 = phys addr >> 12 + + MOV r2, #0 + LDR r6, [r2, #MaxCamEntry] + MOV r5, #PhysRamTable +10 + CMP r2, r6 ; if page we've got to is >= max + BHI %FT92 ; then corrupt + LDMIA r5!, {r7, lr} ; get phys.addr, size + SUB r7, r12, r7, LSR #12 ; number of pages into this bank + CMP r7, lr, LSR #12 ; if too many + ADDCS r2, r2, lr, LSR #12 ; then advance physical page no. + BCS %BT10 ; and loop + + ADD r2, r2, r7 ; add on number of pages within bank + STR r2, [sp, #3*4] ; store new page number at offset 3 in frame + BL BangCamUpdate + EXIT VS + +; now check if page being snaffled is a L2 page, and if so, change L1 contents to point to new page + + SUBS lr, r3, #L2PT ; check if destination page points in L2PT area + BCC %FT20 ; below L2PT, so OK + CMP lr, #4*1024*1024 ; is offset into L2PT less than size of L2PT? + BCS %FT20 ; no, so OK + + LDR r1, =L1PT + ADD r1, r1, lr, LSR #(12-4) ; address in L1 of 4 consecutive words to update + LDR r2, [r1] ; load 1st word, to get AP etc bits + MOV r2, r2, LSL #(31-9) ; junk other bits + MOV r2, r2, LSR #(31-9) + ORR r2, r2, r12, LSL #12 ; merge with address bits + STR r2, [r1], #4 + ADD r2, r2, #&400 + STR r2, [r1], #4 + ADD r2, r2, #&400 + STR r2, [r1], #4 + ADD r2, r2, #&400 + STR r2, [r1], #4 +20 +; now issue the service + + MOV r1, #Service_PagesSafe + MOV r2, #1 ; 1 page at a time + MOV r3, sp ; 1st frame starts at sp + ADD r4, r3, #3*4 ; 2nd frame starts at sp +12 + BL Issue_Service + CLRV + EXIT + +90 + ADR lr, NoL2ForPageBeingRemovedError +95 + STR lr, [sp] ; update returned r0 + BL StoreDebugRegs + PullEnv ; seriously broken memory + SETV + MOV pc, lr + +91 + ADR lr, PageBeingRemovedNotPresentError + B %BT95 + +92 + ADR lr, PhysicalAddressNotFoundError + B %BT95 + + ] + + [ :LNOT: NewStyle_RAMDisc +;........................................ +; Old style RAMFS bashing + +CheckRAMFSChangeOK + Push "r0-r5" + MOV r0, #5 + ADR r1, ramcolondollardotstar + SWI XOS_File + CMPVC r0, #0 + Pull "r0-r5" + BVS AllowRAMFSChange ; ramfs not present + BEQ AllowRAMFSChange ; ramfs empty + ADR r0, ErrorBlock_RAMFsUnchangeable + B ChangeDynamic_Error + MakeErrorBlock RAMFsUnchangeable + +ramcolondollardotstar = "ram:$.*",0 +ramfsname = "ramfs",0 + + ALIGN + +reinitialise_RAMFS + Push "r0-r6" + MOV r0, #ModHandReason_EnumerateROM_Modules + MOV r1, #0 + MOV r2, #-1 +look_for_RAMFS + SWI XOS_Module + BVS OKtoreinitRAMFS ; can't find it: may be in ram + ADR r5, ramfsname +nameloop + LDRB r6, [r3], #1 + CMP r6, #" " + BLE foundramfs + LowerCase r6, lr + LDRB lr, [r5], #1 + CMP lr, r6 + BEQ nameloop + B look_for_RAMFS + +foundramfs + CMP r4, #-1 + BNE OKtoreinitRAMFS + Pull "r0-r6" + B CDS_PostService + +OKtoreinitRAMFS + MOV r0, #ModHandReason_ReInit + ADR r1, ramfsname + SWI XOS_Module + Pull "r0-r6" + B CDS_PostService + ] + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r0 bits 0..6 = area number +; r0 bit 7 set => return max area size in r2 (implemented 13 Jun 1990) +; this will return an error if not implemented +; Out r0 = address of area +; r1 = current size of area +; r2 = max size of area if r0 bit 7 set on entry (preserved otherwise) + +; TMD 19-May-93: When this is updated to new CDA list, change meaning as follows: + +; r0 in range 0..&7F return address, size of area r0 +; &80..&FF return address, size, maxsize of area (r0-&80) +; &100.. return address, size, maxsize of area r0 + +; TMD 20-Aug-93: New bit added - if r0 = -1 on entry, then returns info on application space +; r0 = base address (&8000) +; r1 = current size (for current task) +; r2 = maximum size (eg 16M-&8000) + +ReadDynamicArea ROUT + +readdyn_returnR2bit * &80 + ASSERT ChangeDyn_MaxArea < readdyn_returnR2bit + + [ NewCDA + CMP r0, #-1 ; if finding out about app space + LDREQ r1, [r0, #AplWorkSize+1] ; then r1 = current size + LDREQ r2, =AplWorkMaxSize ; and r2 = max size + MOVEQ r0, #&8000 ; r0 = base address + SUBEQ r1, r1, r0 ; adjust size and maxsize + SUBEQ r2, r2, r0 ; to remove bottom 32K + ExitSWIHandler EQ + +; first check if it's one of the new ones + + Push "r1,lr" + CMP r0, #&100 ; if area >= &100 + MOVCS r1, r0 ; then just use area + BICCC r1, r0, #readdyn_returnR2bit ; else knock off bit 7 + BL CheckAreaNumber ; out: r10 -> node + Pull "r1,lr" + BCC %FT05 ; [not a new one, so use old code] + + CMP r0, #&80 ; CS => load maxsize into R2 + ; (do this either if bit 7 set, or area >=&100) + LDRCS r2, [r10, #DANode_MaxSize] + LDR r1, [r10, #DANode_Size] ; r1 = current size + LDR r0, [r10, #DANode_Base] ; r0 -> base + LDR r11, [r10, #DANode_Flags] ; if doubly mapped + TST r11, #DynAreaFlags_DoublyMapped + SUBNE r0, r0, r1 ; then return start of 1st copy for compatibility + ExitSWIHandler +05 + ] + [ :LNOT: NewStyle_All + BIC r10, r0, #readdyn_returnR2bit + CMP r10, #ChangeDyn_MaxArea + BLS %FT07 + ] + ADRL r0, ErrorBlock_BadDynamicArea + [ International + Push "lr" + BL TranslateError + Pull "lr" + ] + B SLVK_SetV + + [ :LNOT: NewStyle_All +07 + TST r0, #readdyn_returnR2bit ; if bit 7 set, R2 = max size of area + [ MEMC_Type = "IOMD" + BEQ %FT10 + EORS r11, r10, #ChangeDyn_Screen ; if screen + LDREQ r2, [r11, #VideoSize] ; then use video size + ADRNEL r11, Grow_LimitsPtrs+4 + LDRNE r2, [r11, r10, LSL #2] ; else use grow limits + LDRNE r2, [r2] ; (grow limits are pointers to max sizes now) +10 + | + ADRNEL r11, Grow_LimitsPtrs+4 + LDRNE r2, [r11, r10, LSL #2] + LDRNE r2, [r2] ; (grow limits are pointers to max sizes now) + ] + + CMP r10, #ChangeDyn_Screen ; screen? + ADRL r0, Current_Size+4 + ADRL r11, StartAddrs+4 + LDR r1, [r0, r10, LSL #2] + LDR r1, [r1] ; r1 = current size of area + LDR r0, [r11, r10, LSL #2] ; r0 = start address of area + SUBEQ r0, r0, r1 ; screen goes wackbords + B SLVK + ] + + MakeErrorBlock BadDynamicArea + +; ************************************************************************* +; User access to CAM mapping +; ReadMemMapInfo: +; returns R0 = pagsize +; R1 = number of pages in use (= R2 returned from SetEnv/Pagesize) +; ************************************************************************* + +ReadMemMapInfo_Code + MOV R10, #0 + LDR R0, [R10, #Page_Size] + LDR R1, [R10, #RAMLIMIT] ; = total memory size + ADRL R11, PageShifts-1 + LDRB R11, [R11, R0, LSR #12] + MOV R1, R1, LSR R11 + ExitSWIHandler + +; ************************************************************************ +; SWI ReadMemMapEntries: R0 pointer to list. +; Entries are three words long, the first of which is the CAM page number. +; List terminated by -1. +; Returns pagenumber (unaltered)/address/PPL triads as below +; ************************************************************************ + +ReadMemMapEntries_Code ROUT + Push "r0,r14" + MOV r14, #0 + LDR r10, [r14, #CamEntriesPointer] + LDR r14, [r14, #MaxCamEntry] +01 + LDR r12, [r0], #4 + CMP r12, r14 + Pull "r0,r14", HI + ExitSWIHandler HI + [ ExpandedCamMap + ADD r11, r10, r12, LSL #3 + LDMIA r11, {r11, r12} + | + LDR r11, [r10, r12, LSL #2] + MOV r12, r11, LSR #28 ; PPL + BIC r11, r11, #&F0000000 + ] + STMIA r0!, {r11, r12} + B %BT01 + +; ************************************************************************ +; SWI FindMemMapEntries: +; In: R0 -> table of 12-byte page entries +; +0 4 probable page number (0..npages-1) (use 0 if no idea) +; +4 4 logical address to match with +; +8 4 undefined +; terminated by a single word containing -1 +; +; Out: table of 12-byte entries updated: +; +0 4 actual page number (-1 => not found) +; +4 4 address (preserved) +; +8 4 page protection level (3 if not found) +; terminator preserved +; +; ************************************************************************ + +FindMemMapEntries_Code ROUT + [ ExpandedCamMap + +; Code for expanded CAM map version + + Push "r0, r9, r14" + MOV r14, #0 + LDR r9, [r14, #MaxCamEntry] + LDR r14, [r14, #CamEntriesPointer] ; r14 -> start of cam map + ADD r9, r14, r9, LSL #3 ; r9 -> first word of last entry in cam map +10 + LDR r10, [r0, #0] ; r10 = guess page number (or -1) + CMP r10, #-1 ; if -1 then end of list + Pull "r0, r9, r14", EQ ; so restore registers + ExitSWIHandler EQ ; and exit + + LDR r11, [r0, #4] ; r11 = logical address + ADD r10, r14, r10, LSL #3 ; form address with 'guess' page + CMP r10, r9 ; if off end of CAM + BHI %FT20 ; then don't try to use the guess + + LDR r12, [r10] ; load address from guessed page + TEQ r11, r12 ; compare address + BEQ %FT60 ; if equal, then guessed page was OK +20 + +; for now, cheat by looking in L2PT, to see if we can speed things up + + Push "r5-r8" ; need some registers here! + LDR r10, =L2PT + MOV r8, r11, LSR #12 ; r8 = logical page number + ADD r8, r10, r8, LSL #2 ; r8 -> L2PT entry for log.addr + MOV r5, r8, LSR #12 ; r5 = page offset to L2PT entry for log.addr + LDR r5, [r10, r5, LSL #2] ; r5 = L2PT entry for L2PT entry for log.addr + TST r5, #3 ; if page not there + SUBEQ r10, r9, #8 ; then invalid page so go from last one + BEQ %FT45 + LDR r8, [r8] ; r8 = L2PT entry for log.addr + MOV r8, r8, LSR #12 ; r8 = physaddr / 4K + + MOV r5, #PhysRamTable + SUB r10, r14, #8 +30 + CMP r10, r9 ; have we run out of RAM banks? + BCS %FT40 ; then fail + LDMIA r5!, {r6,r7} ; load next address, size + SUB r6, r8, r6, LSR #12 ; number of pages into this bank + CMP r6, r7, LSR #12 ; if more than there are + ADDCS r10, r10, r7, LSR #12-3 ; then advance CAM entry position + BCS %BT30 ; and loop to next bank + + ADD r10, r10, r6, LSL #3 ; advance by 2 words for each page in this bank +40 + SUBCS r10, r9, #8 ; search from last one, to fail quickly (if CS) +45 + Pull "r5-r8" +50 + CMP r10, r9 ; if not just done last one, + LDRNE r12, [r10, #8]! ; then get logical address + TEQNE r11, r12 ; compare address + BNE %BT50 ; loop if not same and not at end + +; either found page or run out of pages + + TEQ r11, r12 ; see if last one matched + ; (we always load at least one!) +60 + LDREQ r12, [r10, #4] ; if match, then r12 = PPL + SUBEQ r10, r10, r14 ; and page number=(r10-r14)>>3 + MOVEQ r10, r10, LSR #3 + + MOVNE r10, #-1 ; else unknown page number indicator + MOVNE r12, #3 ; and PPL=3 (no user access) + + STMIA r0!, {r10-r12} ; store all 3 words + B %BT10 ; and go back for another one + | + +; Code for non-expanded CAM map version + + Push "r0, r9, r14" + MOV r14, #0 + LDR r9, [r14, #MaxCamEntry] + LDR r14, [r14, #CamEntriesPointer] ; r14 -> start of cam map + ADD r9, r14, r9, LSL #2 ; r9 -> last entry in cam map +10 + LDR r10, [r0, #0] ; r10 = guess page number (or -1) + CMP r10, #-1 ; if -1 then end of list + Pull "r0, r9, r14", EQ ; so restore registers + ExitSWIHandler EQ ; and exit + + LDR r11, [r0, #4] ; r11 = logical address + MOV r11, r11, LSL #4 ; shift up so we can compare with + ; shifted up addresses + ADD r10, r14, r10, LSL #2 ; form address with 'guess' page + CMP r10, r9 ; if off end of CAM + BHI %FT15 ; then don't try to use the guess + + LDR r12, [r10] ; load address+ppl from guessed page + TEQ r11, r12, LSL #4 ; compare address + BEQ %FT30 ; if equal, then guessed page was OK +15 + [ MEMM_Type = "ARM600" + +; for now, cheat by looking in L2PT, to see if we can speed things up + + Push "r5-r8" ; need some registers here! + LDR r10, =L2PT + CMP r11, #256*1024*1024*4 ; if address >= 256M + BCS %FT17 ; then invalid, so search from last one + + MOV r8, r11, LSR #16 ; r8 = logaddr / 4K + LDR r8, [r10, r8, LSL #2] ; get page table entry + MOV r8, r8, LSR #12 ; r8 = physaddr / 4K + + MOV r5, #VideoPhysAddr + SUB r10, r14, #4 +16 + CMP r10, r9 ; have we run out of RAM banks? + BCS %FT17 ; then fail + LDMIA r5!, {r6,r7} ; load next address, size + SUB r6, r8, r6, LSR #12 ; number of pages into this bank + CMP r6, r7, LSR #12 ; if more than there are + ADDCS r10, r10, r7, LSR #12-2 ; then advance CAM entry position (bank size must be multiple of 4K) + BCS %BT16 ; and loop to next bank + + ADD r10, r10, r6, LSL #2 ; advance by 1 word for each page in this bank +17 + SUBCS r10, r9, #4 ; search from last one, to fail quickly (if CS) + Pull "r5-r8" + | + SUB r10, r14, #4 ; move pointer to start of CAM -4 + ] + +20 + CMP r10, r9 ; if not just done last one, get + LDRNE r12, [r10, #4]! ; address in bits 0..27, PPL in 28..31 + TEQNE r11, r12, LSL #4 ; compare address + BNE %BT20 ; loop if not same and not at end + +; either found page or run out of pages + + TEQ r11, r12, LSL #4 ; see if last one matched + ; (we always load at least one!) +30 + SUBEQ r10, r10, r14 ; if match, then + MOVEQ r10, r10, LSR #2 ; page number=(r10-r14)>>2 + MOVEQ r12, r12, LSR #28 ; and PPL=r12>>28 + + MOVNE r10, #-1 ; else unknown page number indicator + MOVNE r12, #3 ; and PPL=3 (no user access) + + MOV r11, r11, LSR #4 ; restore r11 to original value + + STMIA r0!, {r10-r12} ; store all 3 words + B %BT10 ; and go back for another one + ] + +;************************************************************************** +; SWI SetMemMapEntries: R0 pointer to list of CAM page/address/PPL triads, +; terminated by -1. +; Any address > 32M means "put the page out of the way" +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +SetMemMapEntries_Code ROUT + Push "r0-r6, r9, lr" + MOV r12, r0 + +; BangCamUpdate takes entry no in r2, logaddr to set to in r3 +; r9 current MEMC, r11 = PPL +; corrupts r0,r1,r4,r6 + + MOV r9, #0 + LDR r5, [r9, #MaxCamEntry] + LDR r9, [r9, #MEMC_CR_SoftCopy] +01 + LDR r2, [r12], #4 + CMP r2, r5 + BHI %FT02 ; finished + LDMIA r12!, {r3, r11} + AND r11, r11, #3 + [ MEMM_Type = "ARM600" + CMP r3, #-1 + | + CMP r3, #32*1024*1024 + ] + LDRHS r3, =DuffEntry + MOVHS r11, #AP_Duff + BL BangCamUpdate + B %BT01 +02 + Pull "r0-r6, r9, lr" + ExitSWIHandler + + LTORG + + [ :LNOT: NewCDA +InitDynamicAreas MOV pc, lr ; if not new world then nothing to initialise + ] + + [ NewCDA + +;************************************************************************** +; +; DynamicAreaSWI - Code to handle SWI OS_DynamicArea +; +; in: r0 = reason code +; Other registers depend on reason code +; +; out: Depends on reason code +; + +DAReason_Create * 0 +DAReason_Remove * 1 +DAReason_GetInfo * 2 +DAReason_Enumerate * 3 +DAReason_Renumber * 4 +DAReason_Limit * 5 + +DynArea_NewAreas * &100 ; Allocated area numbers start here +DynArea_NewAreasBase * &04000000 ; Allocated area addresses start here + +; Bits in dynamic area flags (and page flags) + +DynAreaFlags_APBits * 15 :SHL: 0 ; currently only uses 2 bits, but may extend to allow svc/usr read-only +DynAreaFlags_NotBufferable * 1 :SHL: 4 +DynAreaFlags_NotCacheable * 1 :SHL: 5 +DynAreaFlags_DoublyMapped * 1 :SHL: 6 +DynAreaFlags_NotUserDraggable * 1 :SHL: 7 + [ DAF_SpecifyBit +DynAreaFlags_NeedsSpecificPages * 1 :SHL: 8 ; whether area will ever require particular physical pages + ] +DynAreaFlags_AccessMask * DynAreaFlags_APBits :OR: DynAreaFlags_NotBufferable :OR: DynAreaFlags_NotCacheable :OR: DynAreaFlags_DoublyMapped + +; The following bits are only present in page flags + +TempUncacheableShift * 9 +PageFlags_TempUncacheableBits * 15 :SHL: TempUncacheableShift ; temporary count of uncacheability, used by DMA mgr +PageFlags_Unavailable * 1 :SHL: 13 ; physical page may not be requested by a PreShrink handler + +; Temporary flags only used by kernel + +PageFlags_Required * 1 :SHL: 14 ; physical page asked for by handler + +DynamicAreaSWI ENTRY + BL DynAreaSub + PullEnv + ORRVS lr, lr, #V_bit + ExitSWIHandler + +DynAreaSub + CMP r0, #DAReason_Limit + ADDCC pc, pc, r0, LSL #2 + B DynArea_Unknown + B DynArea_Create + B DynArea_Remove + B DynArea_GetInfo + B DynArea_Enumerate + B DynArea_Renumber + +; unknown OS_DynamicArea reason code + +DynArea_Unknown + ADRL r0, ErrorBlock_HeapBadReason +DynArea_TranslateAndReturnError + [ International + Push lr + BL TranslateError + Pull lr + ] +DynArea_ReturnError + SETV + MOV pc, lr + +;************************************************************************** +; +; DynArea_Create - Create a dynamic area +; +; Internal routine called by DynamicAreaSWI and by reset code +; +; in: r0 = reason code (0) +; r1 = new area number, or -1 => RISC OS allocates number +; r2 = initial size of area (in bytes) +; r3 = base logical address of area, or -1 => RISC OS allocates address space +; r4 = area flags +; bits 0..3 = access privileges +; bit 4 = 1 => not bufferable +; bit 5 = 1 => not cacheable +; bit 6 = 0 => area is singly mapped +; = 1 => area is doubly mapped +; bit 7 = 1 => area is not user draggable in TaskManager window +; bits 8..31 = 0 (bits 8..12 are used in page flags, but not for areas) +; +; r5 = maximum size of area, or -1 for total RAM size +; r6 -> area handler routine +; r7 = workspace pointer for area handler (-1 => use base address) +; r8 -> area description string (null terminated) (gets copied) +; +; out: r1 = given or allocated area number +; r3 = given or allocated base address of area +; r5 = given or allocated maximum size +; r0, r2, r4, r6-r9 preserved +; r10-r12 may be corrupted +; + +DynArea_Create ENTRY "r2,r6-r8" + CMP r1, #-1 ; do we have to allocate a new area number + BEQ %FT10 + + BL CheckAreaNumber ; see if area number is unique + BCC %FT20 ; didn't find it, so OK + + ADR r0, ErrorBlock_AreaAlreadyExists +DynArea_ErrorTranslateAndExit + PullEnv + B DynArea_TranslateAndReturnError + + MakeErrorBlock AreaAlreadyExists + MakeErrorBlock AreaNotOnPageBdy + MakeErrorBlock OverlappingAreas + MakeErrorBlock CantAllocateArea + MakeErrorBlock CantAllocateLevel2 + MakeErrorBlock UnknownAreaHandler + +; we have to allocate an area number for him + +10 + MOV r1, #DynArea_NewAreas +12 + BL CheckAreaNumber + ADDCS r1, r1, #1 ; that area number already exists, so increment + BCS %BT12 ; and try again +20 + +; now validate maximum size of area + + MOV r10, #0 + LDR r11, [r10, #Page_Size] + LDR r10, [r10, #RAMLIMIT] ; get total RAM size + CMP r5, r10 ; if requested maximum size is > total + MOVHI r5, r10 ; then set max to total (NB. -1 passed in always yields HI) + + SUB r10, r11, #1 ; also round up to a page multiple + ADD r5, r5, r10 + BIC r5, r5, r10 + +; now see if we have to allocate a logical address space + + CMP r3, #-1 ; if we are to allocate the address space + BEQ %FT30 ; then go do it + +; otherwise we must check that the address does not clash with anything else + + TST r3, r10 ; does it start on a page boundary + ADRNE r0, ErrorBlock_AreaNotOnPageBdy ; if not then error + BNE DynArea_ErrorTranslateAndExit + + BL CheckForOverlappingAreas ; in: r3 = address, r4 = flags, r5 = size; out: if error, r0->error, V=1 + BVC %FT40 +25 + PullEnv + B DynArea_ReturnError + +30 + BL AllocateAreaAddress ; in: r4 = flags, r5 = size of area needed; out: r3, or V=1, r0->error + BVS %BT25 +40 + BL AllocateBackingLevel2 ; in: r3 = address, r4 = flags, r5 = size; out: VS if error + BVS %BT25 + + Push "r0,r1,r3" + MOV r3, #DANode_NodeSize + BL ClaimSysHeapNode ; out: r2 -> node + STRVS r0, [sp] + Pull "r0,r1,r3" + BVS %BT25 ; failed to claim node + +; now store data in node (could probably use STM if we shuffled things around) + + CMP r7, #-1 ; if workspace ptr = -1 + MOVEQ r7, r3 ; then use base address + + STR r1, [r2, #DANode_Number] + STR r3, [r2, #DANode_Base] + STR r4, [r2, #DANode_Flags] + STR r5, [r2, #DANode_MaxSize] + STR r6, [r2, #DANode_Handler] + STR r7, [r2, #DANode_Workspace] + MOV r7, #0 ; initial size is zero + STR r7, [r2, #DANode_Size] ; before we grow it + +; now make copy of string - first find out length of string + + MOV r7, r8 +45 + LDRB r6, [r7], #1 + TEQ r6, #0 + BNE %BT45 + + Push "r0-r3" + SUB r3, r7, r8 ; r3 = length inc. term. + BL ClaimSysHeapNode + STRVS r0, [sp] + MOV r7, r2 + Pull "r0-r3" + BVS StringNodeClaimFailed + + STR r7, [r2, #DANode_Title] +50 + LDRB r6, [r8], #1 ; copy string into claimed block + STRB r6, [r7], #1 + TEQ r6, #0 + BNE %BT50 + +; now put node on list - list is sorted in ascending base address order + + MOV r8, #DAList + LDR r6, [r2, #DANode_Base] +60 + MOV r7, r8 + ASSERT DANode_Link = 0 + LDR r8, [r7, #DANode_Link] ; get next node + TEQ r8, #0 ; if no more + BEQ %FT70 ; then put it on here + LDR lr, [r8, #DANode_Base] + CMP lr, r6 ; if this one is before ours + BCC %BT60 ; then loop + +70 + STR r8, [r2, #DANode_Link] + STR r2, [r7, #DANode_Link] + +; now we need to grow the area to its requested size + + Push "r0, r1" + LDR r0, [r2, #DANode_Number] + LDR r1, [sp, #2*4] ; reload requested size off stack + SWI XOS_ChangeDynamicArea + BVS %FT90 + +; Now issue service to tell TaskManager about it + + MOV r2, r0 ; r2 = area number + MOV r1, #Service_DynamicAreaCreate + BL Issue_Service + Pull "r0, r1" + + CLRV + EXIT + +90 + +; The dynamic area is not being created, because we failed to grow the area to the required size. +; The area itself will have no memory allocated to it (since if grow fails it doesn't move any). +; We must delink the node from our list, free the string node, and then the area node itself. + + STR r0, [sp, #0*4] ; remember error pointer in stacked r0 + STR r8, [r7, #DANode_Link] ; delink area + MOV r6, r2 ; save pointer to DANode itself + LDR r2, [r6, #DANode_Title] + BL FreeSysHeapNode ; free title string node + MOV r2, r6 ; point r2 back at DANode + Pull "r0, r1" ; pull stacked registers, and drop thru to... + +; The dynamic area is not being created, because there is no room to allocate space for the title string +; We must free the DANode we have allocated +; It would be nice to also free the backing L2, but we'll leave that for now. + +; in: r2 -> DANode + +StringNodeClaimFailed + Push "r0, r1" + BL FreeSysHeapNode + Pull "r0, r1" + PullEnv + B DynArea_ReturnError + +;************************************************************************** +; +; DynArea_Remove - Remove a dynamic area +; +; Internal routine called by DynamicAreaSWI +; +; in: r0 = reason code (1) +; r1 = area number +; +; out: r10-r12 may be corrupted +; All other registers preserved +; + +DynArea_Remove ENTRY + BL CheckAreaNumber ; check that area is there + BCC UnknownDyn ; [not found] + +; First try to shrink area to zero size + + Push "r0-r2" + MOV r0, r1 ; area number + LDR r2, [r10, #DANode_Size] ; get current size + RSB r1, r2, #0 ; negate it + SWI XOS_ChangeDynamicArea + BVS %FT80 + STRVS r0, [sp] + Pull "r0-r2" + EXIT VS + +; Issue service to tell TaskManager + + Push "r1, r2" + MOV r2, r1 + MOV r1, #Service_DynamicAreaRemove + BL Issue_Service + Pull "r1, r2" + +; Now just de-link from list (r10 -> node, r11 -> prev) + + LDR lr, [r10, #DANode_Link] ; store our link + STR lr, [r11, #DANode_Link] ; in prev link + + Push "r0-r2" + LDR r2, [r10, #DANode_Title] ; free title string block + BL FreeSysHeapNode + MOV r2, r10 ; and free node block + BL FreeSysHeapNode + Pull "r0-r2" + CLRV + EXIT + +; come here if shrink failed - r0-r2 stacked + +80 + STR r0, [sp] ; overwrite stacked r0 with error pointer + LDR r0, [sp, #1*4] ; reload area number + LDR r1, [r10, #DANode_Size] ; get size after failed shrink + SUB r1, r2, r1 ; change needed to restore original size + SWI XOS_ChangeDynamicArea ; ignore any error from this + SETV + EXIT + +UnknownDyn + ADRL r0, ErrorBlock_BadDynamicArea + [ International + BL TranslateError + ] +90 + SETV + EXIT + +;************************************************************************** +; +; DynArea_GetInfo - Get info on a dynamic area +; +; Internal routine called by DynamicAreaSWI +; +; in: r0 = reason code (2) +; r1 = area number +; +; out: r2 = current size of area +; r3 = base logical address +; r4 = area flags +; r5 = maximum size of area +; r6 -> area handler routine +; r7 = workspace pointer +; r8 -> title string +; r10-r12 may be corrupted +; All other registers preserved +; + +DynArea_GetInfo ALTENTRY + BL CheckAreaNumber ; check area exists + BCC UnknownDyn ; [it doesn't] + +; r10 -> node, so get info + + LDR r2, [r10, #DANode_Size] + LDR r3, [r10, #DANode_Base] + LDR r4, [r10, #DANode_Flags] + LDR r5, [r10, #DANode_MaxSize] + LDR r6, [r10, #DANode_Handler] + LDR r7, [r10, #DANode_Workspace] + LDR r8, [r10, #DANode_Title] + CLRV + EXIT + +;************************************************************************** +; +; DynArea_Enumerate - Enumerate dynamic areas +; +; Internal routine called by DynamicAreaSWI +; +; in: r0 = reason code (3) +; r1 = -1 to start enumeration, or area number to continue from +; +; out: r1 = next area number or -1 if no next +; r10-r12 may be corrupted +; All other registers preserved + +DynArea_Enumerate ALTENTRY + CMP r1, #-1 ; if starting from beginning + LDREQ r10, [r1, #DAList+1] ; then load pointer to 1st node + BEQ %FT10 ; and skip + + BL CheckAreaNumber ; else check valid area number + BCC UnknownDyn ; complain if passed in duff area number + + LDR r10, [r10, #DANode_Link] ; find next one +10 + TEQ r10, #0 ; if at end + MOVEQ r1, #-1 ; then return -1 + LDRNE r1, [r10, #DANode_Number] ; else return number + CLRV + EXIT + +;************************************************************************** +; +; DynArea_Renumber - Renumber dynamic area +; +; Internal routine called by DynamicAreaSWI +; +; in: r0 = reason code (4) +; r1 = old area number +; r2 = new area number +; + +DynArea_Renumber ALTENTRY + BL CheckAreaNumber ; check valid area number + BCC UnknownDyn ; [it's not] + + Push "r1" + MOV r12, r10 ; save pointer to node + MOV r1, r2 + BL CheckAreaNumber ; check area r2 doesn't already exist + Pull "r1" + BCS %FT90 ; [area r2 already exists] + + STR r2, [r12, #DANode_Number] + +; Now issue service to tell TaskManager + + Push "r1-r3" + MOV r3, r2 ; new number + MOV r2, r1 ; old number + MOV r1, #Service_DynamicAreaRenumber + BL Issue_Service + Pull "r1-r3" + + CLRV + EXIT + +90 + ADRL r0, ErrorBlock_AreaAlreadyExists + [ International + BL TranslateError + ] + SETV + EXIT + +;************************************************************************** +; +; CheckAreaNumber - Try to find area with number r1 +; +; Internal routine called by DynArea_Create +; +; in: r1 = area number to match +; out: If match, then +; C=1, r10 -> node, r11 -> previous node +; else +; C=0, r10,r11 corrupted +; endif + +CheckAreaNumber ENTRY + MOV r10, #DAList + ASSERT DANode_Link = 0 ; because DAList has only link +10 + MOV r11, r10 ; save prev + LDR r10, [r10, #DANode_Link] ; and load next + CMP r10, #1 ; any more nodes? + EXIT CC ; no, then no match + LDR lr, [r10, #DANode_Number] ; get number + CMP lr, r1 ; does number match + BNE %BT10 ; no, try next + EXIT ; (C=1 from CMP lr,r1) + +;************************************************************************** +; +; CheckForOverlappingAreas - Check that given area does not overlap any existing ones +; +; Internal routine called by DynArea_Create +; +; in: r3 = base address +; r4 = area flags (NB if doubly mapped, then have to check both halves for overlap) +; r5 = size (of each half in doubly mapped areas) +; +; out: If this area overlaps with an existing one, then +; r0 -> error +; V=1 +; else +; r0 preserved +; V=0 +; endif +; + +CheckForOverlappingAreas ENTRY "r0-r5" + TST r4, #DynAreaFlags_DoublyMapped ; check if doubly mapped + BEQ %FT05 ; [not, so don't mangle] + + SUBS r3, r3, r5 ; move start address back + BCC %FT20 ; oh dear! - it went back to below 0 + MOVS r5, r5, LSL #1 ; and double size + BCS %FT20 ; if that wrapped then that's bad, too +05 + ADDS r5, r5, r3 ; r5 -> end +1 + BHI %FT20 ; if CS, indicating wrap, and not EQ (ie just ending at 0), then bad + +; First, check against list of fixed areas + + ADR lr, FixedAreasTable +10 + LDMIA lr!, {r0, r1} ; r0 = start addr, r1 = size + CMP r0, #-1 ; if at end of list + BEQ %FT30 ; then OK wrt fixed areas + ADD r1, r1, r0 ; r1 = end addr+1 + CMP r5, r0 ; if end of our area is <= start of fixed, then OK wrt fixed areas + BLS %FT30 + CMP r3, r1 ; if start of our area is >= end of fixed, then go onto next area + BCS %BT10 + +20 + ADRL r0, ErrorBlock_OverlappingAreas + [ International + BL TranslateError + ] + STR r0, [sp] + SETV + EXIT + +; Now, check against DAList + +30 + MOV lr, #DAList + ASSERT DANode_Link = 0 +40 + LDR lr, [lr, #DANode_Link] + CMP lr, #0 ; if got to end of list (V=0) + BEQ %FT50 ; then exit saying OK + LDR r0, [lr, #DANode_Base] + LDR r1, [lr, #DANode_Flags] + TST r1, #DynAreaFlags_DoublyMapped + LDR r1, [lr, #DANode_MaxSize] + SUBNE r0, r0, r1 ; if doubly mapped then move back + MOVNE r1, r1, LSL #1 ; and double size + ADD r1, r1, r0 ; r1 -> end + CMP r5, r0 ; if end of our area is <= start of dyn, then OK wrt dyn areas) + BLS %FT50 + CMP r3, r1 ; if start of our area is >= end of dyn, then go onto next area + BCS %BT40 + B %BT20 ; else it overlaps + +50 + CLRV ; OK exit + EXIT + + +FixedAreasTable ; table of fixed areas (address, size) + & 0, AplWorkMaxSize ; application space + [ :LNOT: NewStyle_RMA + & RMAAddress, RMAMaxSize ; RMA (to be removed from here eventually) + ] + [ :LNOT: NewStyle_SysHeap + & SysHeapChunkAddress, SysHeapMaxSize+SVCStackSize ; system heap (to be removed eventually) + ] + & UndStackSoftCamChunk, 1024*1024 ; undefined stack / soft cam map + & CursorChunkAddress, 64*1024 ; 32K for cursor, 32K for "nowhere" + & L2PT, 4*1024*1024 ; L2PT (and L1PT) + & &03000000, 16*1024*1024 ; I/O + ROM + [ :LNOT: NewStyle_Screen + & ScreenEndAdr-16*1024*1024, 32*1024*1024 ; Screen (removable later) + ] + [ :LNOT: NewStyle_FontArea + & FontCacheAddress, FontCacheMaxSize ; Font cache (removable later) + ] + [ :LNOT: NewStyle_SpriteArea + & SpriteSpaceAddress, SpriteSpaceMaxSize ; Sprite area (removable later) + ] + [ :LNOT: NewStyle_RAMDisc + & RAMDiscAddress, RAMDiscMaxSize ; RAM disc (removable later) + ] + & PhysSpace, 512*1024*1024 ; PhysSpace + & &FF800000, &007FFFFF ; Shadow ROM (length has been bodged to avoid wrap problems) + & -1, 0 ; termination + +;************************************************************************** +; +; AllocateAreaAddress - Find an area of logical space to use for this area +; +; Internal routine called by DynArea_Create +; +; in: r4 = area flags (NB if doubly mapped, we have to find space for both halves) +; r5 = size (of each half in doubly mapped areas) +; +; out: If successfully found an address, then +; r0 preserved +; r3 = logical address +; V=0 +; else +; r0 -> error +; r3 preserved +; V=1 +; endif + +AllocateAreaAddress ENTRY "r0-r2,r4-r7" + TST r4, #DynAreaFlags_DoublyMapped ; check if doubly mapped + BEQ %FT05 ; [not, so don't mangle] + MOVS r5, r5, LSL #1 ; double size + BCS %FT90 ; if that wrapped then that's bad +05 + LDR r3, =DynArea_NewAreasBase ; r3 is our current attempt + ADR r0, FixedAreasTable ; r0 is ptr into fixed areas table + MOV r1, #DAList ; r1 is ptr into dyn areas list +10 + ADDS r7, r3, r5 ; r7 is our end+1 + BHI %FT90 ; if we wrapped (but not end+1=0) then we failed + BL GetNextRange ; get next range from either list (r2=start, r6=end+1) + CMP r7, r2 ; if end(ours) <= start(next) then this is OK + BLS %FT80 ; (note this also works when r2=-1) + CMP r3, r6 ; else if start(ours) >= end(next) + BCS %BT10 ; then get another + MOV r3, r6 ; else make start(ours) := end(next) + B %BT10 ; and go back for another try + +; we've succeeded - just apply unbodge for doubly-mapped areas + +80 + TST r4, #DynAreaFlags_DoublyMapped ; if doubly mapped + MOVNE r5, r5, LSR #1 ; halve size again + ADDNE r3, r3, r5 ; and advance base address to middle + CLRV + EXIT + +90 + ADRL r0, ErrorBlock_CantAllocateArea + [ International + BL TranslateError + ] + STR r0, [sp] + SETV + EXIT ; say we can't do it + +;************************************************************************** +; +; GetNextRange - Get next lowest range from either fixed or dynamic list +; +; Internal routine called by AllocateAreaAddress +; +; in: r0 -> next entry in fixed list +; r1!0 -> next entry in dyn list +; +; out: r2 = next lowest area base (-1 if none) +; r6 = end of that range (undefined if none) +; Either r0 or r1 updated to next one (except when r2=-1 on exit) +; + +GetNextRange ENTRY "r7,r8" + LDMIA r0, {r2, r6} ; load start, size from fixed list + ADD r6, r6, r2 ; r6 = end+1 + + ASSERT DANode_Link = 0 + LDR r7, [r1, #DANode_Link] ; get next from dyn + TEQ r7, #0 ; if none + MOVEQ r8, #-1 ; then use addr -1 + BEQ %FT10 + + LDR r8, [r7, #DANode_Flags] ; more double trouble + TST r8, #DynAreaFlags_DoublyMapped + LDR r8, [r7, #DANode_Base] + LDR lr, [r7, #DANode_MaxSize] + SUBNE r8, r8, lr + MOVNE lr, lr, LSL #1 + ADD lr, lr, r8 ; now r8 = start addr, lr = end+1 +10 + CMP r8, r2 ; if dyn one is earlier + MOVCC r2, r8 ; then use dyn start + MOVCC r6, lr ; and end + MOVCC r1, r7 ; and advance dyn ptr + EXIT CC ; then exit + CMP r2, #-1 ; else if not at end of fixed + ADDNE r0, r0, #8 ; then advance fixed ptr + EXIT + +;************************************************************************** +; +; AllocateBackingLevel2 - Allocate L2 pages for an area +; +; Internal routine called by DynArea_Create +; +; in: r3 = base address (will be page aligned) +; r4 = area flags (NB if doubly mapped, then have to allocate for both halves) +; r5 = size (of each half in doubly mapped areas) +; +; out: If successfully allocated pages, then +; All registers preserved +; V=0 +; else +; r0 -> error +; V=1 +; endif + +AllocateBackingLevel2 ENTRY "r0-r8,r11" + TST r4, #DynAreaFlags_DoublyMapped ; if doubly mapped + SUBNE r3, r3, r5 ; then area starts further back + MOVNE r5, r5, LSL #1 ; and is twice the size + +; NB no need to do sanity checks on addresses here, they've already been checked + +; now round address range to 4M boundaries + + ADD r5, r5, r3 ; r5 -> end + MOV r0, #1 :SHL: 22 + SUB r0, r0, #1 + BIC r8, r3, r0 ; round start address down (+ save for later) + ADD r5, r5, r0 + BIC r5, r5, r0 ; but round end address up + +; first go through existing L2PT working out how much we need + + LDR r7, =L2PT + ADD r3, r7, r8, LSR #10 ; r3 -> start of L2PT for area + ADD r5, r7, r5, LSR #10 ; r5 -> end of L2PT for area +1 + + ADD r1, r7, r3, LSR #10 ; r1 -> L2PT for r3 + ADD r2, r7, r5, LSR #10 ; r2 -> L2PT for r5 + + TEQ r1, r2 ; if no pages needed + BEQ %FT30 + + MOV r4, #0 ; number of backing pages needed +10 + LDR r6, [r1], #4 ; get L2PT entry for L2PT + TST r6, #3 ; EQ if translation fault + ADDEQ r4, r4, #1 ; if not there then 1 more page needed + TEQ r1, r2 + BNE %BT10 + +; if no pages needed, then exit + + TEQ r4, #0 + BEQ %FT30 + +; now we need to claim r4 pages from the free pool, if possible; return error if not + + MOV r1, #0 + LDR r6, [r1, #FreePoolDANode + DANode_Size] + SUBS r6, r6, r4, LSL #12 ; reduce free pool size by that many pages + BCS %FT14 ; if enough, skip next bit + +; not enough pages in free pool currently, so try to grow it by the required amount + + Push "r0, r1" + MOV r0, #ChangeDyn_FreePool + RSB r1, r6, #0 ; size change we want (+ve) + SWI XOS_ChangeDynamicArea + Pull "r0, r1" + BVS %FT90 ; didn't manage change, so report error + + MOV r6, #0 ; will be no pages left in free pool after this +14 + STR r6, [r1, #FreePoolDANode + DANode_Size] ; if possible then update size + +; after that we need to zero all these pages out (=> cause translation fault for area initially) + + LDR r0, [r1, #FreePoolDANode + DANode_Base] ; r0 -> base of free pool + ADD r0, r0, r6 ; r0 -> first byte we're taking out of free pool + ADD r6, r0, r4, LSL #12 ; r6 -> byte after last in free pool + Push r8 ; save original logical address + MOV r8, #0 ; 0 => translation fault (note r1 already zero) + MOV r11, #0 + MOV lr, #0 +15 + STMIA r0!, {r1,r8,r11,lr} ; store data + TEQ r0, r6 + BNE %BT15 + Pull r8 + +; now r0 -> after end of free pool (log addr) + + LDR lr, =L1PT + ADD r8, lr, r8, LSR #18 ; point r8 at start of L1 we may be updating + ADD r1, r7, r3, LSR #10 ; point r1 at L2PT for r3 again + MOV r11, #AP_L2PT ; access privs (+CB bits) +20 + LDR r6, [r1], #4 ; get L2PT entry again + TST r6, #3 ; if no fault + BNE %FT25 ; then skip + + SUB r0, r0, #4096 ; move free pointer back + Push "r2,r4,r5" + BL MoveCAMatR0toR3 ; else move page from end of free pool to r3 + Pull "r2,r4,r5" + +; now update 4 words in L1PT (corresponding to 4M of address space which is covered by the 4K of L2) +; and point them at the physical page we've just allocated (r1!-4 will already hold physical address+bits now!) + + LDR r6, [r1, #-4] ; r6 = physical address for L2 page + other L2 bits + MOV r6, r6, LSR #12 ; r6 = phys.addr >> 12 + LDR lr, =L1_Page + L1_U ; form other bits to put in L1 + ORR lr, lr, r6, LSL #12 ; complete L1 entry + STR lr, [r8, #0] ; store entry for 1st MB + ADD lr, lr, #1024 ; advance L2 pointer + STR lr, [r8, #4] ; store entry for 2nd MB + ADD lr, lr, #1024 ; advance L2 pointer + STR lr, [r8, #8] ; store entry for 3rd MB + ADD lr, lr, #1024 ; advance L2 pointer + STR lr, [r8, #12] ; store entry for 4th MB + SetCop lr, CR_TLBFlush ; junk the TLB (probably not necessary) +25 + ADD r3, r3, #4096 ; advance L2PT logical address + ADD r8, r8, #16 ; move onto L1 for next 4M + + TEQ r1, r2 + BNE %BT20 +30 + CLRV + EXIT + + LTORG + +; Come here if not enough space in free pool to allocate level2 + +90 + ADRL r0, ErrorBlock_CantAllocateLevel2 + [ International + BL TranslateError + ] + STR r0, [sp] + SETV + EXIT + +;************************************************************************** +; +; InitDynamicAreas - Initialise nodes for dynamic areas +; +; It only initialises free pool, appspace and sysheap nodes +; The other areas are created properly, after the screen area has been created (improperly) +; +; in: - +; out: - +; + +InitDynamicAreas ENTRY "r0-r8,r11" + MOV lr, #AppSpaceDANode + ADR r0, InitAppSpaceTable + LDMIA r0, {r0-r8} + STMIA lr, {r0-r8} + + MOV lr, #FreePoolDANode + ADR r0, InitFreePoolTable + LDMIA r0, {r0-r8} ; copy initial data into node + LDR r5, [lr, #RAMLIMIT-FreePoolDANode] ; max size is RAMLIMIT + STMIA lr, {r0-r8} + + [ GetPagesFromFreePool + +; We have to move all free pages (ie ones not occupied by the static pages) into the free pool +; The lowest numbered physical pages must be put in last, so that when ReadCMOSAndConfigure is +; called to put in the screen, it will get the pages starting at 0 (when the screen is created +; as a dynamic area, this limitation can be removed). + +; The free pages consist of two chunks of pages, each of which having consecutive physical page +; numbers. We start at MaxCamEntry and move back until we hit the end of the statics (which are +; at the start of the 1st non-video-RAM chunk). We then separately do the video RAM. + + MOV r11, r3 ; r11 = PPL (inc CB) for free pool + MOV r3, r2 ; r3 = base address of free pool, ie where to put stuff + MOV r5, #0 ; r5 = amount of memory in free pool so far (and ptr to 0) + LDR r2, [r5, #MaxCamEntry] ; r2 = 1st page to put in free pool + LDR r7, [r5, #VideoSize] ; r7 = size of video RAM + MOV r7, r7, LSR #12 ; r7 = page number of start of static chunk + ASSERT SoftCamMapSize = L2PTSize +4 + MOV r0, #L2PTSize + LDMIA r0, {r0, r8} ; r0 = L2PTSize, r8 = SoftCamMapSize + ADD r8, r8, r0 ; add sizes together + ADD r8, r8, #StaticPagesSize + UndStackSize ; + number of bytes used for other static bits + ADD r8, r7, r8, LSR #12 ; r8 = page number of 1st page in 1st chunk not used for statics +10 + CMP r2, r8 ; are we into statics already + SUBCC r2, r7, #1 ; if so, then move to last page of video RAM + MOVCC r8, #0 ; and move barrier so we never hit it again + BL BangCamUpdate + ADD r3, r3, #4096 ; advance logical address + ADD r5, r5, #4096 + SUBS r2, r2, #1 ; decrement page number + BCS %BT10 ; if we haven't gone negative, then loop + + MOV lr, #FreePoolDANode ; may be used below to update DAList head ptr + STR r5, [lr, #DANode_Size] ; update size of free pool in node + +; Now initialise the system heap by hand, so we can start creating dynamic areas + + LDR r0, =SysHeapStart + LDR r1, =magic_heap_descriptor + MOV r2, #Nil + MOV r3, #hpdsize + MOV r4, #32*1024 - (SysHeapStart-SysHeapChunkAddress) + STMIA r0, {r1-r4} + + MOV r0, #0 ; initialise module list to empty + STR r0, [r0, #Module_List] + ] + [ NewStyle_SysHeap + MOV lr, #SysHeapDANode ; initialise system heap node + ADR r0, InitSysHeapTable + LDMIA r0, {r0-r8} + STMIA lr, {r0-r8} + ] + MOV r0, #0 + STR lr, [r0, #DAList] ; store pointer to 1st node on list (either free pool or sys heap) + + [ NewStyle_All + STR r0, [r0, #CDASemaphore] ; clear CDASemaphore + ] + + EXIT + +InitFreePoolTable + & 0 ; link: no more nodes on list + & ChangeDyn_FreePool + & FreePoolAddress + & AP_FreePool + & 0 ; size will be updated later + & 0 ; max size is computed + & 0 ; no workspace needed + & 0 ; no handler needed + & FreePoolString ; title + +InitSysHeapTable + & FreePoolDANode ; link -> free pool node, since FreePoolAddress > SysHeapStart + & ChangeDyn_SysHeap + & SysHeapStart + & AP_SysHeap + & 32*1024-(SysHeapStart-SysHeapChunkAddress) ; size + & SysHeapMaxSize + & SysHeapStart ; workspace pointer -> base of heap + & DynAreaHandler_SysHeap ; area handler + & SysHeapString ; title + +InitAppSpaceTable + & 0 ; link: not on list + & ChangeDyn_AplSpace + & 0 ; base address + & AP_AppSpace + & 0 ; size will be set up later + & AplWorkMaxSize + & 0 ; no workspace needed + & 0 ; no handler needed + & AppSpaceString ; title + +FreePoolString + = "Free pool", 0 +AppSpaceString + = "Application space", 0 +SysHeapString + = "System heap", 0 + ALIGN + + ] + + [ NewCDA2 + [ NewStyle_All +ChangeDynamicSWI ROUT + Push "r0, r2-r9, r10, lr" + +; and drop thru to ... + ] + +;************************************************************************** +; +; CheckForNewArea - Perform operation of OS_ChangeDynamicArea, if +; area is on new list +; +; in: r0 = area number +; r1 = size of change +; stack: r0,r2-r9,r10,lr +; +; out: If not on list, then return to old routine at IsOldArea +; Else perform operation and exit ourselves +; + +CheckForNewArea ROUT + MOV r10, #0 ; check we're not in an IRQ + LDR r10, [r10, #IRQsema] + TEQ r10, #0 + [ NewStyle_All + LDREQ r10, [r10, #CDASemaphore] ; now also check whether ChangeDynamicArea is already threaded + TEQEQ r10, #0 + BNE failure_IRQgoing + MOV r10, #1 + STR r10, [r10, #CDASemaphore-1] ; store non-zero value in CDASemaphore, to indicate we're threaded + | + BNE failure_IRQgoing + ] + + [ DebugCDA2 + DLINE "Entering OS_ChangeDynamicArea (new code)" + ] + + Push "r1" + MOV r1, r0 + [ DebugCDA2 + DREG r1, "Checking list for area number " + ] + BL CheckAreaNumber ; check area number is on list + Pull "r1" + [ NewStyle_All + BCC failure_IRQgoingClearSemaphore + | + BCC IsOldArea ; if not, then use old code + ] + + [ DebugCDA2 + DLINE "Found entry on list" + ] + + MOV r5, #0 + LDR r5, [r5, #Page_Size] ; r5 = page size throughout + SUB r12, r5, #1 ; r12 = page mask + ADD r1, r1, r12 + BICS r1, r1, r12 + BEQ IssueServiceMemoryMoved ; zero pages! (r0 = area number, r1 = size change (0)) + BPL AreaGrow + +AreaShrink + RSB r1, r1, #0 ; make size change positive + [ DebugCDA2 + DREG r0, "Shrinking area ", cc + DREG r1, " by " + ] + MOV r11, r10 ; source is area + CMP r0, #ChangeDyn_FreePool ; if source is free pool + ADREQ r12, AppSpaceDANode ; then dest is appspace + ADRNE r12, FreePoolDANode ; else dest is free pool + + ASSERT DANode_MaxSize = DANode_Size +4 + ADD r2, r12, #DANode_Size + LDMIA r2, {r2, r3} + SUB lr, r3, r2 ; lr = amount dest could grow + + LDR r2, [r11, #DANode_Size] ; amount src could shrink + CMP r2, lr + MOVCC lr, r2 ; lr = min(amount dest could grow, amount src could shrink) + + CMP r1, lr + BLS %FT15 + +; we can't move all that is required, so move smaller amount + + MOV r1, lr ; move smaller amount + BL GenNotAllMovedError + SUB lr, r5, #1 ; lr = pagesize mask + BICS r1, r1, lr ; a pagesize multiple + BEQ IssueServiceMemoryMoved +15 + CMP r11, #AppSpaceDANode ; if src <> appspace + CMPNE r12, #AppSpaceDANode ; and dst <> appspace + BNE %FT17 ; then don't call app + Push "r10" ; save -> to area we tried to shrink + MOV r10, r1 + BL CheckAppSpace + Pull "r10" + BVS ChangeDynError +17 + BL CallPreShrink + BVS ChangeDynError ; (r10 still points to area we tried to shrink) + CMP r2, r1 ; can we move as much as we wanted? + MOVCS r2, r1 ; if not, then move lesser amount (r2 = amount we're moving) + BLCC GenNotAllMovedError ; store error, but continue + + TEQ r2, #0 ; if can't move any pages + BEQ NoMemoryMoved ; then exit, issuing Service_MemoryMoved + +; Now move pages starting from end of area + + LDR r0, [r11, #DANode_Base] + LDR r3, [r11, #DANode_Size] + LDR r6, [r11, #DANode_Flags] ; r6 = src flags + Push "r3, r6" ; save src old size, src flags for later + TST r6, #DynAreaFlags_DoublyMapped ; if src is doubly mapped + MOVNE r9, r3 ; then set up offset from 1st copy to 2nd copy = old src size + ADD r0, r0, r3 ; move r0 to point to after end of area (2nd copy) + SUB r3, r3, r2 + STR r3, [r11, #DANode_Size] ; store reduced source size + + LDR r1, [r12, #DANode_Base] ; this is free pool or app space, so it can't be doubly mapped! + LDR r3, [r12, #DANode_Size] + ADD r1, r1, r3 ; r1 -> address of 1st extra page + + MOV r4, r2 + LDR r6, [r12, #DANode_Flags] ; r6 = dst flags + AND r6, r6, #DynAreaFlags_AccessMask +20 + SUB r0, r0, r5 ; pre-decrement source pointer + [ DebugCDA2 + DREG r0, "Moving page at ", cc + DREG r1, " to ", cc + DREG r6, " with PPL " + ] + BL MovePageAtR0ToR1WithAccessR6 + ADD r1, r1, r5 + SUBS r4, r4, r5 + BNE %BT20 + + ADD r3, r3, r2 + STR r3, [r12, #DANode_Size] ; store increased destination size + EORS lr, r12, #AppSpaceDANode ; check if dest = appspace (if so lr:=0) + STREQ r3, [lr, #MemLimit] ; update memlimit if so + + Pull "r3, r6" ; restore src old size, src flags + TST r6, #DynAreaFlags_DoublyMapped ; if src doubly mapped + SUBNES r4, r3, r2 ; then set r4 = number of pages to shuffle up + BEQ %FT30 ; [not doubly mapped, or no pages left, so skip] + + SUB r0, r0, r3 ; move r0 back to end of 1st copy of pages remaining + ADD r1, r0, r2 ; r1 is end of where they're moving to (should be src base address!) + [ 1 = 1 + | + AND r6, r6, #DynAreaFlags_AccessMask + ] + MOV r9, #0 ; no funny stuff while moving these pages +25 + SUB r0, r0, r5 + SUB r1, r1, r5 + [ 1 = 1 + BL GetPageFlagsForR0IntoR6 + ] + BL MovePageAtR0ToR1WithAccessR6 + SUBS r4, r4, r5 + BNE %BT25 + +30 + BL CallPostShrink + RSB r1, r2, #0 + LDR r0, [r11, #DANode_Number] ; reload dynamic area number + B IssueServiceMemoryMoved + +AreaGrow + [ DebugCDA2 + DREG r0, "Growing area ", cc + DREG r1, " by " + ] + MOV r12, r10 ; dest is area specified + CMP r0, #ChangeDyn_FreePool ; if dest is free pool + ADREQ r11, AppSpaceDANode ; then src is appspace + ADRNE r11, FreePoolDANode ; else src is free pool (may later be free+apl) + + ASSERT DANode_MaxSize = DANode_Size +4 + ADD r2, r12, #DANode_Size + LDMIA r2, {r2, r3} + SUB lr, r3, r2 ; lr = amount dest could grow + + [ DebugCDA2 + DREG lr, "Dest could grow by " + ] + + LDR r2, [r11, #DANode_Size] ; amount src could shrink + CMP r11, #AppSpaceDANode ; if appspace + SUBEQ r2, r2, #&8000 ; then can't take away last 32K (0..&7FFF) + + [ DebugCDA2 + DREG r2, "Src could shrink by " + ] + + CMP r1, lr ; if enough room in dest + CMPLS r1, r2 ; and enough space in src + MOVLS r3, r1 ; then can do full amount + BLS %FT65 ; so skip this bit + +; we can't move all that is required +; +; if src = AplSpace then +; (dest must be free pool) +; move reduced amount +; else +; (src must be free pool) +; (dest <> AplSpace, cos that's a shrink!) +; so check if adding aplspace would allow us to succeed +; if it does then adjust registers, else give error +; endif +; + + [ DebugCDA2 + DLINE "Can't move all required using just free pool" + ] + + CMP r11, #AppSpaceDANode + BNE %FT62 + MOV r1, lr + CMP r1, r2 + MOVHI r1, r2 ; move min(max addable to dest, max removable from src) + + [ DebugCDA2 + DREG r1, "Dest is free pool, moving reduced amount of " + ] + +61 + BL GenNotAllMovedError + SUB lr, r5, #1 ; lr = pagesize mask + BICS r1, r1, lr ; a pagesize multiple + BEQ IssueServiceMemoryMoved + MOV r3, r1 + B %FT65 + +62 + MOV r4, #AppSpaceDANode + LDR r6, [r4, #DANode_Size] ; get current size of apl space + SUB r6, r6, #&8000 ; can't take away 0-&7FFF + ADD r3, r2, r6 ; add on to amount we could remove from free pool + + [ DebugCDA2 + DREG r6, "Can get from app space an additional ", cc + DREG r3, " making a total of " + ] + + CMP r1, lr ; if not enough room in dest + CMPLS r1, r3 ; or src still doesn't have enough + MOVHI r1, #0 ; then don't move any + BHI %BT61 ; and return error + + MOV r3, r1 ; amount actually doing + + TEQ r2, #0 ; else check to see if there was any at all in free pool + MOVEQ r11, #AppSpaceDANode ; if not, then just take from aplspace + MOVEQ r7, r3 ; and do all + + MOVNE r11, #0 ; else make src indicator reflect that we need both + MOVNE r7, r2 ; but save amount we are taking from freepool + +65 + + Push "r10" + MOV r10, #0 ; default value if apl space not involved + CMP r11, #AppSpaceDANode ; if source = aplspace + RSBEQ r10, r3, #0 ; then make amount -ve + CMP r11, #0 ; if source = free and apl + SUBEQ r10, r7, r3 ; then make it -(amount removing from apl space) + MOVNE r7, r3 ; else set up r7 to be total amount (wasn't set up above) + + [ DebugCDA2 + DREG r3, "Amount actually moving into area = " + DREG r7, "Amount coming from 1st src area = " + ] + + CMP r10, #0 ; if neither of the above then don't talk to app (CMP clears V) + BLNE CheckAppSpace ; else check app agrees + Pull "r10" + BVS ChangeDynError + +; now split up grow into bite-size chunks, and call DoTheGrow to do each one + + Push "r3" ; save original total amount + TEQ r11, #0 ; if taking from both free + apl + MOVEQ r11, #FreePoolDANode ; then start with free + [ DAF_SpecifyBit + LDR lr, [r12, #DANode_Flags] ; could this area require particular physical pages at all? + TST lr, #DynAreaFlags_NeedsSpecificPages + BNE %FT70 ; [yes it could, so do it in lumps] + + MOV r1, #0 ; no page block + MOV r2, r3, LSR #12 ; number of pages to do + BL CallPreGrow + LDRVS r3, [sp] ; if error, haven't done any, so restore total as how much to do + BVS %FT95 + + Push "r3, r7" + MOV r2, r7, LSR #12 + BL DoTheGrowNotSpecified + Pull "r3, r7" + SUBS r3, r3, r7 ; subtract off what we just did + + MOVHI r7, r3 ; if not finished, then start 2nd half + MOVHI r11, #AppSpaceDANode ; which is app space + MOVHI r2, r7, LSR #12 + BLHI DoTheGrowNotSpecified + + LDR r3, [sp] ; restore total amount + MOV r1, #0 ; indicate no page block (and ptr to semaphore) + STR r1, [r1, #CDASemaphore] ; OK to reenter now (we've done the damage) + MOV r2, r3, LSR #12 + BL CallPostGrow + BVS %FT95 + B %FT80 + ] + +70 + Push "r3, r7" + CMP r7, #PageBlockChunk ; only do 1 area, so do min(r7,page) + MOVHI r7, #PageBlockChunk + MOV r2, r7, LSR #12 ; number of entries to fill in in page block + BL DoTheGrow + Pull "r3, r7" + BVS %FT95 + CMP r7, #PageBlockChunk ; if 1st area is more than 1 page + SUBHI r3, r3, #PageBlockChunk ; then reduce total + SUBHI r7, r7, #PageBlockChunk ; and partial amounts by 1 page and do it again + BHI %BT70 + + SUBS r3, r3, r7 ; subtract off what we just did + MOVHI r7, r3 ; if not finished, then start 2nd half + MOVHI r11, #AppSpaceDANode ; which is app space + BHI %BT70 ; and loop +80 + Pull "r3" ; restore total amount + + MOV r1, r3 + LDR r0, [r12, #DANode_Number] ; reload dynamic area number + B IssueServiceMemoryMoved + +95 + Pull "r1" ; restore total amount + SUB r1, r1, r3 ; subtract off amount left, to leave done amount + B ChangeDynErrorSomeMoved + +GenNotAllMovedError ENTRY "r0" + ADRL r0, ErrorBlock_ChDynamNotAllMoved + [ International + BL TranslateError + ] + STR r0, [sp, #2*4] ; sp -> r0,lr, then stacked r0,r2-r9,r10,lr + LDR lr, [sp, #12*4] + ORR lr, lr, #V_bit + STR lr, [sp, #12*4] + EXIT + +ChangeDynError + +; in: r0 -> error +; r10 -> area that we tried to shrink/grow + + MOV r1, #0 +ChangeDynErrorSomeMoved + STR r0, [sp] + LDR lr, [sp, #10*4] + ORR lr, lr, #V_bit + STR lr, [sp, #10*4] + B SomeMemoryMoved + +NoMemoryMoved + MOV r1, #0 ; nothing moved +SomeMemoryMoved + LDR r0, [r10, #DANode_Number] ; reload area number + +; and drop thru to... + +IssueServiceMemoryMoved + +; in: r0 = area number that was shrunk/grown +; r1 = amount moved (signed) +; + Push "r1" + MOV r2, r0 ; r2 = area number + MOV r0, r1 ; amount moved (signed) + MOV r1, #Service_MemoryMoved + BL Issue_Service + Pull "r1" ; restore amount moved + TEQ r1, #0 + RSBMI r1, r1, #0 ; r1 on exit = unsigned amount + + [ NewStyle_All + MOV r0, #0 + STR r0, [r0, #CDASemaphore] ; clear CDASemaphore + ] + Pull "r0, r2-r9, r10, lr" + ExitSWIHandler + +; *********************************************************************************** +; +; DoTheGrow - Do one chunk of growing, small enough to fit into the page block on the stack +; +; in: r2 = number of entries to put in page block (for this chunk) +; r5 = page size +; r7 = amount taking from src area (in this chunk) +; (r10 -> dest area) +; r11 -> src area +; r12 -> dest area +; +; out: r0-r2,r4,r6-r9 may be corrupted +; r3,r5,r10-r12 preserved +; +; Note: Removal is from one area only, the calling routine breaks the chunks up at free/app boundary. + +; Temporary (stack frame) workspace used by this routine + + ^ 0, sp +NumEntries # 4 ; Number of entries to do for this chunk +DestAddr # 4 ; Log addr of 1st page being added to dest +DestFlags # 4 ; Page flags for destination area +TotalAmount # 4 ; Total size of grow for this chunk (ie entry value of r3) +SavedPSR # 4 ; PC+PSR before IRQs disabled +Offset1To2 # 4 ; Offset from 1st to 2nd bank + + [ DAF_SpecifyBit +DoTheGrowNotSpecifiedStackSize * :INDEX: @ ; amount of stack needed for 'not specified' version + ] + +PageBlock1 # PageBlockSize ; 1st page block, for original page numbers and phys. addrs +PageBlock2 # PageBlockSize ; 2nd page block, for new page numbers and phys. addrs + +DoTheGrowStackSize * :INDEX: @ + +DoTheGrow ENTRY "r3,r5,r10-r12", DoTheGrowStackSize + +; First fill in the page block with -1 in the physical page number words + + STR r2, NumEntries ; save number of entries for use later + STR r7, TotalAmount ; save amount growing by + + ADR r1, PageBlock1 ; point at 1st page block on stack + ADD lr, r2, r2, LSL #1 ; lr = number of words in page block + ADD lr, r1, lr, LSL #2 ; lr -> off end of page block + MOV r0, #-1 +10 + STR r0, [lr, #-12]! ; store -1, going backwards + STR r0, [lr, #PageBlockSize] ; and put -1 in 2nd page block as well + TEQ lr, r1 ; until the end + BNE %BT10 + +; Now call the pre-grow handler + + MOV r3, r7 + BL CallPreGrow + EXIT VS + +; now check to see if particular pages are required + + LDR lr, [r1] ; load page number in 1st entry + CMP lr, #-1 ; is it -1? + BNE DoTheGrowPagesSpecified ; if not, then jump to special code + +; now move pages starting from end of area + + MOV r2, r3 ; amount moving + LDR r0, [r11, #DANode_Base] + LDR r3, [r11, #DANode_Size] + ADD r0, r0, r3 ; move r0 to point to after end of area + SUB r3, r3, r2 ; reduce by amount moving from area + STR r3, [r11, #DANode_Size] ; store reduced source size + TEQ r11, #AppSpaceDANode ; if just appspace + STREQ r3, [r11, #MemLimit-AppSpaceDANode] ; then store in memlimit + + LDR r1, [r12, #DANode_Base] + LDR r3, [r12, #DANode_Size] + + LDR r6, [r12, #DANode_Flags] ; r6 = dst flags + AND r6, r6, #DynAreaFlags_AccessMask + TST r6, #DynAreaFlags_DoublyMapped ; check if dst is doubly mapped + BEQ %FT25 ; [it's not, so skip all this] + +; we must shunt all existing pages in dest area down + + MOVS r4, r3 ; amount to do + BEQ %FT20 ; [none, so skip all this] + Push "r0, r1" + SUB r0, r1, r3 ; src starts at start of 1st copy = start of 2nd - old size + SUB r1, r0, r2 ; dst start = src start - amount of room needed + MOV r9, #0 ; no funny business while moving these pages +15 + BL MovePageAtR0ToR1WithAccessR6 ; move page + ADD r0, r0, r5 ; advance src ptr + ADD r1, r1, r5 ; advance dst ptr + SUBS r4, r4, r5 ; one less page to move + BNE %BT15 ; loop if more + Pull "r0, r1" ; restore original regs +20 + ADD r9, r3, r2 ; set up offset from 1st copy to 2nd copy (= new size) +25 + ADD r1, r1, r3 ; r1 -> address of 1st extra page + MOV r4, #0 ; amount done so far + MOV r10, r2 ; move amount to do into r10, as routine returns page number in r2 + ADR r3, PageBlock1 ; point at 1st entry we have to update +30 + SUB r0, r0, r5 ; pre-decrement source pointer + [ DebugCDA2 + DREG r0, "Moving page at ", cc + DREG r1, " to ", cc + DREG r6, " with PPL " + ] + BL MovePageAtR0ToR1WithAccessR6ReturnPageNumber + STR r2, [r3], #12 ; store page number and move on + ADD r1, r1, r5 + ADD r4, r4, r5 + CMP r4, r10 ; have we done all of it? + BNE %BT30 ; [no, so loop] +35 + LDR r3, [r12, #DANode_Size] + ADD r3, r3, r10 + STR r3, [r12, #DANode_Size] ; store increased destination size + + MOV r3, r10 ; r3 = size of change + LDR r2, NumEntries ; restore number of entries in page block + ADR r1, PageBlock1 ; point at page block 1 with page numbers filled in + BL CallPostGrow + CLRV + EXIT + +37 + +; Come here if a required page is not available +; First we need to go back thru all the part of the page block we've already done, +; marking the pages as not being used after all + + ADR r2, PageBlock1 +38 + LDR r4, [r1, #-12]! ; r4 = physical page number + ADD r4, r0, r4, LSL #3 ; point at cam entry + LDMIA r4, {r8, lr} + BIC lr, lr, #PageFlags_Required + STMIA r4, {r8, lr} + TEQ r1, r2 + BNE %BT38 + +; since pre-grow handler exited without an error, we have to keep our promise +; to call the post-grow handler + + MOV r3, #0 ; no pages moved + MOV r2, #0 ; no pages moved + ADR r1, PageBlock1 ; not really relevant + BL CallPostGrow + + ADR r0, ErrorBlock_CantGetPhysMem + [ International + BL TranslateError + ] + SETV + EXIT + + MakeErrorBlock CantGetPhysMem + +DoTheGrowPagesSpecified + +; First check if any of the pages requested are unavailable +; At the same time as we're doing this, we fill in the log. and phys. addresses in the block + + MOV r0, #0 + LDR r0, [r0, #CamEntriesPointer] + LDR r6, =L2PT +40 + LDR r3, [r1], #12 ; r4 = physical page number + ADD r4, r0, r3, LSL #3 ; point at cam entry + LDMIA r4, {r8, lr} ; r8 = log. addr, lr = PPL + STR r8, [r1, #4-12] ; store log. addr in page block + STR r8, [r1, #PageBlockSize+4-12] ; and in 2nd page block + + TST lr, #PageFlags_Unavailable :OR: PageFlags_Required ; if page in use by someone else, or by us, then return error + BNE %BT37 + ORR lr, lr, #PageFlags_Required ; set bit in flags to say page will be needed + STR lr, [r4, #4] ; and store back + +; work out physical address direct from physical page number, NOT from logical address, since log addr may be 01F08000 (multiply mapped) + + MOV r4, #PhysRamTable +42 + LDMIA r4!, {r8, lr} ; load phys addr, size + SUBS r3, r3, lr, LSR #12 ; subtract off number of pages in this chunk + BCS %BT42 + + ADD r3, r3, lr, LSR #12 ; put back what could not be subtracted + ADD r8, r8, r3, LSL #12 ; and add onto base address + STR r8, [r1, #8-12] ; store physical address in page block + + SUBS r2, r2, #1 + BNE %BT40 + +; now issue Service_PagesUnsafe + + ADR r2, PageBlock1 ; r2 -> 1st page block + LDR r3, NumEntries ; r3 = number of entries in page block + MOV r1, #Service_PagesUnsafe + BL Issue_Service + +; now move the pages + + LDR r2, TotalAmount ; amount moving + LDR r0, [r11, #DANode_Base] + LDR r3, [r11, #DANode_Size] + ADD r0, r0, r3 ; move r0 to point to after end of area + SUB r3, r3, r2 ; reduce by amount moving from area + STR r3, [r11, #DANode_Size] ; store reduced source size + TEQ r11, #AppSpaceDANode ; if appspace + STREQ r3, [r11, #MemLimit-AppSpaceDANode] ; then update memlimit + + LDR r1, [r12, #DANode_Base] + LDR r3, [r12, #DANode_Size] + + LDR r6, [r12, #DANode_Flags] ; r6 = dst flags + AND r6, r6, #DynAreaFlags_AccessMask + ORR r6, r6, #PageFlags_Unavailable ; set unavailable bit + STR r6, DestFlags ; save for later + TST r6, #DynAreaFlags_DoublyMapped ; check if dst is doubly mapped + BEQ %FT55 ; [it's not, so skip all this, and r9 will be irrelevant] + +; we must shunt all existing pages in dest area down + + MOVS r4, r3 ; amount to do + BEQ %FT50 ; [none, so skip all this] + Push "r0, r1" + SUB r0, r1, r3 ; src starts at start of 1st copy = start of 2nd - old size + SUB r1, r0, r2 ; dst start = src start - amount of room needed + MOV r9, #0 ; no funny business while moving these pages +45 + BL MovePageAtR0ToR1WithAccessR6 ; move page + ADD r0, r0, r5 ; advance src ptr + ADD r1, r1, r5 ; advance dst ptr + SUBS r4, r4, r5 ; one less page to move + BNE %BT45 ; loop if more + Pull "r0, r1" ; restore original regs +50 + ADD r9, r3, r2 ; set up offset from 1st copy to 2nd copy (= new size) +55 + STR r9, Offset1To2 ; store offset 1st to 2nd copy + ADD r1, r1, r3 ; r1 -> address of 1st extra page + STR r1, DestAddr + ADR r8, PageBlock1 ; r8 -> position in 1st page block + SUB r2, r0, r2 ; r2 = lowest address being removed from src + MOV r3, #0 + LDR r3, [r3, #CamEntriesPointer] + MOV r4, r0 ; r4 is where we're at in allocating spare logical addresses + LDR r9, NumEntries ; number of entries still to do in 1st loop + +; Now before we start, we must construct the second page block, with replacement page numbers + +; DLINE "Start of 1st loop" + +60 + LDR r6, [r8], #12 ; r6 = page number required + LDR r10, [r8, #8-12] ; r10 = phys addr + LDR lr, [r3, r6, LSL #3] ; lr = logical address for this page + +; DREG r6, "Checking page ", cc +; DREG lr, "at address " + + CMP lr, r2 ; check if address is one being taken from src anyway + BCC %FT63 + CMP lr, r0 + BCS %FT63 + +; DLINE "Page is being taken away anyway" + B %FT68 ; [page is being taken anyway, so use same page number + phys addr in 2nd block] + +; page is not one being taken away, so put in 1st replacement page that isn't required by area + +63 +; DLINE "Page is not being taken, looking for replacement" + +64 + SUB r4, r4, r5 ; go onto next page being taken from src +; DREG r4, "Considering address " + + LDR lr, =L2PT + LDR lr, [lr, r4, LSR #10] ; get L2PT entry (to get phys addr) for next free page + MOV r10, lr, LSR #12 ; r10 = phys addr >>> 12 + +; now convert phys addr to page number + + MOV r6, #0 + MOV r1, #PhysRamTable +66 + LDMIA r1!, {r7, lr} ; load phys addr, size + SUB r7, r10, r7, LSR #12 ; number of pages into this bank + CMP r7, lr, LSR #12 ; if more than there are here, + ADDCS r6, r6, lr, LSR #12 ; then advance page number by number of pages in this bank + BCS %BT66 ; and go onto next bank + + ADD r6, r6, r7 ; advance page number by no. of pages into this bank + + ADD r1, r3, r6, LSL #3 ; r1 -> cam entry for this page + LDR r1, [r1, #4] ; get PPL for this page + TST r1, #PageFlags_Required ; if this page is required for the operation + BNE %BT64 ; then try next page + + MOV r10, r10, LSL #12 ; make r10 proper phys addr +; DREG r6, "Using page number " +68 + STR r6, [r8, #PageBlockSize-12] ; store page number in 2nd block + STR r10, [r8, #PageBlockSize+8-12] ; and store phys addr + + SUBS r9, r9, #1 ; one less entry to do + BNE %BT60 + + MOV r7, r3 ; r7 -> camentries + +; Now we can go onto the 2nd loop which actually moves the pages + + LDR r1, DestAddr + MOV r4, #0 ; amount done + MOV r0, r7 ; point r0 at camentries + LDR r7, TotalAmount ; amount to do + ADR r8, PageBlock1 + LDR r9, Offset1To2 +70 + STR pc, SavedPSR ; save old PSR (note: stack must be flat when we do this!) + + Push "r0-r4,r7-r12" ; save regs used during copy + MOV r1, #Service_ClaimFIQ + BL Issue_Service + + TEQP pc, #SVC_mode + I_bit ; disable IRQs round here + NOP + + LDR r6, [r8, #0] ; r6 = page number required + LDR lr, [r8, #PageBlockSize+0] ; lr = page number of replacement page + TEQ r6, lr ; if the same + Pull "r0-r4,r7-r12", EQ ; then restore registers + BEQ %FT76 ; and skip copy and first page move + + LDR r0, [r0, lr, LSL #3] ; r0 = log. address for replacement page (NB use logical address to write to, for cache consistency) + LDR r6, [r8, #8] ; r6 = physical address of src for copy + ORR r6, r6, #PhysSpace ; must use physical address, as page may be mapped to 01F08000 along with others + ADD lr, r6, r5 ; lr = end src address +72 + LDMIA r6!, {r2, r3, r4, r7, r9, r10, r11, r12} + STMIA r0!, {r2, r3, r4, r7, r9, r10, r11, r12} + TEQ r6, lr + BNE %BT72 + +; now check if page we're replacing is in L2PT, and if so then adjust L1PT entries (4 of these) + + LDR r6, [r8, #4] ; look at logical address of page being replaced + SUBS r6, r6, #L2PT + BCC %FT74 ; address is below L2PT + CMP r6, #4*1024*1024 + BCS %FT74 ; address is above L2PT + + LDR r2, =L1PT + ADD r2, r2, r6, LSR #(12-4) ; address in L1 of 4 consecutive words to update + LDR r3, [r2] ; load 1st word, to get AP etc bits + MOV r3, r3, LSL #(31-9) ; junk other bits + LDR r4, [r8, #PageBlockSize+8] ; load new physical address for page + ORR r3, r4, r3, LSR #(31-9) ; and merge with AP etc bits + STR r3, [r2], #4 + ADD r3, r3, #&400 + STR r3, [r2], #4 + ADD r3, r3, #&400 + STR r3, [r2], #4 + ADD r3, r3, #&400 + STR r3, [r2], #4 +74 + Pull "r0-r4,r7-r12" ; restore registers + + MOV lr, #0 + LDR lr, [lr, #CamEntriesPointer] ; lr -> soft cam map + ADD lr, lr, #4 ; point at PPLs, not addresses + LDR r2, [r8, #0] ; need to get PPL for page being replaced + LDR r11, [lr, r2, LSL #3] + BIC r11, r11, #PageFlags_Required ; knock off bits that indicate that it was a required page + + ADD lr, r8, #PageBlockSize + LDMIA lr, {r2, r3} ; get page number, logical address + BL Call_CAM_Mapping ; move replacement page in +76 + LDR r2, [r8, #0] + MOV r3, r1 + LDR r11, DestFlags + BL Call_CAM_Mapping ; move needed page to destination + + LDR lr, SavedPSR + TEQP lr, #0 + + Push "r1" + MOV r1, #Service_ReleaseFIQ + BL Issue_Service + Pull "r1" + + ADD r1, r1, r5 ; advance dest ptr + ADD r4, r4, r5 ; increment amount done + ADD r8, r8, #12 ; advance page block ptr + CMP r4, r7 ; have we done all? + BNE %BT70 ; [no, so loop] + + LDR r3, [r12, #DANode_Size] + ADD r3, r3, r7 + STR r3, [r12, #DANode_Size] ; store increased destination size + +; now issue Service_PagesSafe + + LDR r2, NumEntries + ADR r3, PageBlock1 + ADR r4, PageBlock2 + MOV r1, #Service_PagesSafe + BL Issue_Service + +; now call Post_Grow handler + + LDR r3, TotalAmount ; size of grow + LDR r2, NumEntries ; restore number of entries in page block + ADR r1, PageBlock1 ; point at page block 1 with page numbers filled in + BL CallPostGrow + CLRV + EXIT + + [ DAF_SpecifyBit +; *********************************************************************************** +; +; DoTheGrowNotSpecified - Do one chunk of growing, with no page block +; But don't call pre-grow or post-grow either +; +; in: r2 = number of pages to do (in this chunk) +; r5 = page size +; r7 = amount taking from src area (in this chunk) +; (r10 -> dest area) +; r11 -> src area +; r12 -> dest area +; +; out: r0-r2,r4,r6-r9 may be corrupted +; r3,r5,r10-r12 preserved +; +; Note: Removal is from one area only, the calling routine breaks the chunk at free/app boundary. + + +DoTheGrowNotSpecified ENTRY "r3,r5,r10-r12", DoTheGrowNotSpecifiedStackSize + + STR r2, NumEntries ; save number of entries for use later + STR r7, TotalAmount ; save amount growing by + +; now move pages starting from end of area + + MOV r2, r7 ; amount moving + LDR r0, [r11, #DANode_Base] + LDR r3, [r11, #DANode_Size] + ADD r0, r0, r3 ; move r0 to point to after end of area + SUB r3, r3, r2 ; reduce by amount moving from area + STR r3, [r11, #DANode_Size] ; store reduced source size + TEQ r11, #AppSpaceDANode ; if just appspace + STREQ r3, [r11, #MemLimit-AppSpaceDANode] ; then store in memlimit + + LDR r1, [r12, #DANode_Base] + LDR r3, [r12, #DANode_Size] + + LDR r6, [r12, #DANode_Flags] ; r6 = dst flags + AND r6, r6, #DynAreaFlags_AccessMask + TST r6, #DynAreaFlags_DoublyMapped ; check if dst is doubly mapped + BEQ %FT25 ; [it's not, so skip all this] + +; we must shunt all existing pages in dest area down + + MOVS r4, r3 ; amount to do + BEQ %FT20 ; [none, so skip all this] + Push "r0, r1" + SUB r0, r1, r3 ; src starts at start of 1st copy = start of 2nd - old size + SUB r1, r0, r2 ; dst start = src start - amount of room needed + MOV r9, #0 ; no funny business while moving these pages +15 + BL MovePageAtR0ToR1WithAccessR6 ; move page + ADD r0, r0, r5 ; advance src ptr + ADD r1, r1, r5 ; advance dst ptr + SUBS r4, r4, r5 ; one less page to move + BNE %BT15 ; loop if more + Pull "r0, r1" ; restore original regs +20 + ADD r9, r3, r2 ; set up offset from 1st copy to 2nd copy (= new size) +25 + ADD r1, r1, r3 ; r1 -> address of 1st extra page + MOV r4, #0 ; amount done so far + MOV r10, r2 ; move amount to do into r10 +30 + SUB r0, r0, r5 ; pre-decrement source pointer + [ DebugCDA2 + DREG r0, "Moving page at ", cc + DREG r1, " to ", cc + DREG r6, " with PPL " + ] + BL MovePageAtR0ToR1WithAccessR6 + ADD r1, r1, r5 + ADD r4, r4, r5 + CMP r4, r10 ; have we done all of it? + BNE %BT30 ; [no, so loop] +35 + LDR r3, [r12, #DANode_Size] + ADD r3, r3, r10 + STR r3, [r12, #DANode_Size] ; store increased destination size + + CLRV + EXIT + + ] ; DAF_SpecifyBit + +; *********************************************************************************** +; +; CheckAppSpace - If appspace involved in transfer, issue Service or UpCall +; +; Internal routine, called by OS_ChangeDynamicArea +; +; in: r0 = area number passed in to ChangeDyn +; r10 = size of change (signed) +; r11 -> node for src +; r12 -> node for dest +; +; out: If appspace not involved, or application said it was OK, then +; V=0 +; All registers preserved +; else +; V=1 +; r0 -> error +; All other registers preserved +; endif +; + +CheckAppSpace ENTRY "r0-r3" + MOV r2, #0 + LDR r3, [r2, #AplWorkSize] + LDR r2, [r2, #Curr_Active_Object] + CMP r2, r3 ; check if CAO outside application space + BHI %FT20 ; [it is so issue Service not UpCall] + +; CAO in application space, so issue UpCall to check it's OK + + MOV r0, #UpCall_MovingMemory :AND: &FF + ORR r0, r0, #UpCall_MovingMemory :AND: &FFFFFF00 + MOVS r1, r10 + RSBMI r1, r1, #0 ; r1 passed in is always +ve (probably a bug, but should be compat.) + + SWI XOS_UpCall + CMP r0, #UpCall_Claimed ; if upcall claimed + EXIT EQ ; then OK to move memory, so exit (V=0 from CMP) + + ADR r0, ErrorBlock_ChDynamCAO +10 + [ International + BL TranslateError + ] + STR r0, [sp] + SETV + EXIT + +; IF service call claimed Then Error AplWSpaceInUse + +20 + MOV r0, r10 ; amount removing from aplspace + MOV r1, #Service_Memory + BL Issue_Service + CMP r1, #Service_Serviced + ADREQ r0, ErrorBlock_AplWSpaceInUse ; if service claimed, then return error + BEQ %BT10 + CLRV ; else OK + EXIT + + ] + MakeErrorBlock AplWSpaceInUse + MakeErrorBlock ChDynamCAO + [ NewCDA2 + +; *********************************************************************************** +; +; CallPreShrink - Call pre-shrink routine +; +; in: r1 = amount shrinking by (+ve) +; r5 = page size +; r11 -> node for area being shrunk +; +; out: If handler exits VC, then r2 = no. of bytes area can shrink by +; else r0 -> error block or 0 for generic error, and r2=0 +; + +CallPreShrink ENTRY "r0,r3,r4, r12" + LDR r0, [r11, #DANode_Handler] ; check if no handler + CMP r0, #0 ; if none (V=0) + EXIT EQ ; then exit + + MOV r0, #DAHandler_PreShrink ; r0 = reason code + MOV r3, r1 ; r3 = amount shrinking by + LDR r4, [r11, #DANode_Size] ; r4 = current size + ASSERT DANode_Handler = DANode_Workspace +4 + ADD r12, r11, #DANode_Workspace + MOV lr, pc + LDMIA r12, {r12, pc} ; load workspace pointer and jump to handler + +; shrink amount returned by handler may not be page multiple (according to spec), +; so we'd better make it so. + + SUB lr, r5, #1 + BIC r2, r3, lr ; make page multiple and move into r2 + EXIT VC + TEQ r0, #0 ; if generic error returned + ADREQL r0, ErrorBlock_ChDynamNotAllMoved ; then substitute real error message + [ International + BLEQ TranslateError + ] + STR r0, [sp] + SETV + EXIT + +; *********************************************************************************** +; +; CallPostShrink - Call post-shrink routine +; +; in: r2 = amount shrinking by (+ve) +; r5 = page size +; r11 -> node for area being shrunk +; +; out: All registers preserved +; + +CallPostShrink ENTRY "r0,r3,r4, r12" + LDR r0, [r11, #DANode_Handler] ; check if no handler + CMP r0, #0 ; if none (V=0) + EXIT EQ ; then exit + + MOV r0, #DAHandler_PostShrink ; r0 = reason code + MOV r3, r2 ; r3 = amount shrunk by + LDR r4, [r11, #DANode_Size] ; r4 = new size + ASSERT DANode_Handler = DANode_Workspace +4 + ADD r12, r11, #DANode_Workspace + MOV lr, pc + LDMIA r12, {r12, pc} ; load workspace pointer and jump to handler + + EXIT + +; *********************************************************************************** +; +; CallPreGrow - Call pre-grow routine +; +; in: Eventually r1 -> page block (on stack) +; r2 = number of entries in block +; but for now these are both undefined +; r3 = amount area is growing by +; r5 = page size +; r12 -> node for area being grown +; +; out: If can't grow, then +; r0 -> error +; V=1 +; else +; page block may be updated with page numbers (but not yet!) +; All registers preserved +; V=0 +; endif +; + +CallPreGrow ENTRY "r0,r4, r12" + LDR r0, [r12, #DANode_Handler] ; check if no handler + CMP r0, #0 ; if none (V=0) + EXIT EQ ; then exit + + MOV r0, #DAHandler_PreGrow ; r0 = reason code + LDR r4, [r12, #DANode_Size] ; r4 = current size + ASSERT DANode_Handler = DANode_Workspace +4 + ADD r12, r12, #DANode_Workspace + MOV lr, pc + LDMIA r12, {r12, pc} ; load workspace pointer and jump to handler + EXIT VC ; if no error then exit + + TEQ r0, #0 ; if generic error returned + ADREQL r0, ErrorBlock_ChDynamNotAllMoved ; then substitute real error message + [ International + BLEQ TranslateError + ] + STR r0, [sp] + SETV + EXIT + +; *********************************************************************************** +; +; CallPostGrow - Call post-grow routine +; +; in: Eventually, r1 -> page block with actual pages put in +; r2 = number of entries in block +; r3 = size of change +; r5 = page size +; r12 -> node for area being grown +; +; out: All registers preserved +; + +CallPostGrow ENTRY "r0,r3,r4, r12" + LDR r0, [r12, #DANode_Handler] ; check if no handler + CMP r0, #0 ; if none (V=0) + EXIT EQ ; then exit + + MOV r0, #DAHandler_PostGrow ; r0 = reason code + LDR r4, [r12, #DANode_Size] ; r4 = new size + ASSERT DANode_Handler = DANode_Workspace +4 + ADD r12, r12, #DANode_Workspace + MOV lr, pc + LDMIA r12, {r12, pc} ; load workspace pointer and jump to handler + EXIT + +; *********************************************************************************** +; +; MovePageAtR0ToR1WithAccessR6 +; +; Internal routine, called by OS_ChangeDynamicArea +; +; in: r0 = logical address where page is now +; r1 = logical address it should be moved to +; r6 = area flags (which contain access privileges, and cacheable/bufferable bits) +; +; out: All registers preserved +; + +MovePageAtR0ToR1WithAccessR6 ENTRY "r2-r5,r11" + MOV r3, r1 + MOV r11, r6 + BL MoveCAMatR0toR3 ; use old internal routine for now + EXIT + +; Same as above, but returns with r2 = page number of page that moved + +MovePageAtR0ToR1WithAccessR6ReturnPageNumber ENTRY "r3-r5,r11" + MOV r3, r1 + MOV r11, r6 + BL MoveCAMatR0toR3 ; use old internal routine for now + EXIT + +; *********************************************************************************** +; +; DynAreaHandler_SysHeap - Dynamic area handler for system heap +; DynAreaHandler_RMA - Dynamic area handler for RMA +; +; in: r0 = reason code (0=>pre-grow, 1=>post-grow, 2=>pre-shrink, 3=>post-shrink) +; r12 -> base of area +; + +DynAreaHandler_SysHeap +DynAreaHandler_RMA ROUT + CMP r0, #4 + ADDCC pc, pc, r0, LSL #2 + B UnknownHandlerError + B PreGrow_Heap + B PostGrow_Heap + B PreShrink_Heap + B PostShrink_Heap + +PostGrow_Heap +PostShrink_Heap + STR r4, [r12, #:INDEX:hpdend] ; store new size + +; and drop thru to... + +PreGrow_Heap + CLRV ; don't need to do anything here + MOV pc, lr ; so just exit + +PreShrink_Heap + Push "r0, lr" + MOV lr, pc ; save old IRQ status + TEQP pc, #SVC_mode + I_bit ; disable IRQs round this bit + LDR r0, [r12, #:INDEX:hpdbase] ; get minimum size + SUB r0, r4, r0 ; r0 = current-minimum = max shrink + CMP r3, r0 ; if requested shrink > max + MOVHI r3, r0 ; then limit it + SUB r0, r5, #1 ; r0 = page mask + BIC r3, r3, r0 ; round size change down to page multiple + SUB r0, r4, r3 ; area size after shrink + STR r0, [r12, #:INDEX:hpdend] ; update size + + TEQP lr, #0 ; restore IRQ status + CLRV + Pull "r0, pc" + +AreaName_RMA + = "Module area", 0 + ALIGN + + ] + + [ NewCDA +UnknownHandlerError + Push "lr" + ADRL r0, ErrorBlock_UnknownAreaHandler + [ International + BL TranslateError + ] + SETV + Pull "pc" + ] + + [ NewStyle_SpriteArea +DynAreaHandler_Sprites + CMP r0, #4 + ADDCC pc, pc, r0, LSL #2 + B UnknownHandlerError + B PreGrow_Sprite + B PostGrow_Sprite + B PreShrink_Sprite + B PostShrink_Sprite + +PostGrow_Sprite +PostShrink_Sprite ENTRY "r0" + +; in - r3 = size change (+ve), r4 = new size, r5 = page size + + MOV lr, #VduDriverWorkSpace + TEQ r4, #0 ; if new size = 0 + STREQ r4, [lr, #SpAreaStart] ; then set area ptr to zero + STRNE r12, [lr, #SpAreaStart] ; else store base address + + MOV r0, #0 + LDR lr, [r0, #SpriteSize] ; load old size + STR r4, [r0, #SpriteSize] ; and store new size + BEQ %FT10 ; if new size is zero, don't try to update header + + STR r4, [r12, #saEnd] ; store new size in header + TEQ lr, #0 ; if old size was zero + STREQ lr, [r12, #saNumber] ; then initialise header (no. of sprites = 0) + MOVEQ lr, #saExten + STREQ lr, [r12, #saFirst] ; ptr to first sprite -> after header + STREQ lr, [r12, #saFree] ; ptr to first free byte -> after header + +10 + CLRV ; don't need to do anything here + EXIT ; so just exit + +PreGrow_Sprite + CLRV ; don't need to do anything here + MOV pc, lr ; so just exit + +PreShrink_Sprite ENTRY "r0" + TEQ r4, #0 ; if current size is zero + BEQ %FT10 ; then any shrink is OK (shouldn't happen) + + LDR r0, [r12, #saFree] ; get used amount + TEQ r0, #saExten ; if only header used, + MOVEQ r0, #0 ; then none really in use + + SUB r0, r4, r0 ; r0 = current-minimum = max shrink + CMP r3, r0 ; if requested shrink > max + MOVHI r3, r0 ; then limit it + SUB r0, r5, #1 ; r0 = page mask + BIC r3, r3, r0 ; round size change down to page multiple +10 + CLRV + EXIT + +AreaName_SpriteArea + = "System sprites", 0 + ALIGN + + ] + + [ NewStyle_RAMDisc +DynAreaHandler_RAMDisc + CMP r0, #4 + ADDCC pc, pc, r0, LSL #2 + B UnknownHandlerError + B PreGrow_RAMDisc + B PostGrow_RAMDisc + B PreShrink_RAMDisc + B PostShrink_RAMDisc + +PostGrow_RAMDisc +PostShrink_RAMDisc ENTRY "r0-r6" + +; in - r3 = size change (+ve), r4 = new size, r5 = page size +; but we don't really care about any of these + +; The only thing we have to do here is ReInit RAMFS, but NOT if +; a) no modules are initialised yet (eg when we're created), or +; b) RAMFS has been unplugged + + MOV r0, #0 + LDR r0, [r0, #Module_List] + TEQ r0, #0 ; any modules yet? + BEQ %FT90 ; no, then don't do anything + + MOV r0, #ModHandReason_EnumerateROM_Modules + MOV r1, #0 + MOV r2, #-1 ; enumerate ROM modules looking for RAMFS +10 + SWI XOS_Module + BVS %FT50 ; no more modules, so it can't be unplugged + ADR r5, ramfsname +20 + LDRB r6, [r3], #1 ; get char from returned module name + CMP r6, #" " ; if a terminator then we have a match + BLS %FT30 ; so check for unplugged + LowerCase r6, lr ; else force char to lower case + LDRB lr, [r5], #1 ; get char from "ramfs" string + CMP lr, r6 ; and if matches + BEQ %BT20 ; then try next char + B %BT10 ; else try next module + +30 + CMP r4, #-1 ; is module unplugged? + BEQ %FT90 ; if so, then mustn't reinit it +50 + MOV r0, #ModHandReason_ReInit ; reinit module + ADR r1, ramfsname + SWI XOS_Module ; ignore any errors from this +90 + CLRV + EXIT + +PreGrow_RAMDisc +PreShrink_RAMDisc ENTRY "r0-r5" + MOV r0, #0 + LDR r0, [r0, #Module_List] ; first check if any modules going + TEQ r0, #0 + BEQ %FT90 ; if not, don't look at filing system + + MOV r0, #5 + ADR r1, ramcolondollardotstar + SWI XOS_File + CMPVC r0, #0 + BVS %FT90 ; if no RAMFS then change OK + BEQ %FT90 ; or if no files, then change OK + ADR r0, ErrorBlock_RAMFsUnchangeable + [ International + BL TranslateError + ] + STR r0, [sp] + SETV + EXIT + +90 + CLRV + EXIT + + MakeErrorBlock RAMFsUnchangeable + +AreaName_RAMDisc + = "RAM disc", 0 +ramcolondollardotstar + = "ram:$.*", 0 +ramfsname + = "ramfs", 0 + ALIGN + + ] + + [ NewStyle_FontArea +DynAreaHandler_FontArea + CMP r0, #4 + ADDCC pc, pc, r0, LSL #2 + B UnknownHandlerError + B PreGrow_FontArea + B PostGrow_FontArea + B PreShrink_FontArea + B PostShrink_FontArea + +PostGrow_FontArea ENTRY "r0-r2" + +; in - r3 = size change (+ve), r4 = new size, r5 = page size + + MOV r1, #0 + LDR r1, [r1, #Module_List] ; any modules active? + TEQ r1, #0 + MOVNE r1, r4 ; there are, so inform font manager of size change + SWINE XFont_ChangeArea + CLRV + EXIT + +PostShrink_FontArea +PreGrow_FontArea + CLRV ; don't need to do anything here + MOV pc, lr ; so just exit + +PreShrink_FontArea ENTRY "r0-r2" + MOV r1, #-1 ; ask font manager for minimum size of font area + MOV r2, #0 ; default value if no font manager + SWI XFont_ChangeArea ; out: r2 = minimum size + + SUB r0, r4, r2 ; r0 = current-minimum = max shrink + CMP r3, r0 ; if requested shrink > max + MOVHI r3, r0 ; then limit it + SUB r0, r5, #1 ; r0 = page mask + BIC r3, r3, r0 ; round size change down to page multiple + + SUB r1, r4, r3 ; r1 = new size + SWI XFont_ChangeArea ; tell font manager to reduce usage + + CLRV + EXIT + +AreaName_FontArea + = "Font cache", 0 + ALIGN + + ] + +; **** New screen stuff **** +; +; +; This source collects together all the new routines needed to make +; the screen into a new dynamic area. +; +; It has the following dependencies elsewhere in the kernel before +; it can be expected to work: +; +; * Symbol NewStyle_Screen defined TRUE in GetAll +; * Definition of AP_Screen in ChangeDyn needs doubly_mapped and +; name_is_token bits set +; * name_is_token handling needs adding (or scrap the bit designation) +; * Call to CreateNewScreenArea from NewReset to create area +; * Tim says doubly-mapped areas are broken - this must be fixed first +; * Old CDA routine may be retired, since screen is its last client +; * Has Tim completed the rest of this work? +; +; Once these routines work, they should be grafted into appropriate +; places in the kernel sources +; +; This source is not intended for stand-alone assembly: it should be +; plumbed into the kernel source build +; +; Version history - remove this once integrated with kernel sources +; +; Vsn Date Who What +; --- -------- --- ---------------------------------------------- +; 000 23/08/93 amg Written +; 001 24/08/93 amg Fixes and changes following review by TMD +; 002 03/09/93 tmd Updated to work! + +; ********************************************************************* +; Create a new style dynamic area for the screen +; ********************************************************************* + +; Entry requirements +; none + + [ NewStyle_Screen +AreaName_Screen + = "Screen memory",0 ;needs replacing with message token + ALIGN + +; ********************************************************************* +; Handler despatch routine for screen dynamic area +; ********************************************************************* + +DynAreaHandler_Screen ;despatch routine for pre/post grow/shrink handlers + CMP r0, #4 + ADDCC pc, pc, R0, LSL #2 + B UnknownHandlerError ;already defined in ChangeDyn + B PreGrow_Screen ;the rest are defined here + B PostGrow_Screen + B PreShrink_Screen + B PostShrink_Screen + +;The sequence of events which these handlers must do is: +; +;Grow Screen +; +;Pre : Remove cursors +; Work out which physical page numbers are needed and return a list +;CDA : Move existing pages lower in memory within first copy (ie change logical address +; associated with physical pages) +; Locate and free the next physical pages in line (if used a page swap must occur) +; Assign the new pages logical addresses in the gap between the end of the present +; logical range and the start of the second physical range +;Post: Adjust screen memory contents & screen start addresses to retain screen display +; +;Shrink Screen +; +;Pre : Remove cursors +; Adjust screen memory contents & screen start addresses to retain screen display +;CDA : Move pages from screen to free pool (creates a gap in first logical range) +; Close up the gap in logical addressing +;Post: Restore cursors +; + +; *********************************************************************************** +; Handlers for the screen dynamic area +; *********************************************************************************** + +;Pregrow entry parameters +; R0 = 0 (reason code) +; R1 -> page block (entries set to -1) +; R2 = number of entries in page block == number of pages area is growing by +; R3 = number of bytes area is growing by (r2 * pagesize) +; R4 = current size (bytes) +; R5 = page size +; +; exit with V clear, all preserved + +PreGrow_Screen ENTRY "r0-r2,r4" + LDR r0, [WsPtr, #CursorFlags] ; test if VDU inited yet + TEQ r0, #0 ; if not, CursorFlags will be zero + SWINE XOS_RemoveCursors ; if VDU inited, then remove cursors + + ADRL r0, PageShifts-1 + LDRB r0, [r0, r5, LSR #12] ; grab log2Pagesize for shifting + MOV r4, r4, LSR r0 ; change present size into number of pages + ; since page numbers are 0 to n-1 thus n + ; is the first page number we want to insist on +10 + STR r4, [r1], #12 ; store physical page number and increment to next + SUBS r2, r2, #1 ; one less to do + ADDNE r4, r4, #1 ; next physical page number + BNE %BT10 ; continue until all pages done + CLRV ; ok, so I'm paranoid... + EXIT + +; ********************************************************************** + +;PostGrow entry parameters +;R0 = 1 (reason code) +;R1 -> page block (only physical page numbers are meaningful) +;R2 = number of entries in page block (= number of pages area grew by) +;R3 = number of bytes area grew by +;R4 = new size of area (bytes) +;R5 = page size + +PostGrow_Screen ENTRY "r0,r5" + LDR r0, [WsPtr, #CursorFlags] ; test if VDU inited (CursorFlags=0 => not) + TEQ r0, #0 + BEQ %FT90 ; if not inited, do nothing + + MOV r5, pc + TEQP pc, #SVC_mode+I_bit ; disable IRQs + + MOV r0, r3 ; move number of bytes area grew by into r0 + BL InsertPages ; only call InsertPages if VDU inited + + TEQP r5, #0 ; restore IRQ state + SWI XOS_RestoreCursors ; and restore cursors +90 + CLRV + EXIT + +; *********************************************************************** + +;PreShrink Entry parameters +;R0 = 2 (reason code) +;R3 = number of bytes area is shrinking by +;R4 = current size of area (bytes) +;R5 = page size +;R12 = vdu workspace + +PreShrink_Screen ENTRY "R0-R2,R4-R5" + + ;need to check whether the proposed shrink still leaves enough for + ;the current amount needed by the vdu drivers, if it doesn't we + ;reduce R3 to be the most we can spare (in whole pages) + + SUB R2, R5, #1 ;make a page mask + + LDR R5, [R12, #ScreenSize] ;get current minimum size + + SUB R1, R4, R5 ;R1 = maximum shrink (current - screensize) + CMP R3, R1 ;if requested shrink > max... + MOVHI R3, R1 ;...then limit it, and... + BICS R3, R3, R2 ;...round down to multiple of page size + BEQ %FT10 ;don't shuffle screen data if resultant + ;shrink is 0 bytes/0 pages + SWI XOS_RemoveCursors + MOV R5, PC + TEQP PC, #SVC_mode+I_bit ;disable interrupts + RSB R0, R3, #0 ;R0= -(number of bytes) for RemovePages + BL RemovePages ;entry: R0 = -(number of bytes) + TEQP PC, R5 ;restore interrupts +10 + CLRV + EXIT + +; ************************************************************************ + +;PostShrink Entry parameters +;R0 = 3 (reason code) +;R3 = number of bytes area shrank by +;R4 = new size of area (bytes) +;R5 = page size + +PostShrink_Screen ENTRY + SWI XOS_RestoreCursors + CLRV ;ok, so I'm paranoid... + EXIT + +; ************************************************************************ + + ] + + END diff --git a/s/Convrsions b/s/Convrsions new file mode 100644 index 0000000000000000000000000000000000000000..6c009b9a06fdc14b0eed49b136a83037ba2c02f5 --- /dev/null +++ b/s/Convrsions @@ -0,0 +1,394 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + TTL => Convrsions : varicose number->string routines + +despatchConvert ROUT + + MOV r12, #0 ; All conversions want initial cnt = 0 + + CMP R11, #OS_ConvertFixedNetStation + BGE EconetStation + + Push "R1, lr" + SUB R10, R11, #OS_ConvertHex1 + 1 + BIC R10, R10, #3 + ADD PC, PC, R10 + B Hex_Output ; one digit : -4 + B Hex_Output ; 2,3,4,8 digits: 0 + B Cardinal_Output ; 4 + B Signed_Output ; 8 + B Binary_Output ; 12 + B Cardinal_Spaced_Output ; 16 + B Signed_Spaced_Output ; 20 + +Hex_Output ROUT + + SUBS R11, R11, #OS_ConvertHex1 + MOVNE R11, R11, LSL #3 + MOVEQ R11, #4 + MOV R0, R0, ROR R11 + +01 MOV R0, R0, ROR #28 + AND R10, R0, #&F + CMP R10, #10 + ADDGE R10, R10, #"A"-10 + ADDLT R10, R10, #"0" + BL addconvchar + BVS naffconversion + SUBS R11, R11, #4 + BNE %BT01 + +endconversion + MOVVC R10, #0 + BLVC addconvchar + BVS naffconversion + + Pull "R0, lr" + SUB R2, R2, R12 + ADD R2, R2, #1 ; null not really a char. + SUB R1, R1, #1 + ExitSWIHandler + +naffconversion + ADRL R0, ErrorBlock_BuffOverflow +naffconversion_ErrorSet + [ International + BL TranslateError + ] + Pull "R1, lr" + B SLVK_SetV + +Binary_Output ROUT + + SUB R11, R11, #OS_ConvertBinary1-1 + MOV R11, R11, LSL #3 + MOV R0, R0, ROR R11 +01 MOV R0, R0, ROR #31 + AND R10, R0, #1 + ADD R10, R10, #"0" + BL addconvchar + BVS naffconversion + SUBS R11, R11, #1 + BNE %BT01 + B endconversion + + +; cardinal output very similar to BinaryToDecimal + +Cardinal_Output ROUT + + SUB R11, R11, #OS_ConvertCardinal1-1 + MOV R11, R11, LSL #3 + MOV R10, #-1 + MOV R10, R10, LSL R11 + BIC R0, R0, R10 + Push "R3-R5" + ADRL R3, TenTimesTable + MOV R5, #9 ; max entry + MOV R4, #0 ; non-0 had flag +02 LDR R11, [R3, R5, LSL #2] + MOV R10, #"0"-1 ; digit value +03 SUBS R0, R0, R11 + ADD R10, R10, #1 + BCS %BT03 + ADD R0, R0, R11 + CMP R10, #"0" + CMPEQ R4, #0 + BNE %FT04 ; put digit + +05 SUBS R5, R5, #1 + BPL %BT02 ; next digit + CMP R4, #0 + BEQ %FT04 ; R5 must be 0 + Pull "R3-R5" + B endconversion + +04 MOV R4, #-1 + BL addconvchar + BVC %BT05 + Pull "R3-R5" + B naffconversion + + +Signed_Output ROUT + + SUB R11, R11, #OS_ConvertInteger1-1 + MOV R11, R11, LSL #3 + AND R11, R11, #31 + RSB R11, R11, #32 + AND R11, R11, #31 + MOV R0, R0, LSL R11 + MOV R0, R0, ASR R11 + MOV R12, R2 + SWI XOS_BinaryToDecimal + MOVVS r2, r12 + ADDVC R1, R1, R2 + Swap R2, R12, VC + B endconversion + + +Cardinal_Spaced_Output ROUT +Signed_Spaced_Output + + Push "R1, R2" + +; copy our code into the stack (!!) + ADR R1, code_segment + LDMIA R1, {R1, R2, R12} + ADD R2, R2, R11 + Pull "R10, R11" + Push "R1, R2, R12" + + SUB sp, sp, #12 ; get 12 byte buffer + MOV R1, sp + MOV R2, #12 + MOV lr, pc + ADD pc, sp, #12 ; oh for an "execute" instruction! + ; note can't get VSet back from this "SWI" + RSB R0, R2, #12 ; bytes got + MOV R1, R10 + MOV R2, R11 + MOV R12, #0 + MOV R11, sp +01 LDRB R10, [R11], #1 + BL addconvchar + BVS space_conv_exit + SUBS R0, R0, #1 + BEQ space_conv_exit + CMP R10, #"-" + BEQ %BT01 + CMP R0, #3 + CMPNE R0, #6 + CMPNE R0, #9 + BNE %BT01 + MOV R10, #" " + BL addconvchar + BVC %BT01 + +space_conv_exit + ADD sp, sp, #12+12 + B endconversion + +code_segment + Push "lr" + SWI XOS_ConvertCardinal1 - OS_ConvertSpacedCardinal1 + Pull "PC" + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; R1 current buffer pos +; R12 character count, R2 character limit +; R10 character + +addconvchar ROUT + + CMP R2, R12 + ORRLES pc, lr, #V_bit + + ADD R12, R12, #1 + STRB R10, [R1], #1 + BICS pc, lr, #V_bit + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; EcoNet conversions + +EconetStation ROUT + + CMP R11, #OS_ConvertFixedFileSize + BGE FileSizeConversion + + Push "R1, lr" + Push "R0" + LDR R0, [R0, #4] + CMP R0, #256 + BHS invalidnetworknumber + MOV R10, #" " + BL doabyte + BVS %FT01 + CMP R10, #"0" + MOVEQ R10, #"." + CMPNE R11, #OS_ConvertFixedNetStation + BLEQ addconvchar + CMP R10, #"." + MOVEQ R10, #"0" + +01 + Pull "R0" + BVS naffconversion + LDR R0, [R0] + CMP R0, #0 + CMPNE R0, #256 + BHS invalidstationnumber + BL doabyte + B endconversion + +invalidnetworknumber + INC sp, 4 ; Pull "R0" + ADR R0, ErrorBlock_BadNetwork + B naffconversion_ErrorSet + +invalidstationnumber + ADR R0, ErrorBlock_BadStation + B naffconversion_ErrorSet + +ErrorBlock_BadNetwork + DCD ErrorNumber_BadNetwork + DCB "BadNet" ; The token for the Global message + DCB 0 + ALIGN + +ErrorBlock_BadStation + DCD ErrorNumber_BadStation + DCB "BadStn" ; The token for the Global message + DCB 0 + ALIGN + +doabyte ROUT + ; R0 is byte, R11 SWI number (to indicate pad or not) + ; return VS for oflo + Push "lr" + CMP R11, #OS_ConvertNetStation + BEQ %FT03 + CMP R0, #100 + BGE %FT03 + BL addconvchar + Pull "PC", VS +02 CMP R0, #10 + BGE %FT03 + BL addconvchar + Pull "PC", VS +03 CMP R0, #0 + BNE %FT01 + CMP R11, #OS_ConvertNetStation + Pull "PC", EQ + Pull "lr" + B addconvchar + +01 MOV R10, R2 + SUB R2, R2, R12 ; bytes left + SWI XOS_BinaryToDecimal + ADD R12, R12, R2 + ADD R1, R1, R2 + MOV R2, R10 + MOV R10, #"0" + Pull "PC" + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Do length as xxxx bytes or xxxx Kbytes or xxxx Mbytes + +; In r0 = size in bytes +; r1 -> buffer +; r2 = buffer length +; r12 = 0 + +; Out r0 = r1in +; r1 -> terminating zero +; r2 = amount of buffer left + +FileSizeConversion ROUT + + Push "r1, lr" + + Push "r4-r7" + SUB sp, sp, #16 ; May need temp frame + + MOV r4, #0 ; No char by default + CMP r0, #4096 ; Only go to 'K' format if > 4K + MOVCS r4, #"K" ; Kilo + MOVCSS r0, r0, LSR #10 ; /1024 + ADC r0, r0, #0 ; Round up iff divided and bit fell out + CMP r0, #4096 ; Only go to 'M' format if > 4M + MOVCS r4, #"M" ; Mega + MOVCSS r0, r0, LSR #10 ; /1024 again + ADC r0, r0, #0 ; Round up iff divided and bit fell out + +; No need to go to 'G' format as 2^32 = 4096M! + + MOV r5, r0 ; Remember for prettiness + + CMP r11, #OS_ConvertFixedFileSize + BNE %FT50 + + Push "r1, r2" ; Remembering state + ADD r1, sp, #4*2 ; Point to our temp buffer + MOV r2, #16 + SWI XOS_BinaryToDecimal ; This will not give error + MOV r7, r2 ; Number of chars to do + RSBS r6, r2, #4 ; Number of spaces needed + Pull "r1, r2" + BLE %FT39 + +30 MOV r10, #" " + BL addconvchar + BVS %FA95 + SUBS r6, r6, #1 + BNE %BT30 + +39 MOV r6, sp ; Stick string in punter's buffer +40 LDRB r10, [r6], #1 + BL addconvchar + BVS %FA95 + SUBS r7, r7, #1 + BNE %BT40 + + B %FT60 + + +50 MOV r12, r2 ; No padding on LHS, easy case + SWI XOS_BinaryToDecimal + MOVVS r2, r12 + ADDVC r1, r1, r2 + Swap r2, r12, VC + +60 MOVVC r10, #" " + BLVC addconvchar + BVS %FA95 + + MOVS r10, r4 ; Char to print ? VClear + BNE %FT70 + + CMP r11, #OS_ConvertFixedFileSize ; VClear + BNE %FT75 + + MOV r10, #" " ; Need to pad in middle + +70 BL addconvchar + +75 MOVVC r10, #"b" ; 'byte' + BLVC addconvchar + MOVVC r10, #"y" + BLVC addconvchar + MOVVC r10, #"t" + BLVC addconvchar + MOVVC r10, #"e" + BLVC addconvchar + BVS %FA95 + + CMP r5, #1 ; Prettify (unpluralisationism). VClear + MOVNE r10, #"s" + BNE %FT90 + + CMP r11, #OS_ConvertFixedFileSize ; VClear + BNE %FA95 + MOV r10, #" " ; Need to pad to right + +90 BL addconvchar + +95 ADD sp, sp, #16 + Pull "r4-r7" + B endconversion + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + END diff --git a/s/ExtraSWIs b/s/ExtraSWIs new file mode 100644 index 0000000000000000000000000000000000000000..f5d13ac0a23323a956b19a50e53cdbe177f6ae60 --- /dev/null +++ b/s/ExtraSWIs @@ -0,0 +1,81 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > ExtraSWIs + + [ ProcessorVectors + +;---------------------------------------------------------------------------------------- +; ClaimProcVecSWI +; +; In: r0 = vector and flags +; bit meaning +; 0-7 vector number +; 0 = 'Branch through 0' vector +; 1 = Undefined instruction +; 2 = SWI +; 3 = Prefetch abort +; 4 = Data abort +; 5 = Address exception (only on ARM 2 & 3) +; 6 = IRQ +; 7+ = reserved for future use +; 8 0 = release +; 1 = claim +; 9-31 reserved (set to 0) +; r1 = replacement value +; r2 = value which should currently be on vector (only needed for release) +; +; Out: r1 = value which has been replaced (only returned on claim) +; +; Allows a module to attach itself to one of the processor vectors. +; +ClaimProcVecSWI ROUT + ENTRY "r3-r5" + + AND r3, r0, #&FF ; Get vector number. + CMP r3, #(ProcVec_End-ProcVec_Start):SHR:2 + ADRCSL r0, ErrorBlock_BadClaimNum + BCS %FT30 + + MOV r4, r1 ; r4 = replacement value + LDR r5, =ProcVec_Start + PHPSEI ; Disable IRQs while we mess around with vectors. + + TST r0, #1:SHL:8 + LDRNE r1, [r5, r3, LSL #2]! ; If claiming then return current value (r5->vector to replace). + BNE %FT10 + + LDR r3, [r5, r3, LSL #2]! ; Releasing so get current value (r5->vector to replace). + TEQ r2, r3 ; Make sure it's what the caller thinks it is. + ADRNEL r0, ErrorBlock_NaffRelease + BNE %FT20 +10 + STR r4, [r5] ; Store replacement value. + PLP ; Restore IRQs. + PullEnv + ExitSWIHandler + +20 + PLP ; Restore IRQs and return error. +30 + [ International + BL TranslateError + ] + PullEnv + B SLVK_SetV + + ] + + + END diff --git a/s/GetAll b/s/GetAll new file mode 100644 index 0000000000000000000000000000000000000000..998f54d97d089645eac0aaed6b91eb76e6895b32 --- /dev/null +++ b/s/GetAll @@ -0,0 +1,618 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > GetAll + + GET Hdr:ListOpts + GET Hdr:Macros + GET Hdr:System + GET Hdr:Machine.<Machine> + GET Hdr:ImageSize.<ImageSize> + $GetCPU + $GetIO + $GetMEMC + $GetMEMM + $GetVIDC + +; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; now the conditional flags for the version we want +; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +; TMD 29-Apr-93: Fix1 conditioning removed for simplicity of code - always true + + [ {TRUE} + ! 0, "Fix1: interrupts re-enabled in ChangeDynamicArea" + ] + + GBLL Fix2 +Fix2 SETL {TRUE} + [ Fix2 + ! 0, "Fix2: TMD optimisations of heap manager" + ] + + GBLL Fix3 +Fix3 SETL {TRUE} + [ Fix3 + ! 0, "Fix3: ExtendHeap stack balanced" + ] + + GBLL Fix4 +Fix4 SETL {TRUE} + [ Fix4 + ! 0, "Fix4: ExtendBlock IRQ latency improved" + ] + + GBLL Fix5 +Fix5 SETL {TRUE} + [ Fix5 + ! 0, "Fix5: SpriteOp made re-entrant" + ] + + GBLL Fix6 +Fix6 SETL {TRUE} + [ Fix6 + ! 0, "Fix6: OS_Byte &87 restores caller's IRQ state" + ] + + GBLL Fix7 +Fix7 SETL {TRUE} + [ Fix7 + ! 0, "Fix7: OS_Word &0E,0 enables IRQs" + ] + + GBLL Fix8 +Fix8 SETL {TRUE} + [ Fix8 + ! 0, "Fix8: OS_Word &15,0 enables IRQs" + ] + + GBLL Fix9 +Fix9 SETL {TRUE} + [ Fix9 + ! 0, "Fix9: Incarnation names not terminated by 1st character" + ] + + GBLL Fix10 +Fix10 SETL {TRUE} + [ Fix10 + ! 0, "Fix10: *Unplug terminated by address bug fixed" + ] + + GBLL Fix11 +Fix11 SETL {TRUE} + [ Fix11 + ! 0, "Fix11: Podule IRQ despatcher doesn't corrupt R0" + ] + + GBLL Fix12 +Fix12 SETL {TRUE} + [ Fix12 + ! 0, "Fix12: Rename incarnation fixed" + ] + +; TMD 04-Sep-89: Fix bug in prefer incarnation - corrupted error pointer if +; module or incarnation didn't exist + + GBLL Fix13 +Fix13 SETL {TRUE} + [ Fix13 + ! 0, "Fix13: Prefer incarnation fixed" + ] + +; TMD 06-Sep-89: Fix bug in CallAfter/Every - the error pointer was corrupted +; (errors caused by supplying non-positive time interval, or by being unable to +; claim a node from the system heap) + + GBLL Fix14 +Fix14 SETL {TRUE} + [ Fix14 + ! 0, "Fix14: CallAfter/Every error pointer not corrupted" + ] + +; TMD 11-Sep-89: Fix bug in AddCallBack - freed wrong heap node when chaining +; down the vector + + GBLL Fix15 +Fix15 SETL {TRUE} + [ Fix15 + ! 0, "Fix15: AddCallBack frees correct heap node" + ] + +; TMD 25-Sep-89: Fix bug in GSRead quoted termination - started skipping spaces +; from the wrong character, and didn't adjust for post increment after loading +; first non-space. + + GBLL Fix16 +Fix16 SETL {TRUE} + [ Fix16 + ! 0, "Fix16: GSRead quoted termination fixed" + ] + +; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; essential global variables +; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + GET Version + GBLS VersionNo +VersionNo SETS "$VString ($Date)" + + GBLS SystemName +SystemName SETS "RISC OS" ; ", p.k.a. Arthur a.k.a. Richard III" + + GBLS MosTitle +MosTitle SETS "$SystemName $VersionNo" + + GBLL AddTubeBashers +AddTubeBashers SETL {FALSE} + +Tube_Normal * 1 +Tube_Simulator * 2 + + GBLA TubeType +TubeType SETA Tube_Simulator + +UserMemStart * &8000 + + GBLL ExceptionsAreErrors +ExceptionsAreErrors SETL 1=1 + +AssemblingArthur SETL {TRUE} +; defined in hdr.system to allow conditionals in macros + + GBLL DoingVdu +DoingVdu SETL {FALSE} ; so can get KeyWS! + GBLL Module +Module SETL {FALSE} + + GBLL IncludeTestSrc ; whether test code is included + [ MorrisSupport +IncludeTestSrc SETL {TRUE} + | +IncludeTestSrc SETL :LNOT: (MEMM_Type = "MEMC2") ; not on internal test versions + ] + + GBLL NormalSpeedROMS +NormalSpeedROMS SETL {TRUE} ;use FALSE for slow EPROMS + + GBLL RISCPCBurstMode +RISCPCBurstMode SETL {FALSE} +;>>>RCM says if the FRM approves the use of burst mode ROMS for +;>>>RISC PC (no reason why it shouldn't) all references to RISCPCBurstMode +;>>>could be replaced by NormalSpeedROMS + + GBLL Select16BitSound +Select16BitSound SETL {TRUE} + + GBLL Simulator ; running on simulator? +Simulator SETL {FALSE} + + GBLL ChopOffTheGoolies +ChopOffTheGoolies SETL {FALSE} + + GBLL ChecksumCMOS +ChecksumCMOS SETL {TRUE} + + GBLL ResetIndirected ; new flag to say if instruction at start of ROM does LDR PC, [PC, #x] +ResetIndirected SETL {TRUE} + + GBLL SqueezeMods ; whether squeezed modules are allowed +SqueezeMods SETL {TRUE} + + GBLL DriversInKernel ; whether serial/parallel drivers are in the kernel +DriversInKernel SETL {FALSE} + + GBLL International ; whether text and error messages come from messaeges file. +International SETL {TRUE} + + GBLL MouseBufferManager ; Whether mouse uses buffer manager +MouseBufferManager SETL {TRUE} + + GBLL IrqsInClaimRelease ; Whether OS_Claim/Release restore IRQ's before releasing heap node +IrqsInClaimRelease SETL {TRUE} + + GBLL TickIrqReenter ; Whether TickEventChain processing re-enables IRQ's +TickIrqReenter SETL {TRUE} + + GBLL SoftResets ; If false, always force a hard reset +SoftResets SETL {FALSE} + + GBLL AlwaysClearRAM ; If true, clear RAM on every break/reset +AlwaysClearRAM SETL {TRUE} + + GBLL CacheCMOSRAM ; Whether to keep a RAM copy of CMOS RAM for faster access +CacheCMOSRAM SETL MEMM_Type = "ARM600" ; (Space only allocated on ARM600 versions) + + GBLL GammaCorrection +GammaCorrection SETL (VIDC_Type = "VIDC20") :LAND: {TRUE} + + GBLL VIDCListType3 +VIDCListType3 SETL (VIDC_Type = "VIDC20") :LAND: {TRUE} + + GBLL ExpandedCamMap ; two words per entry instead of one +ExpandedCamMap SETL MEMM_Type = "ARM600" ; NB ARM600 code assumes expanded map + + GBLL UseFreePool ; whether OS_ChangeDynamicArea puts and gets memory to and from free pool +UseFreePool SETL MEMM_Type = "ARM600" :LAND: {TRUE} + + GBLL NewCDA ; new change dynamic area code +NewCDA SETL MEMM_Type = "ARM600" :LAND: {TRUE} ; let's give it a try! + + GBLL ModeSelectors ; whether mode selectors are understood +ModeSelectors SETL (VIDC_Type = "VIDC20") :LAND: {TRUE} + + GBLL MakeModeSelectorsForModeNumbers +MakeModeSelectorsForModeNumbers SETL ModeSelectors :LAND: {FALSE} ; not actually needed after all + + GBLL IgnoreVRAM ; if true, don't add VRAM to the RAM list (+ don't use for screen) +IgnoreVRAM SETL {FALSE} + + GBLL LateAborts ; if true, use late abort mode on ARM600 (compulsory on ARM700) +LateAborts SETL MEMM_Type = "ARM600" :LAND: {TRUE} + + GBLL CheckProtectionLink ; if true, disallow CMOS RAM changes if link in protected position +CheckProtectionLink SETL (IO_Type = "IOMD") :LAND: {TRUE} ; NB affects Delete/Copy/R/T and 0-9/. + + GBLL RMTidyDoesNowt ; if true, RMTidy does nothing +RMTidyDoesNowt SETL (MEMC_Type = "IOMD") :LAND: {TRUE} ; should really be "machine has FSLock in ROM" + + GBLL RogerEXEY ; if true, use Roger's new algorithm for XEigFactor, YEigFactor +RogerEXEY SETL {FALSE} ; Marketing don't like it! + + GBLL DAF_SpecifyBit ; enable use of dynamic area flag which says an area may need specific pages +DAF_SpecifyBit SETL {TRUE} + + GBLL DebugROMInit +DebugROMInit SETL (MEMC_Type = "IOMD") :LAND: {FALSE} + + GBLL DebugROMErrors +DebugROMErrors SETL (MEMC_Type = "IOMD") :LAND: {FALSE} + + GBLL DebugHeaps ; initialise claimed and freed blocks +DebugHeaps SETL {FALSE} ; (may slow things down unacceptably) + +; ChangeDynamicArea and related options + + GBLL DebugCDA +DebugCDA SETL {FALSE} + + GBLL DebugCDA2 +DebugCDA2 SETL {FALSE} + + GBLL NewCDA2 ; whether all the new CDA code is in there +NewCDA2 SETL NewCDA :LAND: {TRUE} + + GBLL NewStyle_RMA ; whether RMA is a new style area +NewStyle_RMA SETL NewCDA :LAND: {TRUE} + + GBLL NewStyle_SpriteArea ; whether sprite area is a new style area +NewStyle_SpriteArea SETL NewCDA :LAND: {TRUE} + + GBLL NewStyle_RAMDisc ; whether RAM disc is a new style area +NewStyle_RAMDisc SETL NewCDA :LAND: {TRUE} + + GBLL NewStyle_FontArea ; whether font cache is a new style area +NewStyle_FontArea SETL NewCDA :LAND: {TRUE} + + GBLL NewStyle_SysHeap ; whether system heap is a new style area (node faked up) +NewStyle_SysHeap SETL NewCDA :LAND: {TRUE} + + GBLL NewStyle_Screen ; whether screen is a new style area +NewStyle_Screen SETL NewCDA :LAND: {TRUE} + + GBLL NewStyle_All ; whether all old-style areas have been converted to new-style +NewStyle_All SETL NewStyle_RMA :LAND: NewStyle_SpriteArea :LAND: NewStyle_RAMDisc :LAND: NewStyle_FontArea :LAND: NewStyle_SysHeap :LAND: NewStyle_Screen + + GBLL StorkPowerSave ;True => power saving for Stork AND A4 +StorkPowerSave SETL MorrisSupport ;False=> older A4 code only + + GBLL FixR9CorruptionInExtensionSWI ; whether R9 corruption by ExtensionSWI handler is fixed +FixR9CorruptionInExtensionSWI SETL {FALSE} ; currently FALSE as CC's !SpellMod (possibly others) rely on it being broken + + + [ DebugHeaps + ! 0, "*** WARNING *** Heap debugging assembled in" + ] + + GBLS GetMessages + [ International +GetMessages SETS "GET s.MsgCode" + | +GetMessages SETS "" + ] + + GBLL DebugForcedReset ; debug forced hard resets +DebugForcedReset SETL {FALSE} + + GBLA ConfiguredLang +ConfiguredLang SETA 10 ; default configured language + + GBLA FirstUnpluggableModule +FirstUnpluggableModule SETA 8 ; Podule, FileSwitch, ResourceFS, Messages, MessageTrans, + ; TerritoryManager, UKTerritory + + [ DebugForcedReset +Reset_CannotResetFlag * 1 +Reset_SysHeapCorrupt * 2 +Reset_WrongCamMapAddress * 3 +Reset_WrongNumberOfPages * 4 +Reset_CamMapCorrupt * 5 +Reset_VectorChainCorrupt * 6 +Reset_TickNodesCorrupt * 7 +Reset_DeviceVectorCorrupt * 8 +Reset_PoduleOrCallBackCorrupt * 9 + ] + +; Flags for RISC OS Blue changes +; + GBLL AssembleA1KeyHandler +AssembleA1KeyHandler SETL {FALSE} + GBLL AssembleKEYV +AssembleKEYV SETL {TRUE} ; Use KEYV. + GBLL AssemblePointerV +AssemblePointerV SETL {TRUE} ; Use PointerV. + GBLL PollMouse +PollMouse SETL {FALSE} ; Poll mouse. + + GBLL ProcessorVectors +ProcessorVectors SETL {TRUE} ; Processor vectors indirected through 0 page. + + GBLS GetUnsqueeze + [ SqueezeMods +GetUnsqueeze SETS "GET s.Unsqueeze" + | +GetUnsqueeze SETS "" + ] + GBLS GetPublicWS + GBLS GetWorkspace + GBLS GetKernelMEMC + GBLS GetPalette + GBLS GetMemInfo + [ MEMM_Type = "ARM600" +GetPublicWS SETS "GET Hdr:PublicWS" +GetWorkspace SETS "GET Hdr:KernelWS" +GetKernelMEMC SETS "GET s.ARM600" +GetMemInfo SETS "GET s.MemInfo" + | +GetPublicWS SETS "" +GetWorkspace SETS "GET Hdr:Old.NewSpace" + [ MEMM_Type = "MEMC2" +GetKernelMEMC SETS "GET s.MEMC2" + | +GetKernelMEMC SETS "GET s.MEMC1" + ] +GetMemInfo SETS "" + ] + + [ VIDC_Type = "VIDC20" +GetPalette SETS "GET s.Vdu.VduPal20" + | +GetPalette SETS "GET s.Vdu.VduPal10" + ] + + + GBLS GetRS423 + [ DriversInKernel +GetRS423 SETS "GET s.PMF.rs423" + | +GetRS423 SETS "" + ] + + GBLS GetKbdDrA1 + [ Keyboard_Type = "A1A500" +GetKbdDrA1 SETS "GET s.PMF.KbdDrA1" + | +GetKbdDrA1 SETS "" + ] + + GBLS GetKbdRes + [ Keyboard_Type = "PC" +GetKbdRes SETS "GET s.KbdResPC" + | +GetKbdRes SETS "GET s.KbdResA1" + ] + + GBLS GetKey2 + [ AssembleA1KeyHandler +GetKey2 SETS "GET s.PMF.Key2" + | +GetKey2 SETS "" + ] + +; control switches for med_00001 (the flood fill routines 1024 line limit). +; Switches have the following effects: +; +; _userma Will use rma if >48K is free, up to a maximum of 128K. It will +; try to acheive the latter by growing the rma if possible. +; _twowords Use two word entries in the queue. This overcomes the limitation +; of the original packed word format. +; _debug Store the queue start, end and 'amount to change the rma dynamic +; area by' in the first three words of OldIRQ1VSpace + + GBLL med_00001_userma + GBLL med_00001_twowords + GBLL med_00001_debug + +med_00001_userma SETL {TRUE} +med_00001_twowords SETL {TRUE} +;med_00001_debug SETL {TRUE} + +;med_00001_userma SETL {FALSE} +;med_00001_twowords SETL {FALSE} +med_00001_debug SETL {FALSE} + + [ med_00001_userma +smallest_rma_size * (48*1024) ; define the low threshold for rma use +largest_rma_size * (128*1024) ; and the ceiling for rma use + ] + + [ med_00001_debug + ! 0,"" + ! 0,",-----------------------------------------------------------------," + ! 0,"| **** WARNING **** |" + ! 0,"| |" + ! 0,"| Audit trail debugging for MED-00001 is enabled. This reuses the |" + ! 0,"| first three words of OldIRQ1Vspace. This should be turned off |" + ! 0,"| once MED-00001 has been tested and marked 'fixed'. |" + ! 0,"| |" + ! 0,"| Usage: |" + ! 0,"| +0 start of area used by flood fill |" + ! 0,"| +4 end+1 of area used by flood fill |" + ! 0,"| +8 amount the rma was grown by |" + ! 0,"'-----------------------------------------------------------------'" + ! 0,"" + ] + +; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; now get the headers +; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + GET Hdr:CMOS + GET Hdr:Heap + $GetPublicWS + $GetWorkspace + GET Hdr:Services + GET Hdr:FSNumbers + GET Hdr:HighFSI + GET Hdr:NewErrors + GET Hdr:Proc + GET Hdr:Sprite + GET Hdr:KeyWS + GET Hdr:RS423 + GET Hdr:ModHand + GET Hdr:Variables + GET Hdr:EnvNumbers + GET Hdr:UpCall + GET Hdr:Sound + GET Hdr:Pointer + GET Hdr:Podule + GET Hdr:VduExt +; GET Hdr:Fox + GET Hdr:Buffer + GET Hdr:Font + GET Hdr:DevNos +; GET Hdr:IOEB + GET Hdr:Territory + GET Hdr:Portable + GET Hdr:MsgTrans + GET Hdr:PaletteV + GET Hdr:Wimp + GET Hdr:ColourTran + GET Hdr:Debug + GET s.PMF.DEF ; Common with 6502 code in the keyboard + Protocol + +; now the main parts of the MOS + + GET s.Kernel + GET s.NewIRQs + GET s.Oscli + GET s.SysComms + GET s.HeapMan + GET s.ModHand + $GetUnsqueeze + GET s.ArthurSWIs + GET s.ChangeDyn + GET s.Arthur2 + GET s.Utility + GET s.MoreComms + GET s.Convrsions + GET s.MoreSWIs + GET s.ExtraSWIs + GET s.HeapSort + GET s.Arthur3 + GET s.SWINaming + GET s.TickEvents + $GetKbdRes + GET s.NewReset + $GetMessages + GET s.Middle + GET s.Super1 + $GetKernelMEMC + $GetMemInfo + ! 0, "Main kernel size = &" :CC: :STR: (.-ROM) +StartOfVduDriver + GET s.vdu.VduDriver + GET s.vdu.VduSWIs + GET s.vdu.VduPalette + $GetPalette + GET s.vdu.VduPlot + GET s.vdu.VduGrafA + GET s.vdu.VduGrafB + GET s.vdu.VduGrafC + GET s.vdu.VduGrafD + GET s.vdu.VduGrafE + GET s.vdu.VduGrafF + GET s.vdu.VduGrafG + GET s.vdu.VduGrafH + GET s.vdu.VduGrafI + GET s.vdu.VduGrafJ + GET s.vdu.VduGrafK + GET s.vdu.VduGrafL + GET s.vdu.VduWrch + GET s.vdu.Vdu23 + GET s.vdu.VduPointer + GET s.vdu.Vdu5 + GET s.vdu.VduCurSoft + GET s.vdu.VduTTX + + GBLS GiveMeBfontAnyDay + [ BleedinDaveBell +GiveMeBfontAnyDay SETS "GET s.vdu.VduFontL1" + | +GiveMeBfontAnyDay SETS "GET s.vdu.VduFont" + ] + + $GiveMeBfontAnyDay + + ! 0, "Vdu drivers size = &" :CC: :STR: (.-StartOfVduDriver) + +StartOfPMF + GET s.PMF.osinit + GET s.PMF.oseven + GET s.PMF.osbyte + GET s.PMF.osword + GET s.PMF.realtime + GET s.PMF.convdate + $GetRS423 + GET s.PMF.i2cutils + GET s.PMF.oswrch + GET s.PMF.buffer + $GetKbdDrA1 + GET s.PMF.key + $GetKey2 + GET s.PMF.mouse + ALIGN +EndOfKernel + & 0 ; for patching by BigSplit et al + + ! 0, "PMF section size = &" :CC: :STR: (.-StartOfPMF) + + [ med_00001_debug + ! 0,"" + ! 0,",-----------------------------------------------------------------," + ! 0,"| **** WARNING **** |" + ! 0,"| |" + ! 0,"| Audit trail debugging for MED-00001 is enabled. This reuses the |" + ! 0,"| first three words of OldIRQ1Vspace. This should be turned off |" + ! 0,"| once MED-00001 has been tested and marked 'fixed'. |" + ! 0,"| |" + ! 0,"| Usage: |" + ! 0,"| +0 start of area used by flood fill |" + ! 0,"| +4 end+1 of area used by flood fill |" + ! 0,"| +8 amount the rma was grown by |" + ! 0,"'-----------------------------------------------------------------'" + ! 0,"" + ] + + END diff --git a/s/HeapMan b/s/HeapMan new file mode 100644 index 0000000000000000000000000000000000000000..08065f3ca64db371e071cf230fb4f352ffa4c751 --- /dev/null +++ b/s/HeapMan @@ -0,0 +1,1914 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + TTL => HeapMan : Heap Allocation SWI + +; Interruptible heap SWI. + +; Look down the IRQ stack to see if anybody was in a heap operation. +; If they were, then (with IRQs off) the foreground call is done first, by +; picking up info from a fixed block. Patch the IRQ stack so that the heap SWI +; is returned to at a "it happened in the background" fixup routine. Current +; request can then be dealt with! Ta Nick. + +; Also has an interlock on the register restore area; otherwise anybody +; with an IRQ process doing heap ops with interrupts enabled will cause +; trouble. + + GBLS HeapBadAsModuleBRA + GBLS HeapBadAsModuleKET +HeapBadAsModuleBRA SETS "[ {FALSE}" ; "" for modular testing version +HeapBadAsModuleKET SETS "]" ; "" for modular testing version + + GBLS RecursiveHeap +RecursiveHeap SETS "XOS_Heap" + + MACRO +$l jeep $r,$var + [ Module +$l ADR $r, $var + | +$l LDR $r, =$var + ] + MEND + + GBLL TubeInfo +TubeInfo SETL {FALSE} + + $HeapBadAsModuleBRA + + GET Hdr:Listopts + GET Hdr:Macros + GET Hdr:System + GET Hdr:ModHand + GET Hdr:Debug + GET Hdr:Heap + GET Hdr:NewErrors + +BranchToSWIExit * 0 +IRQsema * &108 + +; debug macro: set the border colour + + MACRO +$l SetBorder $reg1, $reg2, $red, $green, $blue + ! 0, "Setborder used" +$l LDR $reg1, =VIDC + LDR $reg2, =&40000000+ $red + $green *16 + $blue *256 + STR $reg2, [$reg1] + MEND + + MACRO + assert $condition + [ :LNOT: ($condition) + ! 1,"Assert failed: $condition" + ] + MEND + + GBLL Module +Module SETL {TRUE} + + LEADR Module_LoadAddr + +HeapTestModule ROUT + & 0 + & 0 + & 0 + & 0 + & Title-HeapTestModule + & Title-HeapTestModule + & 0 + & 1024 + +RecursiveHeap SETS "1024 + (1:SHL:17)" + + & HeapEntry-HeapTestModule + +Title = "HeapTestModule",0 + + $HeapBadAsModuleKET + + GBLL debheap +debheap SETL 1=0 + + [ DebugHeaps +FreeSpaceDebugMask * &04000000 +UsedSpaceDebugMask * &08000000 + ] + +Nil * 0 +TTMMask * 32*1024*1024 ; thirty-two meg mask + +hpd RN r1 ; The punter sees these +addr RN r2 +size RN r3 + +HpTemp RN r10 ; But not these +tp RN r11 +bp RN r12 +work RN r4 ; This is the only one we have to save. + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; + H E A P O R G A N I S A T I O N + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; A heap block descriptor (hpd) has the form + +; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -+ -+ -+ -+ +; | magic | free | base | end | debug | +; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+- +- +- +- + +; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 + + ^ 0, hpd +hpdmagic # 4 +hpdfree # 4 +hpdbase # 4 +hpdend # 4 ; Needed for debugging heap, and top end validation + [ debheap +hpddebug # 4 ; 0 -> No debug, ~0 -> Debug + ] + +hpdsize * @-hpdmagic + +magic_heap_descriptor * (((((("p":SHL:8)+"a"):SHL:8)+"e"):SHL:8)+"H") + +; hpdmagic is a unique identification field +; hpdfree is the offset of the first block in the free space list +; hpdbase is the offset of the byte above the last one used +; hpdend is the offset of the byte above the last one usable + +; | hpdbase +; \|/ +; +---+--------------------+--------+ +; low |hpd| heap blocks | unused | high +; +---+--------------------+---------+ +; /|\ /|\ +; | hpdfree | hpdend +; | in here somewhere. + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Blocks in the free space list have the form : + +; +--+--+--+--+--+--+--+--+--+ ~ -+--+ +; | long link | long size | | +; +--+--+--+--+--+--+--+--+--+ ~ -+--+ +; 0 1 2 3 4 5 6 7 8 (size-1) +; +; where the link field is an offset to the next free block + + ^ 0 ; Can't use register relative unfortunately as many regs used +frelink # 4 +fresize # 4 +freblksize # 0 + +; The link field is Nil (0) for the last block in the list + +; Block sizes must be forced to a multiple of 8 bytes for subsequent link and +; size information to be stored in them if they are disposed of by the user. + +; They must also be capable of storing a 4 byte size field while allocated. +; This field is used to size the block to free when FreeArea is called. + + + ALIGN + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; The Macros +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Check hpd valid + + MACRO +$label ValidateHpd $faildest +$label BL ValidateHpdSubr + BNE $faildest._badhpd + MEND + +; check pointer sensible. Exit EQ if OK +; valid RAM checks done elsewhere + + MACRO +$label CheckPtr $reg,$cond,$xtrabits +$label TST$cond $reg, #ARM_CC_Mask + [ "$xtrabits" = "" + TSTEQ $reg, #TTMMask ; check < 32M + | + TSTEQ $reg, #TTMMask + $xtrabits ; check < 32M, with other bits. + ] + MEND + + $HeapBadAsModuleBRA + + [ TubeInfo +DebugTUBE * &03340000+1*&4000 ; tube in podule #1 +; Tube register offsets + ^ 0 +R1STAT # 4 +R1DATA # 4 + ] + +; routine to stuff a char down the Tube + MACRO +$l TubeChar $reg1, $reg2, $chworkt, $stackthere + ! 0, "TubeChar used." +$l + [ "$stackthere"="" + Push "$reg1, $reg2" + ] + LDR $reg1, =DebugTUBE +01 LDRB $reg2, [$reg1, #R1STAT] + TST $reg2, #&40 + BEQ %BT01 + $chworkt + STRB $reg2, [$reg1, #R1DATA] + [ "$stackthere"="" + Pull "$reg1, $reg2" + ] + MEND + + $HeapBadAsModuleKET + +;**************************************************************************** + +; These bits of ExtendBlock are outside the IRQ HeapOp range because they +; don't update the heap structure, so we can safely restore old IRQ status + + [ Fix4 +CopyBackwardsInSafeZone + LDR work, [stack, #3*4] ; get user link + ANDS work, work, #I_bit ; look at I_bit + TEQEQP PC, #SVC_mode ; if was clear then clear it now + + ADD bp, bp, #4 ; new block pointer + STR bp, [stack] ; return to user + +; copy wackbords: HpTemp-4 bytes from addr+4 to bp, in appropriate order! +cpe_prev + SUBS HpTemp, HpTemp, #4 + LDRGT work, [addr, #4]! + STRGT work, [bp], #4 + BGT cpe_prev + + TEQP PC, #SVC_mode + I_bit ; disable IRQs before we venture back + B GoodExtension ; into danger zone + +ReallocateInSafeZone + LDR work, [addr, hpd]! ; get block size, set block addr + ADD size, size, work + SUB size, size, #4 ; block size to claim + ADD addr, addr, #4 + MOV bp, addr ; address to copy from + Push addr ; save for later freeing + + MOV R0, #HeapReason_Get + SWI $RecursiveHeap + Pull addr, VS + BVS SafeNaffExtension + + [ debheap + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT06 + DREG work, "got new block : copying " +06 + ] + + STR addr, [stack, #4] + +; claimed : copy work-4 bytes from bp to addr +CopyForExtension + SUBS work, work, #4 + LDRGT HpTemp, [bp],#4 + STRGT HpTemp, [addr],#4 + BGT CopyForExtension + +; free the old block! + + [ debheap + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT08 + WRLN "freeing old block" +08 + ] + +; recursive SWI to free old block; we have invalidated any held information + + MOV R0, #HeapReason_Free + Pull addr ; heap block addr + SWI $RecursiveHeap + + MOV R0, #HeapReason_ExtendBlock + TEQP PC, #SVC_mode + I_bit ; disable IRQs before we venture back + B GoodExtension ; into danger zone + +SafeNaffExtension + TEQP PC, #SVC_mode + I_bit ; disable IRQs before we venture back + B NaffExtension ; into danger zone + + ] + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Here's the bit that gets returned to if the heap op was done in the +; background. Pick up the registers, look at the saved PC to see if error +; return or OK. +; This bit musn't be in range of the IRQ Heap Op checking!!! +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +heapopdoneinbackground ROUT + $HeapBadAsModuleBRA + SetBorder R10, R11, 0, 0, 10 ; blue for returning + $HeapBadAsModuleKET + jeep R12, HeapReturnedReg_R0 + + [ TubeInfo + LDR R0, [R12] + BL TubeDumpR0 + LDR R0, [R12, #4] + BL TubeDumpR0 + LDR R0, [R12, #8] + BL TubeDumpR0 + LDR R0, [R12, #24] + TST R0, #V_bit + MOVEQ R0, #"v" + MOVNE R0, #"V" + TubeChar R1, R2, "MOV R2, r0" + TubeChar R0, R1, "MOV R1, #10" + TubeChar R0, R1, "MOV R1, #13" + ] + + LDMIA R12, {R0-R4, R10, R11} + MOV stack, R10 + MOV R10, #0 + STR R10, [R12, #HeapReturnedReg_PC-HeapReturnedReg_R0] + ; clear the interlock + TST R11, #V_bit ; look at returned error + BEQ GoodHeapExit + B NaffHeapExit + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; HeapEntry. SWI level entry +; ========= +; +; Perform actions on the heap block described by r1(hpd) + +; In r0 = heap action requested +; r1(hpd) -> heap block +; r2(addr) -> start of block +; r3(size) = size of block + +; Out VClear -> Action performed +; VSet -> Something terrible has happened, error set +; Rest of universe ok + +HeapEntry ROUT + Push lr + MOV lr, PC ; hang on to interrupt state + + ; First check that we aren't in an interrupted Heap Op + TEQP PC, #SVC_mode+I_bit + MOV R11, #IRQsema +inspect_IRQ_stack + LDR R11, [R11] + CMP R11, #0 + BEQ iis_end + LDR R10, [R11, #4*7] + BIC R10, R10, #ARM_CC_Mask + ADR R12, first_heap_address_to_trap + CMP R10, R12 + ADRGEL R12, HeapCode_end + CMPGE R12, R10 + BLT inspect_IRQ_stack + + ; somebody's in the heap code! Time for perversion. + ; Pick up registers, do foreground op, poke IRQstack return address + + $HeapBadAsModuleBRA + Push "R0, R1, lr" + MOV R0, R10 + [ TubeInfo + BL TubeDumpR0 + ] + SetBorder R0, R1, 15, 8, 6 + Pull "R0, R1, lr" + $HeapBadAsModuleKET + + ADRL R10, heapopdoneinbackground + ORR R10, R10, #SVC_mode+I_bit + STR R10, [R11, #4*7] ; return address zapped + + Push "R0-R3, lr" + + jeep R10, HeapSavedReg_R0 + +; This can't happen: heap ops are non-interruptible while foreground ops +; are waiting to complete +; LDR R12, [R10, #HeapReturnedReg_PC-HeapSavedReg_R0] +; CMP R12, #0 +; BNE HeapInUse + + LDMIA R10, {R0-R3, R10, R11} + SWI $RecursiveHeap ; with interrupts off! + jeep R12, HeapReturnedReg_R0 + ; Could we poke these into the IRQ stack too...? + ; would allow interruptible IRQ processes to do heap ops!!! + STMIA R12, {R0-R3, R10, R11, PC} + Pull "R0-R3, lr" + +iis_end ; store the registers in the info block + jeep R12, HeapSavedReg_R0 + STMIA R12, {R0-R4, stack} + +first_heap_address_to_trap ; because register saveblock now set. + LDR R12, [R12, #HeapReturnedReg_PC-HeapSavedReg_R0] + CMP R12, #0 + TEQEQP PC, lr ; restore callers interrupt state + ; only if no foreground waiting to + ; complete + + CMP r0, #MaxHeapCode ; now despatch it. + ADDLS pc, pc, r0, LSL #2 ; Tutu : faster & shorter + B NaffHeapReason ; Return if unknown call reason + +HeapJumpTable ; Check reason codes against Hdr:Heap defs + + assert ((.-HeapJumpTable) :SHR: 2) = HeapReason_Init + B InitHeap + assert ((.-HeapJumpTable) :SHR: 2) = HeapReason_Desc + B DescribeHeap + assert ((.-HeapJumpTable) :SHR: 2) = HeapReason_Get + B GetArea + assert ((.-HeapJumpTable) :SHR: 2) = HeapReason_Free + B FreeArea + assert ((.-HeapJumpTable) :SHR: 2) = HeapReason_ExtendBlock + B ExtendBlock + assert ((.-HeapJumpTable) :SHR: 2) = HeapReason_ExtendHeap + B ExtendHeap + assert ((.-HeapJumpTable) :SHR: 2) = HeapReason_ReadBlockSize + B ReadBlockSize + [ debheap + B ShowHeap + ] +MaxHeapCode * (.-HeapJumpTable-4) :SHR: 2 ; Largest valid reason code + + +NaffHeapReason + ADR R0, ErrorBlock_HeapBadReason + [ International + BL TranslateError + ] +NaffHeapExit ; get here with R0 = error ptr + SETV +GoodHeapExit ; V cleared on entry to SWI dispatch + MOV R12, PC + ORR R12, R12, #I_bit ; IRQs off + TEQP PC, R12 + MOVNV R0, R0 + Pull lr + ORRVS lr, lr, #V_bit ; VSet Exit + + $HeapBadAsModuleBRA + MOVS PC, lr + $HeapBadAsModuleKET + + ExitSWIHandler ; Like all good SWI handlers + +;HeapInUse +; $HeapBadAsModuleBRA +; SetBorder R10, R11, 15, 0, 0 +; $HeapBadAsModuleKET + +; ADR R0, ErrorBlock_HeapFail_HeapLocked +; B NaffHeapExit + +; Errors + MakeErrorBlock HeapBadReason + MakeErrorBlock HeapFail_Init + MakeErrorBlock HeapFail_BadDesc + MakeErrorBlock HeapFail_BadLink + MakeErrorBlock HeapFail_Alloc + MakeErrorBlock HeapFail_NotABlock + MakeErrorBlock HeapFail_BadExtend + MakeErrorBlock HeapFail_ExcessiveShrink +; MakeErrorBlock HeapFail_HeapLocked + + $HeapBadAsModuleBRA + +; inline workspace for testing + +HeapSavedReg_R0 & 0 +HeapSavedReg_R1 & 0 +HeapSavedReg_R2 & 0 +HeapSavedReg_R3 & 0 +HeapSavedReg_R4 & 0 +HeapSavedReg_R13 & 0 +HeapReturnedReg_R0 & 0 +HeapReturnedReg_R1 & 0 +HeapReturnedReg_R2 & 0 +HeapReturnedReg_R3 & 0 +HeapReturnedReg_R4 & 0 +HeapReturnedReg_R13 & 0 +HeapReturnedReg_PC & 0 ; also acts as interlock + + $HeapBadAsModuleKET + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Subroutine to validate heap pointer +; checks hpd points at existing LogRam +; and also that internal offsets fall into the same block of RAM + +ValidateHpdSubr + Push "R0-R2, lr" + + TEQP PC, #SVC_mode+I_bit ; interrupts off for validation + MOV R0, hpd + ADD R1, hpd, #hpdsize+freblksize + SWI XOS_ValidateAddress + BCS vhpds_fail + + TST R0, #3 ; check alignment + LDREQ HpTemp, =magic_heap_descriptor + LDREQ tp, [R0, #:INDEX: hpdmagic] + CMPEQ tp, HpTemp + BNE vhpds_fail ; failure + + LDR R1, [R0, #:INDEX: hpdend] + ADD R1, R1, R0 + SWI XOS_ValidateAddress + BCS vhpds_fail ; failure + + Pull "R0-R2, lr" + ORRS PC, lr, #Z_bit ; success + +vhpds_fail + Pull "R0-R2, lr" + BICS PC, lr, #Z_bit ; NE returned ; fails + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; InitHeap. Top level HeapEntry +; ======== +; +; Initialise a heap descriptor block + +; In : hpd -> block to initialise, size = size of block + +; Out : VClear -> Block initialised +; VSet -> Something terrible has happened +; Rest of universe ok + +; To initialise (or even reinitialise) a heap descriptor: +; $( +; hpd!magic := magic_heap_descriptor +; hpd!free := Nil +; hpd!base := hpdsize +; hpd!end := size +; $) + +InitHeap ROUT + [ MEMM_Type <> "ARM600" ; If on ARM600 these checks are not valid + CheckPtr hpd ; Is either hpd or size bad ? + CheckPtr size, EQ, (16*1024*1024) ; If hpd ok, check size < 16M + BNE NaffHeapInitialise + ] + CMP size,#hpdsize+freblksize + BLT NaffHeapInitialise ; can't get hpd and 1 block in + + Push "R0, R1" + MOV R0, hpd + ADD R1, hpd, size + SWI XOS_ValidateAddress + Pull "R0, R1" + BCS NaffHeapInitialise + + [ DebugHeaps + ORR lr, hpd, #FreeSpaceDebugMask ; form word to store throughout heap + ADD HpTemp, hpd, size ; HpTemp -> end of heap +10 + STR lr, [HpTemp, #-4]! ; store word, pre-decrementing + TEQ HpTemp, hpd ; until we get to start + BNE %BT10 + ] + + LDR HpTemp, =magic_heap_descriptor + STR HpTemp, hpdmagic ; hpd!magic := magic_heap_desc + MOV HpTemp, #Nil + STR HpTemp, hpdfree ; hpd!free := Nil + MOV HpTemp, #hpdsize + STR HpTemp, hpdbase ; hpd!base := hpdsize + STR size, hpdend ; hpd!end := size + + [ debheap + MOV HpTemp, #0 ; No debugging until the punter sets this Word + STR HpTemp, hpddebug + ] + B GoodHeapExit + +NaffHeapInitialise + [ debheap + WRLN "Unaligned/too big hpd/size: InitHeap failed" + ] + ADR R0, ErrorBlock_HeapFail_Init + [ International + BL TranslateError + ] + B NaffHeapExit ; VSet exit + + LTORG + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; DescribeHeap. Top level HeapEntry +; ============ +; +; Return information about the heap whose descriptor is pointed to by hpd + +; In : hpd -> heap descriptor + +; Out : VClear -> addr = max block size claimable, size = total free store +; VSet -> Something wrong +; Rest of universe ok + +DescribeHeap ROUT + ValidateHpd describefailed + + [ debheap + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT00 + Push link + WRLN "DescribeHeap" + BL iShowHeap + Pull link +00 + ] + LDR addr, hpdend + LDR HpTemp, hpdbase + + SUB addr, addr, HpTemp ; unused area at base to end + MOV size, addr + + LDR bp, hpdfree + ADR tp, hpdfree + ADD HpTemp, HpTemp, hpd ; address of end of allocated memory + B %FT20 + + +; Main loop chaining up free space list. size = total, addr = maxvec + +15 ADD tp, tp, bp ; get address of next + CMP tp, HpTemp + BHS describefailed_badlink ; points outside allocated memory + LDR bp, [tp, #fresize] ; Size of this block. + CMP bp, addr ; if size > maxvec then maxvec := size + MOVHI addr, bp + ADD size, size, bp ; tfree +:= size + LDR bp, [tp, #frelink] ; Get offset to next block +20 CMP bp,#Nil ; we know Nil is 0! + BLT describefailed_badlink ; -ve are naff + BNE %BT15 + + CMP addr, #0 + SUBGT addr, addr, #4 ; max block claimable + B GoodHeapExit ; VClear Exit + + +describefailed_badhpd + [ debheap + WRLN "Invalid heap descriptor: DescribeHeap failed" + ] + ADR R0, ErrorBlock_HeapFail_BadDesc + [ International + BL TranslateError + ] + B NaffHeapExit ; VSet Exit + +describefailed_badlink + [ debheap + WRLN "Invalid heap link: DescribeHeap failed" + ] + ADR R0, ErrorBlock_HeapFail_BadLink + [ International + BL TranslateError + ] + B NaffHeapExit ; VSet Exit + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; GetArea. Top level HeapEntry +; ======= +; +; Allocate a block of memory from the heap + +; This will allocate the first block of sufficiently large size in the free +; list, with an oversize block being split. +; Failure to find a large enough block on the free list will try to claim +; space out of the heap block. +; Fails if requesting size = 0 + +; In : hpd -> heap pointer, size = size of block required + +; Out : VClear : addr -> got a block +; VSet : addr = 0, couldn't get block +; Rest of universe ok + +GetArea ROUT + Push "size" + ValidateHpd garfailed + + [ debheap +; HpTemp not critical + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT00 + Push "r0, link" + MOV r0, size + DREG r0, "GetArea " + BL iShowHeap + Pull "r0, link" +00 + ] + + CMP size, #0 ; Can't deallocate 0, so there! + BLE garfailed_zero ; And -ve is invalid as well! + ; note sizes of many megabytes thrown out by looking. + + ADD size, size, #(freblksize-1)+4 ; Make block size granular + BIC size, size, #(freblksize-1) ; with size field added + + ADR addr, hpdfree-frelink ; addr:= @(hpd!free)-frelink + +garloop + [ Fix2 + LDR tp, [addr, #frelink] ; tp := addr!fre.link + CMP tp, #Nil ; Is this the end of the chain ? + BEQ garmore ; - so try main blk + | + MOV tp, addr ; tp := addr Keep ptr to prev block + LDR addr, [addr, #frelink] ; addr := addr!fre.link + CMP addr, #Nil ; Is this the end of the chain ? + BEQ garmore ; - so try main blk + ] + ADD addr, addr, tp ; convert offset + LDR HpTemp, [addr, #fresize] ; If length < size then no good + SUBS HpTemp, HpTemp, size ; In case this works, for below split + BLO garloop + +; Now addr -> a block on the free space list that our item will fit in +; If we have an exact fit (or as close as the granularity of the free list will +; allow), unlink this block and return it + + BNE SplitFreeBlock + + [ debheap + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT60 + WRLN "Got an exact fit block" +60 + ] + + LDR HpTemp, [addr, #frelink] ; Move this block's link field + CMP HpTemp, #Nil + [ Fix2 + ADDNE HpTemp, HpTemp, tp ; convert offset into offset from + ; previous block + TEQP PC, #SVC_mode+I_bit + ASSERT frelink=0 + STR HpTemp, [addr, -tp] ; store in link of previous block + | + ADDNE HpTemp, HpTemp, addr ; convert to address (if not Nil!) + SUBNE HpTemp, HpTemp, tp ; and back to offset + TEQP PC, #SVC_mode+I_bit + STR HpTemp, [tp, #frelink] ; into link of previous free block + ] + B ResultIsAddrPlus4 + +SplitFreeBlock +; Need to split the free block, returning the end portion to the caller + + [ debheap +; HpTemp critical + Push HpTemp + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT70 + WRLN "Splitting free block" +70 + Pull HpTemp + ] + + TEQP PC, #SVC_mode+I_bit + STR HpTemp, [addr, #fresize] ; Adjust size of free block remaining + ADD addr, addr, HpTemp ; addr -> free block just deallocated + +ResultIsAddrPlus4 + [ DebugHeaps + ORR lr, hpd, #UsedSpaceDebugMask ; form word to store throughout block + ADD HpTemp, addr, size ; HpTemp -> end of block +75 + STR lr, [HpTemp, #-4]! ; store word, pre-decrementing + TEQ HpTemp, addr + BNE %BT75 + ] + + STR size, [addr], #4 ; Store block size and increment addr + Pull "size" ; Return original value to the punter + ; Note : real size got would be an option! + B GoodHeapExit ; RESULTIS addr + + +; Got no more free blocks of length >= size, so try to allocate more heap space +; out of the block described by hpd + +garmore + [ debheap +; HpTemp not critical + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT80 + WRLN "Trying to get more from main block" +80 + ] + + LDR addr, hpdbase + ADD tp, addr, size ; addr := (hpd!base +:= size) + LDR HpTemp, hpdend + TEQP PC, #SVC_mode+I_bit + CMP tp, HpTemp ; See if we'd fall out of the bottom + STRLS tp, hpdbase ; Only adjust hpdbase if valid alloc + ADDLS addr, addr, hpd ; offset conversion + BLS ResultIsAddrPlus4 + [ debheap + STRIM "Not enough room to allocate in main block" + ] + +garfailed + ADR R0, ErrorBlock_HeapFail_Alloc + [ International + BL TranslateError + ] + [ debheap + WRLN " : GetArea failed" + ] +garfail_common + MOV addr, #0 ; addr := 0 if we couldn't allocate + Pull "size" ; RESULTIS 0 + B NaffHeapExit ; VSet Exit + +garfailed_badhpd + [ debheap + STRIM "Invalid heap descriptor" + ] + ADR R0, ErrorBlock_HeapFail_BadDesc + [ International + BL TranslateError + ] + B garfail_common + + [ debheap +garfailed_zero + STRIM "Can't allocate 0 or less bytes" + B garfailed + | +garfailed_zero * garfailed + ] + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; FreeArea. Top level HeapEntry +; ======== +; +; Return an area of store to the heap + +; In : hpd -> heap descriptor, addr -> block to free + +; Out : VClear -> block freed +; VSet -> failed to free block, size invalid +; Rest of universe ok + +; The block to be freed is matched against those on the free list and inserted +; in it's correct place, with the list being maintained in ascending address +; order. If possible, the freed block is merged with contigous blocks above +; and below it to give less fragmentation, and if contiguous with main memory, +; is merged with that. If the latter, check to see if there is a block which +; would be made contiguous with main memory by the former's freeing, and if so, +; merge that with main memory too. Phew ! + +FreeArea ROUT + Push "addr, size, work" + + [ debheap +; HpTemp not critical + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT00 + Push "r0, link" + STRIM "FreeArea " + SUB r0, addr, hpd + SUB r0, r0, #4 + BL PrintOffsetLine + BL iShowHeap + Pull "r0, link" +00 + ] + BL FindHeapBlock + BLVC FreeChunkWithConcatenation + + Pull "addr, size, work" + BVC GoodHeapExit + B NaffHeapExit ; VSet Exit + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; ExtendBlock. Top level HeapEntry +; =========== +; +; Extend or reallocate existing block + +; In : hpd -> heap descriptor, addr -> block, size = size to change by + +; Out : VClear -> block freed, addr new block pointer +; VSet -> failed to extend block +; Rest of universe ok + +ExtendBlock + + Push "addr, size, work" + + [ debheap +; HpTemp not critical + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT00 + Push "r0, link" + DREG size, "ExtendBlock by ",concat + STRIM " block at " + SUB r0, addr, hpd + SUB r0, r0, #4 + BL PrintOffsetLine + BL iShowHeap + Pull "r0, link" +00 + ] + BL FindHeapBlock + BVS NaffExtension + + ADD size, size, #freblksize-1 ; round size as appropriate : + BICS size, size, #freblksize-1 ; round up to nearest 8 + + BEQ GoodExtension ; get the easy case done. + BPL MakeBlockBigger + + RSB size, size, #0 + LDR bp, [addr, hpd] ; get block size + TEQP PC, #SVC_mode+I_bit + SUBS bp, bp, size ; size of block left + + [ debheap +; HpTemp not critical, GE/LT critical + BLE %FT01 + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT01 + WRLN "Freeing part of block" +01 + CMP bp, #0 ; restore GE/Lt + ] + + MOVLE HpTemp, #-1 ; if discarding block, then + STRLE HpTemp, [stack] ; make pointer really naff. + + STRGT bp, [addr, hpd] ; update size of block left + ADDGT addr, addr, bp ; offset of block to free + STRGT size, [addr, hpd] ; construct block for freeing + + BL FreeChunkWithConcatenation ; work still set from block lookup +GoodExtension + Pull "addr, size, work" + [ DebugHeaps + ADD lr, size, #freblksize-1 ; work out how much we actually extended by + BICS lr, lr, #freblksize-1 + BEQ %FT99 ; if zero or negative + BMI %FT99 ; then nothing to do + LDR HpTemp, [addr, #-4] ; get new block size + SUB HpTemp, HpTemp, #4 ; Exclude size word itself + ADD HpTemp, addr, HpTemp ; end of new block + SUB lr, HpTemp, lr ; start of new extension + ORR bp, hpd, #UsedSpaceDebugMask +98 + STR bp, [HpTemp, #-4]! ; store word + TEQ HpTemp, lr + BNE %BT98 +99 + ] + B GoodHeapExit + +MakeBlockBigger + LDR HpTemp, [addr, hpd] ; get size + ADD HpTemp, HpTemp, addr ; block end + [ Fix2 +; TMD 01-Mar-89: FindHeapBlock now never returns tp=Nil, only tp=hpdfree, +; so no need for check + LDR bp, [tp, hpd] ; next free + CMP bp, #Nil + | + CMP tp, #Nil + LDRNE bp, [tp, hpd] ; next free + CMPNE bp, #Nil + ] + ADDNE bp, bp, tp + LDREQ bp, hpdbase + +; bp is potential following block + CMP HpTemp, bp + BNE try_preceding_block + +; now get size available, see if fits + + LDR HpTemp, hpdbase + CMP bp, HpTemp + ADDNE HpTemp, bp, hpd + LDRNE HpTemp, [HpTemp, #fresize] + LDREQ HpTemp, hpdend + SUBEQ HpTemp, HpTemp, bp + BICEQ HpTemp, HpTemp, #(freblksize-1) + ; force it to a sensible blocksize + MOV lr, PC ; save EQ/NE state + + CMP HpTemp, size + BLT try_add_preceding_block + + ORR lr, lr, #I_bit ; disable IRQs + TEQP PC, lr + + [ debheap +; HpTemp, EQ/NE critical + Push "HpTemp,lr" + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT02 + STRIM "Extending block into " +02 + Pull "HpTemp,lr" + TEQP PC, lr + ] + + LDR work, [addr, hpd] ; get size back + ADD work, work, size ; new size + STR work, [addr, hpd] ; block updated + +; now see which we're extending into + BNE IntoFreeEntry + + [ debheap + Push HpTemp + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT03 + WRLN "base-end area" +03 + Pull HpTemp + ] + ADD work, work, addr + STR work, hpdbase + B GoodExtension + +IntoFreeEntry + + [ debheap + Push HpTemp + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT04 + WRLN "free entry" +04 + Pull HpTemp + ] + + CMP HpTemp, size + BNE SplitFreeBlockForExtend + +; free entry just right size : remove from free list + LDR HpTemp, [bp, hpd] ; free link + CMP HpTemp, #Nil + ADDNE HpTemp, HpTemp, bp ; offset from heap start + SUBNE HpTemp, HpTemp, tp + STR HpTemp, [tp, hpd] ; free list updated + B GoodExtension + +SplitFreeBlockForExtend + LDR work, [tp, hpd] + ADD work, work, size + STR work, [tp, hpd] ; prevnode points at right place + ADD work, work, tp ; offset of new free entry + ADD work, work, hpd + SUB HpTemp, HpTemp, size ; new freblk size + STR HpTemp, [work, #fresize] + LDR HpTemp, [bp, hpd] + CMP HpTemp, #Nil + SUBNE HpTemp, HpTemp, size ; reduced offset for free link + STR HpTemp, [work, #frelink] + B GoodExtension + +try_preceding_block + [ {TRUE} + [ Fix2 +; TMD 01-Mar-89: FindHeapBlock now never returns tp=Nil, only tp=hpdfree, +; so no need for check + CMP tp, #:INDEX: hpdfree ; no real preceder? + | + CMP tp, #Nil ; no free list? + CMPNE tp, #:INDEX: hpdfree ; or no real preceder? + ] + BEQ got_to_reallocate + ADD bp, tp, hpd + LDR bp, [bp, #fresize] + ADD bp, bp, tp ; end of preceding block + CMP addr, bp + BNE got_to_reallocate + +; now get size available, see if fits + + SUB bp, bp, tp ; freblk size + SUBS bp, bp, size ; compare, find free size left + BLT got_to_reallocate + + [ debheap + Push "HpTemp,lr" + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT10 + CMP bp, #0 + BEQ %FT11 + STRIM "Extending block into previous free" + B %FT12 +11 + STRIM "Previous free perfect fit" +12 + SWI XOS_NewLine +10 + Pull "HpTemp,lr" + ] + + TEQP PC, #SVC_mode+I_bit ; IRQs off + +hack_preceder +; bp is new size of preceding block +; tp is prevfree offset +; work is prevprevfree offset +; size is amount block grows by +; addr is block offset + CMP bp, #0 + ADDNE HpTemp, tp, hpd + STRNE bp, [HpTemp, #fresize] ; prevblock shrunk + BNE copy_backwards + + ; free freblk: work is still prevprevblk pointer + LDR HpTemp, [tp, hpd] + CMP HpTemp, #Nil + ADDNE HpTemp, HpTemp, tp ; offset from heap start + SUBNE HpTemp, HpTemp, work + STR HpTemp, [work, hpd] ; free list updated + +copy_backwards + ADD bp, bp, tp + LDR HpTemp, [addr, hpd]! ; current block size + ADD size, HpTemp, size + STR size, [bp, hpd]! ; update blocksize + + [ debheap + Push r0 + LDR r0, hpddebug + CMP r0, #0 + BEQ %FT06 + DREG HpTemp, "copying -4+",concat + STRIM " from " + SUB R0, addr, hpd + BL PrintOffset + STRIM " to " + SUB R0, bp, hpd + BL PrintOffsetLine +06 + Pull r0 + ] + + [ Fix4 +; TMD 02-Mar-89: We've finished messing about with the heap structure +; so we can branch outside danger zone and restore IRQ status while doing copy + B CopyBackwardsInSafeZone + | + + ADD bp, bp, #4 ; new block pointer + STR bp, [stack] ; return to user + +; copy wackbords: HpTemp-4 bytes from addr+4 to bp, in appropriate order! +cpe_prev + SUBS HpTemp, HpTemp, #4 + LDRGT work, [addr, #4]! + STRGT work, [bp], #4 + BGT cpe_prev + B GoodExtension + ] + ] +try_add_preceding_block + [ {TRUE} +; HpTemp is size of following block + CMP tp, #:INDEX: hpdfree ; no real preceder? + BEQ got_to_reallocate + Push "work, size" ; need prevprevblk ptr + SUB size, size, HpTemp ; size still needed + ADD HpTemp, tp, hpd + LDR HpTemp, [HpTemp, #fresize] + ADD HpTemp, HpTemp, tp ; end of preceding block + CMP addr, HpTemp + BNE got_to_reallocate2 + +; now get size available, see if fits + + SUB HpTemp, HpTemp, tp ; freblk size + SUBS HpTemp, HpTemp, size + BLT got_to_reallocate2 + + [ debheap + Push "HpTemp,lr" + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT10 + Pull HpTemp + CMP HpTemp, #0 + BEQ %FT11 + STRIM "Extending block into previous free and block after" + B %FT12 +11 + STRIM "Previous free+nextblock perfect fit" +12 + SWI XOS_NewLine +10 + Pull "lr" + ] + + TEQP PC, #SVC_mode+I_bit ; IRQs off + ; delink block at bp + LDR work, hpdbase + CMP bp, work ; extend into free, or delink block? + BNE ext_delink + LDR work, hpdend + SUB work, work, bp ; get back real size + BIC work, work, #(freblksize-1) + ADD work, work, bp + STR work, hpdbase ; all free allocated + B ext_hack +ext_delink + LDR work, [bp, hpd] + CMP work, #Nil + ADDNE work, work, bp + SUBNE work, work, tp + STR work, [tp, hpd] ; block delinked +ext_hack + MOV bp, HpTemp + Pull "work, size" +; bp is new size of preceding block +; tp is prevfree offset +; work is prevprevfree offset +; size is amount block grows by +; addr is block offset + B hack_preceder + +got_to_reallocate2 + Pull "work, size" + ] +got_to_reallocate +; claim block of new size ; copy data +; Done by recursive SWIs: somewhat inefficient, but simple. + + [ debheap + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT05 + WRLN "reallocating block" +05 + ] + + [ Fix4 + B ReallocateInSafeZone + | + TEQP PC, #SVC_mode+I_bit ; no interrupts during this + LDR work, [addr, hpd]! ; get block size, set block addr + ADD size, size, work + SUB size, size, #4 ; block size to claim + ADD addr, addr, #4 + MOV bp, addr ; address to copy from + Push addr ; save for later freeing + + MOV R0, #HeapReason_Get + SWI $RecursiveHeap + Pull addr, VS + BVS NaffExtension + + [ debheap + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT06 + DREG work, "got new block : copying " +06 + ] + + STR addr, [stack, #4] + +; claimed : copy work-4 bytes from bp to addr +CopyForExtension + SUBS work, work, #4 + LDRGT HpTemp, [bp],#4 + STRGT HpTemp, [addr],#4 + BGT CopyForExtension + +; free the old block! + + [ debheap + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT08 + WRLN "freeing old block" +08 + ] + +; recursive SWI to free old block; we have invalidated any held information + + MOV R0, #HeapReason_Free + Pull addr ; heap block addr + SWI $RecursiveHeap + + MOV R0, #HeapReason_ExtendBlock + B GoodExtension + ] + +NaffExtension + Pull "addr, size, work" + B NaffHeapExit + + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; ExtendHeap. Top level HeapEntry +; ========== +; +; Extend or shrink heap + +; In : hpd -> heap descriptor, size = size to change by + +; Out : VClear -> heap size changed OK +; VSet -> failed to change by specified amount +; size = amount changed by + +ExtendHeap ROUT + ValidateHpd ExtendHeap + + CMP r3, #0 + ADDMI r3, r3, #3 ; round towards 0 + BIC R3, R3, #3 ; ensure word amount + + LDR HpTemp, hpdend + ADD HpTemp, HpTemp, R3 ; HpTemp := new size + LDR tp, hpdbase + CMP tp, HpTemp + BGT ExtendHeap_badshrink + + TEQP PC, #SVC_mode+I_bit + Push "R0, R1" + MOV R0, hpd ; Ensure heap will be in valid area + ADD R1, hpd, HpTemp + SWI XOS_ValidateAddress + Pull "R0, R1" + BCS ExtendHeap_nafforf + + [ DebugHeaps + CMP R3, #0 ; if shrunk or stayed same + BLE %FT15 ; then nothing to do + ADD tp, hpd, HpTemp ; tp -> end of heap + SUB bp, tp, R3 ; bp -> start of new bit + ORR lr, hpd, #FreeSpaceDebugMask +10 + STR lr, [tp, #-4]! ; store word + TEQ tp, bp + BNE %BT10 +15 + ] + + STR HpTemp, hpdend ; uppy date him + B GoodHeapExit ; moved all the size asked for + +ExtendHeap_badhpd + ADRL R0, ErrorBlock_HeapFail_BadDesc + [ International + BL TranslateError + ] + MOV size, #0 + B NaffHeapExit + +ExtendHeap_nafforf + ADRL R0, ErrorBlock_HeapFail_BadExtend + [ International + BL TranslateError + ] + MOV size, #0 + [ Fix3 + | + Pull lr + ] + B NaffHeapExit + +ExtendHeap_badshrink + LDR HpTemp, hpdend + STR tp, hpdend ; update heap + SUB size, HpTemp, tp ; size managed to change by + ADRL R0, ErrorBlock_HeapFail_ExcessiveShrink + [ International + BL TranslateError + ] + B NaffHeapExit ; and sort of fail + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; ReadBlockSize. Top level HeapEntry +; ============= +; + +ReadBlockSize + + Push "addr, work" + BL FindHeapBlock + LDRVC size, [addr, hpd] + Pull "addr, work" + BVC GoodHeapExit + B NaffHeapExit + +;************************************************************************** +; Common routines for free/extend + +FindHeapBlock ROUT +; Convert addr to address +; Validate heap +; check block is an allocated block +; return tp = free list entry before the block (hpdfree if none) +; work = free list before that (if exists) +; corrupts HpTemp, bp + + Push lr + + ValidateHpd findfailed + + SUB addr, addr, hpd ; convert to offset + SUB addr, addr, #4 ; real block posn + +; Find block in heap by chaining down freelist, stepping through blocks + [ Fix2 + +; TMD 01-Mar-89 +; no need to check explicitly for null free list, code drops thru OK + + | + LDR tp, hpdfree ; first find bounding free blocks + CMP tp, #Nil ; no free? + [ debheap +; HpTemp not critical +; EQ critical + BNE %FT01 + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT01 + Push "link" + WRLN "No free list - scan all blocks" + Pull "link" + CMP R0,R0 ; restore EQ +01 + ] + MOVEQ bp, #hpdsize ; load block limits to look through + LDREQ HpTemp, hpdbase + BEQ ScanAllocForAddr + ] + [ debheap + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT03 + Push lr + WRLN "Scanning freelist" + Pull lr +03 + ] + +; step down free list to find appropriate chunk +; get tp = free block before addr +; HpTemp = " " after " +; work = block before tp + + MOV tp, #:INDEX: hpdfree +StepDownFreeList + LDR HpTemp, [hpd, tp] ; link offset + CMP HpTemp,#Nil + BEQ ListEnded ; EQ state used! + ADD HpTemp, HpTemp, tp + CMP HpTemp, addr + MOVLS work, tp + MOVLS tp, HpTemp + BLS StepDownFreeList +ListEnded + LDREQ HpTemp, hpdbase ; if EQ from CMP HpTemp, addr + ; then bad block anyway + CMP tp, #:INDEX: hpdfree + MOVEQ bp, #hpdsize ; is this a fudge I see before me? + BEQ ScanAllocForAddr + [ Fix2 + ADD bp, tp, #fresize + LDR bp, [hpd, bp] + | + ADD tp, tp, #fresize + LDR bp, [hpd,tp] + SUB tp, tp, #fresize + ] + ADD bp, tp, bp + +ScanAllocForAddr +; bp -> start of allocated chunk +; HpTemp -> end " " " +; scan to find addr, error if no in here + + Push work ; keep prevlink ptr + + [ debheap +; HpTemp critical + Push "HpTemp, R0, link" + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT02 + STRIM "Scan for addr from " + MOV R0, bp + BL PrintOffset + STRIM " to " + LDR R0,[stack,#4] ; HpTemp + BL PrintOffsetLine +02 + Pull "HpTemp, r0, link" + ] + B CheckForNullAllocn + +ScanAllocForAddrLoop + CMP bp, addr + BEQ ValidBlock + LDR work, [bp, hpd] ; get size + ADD bp, bp, work +CheckForNullAllocn + CMP bp, HpTemp + BLT ScanAllocForAddrLoop + + [ debheap + Push lr + STRIM "Given pointer not a block" + Pull lr + ] + ADRL R0, ErrorBlock_HeapFail_NotABlock + [ International + BL TranslateError + ] + Pull "work, lr" + ORRS PC, lr, #V_bit + +ValidBlock ; tp = free link offset, addr = block offset + Pull "work, lr" + BICS PC, lr, #V_bit + +findfailed_badhpd + [ debheap + Push lr + STRIM "Invalid heap descriptor" + Pull lr + ] + ADRL R0, ErrorBlock_HeapFail_BadDesc + [ International + BL TranslateError + ] + Pull lr + ORRS PC, lr, #V_bit + +;**************************************************************************** + +FreeChunkWithConcatenation ROUT +; in : addr -> block +; tp -> preceding free list entry +; out : block freed, concatenated with any free parts on either side, +; base reduced if can do +; corrupts HpTemp, bp, size, addr + + [ Fix2 +; TMD 01-Mar-89: FindHeapBlock now never returns tp=Nil, only tp=hpdfree, +; so no need for check, code will get there eventually! + | + CMP tp, #Nil + MOVEQ tp, #:INDEX: hpdfree + BEQ NoConcatenation + ] + +; attempt concatenation with free blocks on both/either side + [ debheap + Push "R0, lr" + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT04 + STRIM "concatenation attempt with free ptr " + MOV R0,tp + BL PrintOffsetLine +04 + Pull "R0, lr" + ] + + [ DebugHeaps + ORR bp, hpd, #FreeSpaceDebugMask + LDR size, [addr, hpd]! + ADD HpTemp, addr, size + SUB HpTemp, HpTemp, #4 ; HpTemp -> last word of block +10 + STR bp, [HpTemp], #-4 ; store word, then go back + TEQ HpTemp, addr ; loop until done, but don't overwrite size field + BNE %BT10 ; otherwise we might get an IRQ with a duff heap + SUB addr, addr, hpd ; make addr an offset again + ] + + LDR size, [addr, hpd] ; block size + ADD bp, size, addr ; eob offset + LDR HpTemp, [tp, hpd] ; Nil doesn't matter here! + ADD HpTemp, HpTemp, tp ; offset of free block after ours + CMP HpTemp, bp ; if tp was hpdfree then <> bp + BNE NoConcatWithNext ; so will take branch + + [ debheap + Push lr + LDR bp, hpddebug + CMP bp, #0 + BEQ %FT05 + WRLN "concatenating with block after" +05 + Pull lr + ] + ADD bp, hpd, HpTemp + LDR bp, [bp, #fresize] + ADD bp, bp, size + TEQP PC, #SVC_mode+I_bit + STR bp, [addr, hpd] ; enlarge our block + LDR bp, [HpTemp, hpd] ; offset in free list + CMP bp, #Nil + ADDNE bp, HpTemp, bp ; offset from heap start + SUBNE bp, bp, tp ; free list offset + STR bp, [tp, hpd] ; free list updated, our block bigger + ; - but not in the free list yet! + +NoConcatWithNext ; tp = free link offset, addr = block offset + ; now try for concatenation with previous block + CMP tp, #:INDEX: hpdfree ; are we before any real free blocks? + BEQ NoConcatenation ; yup + + ADD HpTemp, tp, hpd + LDR size, [HpTemp, #fresize] + ADD bp, size, tp + CMP bp, addr + BNE NoConcatenation + [ debheap + Push lr + LDR bp, hpddebug + CMP bp, #0 + BEQ %FT06 + WRLN "concatenating with block before" + STRIM "prevfree = " + Push R0 + MOV R0, work + BL PrintOffsetLine + Pull R0 +06 + Pull lr + ] + LDR bp, [addr, hpd] ; get block size + ADD size, bp, size ; new free block size + TEQP PC, #SVC_mode+I_bit + STR size, [HpTemp, #fresize] +; now check for butts against base : work is still prevnode to tp + ADD HpTemp, size, tp + LDR bp, hpdbase + CMP bp, HpTemp + ORRNES PC, lr, #I_bit ; all done : exit keeping IRQs off + SUB bp, bp, size + STR bp, hpdbase ; step unused bit back + MOV bp, #Nil ; this MUST have been last free block! + STR bp, [work, hpd] + ORRS PC, lr, #I_bit ; Whew! + +NoConcatenation ; check if block butts against base +; tp = previous freelink offset + LDR size, [addr, hpd] + ADD HpTemp, size, addr + LDR bp, hpdbase + CMP bp, HpTemp + BNE AddToFreeList + SUB bp, bp, size + TEQP PC, #SVC_mode+I_bit + STR bp, hpdbase + ORRS PC, lr, #I_bit + +AddToFreeList ; block at addr, previous free at tp + [ debheap + Push "R0, lr" + LDR HpTemp, hpddebug + CMP HpTemp, #0 + BEQ %FT07 + STRIM "add to free list : free link " + MOV R0,tp + BL PrintOffset + STRIM ", block " + MOV R0, addr + BL PrintOffsetLine +07 + Pull "R0, lr" + ] + LDR size, [addr, hpd]! + TEQP PC, #SVC_mode+I_bit + STR size, [addr, #fresize] + SUB addr, addr, hpd + LDR size, [hpd, tp] ; prevlink + CMP size, #Nil + SUBNE size, size, addr + ADDNE size, size, tp ; form offset if not eolist + STR size, [addr, hpd] + SUB size, addr, tp + STR size, [tp, hpd] + ORRS PC, lr, #I_bit + +;***************************************************************************** + + [ debheap +; +; ShowHeap. Top level HeapEntry +; ======== +; +; Dump the heap pointed to by hpd + +ShowHeap + Push link + BL iShowHeap ; Needed to fudge link for SVC mode entry + Pull link + B GoodHeapExit + + +iShowHeap ROUT ; Internal entry point for debugging heap + + Push "r0, hpd, addr, size, work, bp, tp, link" + + ValidateHpd showfailed ; debugging heaps won't work interruptibly + + LDR tp, hpdfree + CMP tp, #Nil + ADDNE tp, tp, #:INDEX: hpdfree + LDR bp, hpdbase + MOV addr, #hpdsize + LDR work, hpdend + + SWI OS_NewLine ; Initial blurb about hpd contents + DREG hpd, "**** Heap map **** : hpd " + STRIM "-> free" + MOV r0, tp + BL PrintOffset + STRIM ", base" + MOV r0, bp + BL PrintOffsetLine + STRIM "-> start" + MOV r0, addr + BL PrintOffset + STRIM ", end" + MOV r0, work + BL PrintOffsetLine + + SUB r0, work, bp ; hpdend-hpdbase + DREG r0,"Bytes free: ",concat, Word + SUB r0, bp, addr ; hpdbase-hpdsize + DREG r0,", bytes used: ",, Word + SWI XOS_NewLine + + CMP tp, #Nil ; No free blocks at all ? + BNE %FT10 + WRLN "No Free Blocks" + + CMP bp, addr ; Is a block allocated at all ? + MOVNE r0, addr ; hpdsize + BNE %FT40 + WRLN "No Used Blocks" + B %FT99 + + +10 CMP tp, addr ; hpdsize ; Allocated block below first free ? + BEQ %FT15 + + MOV r0, addr ; hpdbase + BL HexUsedBlk + SUB r0, tp, addr ; hpdfree-hpdsize + DREG r0 + SWI XOS_NewLine + +; Main loop chaining up free space list + +15 ADD addr, tp, hpd ; convert to address + LDR size, [addr, #fresize] ; Size of this block + LDR addr, [addr, #frelink] ; offset to next block + + STRIM "Free Block " + MOV r0, tp + BL PrintOffset + DREG size, ", size " + + ADD r0, tp, size ; r0 -> eob. Adjacent free blocks don't exist + + CMP addr, #Nil ; If last block, then must we see if we're = hpdbase + BEQ %FT40 + +; Used block starts at r0, ends at addr+tp - so size = (addr+tp)-r0 + + BL HexUsedBlk + SUB r0, addr, r0 ; addr-r0 + ADD r0, r0, tp ; used block size + DREG r0 + SWI XOS_NewLine + + ADD tp, addr, tp ; step down free list + B %BT15 ; And loop + + +40 CMP r0, bp ; Is there any allocated space after this block ? + BEQ %FT99 + BL HexUsedBlk + SUB r0, bp, r0 ; hpdbase-sob + DREG r0 + SWI XOS_NewLine + +99 + GRABS "r0, hpd, addr, size, work, bp, tp, pc" + + +showfailed_badhpd + WRLN "Invalid heap descriptor : ShowHeap failed" + GRABS "r0, hpd, addr, size, work, bp, tp, pc" + + +HexUsedBlk + Push "lr" + STRIM "Used Block " + BL PrintOffset + STRIM ", size" + Pull "lr" + MOVS PC, R14 + +PrintOffset + Push "r0, lr" + DREG r0 + CMP R0, #0 + ADDNE R0, R0, hpd + DREG r0," (",concat + STRIM ")" + GRABS "R0, PC" + +PrintOffsetLine + Push "lr" + BL PrintOffset + SWI XOS_NewLine + Pull "PC" + + ] + + [ TubeInfo +TubeDumpR0 ROUT + Push "R1, R2, lr" + TubeChar R0, R1, "MOV R1, #10" + TubeChar R0, R1, "MOV R1, #13" + MOV R1, #7 +01 MOV R0, R0, ROR #28 + AND R2, R0, #&F + TubeChar R0, R1, "ADD R1, R2, #""0""" + SUBS R1, R1, #1 + BPL %BT01 + Pull "R1, R2, PC", ,^ + ] + +HeapCode_end + +; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + $HeapBadAsModuleBRA + InsertDebugRoutines + $HeapBadAsModuleKET + + END diff --git a/s/HeapSort b/s/HeapSort new file mode 100644 index 0000000000000000000000000000000000000000..1ded77acd20d1565985f6b6da2121424cd218daa --- /dev/null +++ b/s/HeapSort @@ -0,0 +1,405 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + SUBT > HeapSort + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; HeapSort routine. Borrowed from Knuth by Tutu. Labels h(i) correspond to +; steps in the algorithm. + +; In r0 = n +; r1 = array(n) of word size objects (r2 determines type) +; bit 31 set -> use r4,r5 on postpass +; bit 30 set -> build (r1) from r4,r5 in prepass +; bit 29 set -> use r6 as temp slot +; r2 = address of comparison procedure +; Special cases: +; 0 -> treat r(n) as array of cardinal +; 1 -> treat r(n) as array of integer +; 2 -> treat r(n) as array of cardinal* +; 3 -> treat r(n) as array of integer* +; 4 -> treat r(n) as array of char* (case insensitive) +; 5 -> treat r(n) as array of char* (case sensitive) +; r3 = wsptr for comparison procedure (only needed if r2 > 5) +; r4 = array(n) of things (only needed if r1 & 0xC0000000) +; r5 = sizeof(element) ( --------- ditto ---------- ) +; r6 = address of temp slot (only needed if r5 > 16K or r1 & 0x20000000) + +; r10-r12 trashable + +hs_array RN r4 +hs_procadr RN r5 +hs_i RN r6 +hs_j RN r7 +hs_K RN r8 +hs_R RN r9 +hs_l RN r10 +hs_r RN r11 +;wp RN r12 + +; User sort procedure entered in SVC mode, interrupts enabled +; r0 = contents of array(1) +; r1 = contents of array(2) +; r0-r3 may be trashed +; wp = value requested (trash at your peril; you'll get the bad one next time) + +; User sort procedure returns: +; LT: if f(r0) < f(r1) +; GE: if f(r0) => f(r1) +; (ie. N_bit and V_bit only considered) + +HeapSortRoutine ROUT + + CMP r0, #2 ; 0 or 1 elements? No data moved either + ExitSWIHandler LO ; VClear in lr and psr + + Push "r0-r3, hs_array, hs_procadr, hs_i, hs_j, hs_K, hs_R, lr" + + MVN r14, #I_bit ; Enable interrupts (may take ages) + TSTP r14, pc + + [ False + STR r0, ndump ; For debugging porpoises + ] + TST r1, #1 :SHL: 30 ; Are we to build the pointer array? + BIC r1, r1, #2_111 :SHL: 29 ; Take out flag bits for now + BEQ %FT01 + +; Build array of pointers to data blocks for the punter if he desires this +; (lazy slobs abound ...) + +; for (i=0; i<n; i++) r(i) = &block + i*sizeof(element); + + MOV r10, r0 ; n + MOV r14, r1 ; r14 -> base of pointer array +00 STR r4, [r14], #4 + ADD r4, r4, r5 ; r4 += sizeof(element) + SUBS r10, r10, #1 + BNE %BT00 + + +01 SUB hs_array, r1, #4 ; HeapSort assumes r(1..n) not (0..n-1) + + MOV hs_procadr, r2 ; Put proc address where we need it + + CMP hs_procadr, #6 ; Special procedure ? + ADRLO r14, hs_Procedures + LDRLO hs_procadr, [r14, hs_procadr, LSL #2] + ADDLO hs_procadr, hs_procadr, r14 + + MOV wp, r3 ; Can now use r3 temp. Keep set up + ; for speed during execution + + MOV hs_l, r0, LSR #1 ; l = floor(n/2) + 1 + ADD hs_l, hs_l, #1 + MOV hs_r, r0 ; r = n + + +h2 CMP hs_l, #1 + BEQ %FT10 + + SUB hs_l, hs_l, #1 + LDR hs_R, [hs_array, hs_l, LSL #2] ; R = R(l) + MOV hs_K, hs_R + B %FT20 + +10 LDR hs_R, [hs_array, hs_r, LSL #2] ; R = R(r) + MOV hs_K, hs_R + LDR r14, [hs_array, #4] ; R(r) = R(1) + STR r14, [hs_array, hs_r, LSL #2] + SUB hs_r, hs_r, #1 + CMP hs_r, #1 ; IF r=1 THEN R(1) = R + STREQ hs_R, [hs_array, #4] +20 + [ False + BL DoDebug + ] + + CMP hs_r, #1 + BEQ %FT90 ; [finished sorting the array] + + +h3 MOV hs_j, hs_l + + +h4 MOV hs_i, hs_j + MOV hs_j, hs_j, LSL #1 + + [ False + DREG hs_i," i ",cc + DREG hs_j," j " + ] + CMP hs_j, hs_r + BEQ h6 + BHI h8 + + +h5 LDR r0, [hs_array, hs_j, LSL #2] + ; IF K(R(j)) < K(R(j+1)) THEN j +:= 1 + ADD r14, hs_j, #1 + LDR r1, [hs_array, r14, LSL #2] + + MOV lr, pc ; r0, r1 for comparison + MOV pc, hs_procadr + + ADDLT hs_j, hs_j, #1 ; Assumes signed comparison done <<<<<< + + +h6 MOV r0, hs_K ; IF K >= K(R(j)) THEN h8 + LDR r1, [hs_array, hs_j, LSL #2] + + MOV lr, pc ; r0, r1 for comparison + MOV pc, hs_procadr + + [ True ; 1.73+ optimisation, faster in all cases + ; Assumes signed comparison done <<<<<< +;h7 + LDRLT r14, [hs_array, hs_j, LSL #2] ; R(i) = R(j) + STRLT r14, [hs_array, hs_i, LSL #2] + BLT h4 + | + BGE h8 ; Assumes signed comparison done <<<<<< + +;h7 + LDR r14, [hs_array, hs_j, LSL #2] ; R(i) = R(j) + STR r14, [hs_array, hs_i, LSL #2] + B h4 + ] + + +h8 STR hs_R, [hs_array, hs_i, LSL #2] ; R(i) = R + B h2 + + +; Array now sorted into order + +90 LDR r14, [sp, #4*1] ; r1in + TST r14, #1 :SHL: 30 + BEQ %FA99 ; [no shuffle required, exit] + +; Reorder the blocks according to the sorted array of pointers + + BIC r2, r14, #2_111 :SHL: 29 ; r2 -> list of pointers + ; keep r14 ok for below + + ADD r1, sp, #4*4 + LDMIA r1, {r1, r8, r9} ; r4,r5,r6in + ; r1 -> list of blocks + [ False + DREG r2, "pointer array " + DREG r1, "base of blocks " + DREG r8, "sizeof(element) " + ] + MOV r3, r2 ; r3 -> first item of current cycle + LDR r0, [sp, #0*4] ; r0 = n + ADD r6, r2, r0, LSL #2 ; r6 -> end of array of pointers + TST r14, #1 :SHL: 29 ; punter forcing use of his temp slot? + BNE %FT94 ; fine by me! + CMP r8, #ScratchSpaceSize + LDRLS r9, =ScratchSpace ; r9 -> temp slot (normally ScratchSpc) +94 + [ False + DREG r9, "temp slot " + ] + +91 SUB r14, r3, r2 + MOV r14, r14, LSR #2 ; r14 = index (0..n-1) of current item + MLA r4, r14, r8, r1 ; r4 -> current block + + MOV r5, r3 ; r5 -> current item + BL MoveToTempSlot ; save first block in temp slot + +92 LDR r7, [r5] ; r7 -> next block + MOV r14, #0 + STR r14, [r5] ; mark item 'done' + + SUB r5, r7, r1 ; r14 := index of next item (r8 pres.) + DivRem r14, r5, r8, r0 ; r5,r0 corrupt + ADD r5, r2, r14, LSL #2 ; r5 -> next item + [ False + DREG r7, " next block " + DREG r5, " next item " + ] + + CMP r5, r3 ; reached start of cycle? + MOVEQ r7, r9 ; get back from temp slot if last one + BL MoveFromGivenSlot ; preserves flags + + MOVNE r4, r7 ; update r4 (current block) + BNE %BT92 + +93 LDR r14, [r3, #4]! ; skip already-copied items + CMP r3, r6 + BCS %FA99 ; [reached end] + CMP r14, #0 + BEQ %BT93 + + B %BT91 ; [found one that hasn't been copied] + + +; No error return from HeapSort + +99 Pull "r0-r3, hs_array, hs_procadr, hs_i, hs_j, hs_K, hs_R, lr" + +; SWIHandler exit takes flags + mode from lr, not psr !!! + + ExitSWIHandler + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r4 -> element to be copied +; r8 = sizeof(element) +; r9 -> temp slot + +; Out all preserved + +MoveToTempSlot ENTRY "r4, r8, r9" + + TST r4, #3 ; If base and element size wordy + TSTEQ r8, #3 ; then do faster copy. Also temp wordy + BNE %FT01 + +00 SUBS r8, r8, #4 + LDRPL r14, [r4], #4 + STRPL r14, [r9], #4 + BPL %BT00 + EXITS + +01 SUBS r8, r8, #1 + LDRPLB r14, [r4], #1 + STRPLB r14, [r9], #1 + BPL %BT01 + EXITS + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r4 -> where element is to be copied +; r7 -> element to be copied +; r8 = sizeof(element) + +; Out all preserved + +MoveFromGivenSlot ENTRY "r4, r7, r8" + + TST r4, #3 ; If dest and element size wordy + TSTEQ r8, #3 ; then do faster copy. Also src wordy + BNE %FT01 + +00 SUBS r8, r8, #4 + LDRPL r14, [r7], #4 + STRPL r14, [r4], #4 + BPL %BT00 + EXITS + +01 SUBS r8, r8, #1 + LDRPLB r14, [r7], #1 + STRPLB r14, [r4], #1 + BPL %BT01 + EXITS + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Built-in sorting procedures + +hs_Procedures + + DCD hs_CardinalCMP - hs_Procedures + DCD hs_IntegerCMP - hs_Procedures + DCD hs_CardinalPtrCMP - hs_Procedures + DCD hs_IntegerPtrCMP - hs_Procedures + DCD hs_StringCMP - hs_Procedures + DCD hs_StringSensCMP - hs_Procedures + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r0, r1 -> cardinals + +; Out flags set on (*r0) - (*r1) + +hs_CardinalPtrCMP + + LDR r0, [r0] + LDR r1, [r1] + +; ............................................................................. +; In r0, r1 = cardinals + +; Out flags set on r0 - r1 + +hs_CardinalCMP + + CMP r0, r1 + BICCSS pc, lr, #N_bit :OR: V_bit ; CS -> GE (nv) + BIC lr, lr, #V_bit + ORRS pc, lr, #N_bit ; CC -> LT (Nv) + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r0, r1 -> integers + +; Out flags set on (*r0) - (*r1) + +hs_IntegerPtrCMP + + LDR r0, [r0] + LDR r1, [r1] + +; ............................................................................. +; In r0, r1 = integers + +; Out flags set on r0 - r1 + +hs_IntegerCMP + + CMP r0, r1 + MOV pc, lr + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Case-insensitive string comparison + +; In r0, r1 -> strings - CtrlChar terminated (NB. Must be same CtrlChar !) + +; Out flags set on (char *)(r0) - (char *)(r1) compare + +hs_StringCMP ROUT + +10 LDRB r2, [r0], #1 + LowerCase r2, r12 + LDRB r3, [r1], #1 + LowerCase r3, r12 + CMP r2, r3 ; Differ ? + MOVNE pc, lr ; GE or LT + CMP r2, #space-1 ; Finished ? + BHI %BT10 + + BICS pc, lr, #N_bit :OR: V_bit ; GE + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Case-sensitive string comparison + +; In r0, r1 -> strings - CtrlChar terminated (NB. Must be same CtrlChar !) + +; Out flags set on (char *)(r0) - (char *)(r1) + +hs_StringSensCMP ROUT + +10 LDRB r2, [r0], #1 + LDRB r3, [r1], #1 + CMP r2, r3 ; Differ ? + MOVNE pc, lr ; GE or LT + CMP r2, #space-1 ; Finished ? + BHI %BT10 + + BICS pc, lr, #N_bit :OR: V_bit ; GE + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + LTORG + + END diff --git a/s/KbdResA1 b/s/KbdResA1 new file mode 100644 index 0000000000000000000000000000000000000000..c869f492c8fad08182a4a832f21d0ec987f29c9f --- /dev/null +++ b/s/KbdResA1 @@ -0,0 +1,330 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > KbdResA1 + +; This file contains all the old-style keyboard control stuff that the kernel does on reset +; The only two hooks in this file used externally are IRQ_Test_CTRL_or_R_Pressed +; and SetUpKbd. + + GBLL KeyboardDebungling +KeyboardDebungling SETL {FALSE} + +; reset code needs to know where CTRL, SHIFT and R are in the kbd matrix +; these are codes given by the keyboard + + [ Keyboard_Type = "A1A500" +A1CtrlLeft * &3B +A1CtrlRight * &61 +A1ShiftLeft * &4C +A1ShiftRight * &58 +A1CTRLLCol * K1kdda + (A1CtrlLeft :AND: 15) +A1CTRLLRow * K1kdda + (A1CtrlLeft :SHR: 4) +A1CTRLRCol * K1kdda + (A1CtrlRight :AND: 15) +A1CTRLRRow * K1kdda + (A1CtrlRight :SHR: 4) +A1SHIFTLCol * K1kdda + (A1ShiftLeft :AND: 15) +A1SHIFTLRow * K1kdda + (A1ShiftLeft :SHR: 4) +A1SHIFTRCol * K1kdda + (A1ShiftRight :AND: 15) +A1SHIFTRRow * K1kdda + (A1ShiftRight :SHR: 4) +A1R_Col * K1kdda + 10 +A1R_Row * K1kdda + 2 +A1T_Col * K1kdda + 11 +A1T_Row * K1kdda + 2 +A1Del_Col * K1kdda + 4 +A1Del_Row * K1kdda + 3 +A1Copy_Col * K1kdda + 5 +A1Copy_Row * K1kdda + 3 + ] + + [ Keyboard_Type = "A1A500" +; old (A500) keyboard positions + +A500CTRLRow * KEYDOWN + &C +A500CTRLCol * KEYDOWN + 0 +A500SHIFTRow * KEYDOWN + &A +A500SHIFTCol * KEYDOWN + 0 +A500R_Row * KEYDOWN + 2 +A500R_Col * KEYDOWN + 7 +A500T_Row * KEYDOWN + 2 +A500T_Col * KEYDOWN + 6 +A500Del_Row * KEYDOWN + 5 +A500Del_Col * KEYDOWN + 7 +A500Copy_Row * KEYDOWN + 0 +A500Copy_Col * KEYDOWN + 8 + ] + +; On ARM600, this routine must work in IRQ32 mode + +IRQ_Test_CTRL_or_R_Pressed ROUT + [ CPU_Type = "ARM600" + BIC pc, pc, #&FC000000 ; take us out of the shadow ROM area + NOP ; (this instruction skipped) + ] + Push "r0-r2, R10-R12, lr" + + MOV R12, #IOC + + MOV r2, #IOC + MOV r0, #32 + BL DoMicroDelay ; quick thumb twiddle until it's REALLY there + LDRB R11, KARTRx ; read byte transmitted by keyboard + + [ KeyboardDebungling + Push R12 + MOV R12, R11, LSR #4 + TubeChar R10, R11, "MOV R11, #""R""" + TubeChar R10, R11, "ADD R11, R12, #""0""" + AND R12, R11, #&F + TubeChar R10, R11, "ADD R11, R12, #""0""" + Pull R12 + ] + + CMP R11, #HRDRESET ; first check for part of reset sequence and reply accordingly + + BEQ fartaboutfornewkbd + + CMP R11, #RST1ACK + MOVEQ R10, #RST2ACK + BEQ send_ack_byte + + CMP R11, #RST2ACK + BNE keytransmission + + MOV R10, #InitKbdWs + LDR R10, [R10, #KeyDataPtr] + CMP R10, #0 + MOVNE R10, #ACK+SCAN + BNE send_ack_byte + MOV R10, #ACK + + [ KeyboardDebungling + Push R12 + MOV R12, R10, LSR #4 + TubeChar R10, R11, "MOV R11, #""k""" + TubeChar R10, R11, "ADD R11, R12, #""0""" + AND R12, R10, #&F + TubeChar R10, R11, "ADD R11, R12, #""0""" + Pull R12 + ] + + STRB R10, KARTTx + BL PollTxBit + MOV R11, #K1rqid + BL SendAndPollRxBit + + [ Keyboard_Type = "A1A500" + AND r10, r11, #&F0 + CMP R11, #IDTYPE ; a500 kbd? + ADREQ R10, DataA500Kbd + BEQ gotkbdid + ] + SUB r11, r11, #K1kbid + 1 + CMP r11, #30 + ADRLSL R10, DataA1Kbd ; only accept ID 1-31 + MOVHI R10, #0 ; else don't know + +gotkbdid + MOV R11, #InitKbdWs + STR R10, [R11, #KeyDataPtr] + [ Keyboard_Type = "A1A500" + ASSERT (DataA1Kbd :AND: 255) <> 0 + ] + [ Keyboard_Type = "A1A500" + ASSERT (DataA500Kbd :AND: 255) <> 0 + ] + STRB R10, [R11, #KB_There_Flag] + ; only there once ID understood + MOV R10, #HRDRESET ; and from the top + B send_ack_byte + +keytransmission +; assume it's key info + MOV R10, #InitKbdWs + LDRB R10, [R10] ; the "had a byte" flag + CMP R10, #0 + BNE hadabyteofkey + MOV R10, #InitKbdWs + STRB R11, [R10] ; first part of 2 byte protocol: set flag + MOV R10, #ACK+&F + B send_ack_byte + +fartaboutfornewkbd + +kickitagain + MOV R11, #HRDRESET + BL SendAndPollRxBit ; get a byte to R11 + BL PollTxBit + CMP R11, #HRDRESET + BNE kickitagain + MOV R11, #RST1ACK + BL SendAndPollRxBit ; get a byte to R11 + BL PollTxBit + CMP R11, #RST1ACK + BNE kickitagain + MOV R10, #RST2ACK + B send_ack_byte + +hadabyteofkey +; now got 1st byte in R10, second byte in R11 : test for CTRL or R + MOV R0, #InitKbdWs + LDR R0, [R0, #KeyDataPtr] +10 LDRB R1, [R0], #1 + CMP R1, #0 + BEQ %FT11 + CMP R1, R10 + LDRB R1, [R0], #1 + CMPEQ R1, R11 + LDRB R1, [R0], #1 + BNE %BT10 + MOV R11, #InitKbdWs + STRB R1, [R11, R1] ; non-zero means pressed +11 + MOV R10, #ACK+SCAN +send_ack_byte + + [ KeyboardDebungling + Push R12 + MOV R12, R10, LSR #4 + TubeChar R10, R11, "MOV R11, #""T""" + TubeChar R10, R11, "ADD R11, R12, #""0""" + AND R12, R10, #&F + TubeChar R10, R11, "ADD R11, R12, #""0""" + Pull R12 + ] + + STRB R10, KARTTx ; assume always able to transmit? + CMP R10, #ACK+&F + MOVNE R11, #InitKbdWs + STRNEB R11, [R11] ; clear "one byte of 2 byte seq had" flag + + Pull "r0-r2, R10-R12, lr" + SUBS PC, R14, #4 + + DCD 0 ; temp fudge + + [ Keyboard_Type = "A1A500" + [ . :AND: 255 = 0 + DCB "S" ; Odd length, should throw us + ] +DataA1Kbd + = A1CTRLLRow, A1CTRLLCol, CTRL_Down_Flag + = A1CTRLRRow, A1CTRLRCol, CTRL_Down_Flag + = A1SHIFTRRow, A1SHIFTRCol, SHIFT_Down_Flag + = A1SHIFTLRow, A1SHIFTLCol, SHIFT_Down_Flag + = A1R_Row, A1R_Col, R_Down_Flag + = A1T_Row, A1T_Col, T_Down_Flag + = A1Del_Row, A1Del_Col, Del_Down_Flag + = A1Copy_Row, A1Copy_Col, Copy_Down_Flag + = 0 + ] + + [ Keyboard_Type = "A1A500" + [ . :AND: 255 = 0 + DCB "K" + ] +DataA500Kbd + = A500CTRLRow, A500CTRLCol, CTRL_Down_Flag + = A500SHIFTRow, A500SHIFTCol, SHIFT_Down_Flag + = A500R_Row, A500R_Col, R_Down_Flag + = A500T_Row, A500T_Col, T_Down_Flag + = A500Del_Row, A500Del_Col, Del_Down_Flag + = A500Copy_Row, A500Copy_Col, Copy_Down_Flag + = 0 + ] + + ALIGN + + LTORG + +PollTxBit ROUT + +01 LDRB R10, [R12, #IOCIRQSTAB] + TST R10, #KARTTxBit + BEQ %BT01 + MOV pc, lr + + +SendAndPollRxBit ROUT + + Push lr + + [ KeyboardDebungling + Push R12 + MOV R12, R11, LSR #4 + TubeChar R10, R11, "MOV R11, #""t""" + TubeChar R10, R11, "ADD R11, R12, #""0""" + AND R12, R11, #&F + TubeChar R10, R11, "ADD R11, R12, #""0""" + Pull R12 + ] + + STRB R11, KARTTx + +01 LDRB R10, [R12, #IOCIRQSTAB] + TST R10, #KARTRxBit + BEQ %BT01 + + MOV r2, #IOC + MOV r0, #32 + BL DoMicroDelay + LDRB R11, KARTRx ; purge KART, or get reply + + [ KeyboardDebungling + Push R12 + MOV R12, R11, LSR #4 + TubeChar R10, R11, "MOV R11, #""r""" + TubeChar R10, R11, "ADD R11, R12, #""0""" + AND R12, R11, #&F + TubeChar R10, R11, "ADD R11, R12, #""0""" + Pull R12 + ] + + Pull pc + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +SetUpKbd +; set up keyboard: initialise baud rate, send dummy, read dummy + MOV R12, #IOC ; code ripped off from pmf.Key + MOV R0, #1 + STRB R0, Timer3Low + MOV R0, #0 + STRB R0, Timer3High + STRB R0, Timer3Go ; baud rate set and going + + STRB R0, KARTTx ; send dummy + + MOV r1, r13 + MOV r13, #&8000 ; need a quick stack - scratchspace + Push r1 ; probably the best bet. + + MOV r0, #&800*2 ; magic delay + MOV r2, #IOC + BL DoMicroDelay + + LDMFD r13, {r13} ; finished with stack + + LDRB R0, KARTRx ; ensure no wally byte in KARTRx + + BL PollTxBit + MOV R0, #HRDRESET ; start reset protocol + STRB R0, KARTTx + + B SetUpKbdReturn + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +KeyboardDebungling SETL {FALSE} + + END diff --git a/s/KbdResPC b/s/KbdResPC new file mode 100644 index 0000000000000000000000000000000000000000..4bd1ddd92b7e57a8a398724bfab89b89813bd772 --- /dev/null +++ b/s/KbdResPC @@ -0,0 +1,187 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > KbdResPC + +; This file contains the minimal PC keyboard control stuff that the kernel does on reset. +; The only two hooks in this file used externally are IRQ_Test_CTRL_or_R_Pressed +; and SetUpKbd. + +; For now, use development podule in slot 0. + [ IO_Type = "IOMD" +IOBase * IOMD_Base +IOData * IOCSERTX +IOStatus * IOMD_KBDCR +IOControl * IOMD_KBDCR +stat_RXF * IOMD_KBDCR_RxF +stat_TXE * IOMD_KBDCR_TxE +ctl_Enable * IOMD_KBDCR_Enable +ctl_EnableIRQ * 0 ; not needed on IOMD + | +IOBase * &03000000 +IOData * 0 +IOStatus * 4 +IOControl * 4 +stat_RXF * &20 +stat_TXE * &80 +ctl_Enable * &08 +ctl_EnableIRQ * &80 + ] + + +; PC keyboard codes we are interested in. +PCReset * &AA +PCSpecial * &E0 +PCCTRLL * &14 +PCCTRLR * &14 ; Preceded by &E0 +PCSHIFTL * &12 +PCSHIFTR * &59 +PCR * &2D +PCT * &2C +PCDelete * &71 ; Preceded by &E0 +PCEnd * &69 ; Preceded by &E0 + +KeyData + DCB PCCTRLL, CTRL_Down_Flag + DCB PCSHIFTL, SHIFT_Down_Flag + DCB PCSHIFTR, SHIFT_Down_Flag + DCB PCR, R_Down_Flag + DCB PCT, T_Down_Flag + DCB 0 + ALIGN + +SpecialData + DCB PCCTRLR, CTRL_Down_Flag + DCB PCDelete, Del_Down_Flag + DCB PCEnd, Copy_Down_Flag + DCB 0 + ALIGN + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +SetUpKbd + MOV r0, #IOBase + MOV r1, #ctl_Enable + ctl_EnableIRQ + STRB r1, [r0, #IOControl] +10 + LDRB r1, [r0, #IOStatus] + TST r1, #stat_TXE + MOVNE r1, #&FF + STRNEB r1, [r0, #IOData] + BEQ %BT10 + + [ MorrisSupport + LDRB R1, [R0, #IOMD_ID0] ;Are we running on Morris + CMP R1, #&98 + LDRB R1, [R0, #IOMD_ID1] + CMPEQ R1, #&5B + BNE %FT30 ;NE: no, assume IOMD, so only one PS2 port + + MOV R1, #IOMD_MSECR_Enable ;yes, so initialise 2nd PS2 (mouse) port cos + STRB R1, [R0, #IOMD_MSECR] ;keyboard may be connected there instead +20 + LDRB R1, [R0, #IOMD_MSECR] + TST R1, #IOMD_MSECR_TxE ;Is port ready to accept data + MOVNE R1, #&FF ;NE: port ready, so send 'reset' command + STRNEB R1, [R0, #IOMD_MSEDAT] ; + BEQ %BT20 ;EQ: loop til port ready + + MOV R1, #IOMD_MouseRxFull_IRQ_bit + STRB R1, [R0, #IOMD_IRQMSKD] + + MOV R0, #InitKbdWs + MOV R1, #2 + STRB R1, [R0, #Port2Present] +30 + ] + MOV r0, #InitKbdWs + ADR r1, KeyData + STR r1, [r0, #KeyDataPtr] + + B SetUpKbdReturn + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +; On ARM600, this routine must work in IRQ32 mode + +IRQ_Test_CTRL_or_R_Pressed ROUT + [ CPU_Type = "ARM600" + BIC pc, pc, #&FC000000 ; take us out of the shadow ROM area + NOP ; (this instruction skipped) + ] + SUB lr, lr, #4 + Push "r0-r2,lr" + + MOV r2, #IOBase + [ MorrisSupport + MOV lr, #InitKbdWs + LDRB r1, [lr, #Port2Present] ;Check if 2nd PS2 port (in Morris) is available + TEQ r1, #0 + + LDRNEB r0, [r2, #IOMD_MSECR] ;NE: yes, so check if interrupt is from it + TSTNE r0, #IOMD_MSECR_RxF ; + LDRNEB r2, [r2, #IOMD_MSEDAT] ;NE: 2nd port present and interrupting, get scan code + MOVNE r1, #2 ;NE: indicate which port + BNE %FT5 ;NE: process it + ;EQ: 2nd port not present or interrupting + ; drop through and check 1st port + ] + LDRB r0, [r2, #IOStatus] + TST r0, #stat_RXF ; If not keyboard then + Pull "r0-r2,pc",EQ,^ ; exit. + + LDRB r2, [r2, #IOData] ; Get scan code. + + [ MorrisSupport + MOV r1, #1 +5 + LDRB r0, [lr, #KB_There_Flag] + + TEQ r2, #0 ;Assume that zero is the end of a mouse AA 00 start up + BICEQ r0, r0, r1 ; sequence, so clear keyboard present indication. + STREQB r0, [lr, #KB_There_Flag] + Pull "r0-r2,pc",EQ,^ ; and exit + + ORRNE r0, r0, r1 ;Not zero, mark keyboard present + ] + + MOV lr, #InitKbdWs + + STRB r0, [lr, #KB_There_Flag] ; Keyboard must be there (r0<>0 from above). + + ADR r1, SpecialData + + TEQ r2, #PCSpecial ; If special code then + STREQ r1, [lr, #KeyDataPtr] ; switch tables + Pull "r0-r2,pc",EQ,^ ; and exit. + + LDR r0, [lr, #KeyDataPtr] ; Get pointer to current table. + + TEQ r0, r1 ; Only use special table once, then + ADREQ r1, KeyData ; switch back to normal table. + STREQ r1, [lr, #KeyDataPtr] +10 + LDRB r1, [r0], #2 ; Get key code from table. + TEQ r1, #0 ; If at end of table then + Pull "r0-r2,pc",EQ,^ ; ignore key. + + TEQ r1, r2 ; If not this key then + BNE %BT10 ; try the next. + + LDRB r1, [r0, #-1] ; Get flag. + STRB r1, [lr, r1] ; Non-zero means pressed. + + Pull "r0-r2,pc",,^ + + END diff --git a/s/Kernel b/s/Kernel new file mode 100644 index 0000000000000000000000000000000000000000..9f15fbb54727d2c6141e3be4c7b56280b0977262 --- /dev/null +++ b/s/Kernel @@ -0,0 +1,1315 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + TTL => Kernel : SWI Despatch, simple SWIs + SUBT Arthur Variables + OPT 4 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; handy macros: +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + MACRO +$l CheckSpaceOnStack $space, $faildest, $tmp + [ True ; SKS +$l MOV $tmp, sp, LSR #15 ; Stack base on 32K boundary + SUB $tmp, sp, $tmp, LSL #15 ; Amount of stack left + CMP $tmp, #$space ; Must have at least this much left + BMI $faildest + | +$l MOV $tmp, #32*1024 ; assume stack ends at next 32K boundary + SUB $tmp, $tmp, #1 + AND $tmp, $tmp, stack + CMP $tmp, #$space + BLT $faildest + ] + MEND + + MACRO + assert $condition + [ :LNOT: ($condition) + ! 1,"Assert failed: $condition" + ] + MEND + +; one that builds a module command table entry: +; set Module_BaseAddr to module base before use. + + GBLA Module_BaseAddr +Module_BaseAddr SETA 0 + +; Command $cmd, $max, $min - declared in hdr.macros. + +; debug macro: set the border colour + + MACRO +$l SetBorder $reg1, $reg2, $red, $green, $blue, $delay + ! 0, "Setborder used" +$l LDR $reg1, =VIDC + [ VIDC_Type = "VIDC20" +; Note $reg, $green and $blue are 4 bit values + LDR $reg2, =&40000000+(($red)*&11)+(($green)*&1100)+(($blue)*&110000) + | + LDR $reg2, =&40000000+ $red + $green *16 + $blue *256 + ] + STR $reg2, [$reg1] + [ "$delay"<>"" + MOV $reg1, #$delay +10 + SUBS $reg1, $reg1, #1 + BNE %BT10 + ] + MEND + + [ AddTubeBashers + [ TubeType = Tube_Normal +DebugTUBE * &03340000+3*&4000 ; tube in podule #3 +; Tube register offsets + ^ 0 +R1STAT # 4 +R1DATA # 4 + | +DebugTUBE * &03000000 ; simulator tube address +R1DATA * 0 + ] + ] + +; routine to stuff a char down the Tube +; should be inside above conditional, but AAsm winges pitifully. + MACRO +$l TubeChar $reg1, $reg2, $charset, $stackthere + ! 0, "TubeChar used." +$l + [ "$stackthere"="" + Push "$reg1, $reg2" + ] + LDR $reg1, =DebugTUBE + [ TubeType = Tube_Normal ; normal tubes have status register, simulator one doesn't +01 LDRB $reg2, [$reg1, #R1STAT] + TST $reg2, #&40 + BEQ %BT01 + ] + $charset + STRB $reg2, [$reg1, #R1DATA] + [ "$stackthere"="" + Pull "$reg1, $reg2" + ] + MEND + + MACRO +$l TubeString $reg1, $reg2, $reg3, $string, $cc + LDR $reg1, =DebugTUBE + ADR $reg2, %FT20 +10 + [ TubeType = Tube_Normal + LDRB $reg3, [$reg1, #R1STAT] + TST $reg3, #&40 + BEQ %BT10 + ] + + LDRB $reg3, [$reg2], #1 + TEQ $reg3, #0 + STRNEB $reg3, [$reg1, #R1DATA] + BNE %BT10 + B %FT30 +20 + = "$string" + [ "$cc" = "" + = 10, 13 + ] + = 0 + ALIGN +30 + MEND + + MACRO +$l TubeDumpNoStack $dump, $t1, $t2, $t3 +$l MOV $t1, #7 +01 + ADRL $t2, HexTable + TubeChar $t3, $t2, "LDRB $t2, [$t2, $dump, LSR #28]", NoStack + MOV $dump, $dump, ROR #28 + SUBS $t1, $t1, #1 + BPL %BT01 + TubeChar $t3, $t2, "MOV $t2, #"" """, NoStack + MEND + + MACRO +$l TubeNewlNoStack $t1, $t2 +$l TubeChar $t1, $t2, "MOV $t2, #10", NoStack + TubeChar $t1, $t2, "MOV $t2, #13", NoStack + MEND + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Various constants +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +MinAplWork * 40*1024 ; minimum size of AplWork + +; Fixed addresses + +MEMCADR * &3600000 +ROM * &3800000 +OSMD * &11111111 + + [ MEMC_Type = "IOMD" +VideoPhysRam * &02000000 ; Amazing - it's in the same place! +DRAM0PhysRam * &10000000 ; 4 DRAM banks +DRAM1PhysRam * &14000000 +DRAM2PhysRam * &18000000 +DRAM3PhysRam * &1C000000 +DRAMBaseAddressMask * &1C000000 ; used to mask off bits after stealing video RAM +PhysSpaceSize * &20000000 ; IOMD physical map is 512M big +PhysROM * &00000000 ; and real ROM starts at 0 +SAMLength * 512*4 ; SAM length in bytes for 1 bank of VRAM +EASISpacePhys * &08000000 +EASISpace * PhysSpace + EASISpacePhys + | +VideoPhysRam * &02000000 +PhysSpaceSize * &04000000 ; MEMC1 physical map is 64M big +PhysROM * &03800000 +PhysRamPhys * &02000000 ; physical space starts here + ] + +; Manifests + +CR * 13 +LF * 10 +space * " " + +; Registers + +SPIRQ RN R13 + +; Callback byte bits: +CBack_OldStyle * 1 +CBack_Postpone * 2 +CBack_VectorReq * 4 + +; Set up symbols for the SWIs which aren't really there yet + + [ :LNOT: ModeSelectors +ScreenModeSWI * NoSuchSWI + ] + [ :LNOT: NewCDA +DynamicAreaSWI * NoSuchSWI + ] +AbortTrapSWI * NoSuchSWI + + SUBT Arthur Code + OPT 4 + +; ***************************************************************************** +; +; Now ready to start the code: off we go! +; +; ***************************************************************************** + + ORG ROM + + GBLS DoMorrisROMHeader + + [ MorrisSupport +DoMorrisROMHeader SETS " GET s.Morris" + | +DoMorrisROMHeader SETS "" + ] + +; now include the test code, if there is any + + GBLS DoTestThings + + [ IncludeTestSrc +DoTestThings SETS " GET TestSrc.Begin" + | +DoTestThings SETS "" + ] + $DoTestThings + + [ IncludeTestSrc +DoMorrisROMHeader SETS "" + ] + + $DoMorrisROMHeader + + [ ProcessorVectors + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; If there is no test code then we want a branch table at the start of ROM to +; handle reset and any aborts etc. in the reset code. +; If MorrisSupport we've already generated 16/32 ROM entry code, so skip this bit + + [ :LNOT: IncludeTestSrc :LAND: :LNOT: MorrisSupport + [ ResetIndirected + LDR pc, .+ResetIndirection ; load PC, PC relative + | + [ MEMC_Type = "IOMD" + B CONT ; PhysROM is at zero on IOMD + | + B MOSROMVecs+CONT ; executed out of ROM or RAM + ] + ] + B UndInstInReset + B SWIInReset + B PrefAbInReset + B DataAbInReset + B AddrExInReset + B IRQInReset + +UndInstInReset + SUB pc, pc, #8 +SWIInReset + SUB pc, pc, #8 +PrefAbInReset + SUB pc, pc, #8 +DataAbInReset + SUB pc, pc, #8 +AddrExInReset + SUB pc, pc, #8 +IRQInReset + SUB pc, pc, #8 + ] + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; This bit (up to EndFiq) is copied to location 0. Processor vectors are +; indirected through 0 page locations so that they can be claimed using +; OS_ClaimProcessorVector. IRQs are initially handled by a branch so that the +; keyboard can be handled during reset but the branch is replaced with a load +; PC, PC relative later on. + +MOSROMVecs + LDR pc, MOSROMVecs+ProcVec_Branch0 + LDR pc, MOSROMVecs+ProcVec_UndInst + LDR pc, MOSROMVecs+ProcVec_SWI + LDR pc, MOSROMVecs+ProcVec_PrefAb + LDR pc, MOSROMVecs+ProcVec_DataAb + LDR pc, MOSROMVecs+ProcVec_AddrEx + B MOSROMVecs+IRQ_Test_CTRL_or_R_Pressed + + MOV r10, #IOC ; we dunno what to do with it - + ; so cut it off - right off! + STRB r10, [r10, #IOCFIQMSK] ; :LSB: IOC = 0 + SUBS pc, r14, #4 +EndFiq + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; This is the table of default processor vectors which is copied to 0 page. + +DefaultProcVecs + & RESET1 + & UndPreVeneer + & SVC + & PAbPreVeneer + & DAbPreVeneer + & AdXPreVeneer + & Initial_IRQ_Code + + ASSERT (.-DefaultProcVecs) = ProcVec_End-ProcVec_Start + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; These are preveneers which must be copied to 0 page locations so that the +; relevant handler can be branched to. This is mainly for non-ARM600 platforms +; although the address exception preveneer (which should not actually be required +; on ARM600) is always copied. + +DefaultPreVeneers + [ CPU_Type <> "ARM600" +UndPreVeneer * ProcVecPreVeneers+(.-DefaultPreVeneers) + LDR PC, DefaultPreVeneers-ProcVecPreVeneers+UndHan +PAbPreVeneer * ProcVecPreVeneers+(.-DefaultPreVeneers) + LDR PC, DefaultPreVeneers-ProcVecPreVeneers+PAbHan +DAbPreVeneer * ProcVecPreVeneers+(.-DefaultPreVeneers) + LDR PC, DefaultPreVeneers-ProcVecPreVeneers+DAbHan + | + DCD 0 + DCD 0 + DCD 0 + ] +AdXPreVeneer * ProcVecPreVeneers+(.-DefaultPreVeneers) + LDR PC, DefaultPreVeneers-ProcVecPreVeneers+AdXHan + + ASSERT (.-DefaultPreVeneers) = ProcVecPreVeneersSize + + | + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; The bit to copy to 0 +; - if no test software present, then it's at the start of the ROM and will get +; executed out of ROM, or from the RAM copy later on +; - if test software is present, then it's not at the start of the ROM, so the +; code will only work when copied to 0! + +MOSROMVecs + [ ResetIndirected + LDR pc, MOSROMVecs+ResetIndirection ; load PC, PC relative + | + [ MEMC_Type = "IOMD" + B CONT ; PhysROM is at zero on IOMD + | + B MOSROMVecs+CONT ; executed out of ROM or RAM + ; or not at all if test software present + ] + ] + + [ CPU_Type = "ARM600" + B MOSROMVecs+UndPreVeneer + B MOSROMVecs+SVC + B MOSROMVecs+PAbPreVeneer + B MOSROMVecs+DAbPreVeneer + | + LDR PC, MOSROMVecs+UndHan + B MOSROMVecs+SVC + LDR PC, MOSROMVecs+PAbHan + LDR PC, MOSROMVecs+DAbHan + ] + LDR PC, MOSROMVecs+AdXHan + B MOSROMVecs+IRQ_Test_CTRL_or_R_Pressed + MOV R10, #IOC ; we dunno what to do with it - + ; so cut it off - right off! + STRB R10, [R10, #IOCFIQMSK] ; :LSB: IOC = 0 + SUBS PC, R14, #4 +EndFiq + + ] + + [ ResetIndirected :LAND: :LNOT: IncludeTestSrc + +; We now waste space until the offset into the ROM is the same as the RAM address of ResetIndirection +; This is so that +; a) on a reset, ROM is paged in at the bottom, so we jump to CONT, and +; b) on a break, RAM is paged in at the bottom, so we jump to CONT_Break + + ASSERT .-ROM <= ResetIndirection + % ResetIndirection-(.-ROM) + & CONT-ROM+PhysROM ; address of reset code in physical space + ] + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Now some initialised workspace/vectors that go at &100 + +; All the stuff from here to after the DirtyBranch instruction is read +; consecutively out of ROM, so don't put anything in between without changing +; the code + + +StartData + ASSERT IRQ1V = &100 + & DefaultIRQ1V + + ASSERT ESC_Status = IRQ1V+4 + & &00FF0000 ; IOCControl set to FF on reset + + ASSERT IRQsema = ESC_Status+4 + & 0 +EndData + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI return handler: checks callback + +SVCDespatcher ROUT + +SWIRelocation * SVCDespatcher-SWIDespatch + +SLVK_SetV * {PC}-SWIRelocation + + ORR lr, lr, #V_bit + +SLVK_TestV * {PC}-SWIRelocation + ! 0,"SLVK_TestV at ":CC:(:STR:SLVK_TestV) + + ORRVS lr, lr, #V_bit + +SLVK * {PC}-SWIRelocation + ! 0,"SLVK at ":CC:(:STR:SLVK) + + Pull r11 + TST lr, #V_bit + BNE %FT50 + +SWIReturn * {PC}-SWIRelocation + ! 0,"SWIReturn at ":CC:(:STR:SWIReturn) + +40 MOV r10, #0 + LDRB r11, [r10, #CallBack_Flag] + CMP r11, #0 + Pull "r10-r12", EQ + MOVEQS pc, lr + + B callback_checking + SWIRelocation + + + ! 0,"VSetReturn at ":CC:(:STR:({PC}-SWIRelocation)) +50 TST r11, #Auto_Error_SWI_bit + BNE %BT40 + + B VSet_GenerateError + SWIRelocation + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; The SWI Despatch routine + +SVC * {PC}-SWIRelocation + + [ CPU_Type = "ARM600" + +; For now, branch back up to ROM to perform ARM600 contortions + + B SVCARM600 + SWIRelocation + +SVCContinue * {PC}-SWIRelocation + + | + Push "r10-r12" + ] + + BIC r12, r14, #ARM_CC_Mask + LDR r11, [r12, #-4] + BIC r11, r11, #&FF000000 + Push r11 + BICS r11, r11, #Auto_Error_SWI_bit + BEQ SWIWriteC + SWIRelocation + + ORR r10, r14, #SVC_mode + TEQP r10, #0 ; restore caller's IRQ state + + CMP r11, #OS_BreakPt + CMPNE r11, #OS_CallAVector + BICNE r14, r14, #V_bit ; clear V unless BreakPoint/CallVector + + CMP r11, #OS_WriteI + LDRCC pc, [pc, r11, LSL #2] + + B NotMainMOSSwi + SWIRelocation + + ASSERT {PC}-SVCDespatcher = SWIDespatch_Size + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; The SWI table + +JTABLE & SWIWriteC ; this entry never gets used (see ^) + & SWIWriteS + & SWIWrite0 + & SWINewLine + +; next section is one where VectorNumber = SWINumber + & VecSwiDespatch ; readc + & VecSwiDespatch ; cli + & NoIrqVecSwiDespatch ; byte + & NoIrqVecSwiDespatch ; word + & VecSwiDespatch ; file + & VecSwiDespatch ; args + & BGetSWI ; bget + & BPutSWI ; bput + & VecSwiDespatch ; gbpb + & VecSwiDespatch ; find + & VecSwiDespatch ; readline + + & SCTRL + & SWI_GetEnv_Code + & SEXIT + & SSTENV + & SINTON + & SINTOFF + & SCALLB + & SENTERSWI + & SBRKPT + & SBRKCT + & SUNUSED + & SSETMEMC + & SSETCALL + & VecMouse + & HeapEntry + & ModuleHandler + & ClaimVector_SWICode + & ReleaseVector_SWICode + & ReadUnsigned_Routine + & GenEvent + & ReadVarValue + & SetVarValue + & GSINIT + & GSREAD + & GSTRANS + & CvtToDecimal + & FSControlSWI + & ChangeDynamicSWI + & GenErrorSWI + & ReadEscapeSWI + & ReadExpression + & SwiSpriteOp + & SWIReadPalette + & Issue_Service_SWI + & SWIReadVduVariables + & SwiReadPoint + & DoAnUpCall + & CallAVector_SWI + & SWIReadModeVariable + & SWIRemoveCursors + & SWIRestoreCursors + & SWINumberToString_Code + & SWINumberFromString_Code + & ValidateAddress_Code + & CallAfter_Code + & CallEvery_Code + & RemoveTickerEvent_Code + & InstallKeyHandler + & SWICheckModeValid + & ChangeEnvironment + & SWIClaimScreenMemory + & ReadMetroGnome + & XOS_SubstituteArgs_code + & XOS_PrettyPrint_code + & SWIPlot + & SWIWriteN + & Add_ToVector_SWICode + & WriteEnv_SWICode + & RdArgs_SWICode + & ReadRAMFSLimits_Code + & DeviceVector_Claim + & DeviceVector_Release + & Application_Delink + & Application_Relink + & HeapSortRoutine + & TerminateAndSodOff + & ReadMemMapInfo_Code + & ReadMemMapEntries_Code + & SetMemMapEntries_Code + & AddCallBack_Code + & ReadDefaultHandler + & SWISetECFOrigin + & SerialOp + & ReadSysInfo_Code + & Confirm_Code + & SWIChangedBox + & CRC_Code + & ReadDynamicArea + & SWIPrintChar + & ChangeRedirection + & RemoveCallBack + & FindMemMapEntries_Code + & SWISetColour + & NoSuchSWI ; Added these to get round OS_ClaimSWI and + & NoSuchSWI ; OS_ReleaseSWI (should not have been allocated here). + [ AssemblePointerV + & PointerSWI + | + & NoSuchSWI + ] + & ScreenModeSWI + & DynamicAreaSWI + & AbortTrapSWI + [ CPU_Type = "ARM600" + & MemorySWI + | + & NoSuchSWI + ] + [ ProcessorVectors + & ClaimProcVecSWI + | + & NoSuchSWI + ] + & PerformReset + [ CPU_Type = "ARM600" + & MMUControlSWI + | + & NoSuchSWI + ] + +MaxSwi * (.-JTABLE)/4 + + ASSERT MaxSwi < OS_ConvertStandardDateAndTime + +; SWIs for time/date conversion are poked in specially + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; The fudge branch to exit a dirty SWI handler + +DirtyBranch + B SLVK +DirtyBranch-BranchToSWIExit + +; All the stuff from MOSROMVecs to here is read consecutively out of ROM, +; so don't put anything in between without changing the code + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + [ CPU_Type = "ARM600" + +; in: SVC32_mode +; For now, only allow SWIs to be executed from below 64M + +SVCARM600 ROUT + Push "r10-r12" ; instruction normally done in SWI despatch area + mrs AL, r11, SPSR_all ; r11 = saved PSR + AND r12, r11, #&F0000003 ; get saved NZCV and 26 bit modes + ORR lr, lr, r12 + AND r12, r11, #I32_bit + F32_bit ; extract I and F from new place + ORR lr, lr, r12, LSL #IF32_26Shift ; lr = combined lr and psr + + SetMode SVC26_mode, r12 ; now switch into SVC26 + + B SVCContinue ; go back into the SWI despatch area + ] + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r10-r12 stacked, lr has bits for return + +VSet_GenerateError ROUT + + Push lr + MOV r1, #Service_Error + BL Issue_Service + + MOV r10, #ErrorV + BL CallVector ; Normally gets to default handler... + + Pull lr ; which raises error; otherwise just + BIC lr, lr, #V_bit ; return with V clear: error claimed! + B SWIReturn + + LTORG + +; ....................... default owner of ErrorV ............................. +; In r0 -> error in current error block + +; Out Exits to user's error handler routine as given by ErrHan +; r1-r9 possibly corrupt. Indeed r10-r12 MAY be duff ... eg. REMOTE + +ErrHandler ROUT + + BL OscliTidy ; close redirection, restore curr FS + + MOV r12, #0 + LDR r11, [r12, #ErrBuf] ; Get pointer to error buffer + + LDR sp_svc, =SVCSTK-4*4 ; Just below top of stack + ; Note gives WRONG pc if error + Pull r14 ; generated by any but bottom SWI + STR r14, [r11], #4 ; Return PC for error + + LDR r14, [r0], #4 ; Copy error number + STR r14, [r11], #4 + + ; Copy error string - truncating at 252 + MOV r10, #256-4 + +10 LDRB r14, [r0], #1 + SUBS r10, r10, #1 + MOVLS r14, #0 + STRB r14, [r11], #1 + TEQ r14, #0 + BNE %BT10 + + LDR r14, [r12, #ErrHan] ; And go to error handler + BIC r14, r14, #ARM_CC_Mask + STR r14, [r12, #Curr_Active_Object] + LDR r0, [r12, #ErrHan_ws] ; r0 is his wp + + LDRB r10, [r12, #CallBack_Flag] + CMP r10, #0 + + Pull "r10-r12", EQ + MOVEQS pc, r14 ; USR mode, IRQs enabled + + B Do_CallBack ; Can't need postponement, r0,r14 + ; such that callback code will normally + ; call error handler + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; check for CallBack possible + +callback_checking + + TST lr, #SVC_mode :OR: I_bit ; user mode, ints enabled? + Pull "r10-r12", NE + MOVNES pc, lr ; Skip the branch for SVC code speed + +; Further checks: postpone callback if returning V set and R0->RAM + + TST lr, #V_bit + BEQ Do_CallBack + TST r11, #CBack_Postpone ; only one postponement + BNE Do_CallBack ; allowed. + CMP r0, #32*1024*1024 + BGE Do_CallBack + + TEQP PC, #SVC_mode+I_bit ; ints off while flag updated + LDRB r11, [r10, #CallBack_Flag] + ORR r11, r11, #CBack_Postpone ; signal to IRQs + STRB r11, [r10, #CallBack_Flag] +back_to_user + Pull "r10-r12" + MOVS PC, lr + +Do_CallBack ; CallBack allowed: + TST r11, #CBack_VectorReq ; now process any vector entries + Push lr, NE + BLNE process_callback_chain + Pull lr, NE + + TST r11, #CBack_OldStyle + BEQ back_to_user + [ {TRUE} ; LRust, Fix RP-0609 +; Check that SVC_sp is empty (apart from r10-r12), i.e. system truly is idle + + LDR r11, =SVCSTK-3*4 ; What SVC_sp should be if system idle + CMP sp, r11 ; Stack empty? + BLO back_to_user ; No then no call back + ] + TEQP PC, #SVC_mode+I_bit ; ints off while flag updated + LDRB r11, [r10, #CallBack_Flag] + BIC r11, r11, #CBack_Postpone+CBack_OldStyle + STRB r11, [r10, #CallBack_Flag] + + MOV r12, #0 + LDR R12, [R12, #CallBf] + STR r14, [r12, #4*15] ; user PC + MOV r14, r12 + Pull "r10-r12" + STMIA r14, {r0-r14}^ ; user registers + + MOV R12, #CallAd_ws + LDMIA R12, {R12, PC} ; jump to CallBackHandler + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Also called from source.pmf.key, during readc + +process_callback_chain ROUT + + Push "r0-r6, r10-r12, lr" ; save some for the callee too. + MOV r10, #0 + + TEQP PC, #SVC_mode+I_bit ; ints off while flag updated + LDRB r11, [r10, #CallBack_Flag] + BIC r11, r11, #CBack_VectorReq + STRB r11, [r10, #CallBack_Flag] + + [ True + [ Fix15 + +; TMD 11-Sep-89; used to free the wrong node here - usually would try to free +; a null node, and claimed node would not get freed - however, if more than one +; request, then it could free the 2nd node before it was used. + +01 TEQP PC, #SVC_mode+I_bit ; ints off while head updated + MOV r2, #0 + LDR r2, [r2, #CallBack_Vector] + TEQ r2, #0 + Pull "r0-r6, r10-r12, PC",EQ,^ + + LDMIA r2, {r10, r11, r12} ; link, addr, r12 + MOV r0, #HeapReason_Free + STR r10, [r0, #CallBack_Vector-HeapReason_Free] ; Keep head valid + + TEQP PC, #SVC_mode ; enable ints for long bits + LDR r1, =SysHeapStart + SWI XOS_Heap + + MOV lr, pc + MOV pc, r11 ; call im, with given r12 + + B %BT01 ; loop + + | +01 TEQP PC, #SVC_mode+I_bit ; ints off while head updated + MOV r10, #0 + LDR r10, [r10, #CallBack_Vector] + TEQ r10, #0 + Pull "r0-r6, r10-r12, PC",EQ,^ + + LDMIA r10, {r2, r11, r12} ; link, addr, r12 + MOV r0, #HeapReason_Free + STR r2, [r0, #CallBack_Vector-HeapReason_Free] ; Keep head valid + + TEQP PC, #SVC_mode ; enable ints for long bits + LDR r1, =SysHeapStart + SWI XOS_Heap + + MOV lr, pc + MOV pc, r11 ; call im, with given r12 + + B %BT01 ; loop + + ] + | ; old one + + TEQP PC, #SVC_mode + + LDR r10, [r10, #CallBack_Vector] +01 MOV r2, r10 ; for freeing + LDMIA r10, {r10, r11, r12} ; link, addr, r12 + MOV r0, #HeapReason_Free + STR r10, [r0, #CallBack_Vector-HeapReason_Free] + LDR r1, =SysHeapStart + SWI XOS_Heap + MOV lr, pc + MOV pc, r11 ; call im + CMP r10, #0 + BNE %BT01 + Pull "r0-r6, r10-r12, PC",,^ + ] + + LTORG + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_WriteC + +; In r11 = 0 (look, up there ^) ! + +SWIWriteC ROUT + + TEQP pc, #SVC_mode ; enable interrupts + + BIC lr, lr, #V_bit ; clear caller's V cos we didn't before + Push lr + + LDR r11, [r11, #VecPtrTab+WrchV*4] ; load top node pointer + CMP r11, #ROM + Push pc, CS ; push address of ReturnFromVectoredWrch + BCS PMFWrchDirect + BCC WrchThruVector + +ReturnFromVectoredWrch + Pull lr + B SLVK_TestV + + +WrchThruVector + MOV r10, #WrchV + BL CallVector + B ReturnFromVectoredWrch + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +SWINewLine ROUT + + MOV r11, lr + SWI XOS_WriteI+10 + SWIVC XOS_WriteI+13 + MOV lr, r11 + B SLVK_TestV + +; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_WriteI+n + +SWIWriteI ROUT + + MOV r10, r0 + AND r0, r11, #&FF + MOV r11, lr ; NB. Order !!! + SWI XOS_WriteC + MOVVC r0, r10 + MOV lr, r11 + B SLVK_TestV ; return setting V + +; ............................................................................. +; define module SWI node format + +ModSWINode_CallAddress * 0 +ModSWINode_MListNode * 4 +ModSWINode_Link * 8 +ModSWINode_Number * 12 +ModSWINode_Size * 16 ; not a field - the node size! + + MACRO +$l ModSWIHashvalOffset $swino, $startreg + [ "$startreg"="" +$l MOV $swino, $swino, LSR #4 + | +$l MOV $swino, $startreg, LSR #4 + ] + AND $swino, $swino, #ModuleSHT_Entries*4-1 + MEND + + MACRO +$l ModSWIHashval $swino, $startreg +$l ModSWIHashvalOffset $swino, $startreg + ADD $swino, $swino, #ModuleSWI_HashTab + MEND + + + +NotMainMOSSwi ; Continuation of SWI despatch + + CMP R11, #&200 + BCC SWIWriteI + +; ............................................................................. +; Look round RMs to see if they want it + +ExtensionSWI ROUT + + Push "r9, lr" ; first construct the link to pass on. + AND r10, lr, #&FC000000 ; copy in user CCodes (inc. IRQ state) + ADR lr, %FT02 + SVC_mode + ORR lr, lr, r10 + + BIC r12, r11, #Module_SWIChunkSize-1 +; BIC r12, r12, #Auto_Error_SWI_bit ; r11 already has this bit knocked off + ModSWIHashvalOffset r10, r12 + LDR r10, [r10, #ModuleSWI_HashTab] +loopoverhashchain + CMP r10, #0 + BEQ VectorUserSWI + LDR r9, [r10, #ModSWINode_Number] + CMP r9, r12 + LDRNE r10, [r10, #ModSWINode_Link] + BNE loopoverhashchain + + LDMIA r10, {r10, r12} + LDR r12, [r12, #Module_incarnation_list] ; preferred life + CMP r12, #0 + + [ FixR9CorruptionInExtensionSWI + Pull "r9", NE ; restore corrupted r9 before calling SWI handler + ;RCM added 'NE' above to fix MED=04655 + ] + + ANDNE r11, r11, #Module_SWIChunkSize-1 + ADDNE r12, r12, #Incarnation_Workspace + MOVNE pc, r10 + + +VectorUserSWI ; Not in a module, so call vec + [ FixR9CorruptionInExtensionSWI + Pull "r9" ; restore corrupted r9 before calling UKSWIV + ] + MOV r10, #UKSWIV ; high SWI number still in R11 + B CallVector ; lr still has user CCs & points at%FT02 + + +02 + [ FixR9CorruptionInExtensionSWI + Pull "lr" ; r9 already pulled off stack before calling SWI handler or UKSWIV + | + Pull "r9,lr" + ] + BIC lr, lr, #&F0000000 ; Can mangle any/all of punter flags + MOV r10, pc, LSR #(32-4) + ORR lr, lr, r10, LSL #(32-4) + B SLVK + +; ....................... default owner of UKSWIV ............................. +; Call UKSWI handler +; Also used to call the upcall handler + +; In r12 = HiServ_ws (or UpCallHan_ws) + +CallUpcallHandler +HighSWI ROUT ; no one on vec wants it: give to handler + + Pull lr ; the link pointing at %BT02 to pass in. + LDMIA r12, {r12, pc} + +; ........................ default UKSWI handler .............................. + +NoSuchSWI ROUT + + Push lr + BL NoHighSWIHandler + Pull lr + B SLVK_SetV + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +NoHighSWIHandler ROUT + + MOV r0, #0 + LDR r0, [r0, #IRQsema] + CMP r0, #0 + ADR r0, ErrorBlock_NoSuchSWI ; Must return static error here + ORRNES pc, lr, #V_bit + +; Not in IRQ: can safely build a dynamic error + + [ International + Push "r1-r4, lr" + SUB sp, sp,#12 + MOV r1, sp + MOV r2, #12 + MOV r0, r11 + SWI XOS_ConvertHex6 ; SWI argument is 00xxxxxx + + MOV r4, r0 ; now strip leading 0s +02 LDRB r2, [r4], #1 + CMP r2, #"0" + BEQ %BT02 + + SUB r4,r4,#1 + ADR r0, ErrorBlock_NoSuchSWI1 + BL TranslateError_UseR4 + ADD sp,sp,#12 + + Pull "r1-r4, lr" + ORRS pc, lr, #V_bit + + MakeErrorBlock NoSuchSWI1 + + | + Push "r1-r3, lr" + LDR r1, =EnvString + LDMIA r0!, {r2, r3} ; number, "SWI " + STMIA r1!, {r2, r3} + MOV r2, #"&" + STRB r2, [r1], #1 + MOV r3, r0 + MOV r0, r11 + MOV r2, #256 + SWI XOS_ConvertHex6 ; SWI argument is 00xxxxxx + +; now strip leading 0s + + MOV r1, r0 +02 LDRB r2, [r1], #1 + CMP r2, #"0" + BEQ %BT02 + CMP r2, #0 + ADDEQ r1, r0, #1 + BEQ %FT03 +04 STRB r2, [r0], #1 + LDRB r2, [r1], #1 + CMP r2, #0 + BNE %BT04 + MOV r1, r0 +03 MOV r2, #" " +01 STRB r2, [r1], #1 + CMP r2, #0 + LDRNEB r2, [r3], #1 + BNE %BT01 + + Pull "r1-r3, lr" + LDR r0, =EnvString + ORRS pc, lr, #V_bit + ] + + MakeErrorBlock NoSuchSWI + + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Fast SWI handlers for BGet and BPut caches + +BGetSWI ROUT ; Done separately for highest speed + + [ {FALSE} ; Kernel now divorced from FileSwitch + Push lr + LDR r12, =VecPtrTab + LDR r10, [r12, r11, LSL #2] ; Load top node pointer for vector + CMP r10, #ROM + BCC BGetThruVector + +; Cache technology deemed to be ok (ensures consistent with ROM FileSwitch) + + LDMIB r10, {wp} ; Get wp from vector node + + ASSERT :INDEX: BGet_shiftedbase = 0 + ASSERT :INDEX: BGet_bufferdata = 4 + ASSERT :INDEX: BGet_scb = 8 + ASSERT :INDEX: BGet_shift = 12 + ASSERT :INDEX: BGet_handle = 16 + LDMIA wp, {r0, r10, r11, r12, r14} ; Get cached data + TEQ r14, r1 ; BGet on cached handle ? + LDREQ r14, [r11, #:INDEX: scb_fileptr] ; Check fileptr in that buffer + TEQEQ r0, r14, LSR r12 + LDREQB r0, [r10, r14] ; Get byte from buffer + ADDEQ r14, r14, #1 + STREQ r14, [r11, #:INDEX: scb_fileptr] ; Increment fileptr + Pull lr, EQ ; Punter lr has VClear + BICEQ lr, lr, #C_bit ; CClear -> ~EOF + BEQ SLVK + +BGetThruVector + | + Push lr + ] + MOV r10, #BGetV ; Cache hit failed, call victor + BL CallVector + Pull lr ; Punter lr has VClear + BIC lr, lr, #C_bit ; Copy C,V to punter lr + ORRCS lr, lr, #C_bit + B SLVK_TestV + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +BPutSWI ROUT ; Done separately for highest speed + + [ {FALSE} ; Kernel now divorced from FileSwitch + Push "r9, lr" ; Needs one other temp register + LDR r12, =VecPtrTab + LDR r10, [r12, r11, LSL #2] ; Load top node pointer for vector + CMP r10, #ROM + BCC BPutThruVector + +; Cache technology deemed to be ok (ensures consistent with ROM FileSwitch) + + LDMIB r10, {wp} ; Get wp from vector node + ; NB. This is not normal wp +; BPut_shiftedbase ; r9 + ASSERT BPut_bufferdata = BPut_shiftedbase + 4 ; r10 + ASSERT BPut_scb = BPut_shiftedbase + 8 ; r11 + ASSERT BPut_shift = BPut_shiftedbase + 12 ; r12 + ASSERT BPut_handle = BPut_shiftedbase + 16 ; r14 + LDMIA wp, {r9, r10, r11, r12, r14} ; Get cached data + TEQ r14, r1 ; BPut on cached handle ? + LDREQ r14, [r11, #:INDEX: scb_fileptr] ; Check fileptr in that buffer + TEQEQ r9, r14, LSR r12 + STREQB r0, [r10, r14] ; Put byte to buffer + ADDEQ r14, r14, #1 + STREQ r14, [r11, #:INDEX: scb_fileptr] ; Increment fileptr + Pull "r9, lr", EQ ; Destack punter r9 and lr(VC) + BEQ SLVK + +BPutThruVector + MOV r10, #BPutV ; Cache hit failed, call victor + BL CallVector + Pull "r9, lr" ; Destack punter r9 and lr(VC) + B SLVK_TestV + | + Push "lr" + MOV r10, #BPutV ; Cache hit failed, call victor + BL CallVector + Pull "lr" ; Destack lr(VC) + B SLVK_TestV + ] + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI handlers for all the vectored SWIs that have vecnum=swinum + +; All defined to affect C & V at most + +FSControlSWI ROUT + + MOV r11, #FSCV ; Pretend to be vecnum = swinum swi + ; and just drop through to ... + +VecSwiDespatch ROUT + + Push lr ; this is user's link + MOV r10, r11 ; SWI number from R11->R10 + ORR r14, lr, #SVC_mode + BIC r14, r14, #I_bit ; Enable IRQs + TEQP r14, #0 + BL CallVector + +; So the vectored routine can update the pushed link CCodes if wanted +; No update return is therefore LDMIA stack!, {PC}^ (sort of) +; Update return pulls lr, molests it, then MOVS PC, lr +; Note either return enables IRQ, FIQ + +; ???? Is the DEFAULT owner allowed to corrupt r10,r11 IFF he claims it ???? + + Pull lr ; Punter lr has VClear + BIC lr, lr, #C_bit ; Copy C,V to punter lr + ORRCS lr, lr, #C_bit + B SLVK_TestV + + +NoIrqVecSwiDespatch ROUT + + Push lr ; this is user's link + MOV r10, r11 ; SWI number from R11->R10 + ORR r14, lr, #SVC_mode+I_bit ; Disable IRQ + TEQP r14, #0 + BL CallVector + Pull lr ; Punter lr has VClear + BIC lr, lr, #C_bit ; Copy C,V to punter lr + ORRCS lr, lr, #C_bit + B SLVK_TestV + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_GetEnv + +SWI_GetEnv_Code ROUT + + LDR r0, =EnvString + MOV r1, #0 + LDR r1, [r1, #MemLimit] + LDR r2, =EnvTime + B SLVK + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_Exit + +SEXIT ROUT + + BL OscliTidy ; shut redirection, restore FS + +; now see if it's an abort Exit + + LDR r12, ABEX + CMP r1, r12 + TSTEQ r0, #ARM_CC_Mask + MOVNE r2, #0 + MOV r12, #0 + STR r2, [r12, #ReturnCode] + LDR r12, [r12, #RCLimit] + CMP r2, r12 + SWIHI OS_GenerateError ; really generate an error + + Pull "r9-r12" ; junk R9 + MOV r0, #0 + LDR lr, [r0, #SExitA] + STR lr, [r0, #Curr_Active_Object] + LDR r12, [r0, #SExitA_ws] + LDR sp_svc, =SVCSTK + BICS pc, lr, #ARM_CC_Mask + +ABEX = "ABEX" ; Picked up as word + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_CallBack: Set/read callback buffer and handler + +SCALLB MOV r10, #CallBackHandler + +handlecomm + Push "r2, r3, lr" + MOV r3, r0 ; buffer + MOV r0, r10 + BL CallCESWI + MOV r0, r3 + Pull "r2, r3, lr" + B SLVK_TestV + +; ............................................................................. +; SWI OS_BreakSet: Set/read breakpoint buffer and handler + +SBRKCT MOV r10, #BreakPointHandler + B handlecomm + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_ReadEscapeState + +ReadEscapeSWI ROUT + + MOV r10, #0 + LDRB r10, [r10, #ESC_Status] + TST r10, #1 :SHL: 6 + BICEQ lr, lr, #C_bit + ORRNE lr, lr, #C_bit + B SLVK + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_ServiceCall + +Issue_Service_SWI ROUT + + Push lr + BL Issue_Service + Pull lr + B SLVK + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_GenerateError + +GenErrorSWI * SLVK_SetV + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + END diff --git a/s/MEMC1 b/s/MEMC1 new file mode 100644 index 0000000000000000000000000000000000000000..2709f3201a43931d8b487ae4f412577e9e3442ea --- /dev/null +++ b/s/MEMC1 @@ -0,0 +1,571 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > MEMC1 + +; MEMC interface file - MEMC1 version + +; Created by TMD 10-Aug-90 + +VInit * &03600000 +VStart * &03620000 +VEnd * &03640000 +CInit * &03660000 +; SStart * &03680000 +; SEnd * &036A0000 +; SPtr * &036C0000 + +; ***************************************************************************** +; +; SetDAG - Program DMA address generator R1 with physical address R0 +; +; in: r0 = physical address +; r1 = index of DMA address generator to program, as defined in vdudecl +; +; out: All registers preserved, operation ignored if illegal +; + +SetDAG ENTRY "r0" + CMP r1, #MEMCDAG_MaxReason + EXIT HI + ADR r14, DAGAddressTable + LDR r14, [r14, r1, LSL #2] ; load base address in MEMC1 + MOV r0, r0, LSR #4 ; bottom 4 bits irrelevant + CMP r0, #(1 :SHL: 15) ; ensure in range + ORRCC r14, r14, r0, LSL #2 + STRCC r14, [r14] ; any old data will do + EXIT + + GBLA DAGIndex +DAGIndex SETA 0 + + MACRO + DAGTab $reason, $address + ASSERT ($reason)=DAGIndex + & $address +DAGIndex SETA DAGIndex + 1 + MEND + +DAGAddressTable + DAGTab MEMCDAG_VInit, VInit + DAGTab MEMCDAG_VStart, VStart + DAGTab MEMCDAG_VEnd, VEnd + DAGTab MEMCDAG_CInit, CInit + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; CAM manipulation utility routines + +BangCamUpdate ROUT + +; R2 = CAM entry no +; R3 = logaddr +; R9 = current MEMC value +; R11 = PPL +; set and update tables + + MOV R4, #0 + LDR R4, [R4, #CamEntriesPointer] + ORR r0, r3, r11, LSL #28 ; top nibble is PPL + STR r0, [R4, R2, LSL #2] + +BangCam + +; r0 corrupted +; r1 corrupted +; R2 = CAM entry no +; R3 = logaddr +; r4 corrupted +; r5 spare! +; r6 corrupted +; r7, r8 spare +; R9 = current MEMC value +; r10 spare +; R11 = PPL +; r12 spare + + AND R4, R9, #&C ; pagesize + ADR R0, PageMangleTable + LDR R0, [R0, R4] ; load data table pointer + MOV R4, #0 +01 LDR R1, [R0], #4 + CMP R1, #-1 + BEQ %FT02 + AND R6, R2, R1 + LDR R1, [R0], #4 + CMP R1, #0 + RSBMI R1, R1, #0 + ORRPL R4, R4, R6, LSL R1 + ORRMI R4, R4, R6, LSR R1 + B %BT01 + +02 LDR R1, [R0], #4 + CMP R1, #-1 + BEQ %FT03 + AND R6, R3, R1 + LDR R1, [R0], #4 + CMP R1, #0 + RSBMI R1, R1, #0 + ORRPL R4, R4, R6, LSL R1 + ORRMI R4, R4, R6, LSR R1 + B %BT02 + +03 ORR R4, R4, #CAM + ORR R4, R4, R11, LSL #8 ; stuff in PPL + STR R4, [R4] ; and write it + MOV PC, LR + +; Data to drive CAM setting + +PageMangleTable + & PageMangle4K + & PageMangle8K + & PageMangle16K + & PageMangle32K + +; For each page size, pairs of masks and shift factors to put the bits in the +; right place. Two sets: operations on Physical Page Number, operations on +; Logical Page Number. + +; Shifts are Shift Left values (<<). Each section terminated by -1 + +PageMangle4K +; PPN: + & 2_011111111 + & 0 ; bits in right place + & -1 +; LPN: + & 2_1100000000000:SHL:12 + & (11-12)-12 ; LPN[12:11] -> A[11:10] + & 2_0011111111111:SHL:12 + & (22-10)-12 ; LPN[10:0 ] -> A[22:12] + & -1 + +PageMangle8K +; PPN: + & 2_010000000 + & 7-7 ; PPN[7] -> A[7] + & 2_001000000 + & 0-6 ; PPN[6] -> A[0] + & 2_000111111 + & 6-5 ; PPN[5:0] -> A[6:1] + & -1 +; LPN: + & 2_110000000000:SHL:13 + & (11-11)-13 ; LPN[11:10] -> A[11:10] + & 2_001111111111:SHL:13 + & (22-9)-13 ; LPN[9:0] -> A[22:13] + & -1 + +PageMangle16K +; PPN: + & 2_010000000 + & 7-7 ; PPN[7] -> A[7] + & 2_001100000 + & 1-6 ; PPN[6:5] -> A[1:0] + & 2_000011111 + & 6-4 ; PPN[4:0] -> A[6:2] + & -1 +; LPN: + & 2_11000000000:SHL:14 + & (11-10)-14 ; LPN[10:9] -> A[11:10] + & 2_00111111111:SHL:14 + & (22-8)-14 ; LPN[8:0] -> A[22:14] + & -1 + +PageMangle32K +; PPN: + & 2_100000000 + & 12-8 ; PPN[8] -> A[12] + & 2_010000000 + & 7-7 ; PPN[7] -> A[7] + & 2_001000000 + & 1-6 ; PPN[6] -> A[1] + & 2_000100000 + & 2-5 ; PPN[5] -> A[2] + & 2_000010000 + & 0-4 ; PPN[4] -> A[0] + & 2_000001111 + & 6-3 ; PPN[3:0] -> A[6:3] + & -1 +; LPN: + & 2_1100000000:SHL:15 + & (11-9)-15 ; LPN[9:8] -> A[11:10] + & 2_0011111111:SHL:15 + & (22-7)-15 ; LPN[7:0] -> A[22:15] + & -1 + +PageSizes + & 4*1024 ; 0 is 4K + & 8*1024 ; 4 is 8K + & 16*1024 ; 8 is 16 + & 32*1024 ; C is 32 + +PageShifts + = 12, 13, 0, 14 ; 1 2 3 4 + = 0, 0, 0, 15 ; 5 6 7 8 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_UpdateMEMC: Read/write MEMC1 control register + +SSETMEMC ROUT + + AND r10, r0, r1 + MOV r12, #0 + TEQP pc, #SVC_mode+I_bit+F_bit + LDR r0, [r12, #MEMC_CR_SoftCopy] ; return old value + BIC r11, r0, r1 + ORR r11, r11, R10 + BIC r11, r11, #&FF000000 + BIC r11, r11, #&00F00000 + ORR r11, r11, #MEMCADR + STR r11, [r12, #MEMC_CR_SoftCopy] + STR r11, [r11] + TEQP pc, #SVC_mode+I_bit + ExitSWIHandler + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; ClearPhysRAM - Routine to clear "all" memory +; +; While this routine is running, keyboard IRQs may happen. For this reason +; it avoids LogRAM 0..31 (where hardware IRQ vector is) and PhysRAM +; 0..31 where the IRQ workspace is. +; +; r7 contains memory speed and must be preserved +; r8 contains page size and must be preserved +; r9 contains MEMC control register and must be preserved +; + +ClearPhysRAM ROUT + MOV r0, #0 + MOV r1, #0 + MOV r2, #0 + MOV r3, #0 + MOV r4, #0 + MOV r5, #0 + MOV r6, #0 + MOV r11, #0 + MOV r12, #PhysRam + CMP r13, #512*1024 + ADDEQ r10, r12, #(512-64)*1024 ; get address that's logram 0 + ADDNE r10, r12, #512*1024 + ADD r13, r13, #PhysRam ; end of memory + ADD r12, r12, #4*8 ; skip minimal startup workspace +10 CMP r12, R10 + ADDEQ r12, r12, #4*8 ; skip physram that's logram 0 + STMNEIA r12!, {r0-r6, r11} + CMP r12, r13 + BNE %BT10 + SUB r13, r13, #PhysRam + + LDR r0, =OsbyteVars + :INDEX: LastBREAK + MOV r1, #&80 + STRB r1, [r0] ; flag the fact that RAM cleared + MOV pc, lr + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; InitMEMC - Initialise memory controller +; + +InitMEMC ROUT + LDR R0, ResetMemC_Value + STR R0, [R0] ; set ROM access times, refresh on flyback, no DMA + MOV pc, lr + +; -> MemSize + +; (non-destructive) algorithm to determine MEMC RAM configuration +; +; Dave Flynn and Alasdair Thomas +; 17-March-87 +; +; Spooling checkered by NRaine and SSwales ! +; 8MByte check bodged in by APT +; +; NOTE: Routines MemSize and TimeCPU are called by the power-on test software, +; so their specifications MUST not change. +; +; Set MEMC for 32-k page then analyse signature of possible +; external RAM configurations... +; The configurations are: +; +; Ram Size Page Size Configuration (Phys RAM) Signature +;-------------------------------------------------------------------- +; 16MByte 32k 4*32*1Mx1 A13,A20,A21,A22,A23,A23.5 distinct +; 16MByte 32k 16*8*256kx4 A13,A20,A21,A22,A23,A23.5 distinct +; +; 12MByte 32k 3*32*1Mx1 A13,A20,A21,A22,A23 OK, A23.5 fail +; 12MByte 32k 12*8*256kx4 A13,A20,A21,A22,A23 OK, A23.5 fail +; +; 8MByte 32k 2*32*1Mx1 A13,A20,A21,A22 distinct, A23 fail +; 8MByte 32k 8*8*256kx4 A13,A20,A21,A22 distinct, A23 fail +; +; 4Mbyte 32k 32*1Mx1 A13,A21,A20 distinct, A22,A23 fail +; 4Mbyte 32k 4*8*256kx4 A13,A21,A20 distinct, A22,A23 fail +; +; 2Mbyte 32k expandable 2*8*256kx4 A13,A20 distinct, A21 fails +; 2Mbyte ??? 16k fixed 2*8*256kx4 A13,A21 distinct, A20 fails +; +; 1Mbyte 8k 32*256kx1 A13,A20 fail, A19,A18,A12 distinct +; 1Mbyte 8k 8*256kx1 A13,A20 fail, A19,A18,A12 distinct +; 1Mbyte 8k 4*8*64kx4 A13,A20 fail, A19,A18,A12 distinct +; +; 512Kbyte 8k expandable 2*8*64kx4 A13,A20,A19 fail, A12,A18 distinct +; 512Kbyte 4k fixed 2*8*64kx4 A13,A20,A12 fail, A19,A18 distinct +; +; 256Kbyte 4K 8*64kx4 A13,A20,A12,A18 fail, A21,A19 ok +; 256Kbyte 4K 32*64kx1 A13,A20,A12,A18 fail, A21,A19 ok +; + +Z_Flag * &40000000 + +; MemSize routine... enter with 32K pagesize set +; R0 returns page size +; R1 returns memory size +; R2 returns value set in MEMC +; uses R3-R7 + +MemSize ROUT + MOV r7, lr + MOV r0, #PhysRam + ADD r1, r0, #A13 + BL DistinctAddresses + BNE %10 + ADD r1, r0, #A21 + BL DistinctAddresses + MOVNE r0, #Page32K + MOVNE r1, #2048*1024 + BNE MemSizeDone + + MOV r0, #PhysRam + ADD r1, r0, #4*1024*1024 + BL DistinctAddresses + MOVNE r0, #Page32K + MOVNE r1, #4*1024*1024 + BNE MemSizeDone + + MOV r0, #PhysRam + ADD r1, r0, #8*1024*1024 + BL DistinctAddresses + MOVNE r0, #Page32K + MOVNE r1, #8*1024*1024 + BNE MemSizeDone + + MOV r0, #PhysRam + ADD r1, r0, #12*1024*1024 + BL DistinctAddresses + MOV r0, #Page32K + MOVNE r1, #12*1024*1024 + MOVEQ r1, #16*1024*1024 + B MemSizeDone + +10 ADD r1, r0, #A20 + BL DistinctAddresses + BNE %20 + MOV r0, #Page16K + MOV r1, #2048*1024 + B MemSizeDone + +20 ADD r1, r0, #A19 + BL DistinctAddresses + BEQ %30 + MOV r0, #Page8K + MOV r1, #512*1024 + B MemSizeDone + +30 ADD r1, r0, #A18 + BL DistinctAddresses + BEQ %40 + MOV r0, #Page4K + MOV r1, #256*1024 + B MemSizeDone + +40 ADD r1, r0, #A12 + BL DistinctAddresses + BEQ %50 + MOV r0, #Page4K + MOV r1, #512*1024 + B MemSizeDone + +50 MOV r0, #Page8K + MOV r1, #1024*1024 + +MemSizeDone + LDR r2, ResetMemC_Value + BIC r2, r2, #&C + ORR r2, r2, r0 + STR r2, [r2] ; set MEMC to right state + ADR r3, PageSizes + LDR r0, [r3, r0] ; r0 = convert from page size indicator into actual page size (in bytes) + MOV pc, r7 + + +; DistinctAddresses routine... +; r0,r1 are the addresses to check +; uses r2-5 +; writes interleaved patterns (to prevent dynamic storage...) +; checks writing every bit low and high... +; return Z-flag set if distinct + +DistinctAddresses ROUT + LDR r2, [r0] ; preserve + LDR r3, [r1] + LDR r4, Pattern + STR r4, [r0] ; mark first + MOV r5, r4, ROR #16 + STR r5, [r1] ; mark second + LDR r5, [r0] + CMP r5, r4 ; check first + BNE %10 ; exit with Z clear + LDR r5, [r1] ; check second + CMP r5, r4, ROR #16 ; clear Z if not same + BNE %10 +; now check inverse bit writes + STR r4, [r1] ; mark second + MOV r5, r4, ROR #16 + STR r5, [r0] ; mark first + LDR r5, [r1] + CMP r5, r4 ; check second + BNE %10 ; exit with Z clear + LDR r5, [r0] ; check first + CMP r5, r4, ROR #16 ; clear Z if not same +10 STR r3, [r1] ; restore + STR r2, [r0] + ORREQ lr, lr, #Z_Flag + BICNE lr, lr, #Z_Flag + MOVS pc, lr + +Pattern + & &AAFF5500 ; shiftable bit check pattern + +; init state with masked out page size + +ResetMemC_Value + & &E010C :OR: MEMCADR ; slugged ROMs + flyback refresh only + 32K page + +; Constants +; +A21 * 1:SHL:21 +A20 * 1:SHL:20 +A19 * 1:SHL:19 +A18 * 1:SHL:18 +A13 * 1:SHL:13 +A12 * 1:SHL:12 + +Page32K * &C ; in MEMC control reg patterns... +Page16K * &8 +Page8K * &4 +Page4K * &0 + + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r0-r6 trashable +; r9 = Current MEMC CR + +; Out r9 MEMC value with slowest ROM speed, correct pagesize +; r7 processor speed in kHz, tbs -> MEMC1a + +ncpuloops * 1024 ; don't go longer than 4ms without refresh ! +nmulloops * 128 + +TimeCPU ROUT + + BIC r9, r9, #3 :SHL: 8 + STR r9, [r9] ; turn off refresh for a bit + +; Time CPU/Memory speed + + LDR r1, =&7FFE ; 32K @ 2MHz = ~16ms limit + MOV r3, #IOC + + MOV r0, r1, LSR #8 + STRB r1, [r3, #Timer1LL] + STRB r0, [r3, #Timer1LH] + LDR r0, =ncpuloops + STRB r0, [r3, #Timer1GO] ; start the timer NOW + B %FT10 ; Looks superfluous, but is required + ; to get ncpuloops pipeline breaks + +10 SUBS r0, r0, #1 ; 1S + BNE %BT10 ; 1N + 2S + + STRB r0, [r3, #Timer1LR] ; latch count NOW + LDRB r2, [r3, #Timer1CL] + LDRB r0, [r3, #Timer1CH] + ADD r2, r2, r0, LSL #8 ; count after looping is ... + + SUB r2, r1, r2 ; decrements ! + MOV r2, r2, LSR #1 ; IOC clock decrements at 2MHz + +; Time CPU/MEMC Multiply time + + MOV r4, #-1 ; Gives worst case MUL + + MOV r0, r1, LSR #8 + STRB r1, [r3, #Timer1LL] + STRB r0, [r3, #Timer1LH] + LDR r0, =nmulloops + STRB r0, [r3, #Timer1GO] ; start the timer NOW + B %FT20 ; Looks superfluous, but is required + ; to get nmulloops pipeline breaks + +20 MUL r5, r4, r4 ; 1S + 16I + MUL r5, r4, r4 ; 1S + 16I + SUBS r0, r0, #1 ; 1S + BNE %BT20 ; 1N + 2S + + STRB r0, [r3, #Timer1LR] ; latch count NOW + LDRB r4, [r3, #Timer1CL] + LDRB r0, [r3, #Timer1CH] + ADD r4, r4, r0, LSL #8 ; count after looping is ... + + SUB r4, r1, r4 ; decrements ! + MOV r4, r4, LSR #1 ; IOC clock decrements at 2MHz + + ORR r9, r9, #1 :SHL: 8 ; set refresh on flyback + STR r9, [r9] ; restore MEMC state a.s.a.p. + +; In ROM - each cpu loop took 4R cycles @ 8/f*500ns/cycle + + LDR r0, =4*(8*500/1000)*ncpuloops*1000 + DivRem r7, r0, r2, r1 ; r2 preserved + MOV r0, #&80 ; At 8 MHz and below, run fast ROMs + LDR r1, =8050 ; Over 8 MHz, need medium ROMs + CMP r7, r1 + MOVHI r0, #&40 + LDR r1, =13000 ; Over 13 MHz, need slowest ROMs + CMP r7, r1 + MOVHI r0, #&00 + ORR r9, r9, r0 + STR r9, [r9] ; Set ROM speed appropriately + + ASSERT ncpuloops = 8*nmulloops ; for given ratio cutoff <------------ + + MOV r4, r4, LSL #10 ; *1024 to get resolution on divide + DivRem r0, r4, r2, r1 + LDR r1, =1100 ; Cutoff point; MEMC1 longer than this + CMP r0, r1 + ORRLO r7, r7, #1 :SHL: 16 ; Note MEMC1a prescence + + MOV pc, lr + +; Typical figures give (in ROM at 8MHz): + +; MEMC1 2048 CPU, 2432 MEMC -> MUL ratio 1216 +; MEMC1a 2048 864 432 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + END diff --git a/s/MEMC2 b/s/MEMC2 new file mode 100644 index 0000000000000000000000000000000000000000..ea1afe572048e1e368a32bc56402e747d278bcd9 --- /dev/null +++ b/s/MEMC2 @@ -0,0 +1,713 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > MEMC2 + +; MEMC interface file - MEMC2 version + +; Created by TMD 10-Aug-90 + +PhysRAML2PT * &02000000 + (512+64)*1024 + +; Synonyms + +VInit * MEMC2Address + MEMC2_VINITe +VStart * MEMC2Address + MEMC2_VSTRTe +VEnd * MEMC2Address + MEMC2_VENDe +CInit * MEMC2Address + MEMC2_CINIT + +; ***************************************************************************** +; +; SetDAG - Program DMA address generator R1 with physical address R0 +; +; in: r0 = physical address +; r1 = index of DMA address generator to program, as defined in vdudecl +; +; out: All registers preserved, operation ignored if illegal +; + +SetDAG ENTRY "r0,r1" + CMP r1, #MEMCDAG_MaxReason + EXIT HI + ADR r14, DAGAddressTable + LDR r14, [r14, r1, LSL #2] ; load base address in MEMC2 + MOV r1, r0, LSR #16 ; r1 is top 16 bits + EOR r0, r0, r1, LSL #16 ; and r0 is bottom 16 bits + BIC r0, r0, #&0F ; bits 0..3 must be clear + BIC r1, r1, #&F000 ; and bits 28..31 must be clear + STMIA r14, {r0, r1} ; atomic update (we believe) + EXIT + + GBLA DAGIndex +DAGIndex SETA 0 + + MACRO + DAGTab $reason, $address + ASSERT ($reason)=DAGIndex + & $address +DAGIndex SETA DAGIndex + 1 + MEND + +DAGAddressTable + DAGTab MEMCDAG_VInit, VInit + DAGTab MEMCDAG_VStart, VStart + DAGTab MEMCDAG_VEnd, VEnd + DAGTab MEMCDAG_CInit, CInit + +; **************** CAM manipulation utility routines *********************************** + +; ************************************************************************************** +; +; BangCamUpdate - Update CAM entry and soft copy +; +; This part of the routine has to do more work on MEMC2 +; +; First look in the CamEntries table to find the logical address L this physical page is +; currently allocated to. Then check in the Level 2 page tables to see if page L is currently +; at page R2. If it is, then map page L to be inaccessible, otherwise leave page L alone. +; Then map logical page R3 to physical page R2. +; +; in: r2 = physical page number +; r3 = logical address +; r9 = current MEMC1 control register (irrelevant on MEMC2) +; r11 = PPL +; +; out: r0, r1, r4, r6 corrupted +; r2, r3, r5, r7-r12 preserved +; +; NB Use of stack is allowed in this routine + +BangCamUpdate ROUT + MOV r1, #0 + LDR r1, [r1, #CamEntriesPointer] + LDR r0, [r1, r2, LSL #2] ; r0 = current logaddress + PPL for phys page r2 + ORR r4, r3, r11, LSL #28 ; new entry for CamEntries + STR r4, [r1, r2, LSL #2] ; update + + BIC r0, r0, #&F0000000 ; just get logical address + LDR r1, =PhysRAML2PT ; point to page tables + LDR r4, [r1, r0, LSR #11] ; get physical page + PPL for this logical page + TEQ r2, r4, LSR #3 ; see if still there + BNE %FT10 ; if not there, then just put in new page + + Push "r3, r14" + MOV r3, r0 ; map out old page at this logical address + MOV r0, #0 ; physical page 0 but PPL(MEMC2)=0 ie no access, not even for me! + BL BangL2PT ; map page out + Pull "r3, r14" +10 + +; and drop thru to ... + +; ************************************************************************************** +; +; BangCam - Update CAM entry, but not soft copy +; +; This routine maps a physical page to a given logical address +; For MEMC2, I assume that the physical page was previously not mapped +; anywhere else - on MEMC1 it would automatically unmap any logical +; address that the physical page was previously at, but on MEMC2 it won't +; +; in: r2 = physical page number +; r3 = logical address +; r9 = current MEMC1 control register (irrelevant on MEMC2) +; r11 = PPL +; +; out: r0, r1, r4, r6 corrupted +; r2, r3, r5, r7-r12 preserved +; +; NB Can't use stack - there might not be one! + +BangCam + ADR r0, PPLTrans ; translate MEMC1 PPL to MEMC2 PPL + LDRB r0, [r0, r11] + ORR r0, r0, r2, LSL #3 ; value to store in level 2 page table + ; is PPL :OR: (phys page number << 3) + + LDR r1, =PhysRAML2PT ; point to level 2 page tables + +BangL2PT ; internal entry point used only by BangCamUpdate + BICS r4, r3, #(3 :SHL: 11) ; ensure going to be on word boundary (EQ => logical page zero) + STR r0, [r1, r4, LSR #11] ; update level 2 page table + + MOV r6, #MEMC2Address + STREQ r0, [r6, #MEMC2_SuperPageZero] ; if logical page 0 then update special entry + + MOV r0, #0 ; now flush the TLB + STR r0, [r6, #MEMC2_Flush] + + MOV pc, lr + +PPLTrans + = 6 ; R any W any + = 3 ; R any W sup + = 2 ; R sup W sup + = 2 ; R sup W sup + +PageSizes + & 4*1024 ; 0 is 4K + & 8*1024 ; 4 is 8K + & 16*1024 ; 8 is 16 + & 32*1024 ; C is 32 + +PageShifts + = 12, 13, 0, 14 ; 1 2 3 4 + = 0, 0, 0, 15 ; 5 6 7 8 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_UpdateMEMC: Read/write MEMC1 control register + +SSETMEMC ROUT + + AND r10, r0, r1 + MOV r12, #0 + TEQP pc, #SVC_mode+I_bit+F_bit + LDR r0, [r12, #MEMC_CR_SoftCopy] ; return old value + BIC r11, r0, r1 + ORR r11, r11, R10 + BIC r11, r11, #&FF000000 + BIC r11, r11, #&00F00000 + ORR r11, r11, #MEMCADR + STR r11, [r12, #MEMC_CR_SoftCopy] + +; We now have to mimic the relevant bits of the MEMC1 control register +; +; bits 0,1 => unused +; bits 2,3 => page size, irrelevant since always 8K +; bits 4,5 => low ROM access time, irrelevant since this has to be fixed +; bits 6,7 => hi ROM access time, -----------------""------------------ +; bits 8,9 => DRAM refresh control, irrelevant (refresh must always be on) +; bit 10 => Video/cursor DMA enable, corresponds to bit venbe of VATT +; (and possibly bit venbo of IATT for interlaced displays) +; Unfortunately VATT (and IATT) is a write-only register. Later on +; we might have a soft copy of these, but for now just write whole +; register. +; bit 11 => Sound DMA enable, ignore for now +; bit 12 => OS mode, ignore + +; Program all of VATT +; +; vdis = 0 (don't disable DMA after one buffer) +; venbe = (bit 10 of r11) +; vrnw = 1 (read from RAM, not write) +; vmske = 0 (no interrupts at end of buffer) + + MOV r12, # (0 * VATT_vdis) + (0 * VATT_venbe) + (1 * VATT_vrnw) + (0 * VATT_vmske) + TST r11, # (1 :SHL: 10) + ORRNE r12, r12, # VATT_venbe + MOV r10, #MEMC2Address + STR r12, [r10, #MEMC2_VATT] + + TEQP pc, #SVC_mode+I_bit + ExitSWIHandler + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; ClearPhysRAM - Routine to clear "all" memory +; +; While this routine is running, keyboard IRQs may happen. For this reason +; it avoids LogRAM 0..31 (where hardware IRQ vector is) and PhysRAM +; 0..31 where the IRQ workspace is. +; +; On MEMC2 it also has to avoid the pages where the level 2 page tables are +; +; r7 contains memory speed and must be preserved +; r8 contains page size and must be preserved +; r9 contains MEMC control register and must be preserved +; + +ClearPhysRAM ROUT + MOV r0, #0 + MOV r1, #0 + MOV r2, #0 + MOV r3, #0 + MOV r11, #0 + MOV r4, #PhysRam + CMP r13, #512*1024 + ADDEQ r10, r4, #(512-64)*1024 ; get address that's logram 0 + ADDNE r10, r4, #512*1024 + ADD r13, r13, #PhysRam ; end of memory + ADD r12, r4, #PhysRAML2PT-PhysRam + ADD r4, r4, #4*8 ; skip minimal startup workspace +10 + CMP r4, r10 + ADDEQ r4, r4, #4*8 ; skip physram that's logram 0 + CMP r4, r12 + ADDEQ r4, r4, #32*1024 ; skip 32K of L2PT + STMNEIA r4!, {r0-r3} + CMP r4, r13 + BNE %BT10 + SUB r13, r13, #PhysRam + + LDR r0, =OsbyteVars + :INDEX: LastBREAK + MOV r1, #&80 + STRB r1, [r0] ; flag the fact that RAM cleared + MOV pc, lr + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; InitMEMC - Initialise memory controller +; + +InitMEMC ROUT + MOV r0, # MEMC2Address + MOV r1, # Control_romfast + STR r1, [r0, #MEMC2_Control] ; make ROMS go fast + + ADR r1, ClockTimingTable ; initialise CLK block + LDMIA r1, {r2-r5} + ADD r1, r0, #MEMC2_clkj0 + STMIA r1, {r2-r5} + + ADR r1, DRAMTimingTable ; initialise DRAM block + LDMIA r1, {r2-r8} + ADD r1, r0, #MEMC2_rwt0 + STMIA r1, {r2-r8} + + LDR r1, rtype_value + STR r1, [r0, #MEMC2_rtype] + + LDR r1, refr_value + STR r1, [r0, #MEMC2_refr] + + MOV r1, # (PhysRAML2PT-PhysRam)/(8*1024) ; level 1 entry (paged) for 0..16M + MOV r2, # (PhysRAML2PT+8*1024-PhysRam)/(8*1024) ; level 1 entry (paged) for 16M..32M + MOV r3, # Prot_UrwSRW+(L1D_RAM :SHL: 3)+(L1D_RAM :SHL: 5)+(L1D_RAM :SHL: 7)+(L1D_RAM :SHL: 9)+(0 :SHL: 11) + ; level 1 entry (direct) for 32M..48M (all RAM, base 0) + LDR r4, = Prot_URwSRW+(L1D_IO :SHL: 3)+(L1D_PROG :SHL: 5)+(L1D_ROM :SHL: 7)+(L1D_ROM :SHL: 9)+(0 :SHL: 11) + ; level 1 entry (direct) for 48M..64M (IO,PROG,ROM,ROM) + ADD r5, r0, #MEMC2_Level1+L1_Paged+L1_Sec0 + ADD r6, r5, #4*2*16 ; cycle thru all 4 bus masters and (USR,SPV) + ADD r7, r5, #(L1_Direct+L1_Sec2)-(L1_Paged+L1_Sec0) +10 + STMIA r5, {r1,r2} ; set up the paged sections 0,1 + STMIA r7, {r3,r4} ; set up the direct sections 2,3 + ADD r5, r5, #16 + ADD r7, r7, #16 + TEQ r5, r6 ; have we got to the end ? + BNE %BT10 + +; Now turn on the translation, but don't set up the level 2 page tables until later, +; when we know the DRAM multiplex option + + LDR r1, = Control_ton + Control_l1on + Control_romfast + STR r1, [r0, #MEMC2_Control] + +; now set up VINC + + MOV r1, #&10 ; low bits + MOV r2, #&00 ; high bits + ADD r3, r0, #MEMC2_VINC + STMIA r3, {r1,r2} + + MOV pc, lr + +ClockTimingTable +J0 & &F200 ; 3 / 2 +J1 & &F200 ; 3 / 2 +RSPEED & &1C00 ; 3 / 3 +ISPEED & &B800 ; 2.5 / 2.5 + +DRAMTimingTable +RWT0 & &2A320 +RRD0 & &2AC80 +RSQ0 & &0B200 +B0Dummy & 0 +RWT1 & &2A320 +RRD1 & &2AC80 +RSQ1 & &0B200 + +rtype_value & &3333 ; Bank Type [x,bank,s1,s0] * 4 ; set largest memory type by default + +refr_value & &1086 ; Enable refresh, refresh length = 10 hclk ticks, refresh period = 12us + +; -> MemSize + +; (non-destructive) algorithm to determine MEMC RAM configuration +; +; Dave Flynn and Alasdair Thomas +; 17-March-87 +; +; Spooling checkered by NRaine and SSwales ! +; 8MByte check bodged in by APT +; +; NOTE: Routines MemSize and TimeCPU are called by the power-on test software, +; so their specifications MUST not change. +; +; Set MEMC for 32-k page then analyse signature of possible +; external RAM configurations... +; The configurations are: +; +; Ram Size Page Size Configuration (Phys RAM) Signature +;-------------------------------------------------------------------- +; 16MByte 32k 4*32*1Mx1 A13,A20,A21,A22,A23,A23.5 distinct +; 16MByte 32k 16*8*256kx4 A13,A20,A21,A22,A23,A23.5 distinct +; +; 12MByte 32k 3*32*1Mx1 A13,A20,A21,A22,A23 OK, A23.5 fail +; 12MByte 32k 12*8*256kx4 A13,A20,A21,A22,A23 OK, A23.5 fail +; +; 8MByte 32k 2*32*1Mx1 A13,A20,A21,A22 distinct, A23 fail +; 8MByte 32k 8*8*256kx4 A13,A20,A21,A22 distinct, A23 fail +; +; 4Mbyte 32k 32*1Mx1 A13,A21,A20 distinct, A22,A23 fail +; 4Mbyte 32k 4*8*256kx4 A13,A21,A20 distinct, A22,A23 fail +; +; 2Mbyte 32k expandable 2*8*256kx4 A13,A20 distinct, A21 fails +; 2Mbyte ??? 16k fixed 2*8*256kx4 A13,A21 distinct, A20 fails +; +; 1Mbyte 8k 32*256kx1 A13,A20 fail, A19,A18,A12 distinct +; 1Mbyte 8k 8*256kx1 A13,A20 fail, A19,A18,A12 distinct +; 1Mbyte 8k 4*8*64kx4 A13,A20 fail, A19,A18,A12 distinct +; +; 512Kbyte 8k expandable 2*8*64kx4 A13,A20,A19 fail, A12,A18 distinct +; 512Kbyte 4k fixed 2*8*64kx4 A13,A20,A12 fail, A19,A18 distinct +; +; 256Kbyte 4K 8*64kx4 A13,A20,A12,A18 fail, A21,A19 ok +; 256Kbyte 4K 32*64kx1 A13,A20,A12,A18 fail, A21,A19 ok +; + +Z_Flag * &40000000 + +; MemSize routine... enter with 32K pagesize set +; R0 returns page size +; R1 returns memory size +; R2 returns value set in MEMC +; uses R3-R7 + +MemSize ROUT + [ {TRUE} ; now work on different configurations, but only bank zero + MOV r7, lr + +; first find out appropriate rtype value +; initial routine has set DRAM type to 3 + + MOV r0, #PhysRam + ADD r1, r0, #A9 ; if A9 ghosts + BL DistinctAddresses + MOVNE r0, #2_00 ; then type 00 + BNE %FT10 + + ADD r1, r0, #A11 ; else if A11 ghosts + BL DistinctAddresses + MOVNE r0, #2_01 ; then type 01 + BNE %FT10 + + ADD r1, r0, #A12 ; else if A12 ghosts + BL DistinctAddresses + MOVNE r0, #2_01 ; then type 01 + MOVEQ r0, #2_11 ; else type 11 +10 + LDR r1, rtype_value + BIC r1, r1, #2_11 + ORR r1, r1, r0 + MOV r0, #MEMC2Address + STR r1, [r0, #MEMC2_rtype] + +; having set up the DRAM multiplexing correctly, we can now zap the L2PT +; to no access for any page + + LDR r1, =PhysRAML2PT + ADD r2, r1, #2*8*1024 ; two L2PT tables at the moment + MOV r3, #0 ; page 0, no access + MOV r4, #0 + MOV r5, #0 + MOV r6, #0 +15 + STMIA r1!,{r3-r6} + TEQ r1, r2 + BNE %BT15 + + STR r3, [r0, #MEMC2_SuperPageZero] ; don't forget super page zero + +; now find out the memory size + + MOV r0, #PhysRam + MOV r6, #256*1024 +20 + ADD r1, r0, r6 + BL DistinctAddresses ; try next address line + BNE %FT30 ; if ghosts or not there then finish + MOV r6, r6, LSL #1 + CMP r6, #16*1024*1024 ; give up if we've got 16MBytes or more + BCC %BT20 +30 + MOV r1, r6 + LDR r2, ResetMemC_Value + BIC r2, r2, #&C + ORR r2, r2, #Page8K + MOV r0, #8*1024 ; fixed 8K page size + MOV pc, r7 + | + MOV r7, lr + MOV r0, #PhysRam + ADD r1, r0, #A13 + BL DistinctAddresses + BNE %10 + ADD r1, r0, #A21 + BL DistinctAddresses + MOVNE r0, #Page32K + MOVNE r1, #2048*1024 + BNE MemSizeDone + + MOV r0, #PhysRam + ADD r1, r0, #4*1024*1024 + BL DistinctAddresses + MOVNE r0, #Page32K + MOVNE r1, #4*1024*1024 + BNE MemSizeDone + + MOV r0, #PhysRam + ADD r1, r0, #8*1024*1024 + BL DistinctAddresses + MOVNE r0, #Page32K + MOVNE r1, #8*1024*1024 + BNE MemSizeDone + + MOV r0, #PhysRam + ADD r1, r0, #12*1024*1024 + BL DistinctAddresses + MOV r0, #Page32K + MOVNE r1, #12*1024*1024 + MOVEQ r1, #16*1024*1024 + B MemSizeDone + +10 ADD r1, r0, #A20 + BL DistinctAddresses + BNE %20 + MOV r0, #Page16K + MOV r1, #2048*1024 + B MemSizeDone + +20 ADD r1, r0, #A19 + BL DistinctAddresses + BEQ %30 + MOV r0, #Page8K + MOV r1, #512*1024 + B MemSizeDone + +30 ADD r1, r0, #A18 + BL DistinctAddresses + BEQ %40 + MOV r0, #Page4K + MOV r1, #256*1024 + B MemSizeDone + +40 ADD r1, r0, #A12 + BL DistinctAddresses + BEQ %50 + MOV r0, #Page4K + MOV r1, #512*1024 + B MemSizeDone + +50 MOV r0, #Page8K + MOV r1, #1024*1024 + +MemSizeDone + LDR r2, ResetMemC_Value + BIC r2, r2, #&C + ORR r2, r2, r0 + STR r2, [r2] ; set MEMC to right state + MOV pc, r7 + + ] + +; DistinctAddresses routine... +; r0,r1 are the addresses to check +; uses r2-5 +; writes interleaved patterns (to prevent dynamic storage...) +; checks writing every bit low and high... +; return Z-flag set if distinct + +DistinctAddresses ROUT + LDR r2, [r0] ; preserve + LDR r3, [r1] + LDR r4, Pattern + STR r4, [r0] ; mark first + MOV r5, r4, ROR #16 + STR r5, [r1] ; mark second + LDR r5, [r0] + CMP r5, r4 ; check first + BNE %10 ; exit with Z clear + LDR r5, [r1] ; check second + CMP r5, r4, ROR #16 ; clear Z if not same + BNE %10 +; now check inverse bit writes + STR r4, [r1] ; mark second + MOV r5, r4, ROR #16 + STR r5, [r0] ; mark first + LDR r5, [r1] + CMP r5, r4 ; check second + BNE %10 ; exit with Z clear + LDR r5, [r0] ; check first + CMP r5, r4, ROR #16 ; clear Z if not same +10 STR r3, [r1] ; restore + STR r2, [r0] + ORREQ lr, lr, #Z_Flag + BICNE lr, lr, #Z_Flag + MOVS pc, lr + +Pattern + & &AAFF5500 ; shiftable bit check pattern + +; init state with masked out page size + +ResetMemC_Value + & &E010C :OR: MEMCADR ; slugged ROMs + flyback refresh only + 32K page + +; Constants +; +A0 * 1 :SHL: 00 +A1 * 1 :SHL: 01 +A2 * 1 :SHL: 02 +A3 * 1 :SHL: 03 +A4 * 1 :SHL: 04 +A5 * 1 :SHL: 05 +A6 * 1 :SHL: 06 +A7 * 1 :SHL: 07 +A8 * 1 :SHL: 08 +A9 * 1 :SHL: 09 +A10 * 1 :SHL: 10 +A11 * 1 :SHL: 11 +A12 * 1 :SHL: 12 +A13 * 1 :SHL: 13 +A14 * 1 :SHL: 14 +A15 * 1 :SHL: 15 +A16 * 1 :SHL: 16 +A17 * 1 :SHL: 17 +A18 * 1 :SHL: 18 +A19 * 1 :SHL: 19 +A20 * 1 :SHL: 20 +A21 * 1 :SHL: 21 +A22 * 1 :SHL: 22 +A23 * 1 :SHL: 23 +A24 * 1 :SHL: 24 +A25 * 1 :SHL: 25 +A26 * 1 :SHL: 26 +A27 * 1 :SHL: 27 +A28 * 1 :SHL: 28 +A29 * 1 :SHL: 29 +A30 * 1 :SHL: 30 +A31 * 1 :SHL: 31 + +Page32K * &C ; in MEMC control reg patterns... +Page16K * &8 +Page8K * &4 +Page4K * &0 + + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r0-r6 trashable +; r9 = Current MEMC CR + +; Out r9 MEMC value with slowest ROM speed, correct pagesize +; r7 processor speed in kHz, bit 16 => can do STM to I/O (ie MEMC1a, MEMC2), bit 17 => MEMC2 + +ncpuloops * 1024 ; don't go longer than 4ms without refresh ! +nmulloops * 128 + +TimeCPU ROUT + [ {TRUE} +; fudge it for now + LDR r7, =6000 + (3 :SHL: 16) ; pretend 6MHz system, and MEMC2 + MOV pc, lr + | + BIC r9, r9, #3 :SHL: 8 + STR r9, [r9] ; turn off refresh for a bit + +; Time CPU/Memory speed + + LDR r1, =&7FFE ; 32K @ 2MHz = ~16ms limit + MOV r3, #IOC + + MOV r0, r1, LSR #8 + STRB r1, [r3, #Timer1LL] + STRB r0, [r3, #Timer1LH] + LDR r0, =ncpuloops + STRB r0, [r3, #Timer1GO] ; start the timer NOW + B %FT10 ; Looks superfluous, but is required + ; to get ncpuloops pipeline breaks + +10 SUBS r0, r0, #1 ; 1S + BNE %BT10 ; 1N + 2S + + STRB r0, [r3, #Timer1LR] ; latch count NOW + LDRB r2, [r3, #Timer1CL] + LDRB r0, [r3, #Timer1CH] + ADD r2, r2, r0, LSL #8 ; count after looping is ... + + SUB r2, r1, r2 ; decrements ! + MOV r2, r2, LSR #1 ; IOC clock decrements at 2MHz + +; Time CPU/MEMC Multiply time + + MOV r4, #-1 ; Gives worst case MUL + + MOV r0, r1, LSR #8 + STRB r1, [r3, #Timer1LL] + STRB r0, [r3, #Timer1LH] + LDR r0, =nmulloops + STRB r0, [r3, #Timer1GO] ; start the timer NOW + B %FT20 ; Looks superfluous, but is required + ; to get nmulloops pipeline breaks + +20 MUL r5, r4, r4 ; 1S + 16I + MUL r5, r4, r4 ; 1S + 16I + SUBS r0, r0, #1 ; 1S + BNE %BT20 ; 1N + 2S + + STRB r0, [r3, #Timer1LR] ; latch count NOW + LDRB r4, [r3, #Timer1CL] + LDRB r0, [r3, #Timer1CH] + ADD r4, r4, r0, LSL #8 ; count after looping is ... + + SUB r4, r1, r4 ; decrements ! + MOV r4, r4, LSR #1 ; IOC clock decrements at 2MHz + + ORR r9, r9, #1 :SHL: 8 ; set refresh on flyback + STR r9, [r9] ; restore MEMC state a.s.a.p. + +; In ROM - each cpu loop took 4R cycles @ 8/f*500ns/cycle + + LDR r0, =4*(8*500/1000)*ncpuloops*1000 + DivRem r7, r0, r2, r1 ; r2 preserved + MOV r0, #&80 ; At 8 MHz and below, run fast ROMs + LDR r1, =8050 ; Over 8 MHz, need medium ROMs + CMP r7, r1 + MOVHI r0, #&40 + LDR r1, =13000 ; Over 13 MHz, need slowest ROMs + CMP r7, r1 + MOVHI r0, #&00 + ORR r9, r9, r0 + STR r9, [r9] ; Set ROM speed appropriately + + ASSERT ncpuloops = 8*nmulloops ; for given ratio cutoff <------------ + + MOV r4, r4, LSL #10 ; *1024 to get resolution on divide + DivRem r0, r4, r2, r1 + LDR r1, =1100 ; Cutoff point; MEMC1 longer than this + CMP r0, r1 + ORRLO r7, r7, #1 :SHL: 16 ; Note MEMC1a prescence + + MOV pc, lr + +; Typical figures give (in ROM at 8MHz): + +; MEMC1 2048 CPU, 2432 MEMC -> MUL ratio 1216 +; MEMC1a 2048 864 432 + + ] + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + END diff --git a/s/MOSDict b/s/MOSDict new file mode 100644 index 0000000000000000000000000000000000000000..6bcc4f159e64340762048c3bcad8f1bd30987c81 --- /dev/null +++ b/s/MOSDict @@ -0,0 +1,69 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + TTL ==> MOSDict + +TokenEscapeChar * 27 +Token0 * 0 + MACRO + TokenString $n,$s +Token$n * $n + = ?Token$n.String +1 +Token$n.String = $s + MEND + +MOSdictionary + TokenString 1,"""Syntax: *"",TokenEscapeChar,Token0,0" + TokenString 2,""" the "",0" + TokenString 3,"""director"",0" + TokenString 4,"""filing system"",0" + TokenString 5,"""current"",0" + TokenString 6,""" to a variable. Other types of value can be assigned with *"",0" + TokenString 7,"""file"",0" + TokenString 8,"""default "",0" + TokenString 9,"""tion"",0" + TokenString 10,"""*Configure "",0" + TokenString 11,"""name"",0" + TokenString 12,""" server"",0" + TokenString 13,"""number"",0" + TokenString 14,"TokenEscapeChar,Token1,"" <"",0" + TokenString 15,""" one or more "",TokenEscapeChar,Token7,""s that match"",TokenEscapeChar,Token2,""given wildcard"",0" + TokenString 16,""" and "",0" + TokenString 17,"""relocatable module"",0" + TokenString 18,"13,""C(onfirm)"",9,""Prompt for confirma"",TokenEscapeChar,Token9,"" of each "",0" + TokenString 19,"""sets"",TokenEscapeChar,Token2,0" + TokenString 20,"TokenEscapeChar,Token1,"" [<disc spec.>]"",0" + TokenString 21,"""}"",13,""V(erbose)"",9,""Print informa"",TokenEscapeChar,Token9,"" on each "",TokenEscapeChar,Token7,"" "",0" + TokenString 22, 0 + TokenString 23,"TokenEscapeChar,Token31,""Landscape [<XScale> [<YScale> [<Margin> [<Threshold>]]]]]"",0" + TokenString 24,"TokenEscapeChar,Token41,""used"",TokenEscapeChar,Token40,""print a hard copy of"",TokenEscapeChar,Token2,""screen on EPSON-"",0" + TokenString 25,"""."",13,""Op"",TokenEscapeChar,Token9,""s: (use ~"",TokenEscapeChar,Token40,""force off, eg. ~"",0" + TokenString 26,"""printe"",0" + TokenString 27,"TokenEscapeChar,Token14,TokenEscapeChar,Token7,TokenEscapeChar,Token11,"">"",0" + TokenString 28,""" select"",0" + TokenString 29,"""xpression"",0" + TokenString 30,"TokenEscapeChar,Token1,"" ["",0" + TokenString 31,"""sprite"",0" + TokenString 32,""" displays"",0" + TokenString 33,"""free space"",0" + TokenString 34,""" {off}"",0" + TokenString 35,"""library"",0" + TokenString 36,"""parameter"",0" + TokenString 37,"""object"",0" + TokenString 38,""" all "",0" + TokenString 39,"""disc"",0" + TokenString 40,""" to "",0" + TokenString 41,""" is "",0" + = 0,0,0,0 + END diff --git a/s/MemInfo b/s/MemInfo new file mode 100644 index 0000000000000000000000000000000000000000..990ab16c1693d5d06ae449841b1b6147f73f482b --- /dev/null +++ b/s/MemInfo @@ -0,0 +1,611 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > MemInfo + + LTORG + +;---------------------------------------------------------------------------------------- +; MemorySWI +; +; In: r0 = reason code and flags +; bits 0-7 = reason code +; bits 3-31 = reason specific flags +; Out: specific to reason codes +; +; Perform miscellaneous operations for memory management. +; +MemorySWI ROUT + Push lr ; Save real return address. + AND lr, r0, #&FF ; Get reason code. + CMP lr, #(%40-%30):SHR:2 ; If valid reason code then + ADDCC lr, lr, #(%30-%10):SHR:2 ; determine where to jump to in branch table, + ADDCC lr, pc, lr, LSL #2 + Push lr, CC ; save address so we can +10 + ADRCC lr, MemReturn ; set up default return address for handler routines + Pull pc, CC ; and jump into branch table. +20 + ADRL r0, ErrorBlock_HeapBadReason ; Otherwise, unknown reason code. + SETV + ; Drop through to... + +MemReturn + [ International + BLVS TranslateError + ] + Pull lr ; Get back real return address. + BVS SLVK_SetV + ExitSWIHandler + +30 + B MemoryConvert + B %BT20 ; Reason codes 1-5 are reserved. + B %BT20 + B %BT20 + B %BT20 + B %BT20 + B MemoryPhysSize + B MemoryReadPhys + B MemoryAmounts + B MemoryIOSpace +40 + + +;---------------------------------------------------------------------------------------- +; MemoryConvert +; +; In: r0 = flags +; bit meaning +; 0-7 0 (reason code) +; 8 page number provided when set +; 9 logical address provided when set +; 10 physical address provided when set +; 11 fill in page number when set +; 12 fill in logical address when set +; 13 fill in physical address when set +; 14-15 0,1=don't change cacheability +; 2=disable caching on these pages +; 3=enable caching on these pages +; 16-31 reserved (set to 0) +; r1 -> page block +; r2 = number of 3 word entries in page block +; +; Out: r1 -> updated page block +; +; Converts between representations of memory addresses. Can also set the +; cacheability of the specified pages. +; + +; Declare symbols used for decoding flags (given and wanted are used +; so that C can be cleared by rotates of the form a,b). We have to munge +; the flags a bit to make the rotates even. +; +ppn * 1:SHL:0 ; Bits for address formats. +logical * 1:SHL:1 +physical * 1:SHL:2 +all * ppn :OR: logical :OR: physical +given * 24 ; Rotate for given fields. +wanted * 20 ; Rotate for wanted fields. +ppn_bits * ((ppn :SHL: 4) :OR: ppn) +logical_bits * ((logical :SHL: 4) :OR: logical) +physical_bits * ((physical :SHL: 4) :OR: physical) +cacheable_bit * 1:SHL:15 +alter_cacheable * 1:SHL:16 +flush_cache * 1:SHL:31 ; Internal flag. + +MemoryConvert ROUT + ENTRY "r0-r11" ; Need lots of registers!! + + BIC lr, r0, #all,given ; Need to munge r0 to get rotates to work (must be even). + AND r0, r0, #all,given + ORR r0, r0, lr, LSL #1 ; Move bits 11-30 to 12-31. + + TST r0, #all,given ; Check for invalid argument (no fields provided) + TEQNE r2, #0 ; (no entries in table). + ADREQL r0, ErrorBlock_BadParameters + BEQ %FT95 + + EOR lr, r0, r0, LSL #given-wanted ; If flag bits 8-10 and 12-14 contain common bits then + AND lr, lr, #all,wanted ; clear bits in 12-14 (ie. don't fill in fields already given). + EOR lr, lr, #all,wanted + BIC r0, r0, lr + + MOV r6, #0 + LDR r7, [r6, #MaxCamEntry] + LDR r6, [r6, #CamEntriesPointer] + LDR r8, =L2PT + + BIC r0, r0, #flush_cache ; Bit set if any page is really made uncacheable (we must flush the cache). +10 + SUBS r2, r2, #1 + BCC %FT70 + + LDMIA r1!, {r3-r5} ; Get next three word entry (PN,LA,PA) and move on pointer. + + TST r0, #physical,wanted ; If PA not wanted + BEQ %FT20 ; then skip. + TST r0, #logical,given ; If LA not given (rotate clears C) then + BLEQ ppn_to_logical ; get it from PN (PA wanted (not given) & LA not given => PN given). + BLCC logical_to_physical ; Get PA from LA. + BCS %FT80 + TST r0, #logical,wanted + STRNE r4, [r1, #-8] ; Store back LA if wanted. + STR r5, [r1, #-4] ; Store back PA. +20 + TST r0, #alter_cacheable ; If altering cacheability + EORNE lr, r0, #ppn,given ; and PN not given + TSTNE lr, #ppn,given + TSTEQ r0, #ppn,wanted ; OR PN wanted then don't skip + BEQ %FT30 ; else skip. + TST r0, #physical_bits,given ; If PA not given and PA not wanted (rotate clears C) then + BLEQ logical_to_physical ; get it from LA (PN wanted/not given & PA not given => LA given). + BLCC physical_to_ppn ; Get PN from PA. + BCS %FT80 + TST r0, #ppn,wanted + STRNE r3, [r1, #-12] ; Store back PN if wanted. +30 + TST r0, #logical,wanted ; If LA wanted + EORNE lr, r0, #physical,wanted + TSTNE lr, #physical,wanted ; and PA not wanted then don't skip + BEQ %FT40 ; else skip. + TST r0, #alter_cacheable ; If not changing cacheability (already have PN) + TSTEQ r0, #ppn_bits,given ; and PN not given and PN not wanted (rotate clears C) then + BLEQ physical_to_ppn ; get it from PA (LA wanted (not given) & PN not given => PA given). + BLCC ppn_to_logical ; Get LA from PN. + BCS %FT80 + STR r4, [r1, #-8] ; Store back LA. +40 + TST r0, #alter_cacheable + BEQ %BT10 + + CMP r7, r3 ; Make sure page number is valid (might not have done any conversion). + BCC %FT80 + + ADD r3, r6, r3, LSL #3 ; Point to CAM entry for this page. + LDMIA r3, {r4,r5} ; Get logical address and PPL. + + AND lr, r5, #PageFlags_TempUncacheableBits + TST r0, #cacheable_bit + BNE %FT50 + + TEQ lr, #PageFlags_TempUncacheableBits ; Make uncacheable (increment count). + BEQ %BT10 ; If count has reached max then go no further (should not happen). + TEQ lr, #0 ; EQ => we have to change L2. + ADD r5, r5, #1:SHL:TempUncacheableShift + B %FT60 +50 + TEQ lr, #0 ; Make cacheable (decrement count). + BEQ %BT10 ; If count is already 0 then go no further (page already cacheable). + SUB r5, r5, #1:SHL:TempUncacheableShift + TST r5, #PageFlags_TempUncacheableBits ; EQ => we have to change L2. +60 + STR r5, [r3, #4] ; Write back new PPL. + BNE %BT10 ; Do next entry if we don't have to change L2. + + MOV r4, r4, LSR #12 + ADD r4, r8, r4, LSL #2 ; Address of L2 entry for logical address. + LDR r5, [r4] ; Get L2 entry (safe as we know address is valid). + TST r0, #cacheable_bit + BICEQ r5, r5, #L2_C ; Disable/enable cacheability. + ORREQ r0, r0, #flush_cache ; If disable then we must flush cache later. + ORRNE r5, r5, #L2_C + STR r5, [r4] ; Write back new L2 entry. + + B %BT10 ; Do next entry. + +70 + TST r0, #flush_cache ; If any page has been made uncacheable in L2 then + SetCop r9, CR_IDCFlush, NE ; flush the cache. + EXIT + +80 + TST r0, #alter_cacheable ; If we haven't changed any cacheability stuff then + BEQ %FT90 ; just return error. + + AND lr, r0, #all,wanted ; Get wanted flags. + LDMIA sp, {r0,r1,r3} ; Get back original flags, pointer and count. + ORR r0, r0, lr, LSR #given-wanted ; Wanted fields are now also given as we have done the conversion. + BIC r0, r0, #all:SHL:11 ; Clear wanted flags, we only want to change cacheability. + EOR r0, r0, #cacheable_bit ; If we made them uncacheable then make them cacheable again & v.v. + SUB r2, r3, r2 + SUBS r2, r2, #1 ; Change back the entries we have changed up to (but excluding) the error entry. + BLNE MemoryConvert +90 + ADRL r0, ErrorBlock_BadAddress +95 + STR r0, [sp] + SETV + EXIT + + +;---------------------------------------------------------------------------------------- +; ppn_to_logical +; +; In: r3 = page number +; r5 = physical address if given +; r6 = CamEntriesPointer +; r7 = MaxCamEntry +; +; Out: r9 corrupted +; CC => r4 = logical address +; CS => invalid page number +; +; Convert physical page number to logical address. +; +ppn_to_logical + CMP r7, r3 ; Validate page number. + ORRCCS pc, lr, #C_bit ; Invalid so return C set. + + LDR r4, [r6, r3, LSL #3] ; If valid then lookup logical address. + TST r0, #physical,given ; If physical address was given then + LDRNE r9, =&FFF + ANDNE r9, r5, r9 ; mask off page offset + ORRNE r4, r4, r9 ; and combine with logical address. + BICS pc, lr, #C_bit ; Return C clear. + + +;---------------------------------------------------------------------------------------- +; logical_to_physical +; +; In: r4 = logical address +; r8 = L2PT +; +; Out: r9 corrupted +; CC => r5 = physical address +; CS => invalid logical address, r5 corrupted +; +; Convert logical address to physical address. +; +logical_to_physical + MOV r9, r4, LSR #12 ; r9 = logical page number + ADD r9, r8, r9, LSL #2 ; r9 -> L2PT entry for logical address + MOV r5, r9, LSR #12 ; r5 = page offset to L2PT entry for logical address + LDR r5, [r8, r5, LSL #2] ; r5 = L2PT entry for L2PT entry for logical address + EOR r5, r5, #2_10 ; Check for valid page. + TST r5, #3 + ORRNES pc, lr, #C_bit + + LDR r5, [r9] ; r5 = L2PT entry for logical address + EOR r5, r5, #2_10 ; Check for valid page. + TST r5, #3 + ORRNES pc, lr, #C_bit + + LDR r9, =&FFF ; Valid so + BIC r5, r5, r9 ; mask off bits 0-11, + AND r9, r4, r9 ; get page offset from logical page + ORR r5, r5, r9 ; combine with physical page address. + BICS pc, lr, #C_bit + + +;---------------------------------------------------------------------------------------- +; physical_to_ppn +; +; In: r5 = physical address +; r7 = MaxCamEntry +; +; Out: r9-r11 corrupted +; CC => r3 = page number +; CS => invalid physical address, r3 corrupted +; +; Convert physical address to physical page number. +; +physical_to_ppn ROUT + MOV r9, #PhysRamTable + MOV r3, #0 ; Start at page 0. +10 + CMP r7, r3 ; Stop if we run out of pages + ORRCCS pc, lr, #C_bit ; (return with C set). + + LDMIA r9!, {r10,r11} ; Get start address and size of next block. + SUB r10, r5, r10 ; Determine if given address is in this block. + CMP r10, r11 + ADDCS r3, r3, r11, LSR #12 ; Move on to next block. + BCS %BT10 + + ADD r3, r3, r10, LSR #12 + BICS pc, lr, #C_bit ; Return with C clear. + + +;---------------------------------------------------------------------------------------- +; Symbols used in MemoryPhysSize and MemoryReadPhys +; + +; Shifts to determine number of bytes/words to allocate in table. +BitShift * 10 +ByteShift * BitShift + 3 +WordShift * ByteShift + 2 + +; Bit patterns for different types of memory. +NotPresent * &00000000 +DRAM_Pattern * &11111111 +VRAM_Pattern * &22222222 +ROM_Pattern * &33333333 +IO_Pattern * &44444444 +NotAvailable * &88888888 + + +;---------------------------------------------------------------------------------------- +; MemoryPhysSize +; +; In: r0 = 6 (reason code with flag bits 8-31 clear) +; +; Out: r1 = table size (in bytes) +; r2 = page size (in bytes) +; +; Returns information about the memory arrangement table. +; +MemoryPhysSize + MOV r1, #PhysSpaceSize :SHR: ByteShift + MOV r2, #4*1024 + MOV pc, lr + + +;---------------------------------------------------------------------------------------- +; MemoryReadPhys +; +; In: r0 = 7 (reason code with flag bits 8-31 clear) +; r1 -> memory arrangement table to be filled in +; +; Out: r1 -> filled in memory arrangement table +; +; Returns the physical memory arrangement table in the given block. +; +MemoryReadPhys ROUT + ENTRY "r1-r10" + + [ OSROM_ImageSize = 4096 + ; &00000000 to &00400000 is ROM. + MOV r2, #(&00400000-&00000000) :SHR: WordShift + LDR r3, =ROM_Pattern :OR: NotAvailable + BL fill_words + + ; &00400000 to &02000000 is allocated to ROM but is not present. + MOV r2, #(&02000000-&00400000) :SHR: WordShift + LDR r3, =NotPresent :OR: NotAvailable + BL fill_words + | + ; &00000000 to &00200000 is ROM. + MOV r2, #(&00200000-&00000000) :SHR: WordShift + LDR r3, =ROM_Pattern :OR: NotAvailable + BL fill_words + + ; &00200000 to &02000000 is allocated to ROM but is not present. + MOV r2, #(&02000000-&00200000) :SHR: WordShift + LDR r3, =NotPresent :OR: NotAvailable + BL fill_words + ] + + ; &02000000 to &02200000 is VRAM or not present. + MOV r4, #0 + LDR r4, [r4, #VRAMSize] ; Get amount of VRAM (in bytes). + TEQ r4, #0 + MOVNE r2, r4, LSR #WordShift ; If there is some then fill part of table. + LDRNE r3, =VRAM_Pattern :OR: NotAvailable + BLNE fill_words + + ; End of VRAM to &03000000 is not present. + RSB r4, r4, #&03000000-&02000000 + MOV r2, r4, LSR #WordShift + LDR r3, =NotPresent :OR: NotAvailable + BL fill_words + + ; &03000000 to &03800000 is I/O. + MOV r2, #(&03800000-&03000000) :SHR: WordShift + LDR r3, =IO_Pattern :OR: NotAvailable + BL fill_words + + ; &03800000 to &08000000 is not present. + MOV r2, #(&08000000-&03800000) :SHR: WordShift + LDR r3, =NotPresent :OR: NotAvailable + BL fill_words + + ; &08000000 to &10000000 is I/O (EASI space). + MOV r2, #(&10000000-&08000000) :SHR: WordShift + LDR r3, =IO_Pattern :OR: NotAvailable + BL fill_words + + ; &10000000 to &20000000 is DRAM or not present. + MOV r2, #&10000000 ; Current physical address. + MOV r3, #0 ; Next word to store in table. + MOV r4, #32 ; How much more we have to shift r3 before storing it. + MOV r5, #0 ; Current page number. + MOV r6, #PhysRamTable + LDR r7, [r3, #CamEntriesPointer] + ADD r7, r7, #4 ; Point to PPL entries. + LDR r8, [r3, #MaxCamEntry] +10 + LDMIA r6!, {r9,r10} ; Get physical address and size of next block. + + CMP r9, #&10000000 ; If not DRAM then + ADDCC r5, r5, r10, LSR #12 ; adjust current page number + BCC %BT10 ; and try next block. + + ADD r10, r10, r9 ; Add amount of unused space between current and start of block. + SUB r10, r10, r2 ; size = size + (physaddr - current) +20 + SUBS r4, r4, #4 ; Reduce shift. + MOVCS r3, r3, LSR #4 ; If more space in current word then shift it. + STRCC r3, [r1], #4 ; Otherwise, store current word + MOVCC r3, #0 ; and start a new one. + MOVCC r4, #28 + + CMP r2, r9 ; If not reached start of block then page is not present. + ORRCC r3, r3, #(NotPresent :OR: NotAvailable) :SHL: 28 + BCC %FT30 + LDR lr, [r7, r5, LSL #3] ; Page is there so get PPL and determine if it's available or not. + TST lr, #PageFlags_Unavailable + ORREQ r3, r3, #DRAM_Pattern :SHL: 28 + ORRNE r3, r3, #(DRAM_Pattern :OR: NotAvailable) :SHL: 28 + ADD r5, r5, #1 ; Increment page count. +30 + ADD r2, r2, #&1000 ; Increase current address. + SUBS r10, r10, #&1000 ; Decrease size of block. + BGT %BT20 ; Stop if no more block left. + + CMP r8, r5 ; Stop if we run out of pages. + BCS %BT10 + + TEQ r3, #0 ; If not stored last word then + MOVNE r3, r3, LSR r4 ; put bits in correct position + ADDNE r2, r2, r4, LSL #BitShift ; adjust current address + RSBNE r4, r4, #32 ; rest of word is not present + LDRNE lr, =NotPresent :OR: NotAvailable + ORRNE r3, r3, lr, LSL r4 + STRNE r3, [r1], #4 ; and store word. + + ; End of last block of DRAM to &20000000 is not present. + RSBS r2, r2, #&20000000 + MOVNE r2, r2, LSR #WordShift + LDRNE r3, =NotPresent :OR: NotAvailable + BLNE fill_words + + EXIT + + +fill_words + STR r3, [r1], #4 + SUBS r2, r2, #1 + BNE fill_words + MOV pc, lr + + +;---------------------------------------------------------------------------------------- +; MemoryAmounts +; +; In: r0 = flags +; bit meaning +; 0-7 8 (reason code) +; 8-11 1=return amount of DRAM +; 2=return amount of VRAM +; 3=return amount of ROM +; 4=return amount of I/O space +; 12-31 reserved (set to 0) +; +; Out: r1 = number of pages of the specified type of memory +; r2 = page size (in bytes) +; +; Return the amount of the specified type of memory. +; +MemoryAmounts ROUT + ENTRY "r3" + + BICS lr, r0, #&FF ; Get type of memory required (leave bits 12-31, non-zero => error). + BEQ %FT30 ; Don't understand 0 (so the spec says). + + TEQ lr, #4:SHL:8 ; Check for IO space. + LDREQ r1, =136*1024*1024 ; Just return 136M (includes VIDC and EASI space). + BEQ %FT20 + + TEQ lr, #3:SHL:8 ; Check for ROM. + LDREQ r1, =OSROM_ImageSize*1024 + BEQ %FT20 + + TEQ lr, #2:SHL:8 ; Check for VRAM. + MOVEQ r1, #0 ; Return amount of VRAM. + LDREQ r1, [r1, #VRAMSize] + BEQ %FT20 + + TEQ lr, #1:SHL:8 ; Check for DRAM. + BNE %FT30 + MOV r1, #0 + LDR lr, [r1, #RAMLIMIT] + LDR r1, [r1, #VRAMSize] + SUB r1, lr, r1 ; Return amount of RAM - amount of VRAM. + +20 + MOV r1, r1, LSR #12 ; Return as number of pages. + MOV r2, #4*1024 ; Return page size. + EXIT + +30 + ADRL r0, ErrorBlock_BadParameters + SETV + EXIT + + +;---------------------------------------------------------------------------------------- +; MemoryIOSpace +; +; In: r0 = 9 (reason code with flag bits 8-31 clear) +; r1 = controller ID +; bit meaning +; 0-7 controller sequence number +; 8-31 controller type: +; 0 = EASI card access speed control +; 1 = EASI space +; 2 = VIDC1 +; 3 = VIDC20 +; +; Out: r1 = controller base address or 0 if not present +; +; Return the location of the specified controller. +; +MemoryIOSpace ROUT + ENTRY "r2" + + AND r2, r1, #&FF ; Get sequence number. + MOV r1, r1, LSR #8 ; Get controller type. + CMP r1, #4 ; Make sure it's in range. + BCS %FT20 + + ADR lr, controller_types + LDR r1, [lr, r1, LSL #2] ; Get base address or offset to table. + TEQ r1, #0 ; If not present or + CMPNE r1, #1024 ; not offset to table then + EXIT GE ; return. + + ADD lr, lr, r1 ; Point to table indexed by sequence number. + LDR r1, [lr], #4 ; Get sequence number limit. + CMP r2, r1 ; Make sure it's in range. + BCS %FT20 + LDR r1, [lr, r2, LSL #2] ; Get base address. + EXIT + +20 + ADRL r0, ErrorBlock_BadParameters + SETV + EXIT + + +controller_types + [ IO_Type = "IOMD" + DCD IOMD_Base + IOMD_ECTCR ; Expansion card timing control. + DCD easi_space_table - controller_types + | + DCD 0 + DCD 0 + ] + [ VIDC_Type = "VIDC20" + DCD 0 + DCD VIDC + | + DCD VIDC + DCD 0 + ] + + [ IO_Type = "IOMD" +easi_space_table + DCD 8 ; Maximum of 8 expansion cards. + DCD PhysSpace + IOMD_EASI_Base0 + DCD PhysSpace + IOMD_EASI_Base1 + DCD PhysSpace + IOMD_EASI_Base2 + DCD PhysSpace + IOMD_EASI_Base3 + DCD PhysSpace + IOMD_EASI_Base4 + DCD PhysSpace + IOMD_EASI_Base5 + DCD PhysSpace + IOMD_EASI_Base6 + DCD PhysSpace + IOMD_EASI_Base7 + ] + + END diff --git a/s/Middle b/s/Middle new file mode 100644 index 0000000000000000000000000000000000000000..f6be1a0af2bebba3c04e58100a71d873cf01cc0d --- /dev/null +++ b/s/Middle @@ -0,0 +1,1293 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + TTL => Middle + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; VecRdLine - Read line from input stream (OSWORD 0 equivalent) + +; In r0 -> buffer for characters +; r1 = max length of line (excluding carriage return) +; r2 = lowest character put into buffer +; r3 = highest character put into buffer +; wp -> OsbyteVars + +; Out r1 = length of line (excluding carriage return) +; C=0 => line terminated by return (CR or LF) +; C=1 => line terminated by ESCAPE + +; ReadLine: suggested extensions (available RSN) +; +; are 1) stopping it reflecting control characters/characters not put in the +; buffer +; 2) making any reflection print a given character (for hiding passwords +; etc +; +; So, definition is : +; +; Top byte R0 contains flags : +; Bit 31 set means don't reflect characters that don't go in the buffer +; Bit 30 set means reflect with the character in R4 +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +VecRdLine ROUT + + Push "R4-R7" + AND R7, R0, #&C0000000 ; extract flags + AND R4, R4, #&FF + ORR R7, R7, R4 ; got flags, potential echo byte in R7 + + BIC R4, R0, #ARM_CC_Mask-3 ; R4 -> buffer + + MOV R6, #0 ; R6 = index into buffer + STRB R6, PageModeLineCount ; reset page lines + + B %FT10 + LTORG + +05 + SWI XOS_WriteC + BVS ReadLine_Vset +10 + SWI XOS_ReadC + BVS ReadLine_Vset + BCS %FT70 ; ESCAPE + + LDRB R5, WrchDest ; does output include VDU ? + TST R5, #2 + BNE %FT30 ; no, then still buffer + + LDRB R5, VDUqueueItems ; is VDU queueing ? + TEQ R5, #0 + BNE %BT05 ; yes, then just print + +30 + TEQ R0, #127 ; is it DELETE ? + TEQNE R0, #8 ; or backspace? + BNE %FT40 ; no, then skip + + TEQ R6, #0 ; yes, then have we any chars ? + BEQ %BT10 ; no, then loop + SUB R6, R6, #1 ; go back 1 char + MOV R0, #127 + B %BT05 ; print DEL and loop + +40 + TEQ R0, #21 ; is it CTRL-U ? + BNE %FT50 ; no, then skip + + TEQ R6, #0 ; yes, then have we any chars ? + BEQ %BT10 ; no, then loop + +45 + SWI XOS_WriteI+127 ; print DELs to start of line + BVS ReadLine_Vset + SUBS R6, R6, #1 + BNE %BT45 + B %BT10 ; then loop + +50 + TEQ R0, #13 ; is it CR ? + TEQNE R0, #10 ; or LF ? + MOVEQ r0, #13 ; always store CR if so + STRB R0, [R4, R6] ; store byte in buffer + BEQ %FT60 ; Exit if either + + CMP R6, R1 ; is buffer full ? + MOVCS R0, #7 ; if so, beep and loop + BCS %BT05 + + CMP R0, R2 ; is char >= min ? + CMPCS R3, R0 ; and char <= max ? + ADDCS R6, R6, #1 ; if so, then inc pointer + BCS %FT80 + CMP R7, #0 ; no reflection + BMI %BT10 ; of non-entered chars + +80 TST R7, #1:SHL:30 + ANDNE R0, R7, #&FF ; echo char -> R0 + + B %BT05 ; echo character + +60 SWI XOS_NewLine + BVS ReadLine_Vset + +; insert code here to call NetVec with R0 = &0D + +70 + CLRV +EndReadLine + MOVVC R0, R4 ; restore R0 + MOV R5, #0 + LDRB R5, [R5, #ESC_Status] + MOVS R5, R5, LSL #(32-6) ; shift esc bit into carry + + MOV R1, R6 ; R1 := length + Pull "R4-R7, lr" ; Always claiming vector + BIC lr, lr, #V_bit :OR: C_bit + MOV r12, pc + AND r12, r12, #V_bit :OR: C_bit + ORRS pc, lr, r12 ; back with C, V affected. + +ReadLine_Vset + SETV + B EndReadLine + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_Control (deprecated): set handlers + +SCTRL Push "R0-R3, lr" + + TEQP PC, #SVC_mode+I_bit ; need IRQs off to get consistent state + MOV R0, #EventHandler + MOV R1, R3 + BL CallCESWI + STR R1, [stack, #3*4] + + MOV R0, #EscapeHandler + LDR R1, [stack, #2*4] + BL CallCESWI + STR R1, [stack, #2*4] + + MOV R0, #ErrorHandler + Pull "R1, R3" + BL CallCESWI + MOV R0, R1 + MOV R1, R3 + + Pull "R2, R3, lr" + ExitSWIHandler + + +CallCESWI + Push lr + MOV r2, #0 ; readonly + SWI XOS_ChangeEnvironment + Pull pc + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_SetEnv (deprecated): Environment setting + +SSTENV Push "R0, R1, lr" + TEQP PC, #SVC_mode+I_bit ; no irqs - want consistent set. + MOV R0, #AddressExceptionHandler + MOV R1, R7 + SWI XOS_ChangeEnvironment + MOV R7, R1 + + MOV R0, #DataAbortHandler + MOV R1, R6 + SWI XOS_ChangeEnvironment + MOV R6, R1 + + MOV R0, #PrefetchAbortHandler + MOV R1, R5 + SWI XOS_ChangeEnvironment + MOV R5, R1 + + MOV R0, #UndefinedHandler + MOV R1, R4 + SWI XOS_ChangeEnvironment + MOV R4, R1 + + MOV R0, #MemoryLimit + LDR R1, [stack, #4] + SWI XOS_ChangeEnvironment + STR R1, [stack, #4] + + MOV R0, #ExitHandler + Pull "R1" + BL CallCESWI + Push "R1" + + MOV R12, #0 + LDR R2, [R12, #RAMLIMIT] ; this is read-only + MOV R3, #0 ; never any Brazil-type buffering + ; m2 tools will complain if there is! + Pull "R0, R1, lr" + ExitSWIHandler + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Change user state SWIs +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +SINTON BIC lr, lr, #I_bit + ExitSWIHandler + +SINTOFF ORR lr, lr, #I_bit + ExitSWIHandler + +SENTERSWI ORR lr, lr, #SVC_mode + ExitSWIHandler + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_BreakPt: user breakpoint - unsuitable for debugging SVC mode code! + +SBRKPT ROUT + + ADD sp, sp, #4 ; discard stacked R11 + MOV r12, #0 + LDR r12, [r12, #BrkBf] + SUB r14, R14, #4 + STR r14, [r12, #15*4] ; PC of the SWI put in. + TST r14, #SVC_mode + BNE %FT01 + STMIA r12!, {r0} + MOV r0, r12 + LDMFD sp, {r10-r12} + STMIA r0, {r1-r12, r13_usr, r14_usr}^ ; user mode case done. + +10 LDR stack, =SVCSTK + MOV r12, #BrkAd_ws + LDMIA r12, {r12, pc} ; call breakpoint handler + + +01 TST r14, #1 ; SWI mode? + TSTNE r14, #2 + BNE %FT02 ; [yes] + + STMIA r12!, {r0} + MOV r0, r12 + LDMFD sp, {r10-r12} ; Not banked if IRQ mode + TEQP pc, R14 ; get at registers + NOP + STMIA r0, {r1-r14} + TEQP pc, #SVC_mode + B %BT10 + + +02 MOV r14, r12 ; supervisor mode. R14 in buffer dead + LDMFD sp!, {r10-r12} + STMIA r14, {r0-r14} + B %BT10 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_UnusedSWI (deprecated): Set the unused SWI handler + +SUNUSED Push "R1, lr" + MOV R1, R0 + MOV R0, #UnusedSWIHandler + SWI XOS_ChangeEnvironment + MOV R0, R1 + Pull "R1, lr" + ExitSWIHandler + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_SetCallBack: Set callback flag + +SSETCALL ROUT + + TEQP pc, #SVC_mode+I_bit + MOV r10, #0 + LDRB r11, [r10, #CallBack_Flag] + ORR r11, r11, #CBack_OldStyle + STRB r11, [r10, #CallBack_Flag] + Pull "r11" + Pull "r10-r12" + MOVS pc, lr ; Do NOT exit via normal mechanism + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI read mouse information +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +VecMouse + MOV R10, #MouseV + TEQP PC, #SVC_mode+I_bit ; no irqs + Push "lr" + BL CallVector + Pull "lr" + ExitSWIHandler + + [ :LNOT: DriversInKernel +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_SerialOp when not in kernel +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +SerialOp ROUT + MOV r10, #SerialV + Push lr + BL CallVector + Pull lr + BICCC lr, lr, #C_bit + ORRCS lr, lr, #C_bit + B SLVK_TestV + ] + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Supervisor routines to set default handlers +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +; Reset Error and Escape handlers + +DEFHAN LDR R1, =GeneralMOSBuffer ; decent length error buffer + ADR R0, ERRORH + ADR R2, ESCAPH + MOV R3, #0 + MOV R4, R14 + SWI XOS_Control + + MOV r0, #UpCallHandler + ADR r1, DefUpcallHandler + MOV r2, #0 + SWI XOS_ChangeEnvironment + + MOV PC, R4 + +; Reset Exception, Event, BreakPoint, UnusedSWI, Exit and CallBack handlers + +DEFHN2 MOV R12, R14 + MOV R0, #0 + MOV R1, #0 + MOV R2, #0 + ADR R3, EVENTH + SWI XOS_Control + LDR R0, =DUMPER + ADR R1, NOCALL + SWI XOS_CallBack + ADRL R0, CLIEXIT + MOV R1, #0 + MOV R2, #0 + ADR R4, UNDEF + ADR R5, ABORTP + ADRL R6, ABORTD + ADRL R7, ADDREX + SWI XOS_SetEnv + LDR R0, =DUMPER + ADR R1, DEFBRK + SWI XOS_BreakCtrl + ADRL R0, NoHighSWIHandler + SWI XOS_UnusedSWI + MOV PC, R12 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; system handlers +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +DefUpcallHandler +ESCAPH +EVENTH MOV pc, lr + + +NOCALL MOV r0, #0 ; default callback routine + LDR r14, [r0, #CallBf] + LDMIA r14, {r0-r12, r13_usr, r14_usr}^ ; load user's regs + NOP + LDR r14, [r14, #4*15] + MOVS pc, r14 + + +ERRORH ROUT + + [ International + ADR R0,KernelMessagesBlock+4 + ADR R1,ErrorToken + MOV R2,#0 + SWI XMessageTrans_Lookup + MOVVC R12,R2 + ADRVS R12,ErrorText + +01 + LDRB R0,[R12],#1 + CMP R0,#32 + BLT %FT99 + CMP R0,#"%" + SWINE XOS_WriteC + BVS %FT99 + BNE %BT01 + + LDRB R0,[R12],#1 ; Found a % + CMP R0,#32 + BLT %FT99 + + CMP R0,#"0" + LDREQ R0,=GeneralMOSBuffer+8 + BEQ %FT10 + CMP R0,#"1" + BNE %BT01 + + LDR R3,=GeneralMOSBuffer+4 + LDR R0,[R3] + LDR R1,=MOSConvertBuffer + MOV R2,#12 + SWI XOS_ConvertHex8 + +02 + LDRB R1, [R0], #1 + CMP R1, #"0" + BEQ %BT02 + CMP R1, #0 + SUBEQ R0, R0, #1 + SUB R0, R0, #1 + +10 + SWI XOS_Write0 + BVC %BT01 + +99 + SWI XOS_NewLine + + MOV R0, #0 + STRB R0, [R0, #ErrorSemaphore] ; Enable error translation, in case we got here in the + ; middle of looking up an error + + B GOSUPV + +ErrorToken = "Error:" +ErrorText = "Error: %0 (Error Number &%1)",0 + ALIGN + | + + SWI OS_WriteS + = 10,13,"Error:",10,13, 0 + ALIGN + LDR r0, =GeneralMOSBuffer+4 + BL PrintError + B GOSUPV + ] + + +DEFBRK + [ International + TEQP pc, #0 + MOV r0, r0 + MOV r13, #0 + LDR r13, [r13, #BrkBf] + LDR r0, [r13, #15*4] + LDR r1, =GeneralMOSBuffer + MOV r2, #?GeneralMOSBuffer + SWI OS_ConvertHex8 + +; r0 -> address + + MOV R4,R0 + ADR R0,KernelMessagesBlock+4 + ADR R1,BreakToken + LDR R2,=GeneralMOSBuffer+16 + MOV R3,#256-16 + SWI XMessageTrans_Lookup + MOVVC R0,R2 + ADRVS R0,BreakText + SWI OS_Write0 + SWI OS_NewLine + + | + SWI OS_WriteS + = "Stopped at break point at &", 0 + ALIGN + TEQP pc, #0 + MOV r0, r0 + MOV r13, #0 + LDR r13, [r13, #BrkBf] + LDR r0, [r13, #15*4] + LDR r1, =GeneralMOSBuffer + MOV r2, #?GeneralMOSBuffer + SWI OS_ConvertHex8 + SWI OS_Write0 + SWI OS_NewLine + ] + +Quit_Code + SWI OS_Exit + + [ International + +BreakToken = "BreakPt:" +BreakText = "Stopped at break point at &%0",0 + ALIGN + + ] + +PrintError + MOV R12, R14 + LDR R10, [R0], #4 + SWI XOS_Write0 + BVS %FT02 + [ :LNOT: International + SWI XOS_WriteS + = " (Error number &", 0 + BVS %FT02 + ] + LDR R1,=GeneralMOSBuffer + MOV R2, #&E0 + MOV R0, R10 + SWI XOS_ConvertHex8 ; can't fail! +01 LDRB R1, [R0], #1 + CMP R1, #"0" + BEQ %BT01 + CMP R1, #0 + SUBEQ R0, R0, #1 + [ International ; We might not have any stack so .. + SUB R11,R0, #1 ; R11 -> Error number + ADR R0, KernelMessagesBlock+4 + ADR R1, PrintErrorString + MOV R2,#0 ; Don't copy message + SWI XMessageTrans_Lookup + ADRVS R2,PrintErrorString+4 ; If no MessageTrans point at english text. +11 + LDRB R0,[R2],#1 + CMP R0,#32 + BLT %FT13 + CMP R0,#"%" + SWINE XOS_WriteC + BVS %FT13 + BNE %BT11 + + LDRB R0,[R2],#1 + CMP R0,#32 + BLT %FT13 ; Just in case the % is the last character ! + + CMP R0,#"0" ; We only know about %0 + BNE %BT11 + +12 + LDRB R0,[R11],#1 ; Print error number. + CMP R0,#32 + BLT %BT11 + SWI XOS_WriteC + BVC %BT12 + +13 + | + SUB R0, R0, #1 + SWI XOS_Write0 + SWIVC XOS_WriteI+")" + ] + SWIVC XOS_NewLine +02 MOVS PC, R12 + + [ International +PrintErrorString + = "Err: (Error number &%0)", 0 + ALIGN + ] + + LTORG + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Exception handling + +DumpyTheRegisters ROUT + LDR R1, [R0, -R0] ; PC when exception happened + STR R1, [R0, #(15-8)*4] ; In the right slot now ... + TST R1, #SVC_mode + STMEQIA R0, {R8-R14}^ ; user mode case done. + BEQ UNDEF1 + + TST R1, #1 ; SWI mode? + TSTNE R1, #2 + BNE %FT02 + ORR R1, R1, #I_bit :OR: F_bit + ; keep interrupts off until handlers restored + TEQP R1, #0 ; get at registers + NOP + STMIA R0, {R8-R14} + TEQP PC, #SVC_mode :OR: I_bit :OR: F_bit + AND R1, R1, #SVC_mode + EORS R2, R1, #FIQ_mode ; Was we in FIQ ? Zero if so + MOVEQ R3, #IOC + STREQB R2, [R3, #IOCFIQMSK] ; Blow away all FIQ sources + B UNDEF1 + +02 STMIA R0, {R8-R14} + +; ... and fall into + +UNDEF1 LDR sp, =SVCSTK ; Flatten superstack + + [ ExceptionsAreErrors + MOV R0, #0 + LDR R0, [R0, #ExceptionDump] + ADD R1, R0, #10*4 ; point at dumped R10 + LDMIA R1, {R10-R12} ; try and put back user registers + Push "R10-R12" ; for error handler to find on stack + LDR R1, [R0, #15*4] + Push R1 + + LDR R0, BranchThroughZeroInstruction ; load the B RESET1 instr. + STR R0, [R1, -R1] ; and store it at zero again + + BIC R14, R14, #ARM_CC_Mask + LDR R0, =GeneralMOSBuffer+128 ; so can do deviant sharing ! + + [ International + MOV r10, #0 + LDRB r10, [r10, #ErrorSemaphore] + TEQ r10, #0 ; if ok to translate error + MOVEQ r10, r14 + BEQ %FT10 + ] + + LDR r11, [r14], #4 ; Copy error number + STR r11, [r0], #4 + +01 LDRB r11, [r14], #1 ; Copy error string + STRB r11, [r0], #1 + CMP r11, #"%" ; Test for "%" near end of string + BNE %BT01 +10 + SUB r1, r0, #1 ; point, ready for conversion + + LDR R2, =GeneralMOSBuffer+?GeneralMOSBuffer + SUB r2, r2, r1 ; amount left in buffer + + MOV R0, #0 + LDR R0, [R0, #ExceptionDump] + LDR R0, [R0, #15*4] ; saved PC + BIC R0, R0, #ARM_CC_Mask + SWI XOS_ConvertHex8 + + [ International + MOV r4, #0 + LDRB r4, [r4, #ErrorSemaphore] + TEQ r4, #0 + LDRNE R0, =GeneralMOSBuffer+128 + MOVEQ R4, R0 + MOVEQ R0, R10 + BLEQ TranslateError_UseR4 + | + LDR R0, =GeneralMOSBuffer+128 + ] + + TEQP PC, #IRQ_mode+I_bit + MOV R1, #0 + STR R1, [R1, #IRQsema] + LDR SPIRQ, =IRQSTK + SWI OS_GenerateError + | + Push R14 + BL DEFHAN + BL DEFHN2 + Pull R0 + TEQP PC, #IRQ_mode + NOP + LDR SPIRQ, =IRQSTK + BIC R0, R0, #ARM_CC_Mask + SWI OS_Write0 + B UNDEF3 + ] + + LTORG + +UNDEF ROUT + TEQP pc, #F_bit :OR: I_bit :OR: SVC_mode ; FIQ off too + STR R14, [R0, -R0] + MOV R14, #0 + LDR R14, [R14, #ExceptionDump] + STMIA R14!, {R0-R7} + MOV R0, R14 + BL DumpyTheRegisters + [ ExceptionsAreErrors + MakeErrorBlock UndefinedInstruction + | + = "Undefined instruction at ", 0 + ALIGN + ] + +ABORTP ROUT + TEQP pc, #F_bit :OR: I_bit :OR: SVC_mode ; FIQ off too + STR R14, [R0, -R0] + MOV R14, #0 + LDR R14, [R14, #ExceptionDump] + STMIA R14!, {R0-R7} + MOV R0, R14 + BL DumpyTheRegisters + + [ ExceptionsAreErrors + MakeErrorBlock InstructionAbort + | + = "Abort on instruction fetch at ", 0 + ALIGN + ] + +ABORTD ROUT + TEQP pc, #F_bit :OR: I_bit :OR: SVC_mode ; FIQ off too + STR R14, [R0, -R0] + MOV R14, #0 + LDR R14, [R14, #ExceptionDump] + STMIA R14!, {R0-R7} + MOV R0, R14 + BL DumpyTheRegisters + [ ExceptionsAreErrors + MakeErrorBlock DataAbort + | + = "Abort on data transfer at ", 0 + ALIGN + ] + + +ADDREX ROUT + TEQP pc, #F_bit :OR: I_bit :OR: SVC_mode ; FIQ off too + STR R14, [R0, -R0] + MOV R14, #0 + LDR R14, [R14, #ExceptionDump] + STMIA R14!, {R0-R7} + MOV R0, R14 + BL DumpyTheRegisters + + [ ExceptionsAreErrors + MakeErrorBlock AddressException + | + = "Address exception at ", 0 + ALIGN + ] + + +; Can branch through zero in any mode + +RESET1 ROUT + + STR R1, [R0, -R0] + MOV R1, #0 + LDR R1, [R1, #ExceptionDump] + STMIA R1, {R0-R15} + LDR R0, [R0, -R0] + STR R0, [R1, #1*4] + SWI XOS_EnterOS + + [ ExceptionsAreErrors + BL UNDEF1 + MakeErrorBlock BranchThrough0 + | + LDR sp, =SVCSTK + TEQP PC, #IRQ_mode + LDR SPIRQ, =IRQSTK + TEQP PC, #0 + BL DEFHAN + BL DEFHN2 + SWI OS_WriteS + = "Entering Supervisor because of branch through 0", 0 + B UNDEF2 + ] + +BranchThroughZeroInstruction + [ ProcessorVectors + LDR PC, .+ProcVec_Branch0 + | + B .+(RESET1-0) + ] + + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI to call the UpCall vector +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +DoAnUpCall ROUT + + Push lr ; better have one of these to pull later ! + AND r10, lr, #&F0000000 ; copy user flags (I_bit clear) + TEQP r10, #SVC_mode ; ints on, stay in SVC mode, flags in psr + MOV r10, #UpCallV + BL CallVector + Pull lr + BIC lr, lr, #&F0000000 + MOV R10, PC, LSR #(32-4) + ORR lr, lr, R10, LSL #(32-4) + ExitSWIHandler + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_ChangeEnvironment: Call the environment change vector +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +ChangeEnvironment ROUT + + Push lr + MOV R10, #ChangeEnvironmentV + BL CallVector + Pull lr + B SLVK_TestV + + +; ..... and the default handler ..... + +AdjustOurSet + TEQP PC, #SVC_mode+I_bit + CMP R0, #MaxEnvNumber + BHI AOS_Silly + + [ False + CMP r0, #CallBackHandler + BLEQ testcallbackpending + ] + + ADR R10, AOS_Table + ADD R11, R0, R0, LSL #1 ; number * 3 + ADD R10, R10, R11, LSL #2 ; point at entry + + MOV R12, R1 + LDR R11, [R10] + CMP R11, #0 + LDRNE R1, [R11] + CMPNE R12, #0 + STRNE R12, [R11] + + MOV R12, R2 + LDR R11, [R10, #4] + CMP R11, #0 + LDRNE R2, [R11] + CMPNE R12, #0 + STRNE R12, [R11] + + MOV R12, R3 + LDR R11, [R10, #8] + CMP R11, #0 + LDRNE R3, [R11] + CMPNE R12, #0 + STRNE R12, [R11] + + Pull pc,,^ + +AOS_Silly + ADR r0, ErrorBlock_BadEnvNumber + [ International + BL TranslateError + ] +exit_AOS + Pull "lr" + ORRS pc, lr, #V_bit + MakeErrorBlock BadEnvNumber + + [ False + +testcallbackpending + CMP r1, #0 ; OK if only reading + CMPEQ r2, #0 + CMPEQ r3, #0 + LDRNEB r10, [r0, #CallBack_Flag-CallBackHandler] + TSTNE r10, #CBack_OldStyle + MOVEQ pc, r14 + SetBorder r0, r14, 15, 0, 0 + ADR r0, ErrorBlock_CallbackPending + B exit_AOS + MakeErrorBlock CallbackPending + ] + +AOS_Table + & MemLimit ; MemoryLimit + & 0 + & 0 + + & UndHan ; UndefinedHandler + & 0 + & 0 + + & PAbHan ; PrefetchAbortHandler + & 0 + & 0 + + & DAbHan ; DatabortHandler + & 0 + & 0 + + & AdXHan ; AddressExceptionHandler + & 0 + & 0 + + & 0 ; OtherExceptionHandler + & 0 + & 0 + + & ErrHan ; ErrorHandler + & ErrHan_ws + & ErrBuf + + & CallAd ; CallBackHandler + & CallAd_ws + & CallBf + + & BrkAd ; BreakPointHandler + & BrkAd_ws + & BrkBf + + & EscHan ; EscapeHandler + & EscHan_ws + & 0 + + & EvtHan ; EventHandler + & EvtHan_ws + & 0 + + & SExitA ; ExitHandler + & SExitA_ws + & 0 + + & HiServ ; UnusedSWIHandler + & HiServ_ws + & 0 + + & ExceptionDump ; ExceptionDumpArea + & 0 + & 0 + + & AplWorkSize ; application space size + & 0 + & 0 + + & Curr_Active_Object + & 0 + & 0 + + & UpCallHan + & UpCallHan_ws + & 0 + + assert (.-AOS_Table)/12 = MaxEnvNumber + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_ReadDefaultHandler + +; In r0 = environment number + +ReadDefaultHandler ROUT + + CMP r0, #(dhte-defhantab)/12 + MOVHS r0, #0 ; return wally value + ADD r10, r0, r0, LSL #1 ; *3 + ADD r10, pc, r10, LSL #2 ; *4 (pc = defhantab-4) + LDMIB r10, {r1-r3} ; gives additional +4 + ExitSWIHandler + +defhantab + & 0 ; wally entry + & 0 + & 0 + + & UNDEF ; UndefinedHandler + & 0 + & 0 + + & ABORTP ; PrefetchAbortHandler + & 0 + & 0 + + & ABORTD ; DataAbortHandler + & 0 + & 0 + + & ADDREX ; AddressExceptionHandler + & 0 + & 0 + + & 0 ; OtherExceptionHandler + & 0 + & 0 + + & ERRORH ; ErrorHandler + & 0 + & GeneralMOSBuffer + + & NOCALL ; CallBackHandler + & 0 + & DUMPER + + & DEFBRK ; BreakPointHandler + & 0 + & DUMPER + + & ESCAPH ; EscapeHandler + & 0 + & GeneralMOSBuffer + + & EVENTH ; EventHandler + & 0 + & 0 + + & CLIEXIT ; ExitHandler + & 0 + & 0 + + & NoHighSWIHandler ; UnusedSWIHandler + & 0 + & 0 + + & 0 ; exception dump + & 0 + & 0 + + & 0 ; app space size + & 0 + & 0 + + & 0 ; cao pointer + & 0 + & 0 + + & DefUpcallHandler ; upcall handler + & 0 + & 0 + +dhte + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r0 = sysinfo handle + +; Out r0 = sysinfo for r0in + +ReadSysInfo_Code ROUT + CMP r0, #1 + BCC %FT00 ; r0 = 0 + BEQ %FT10 ; r0 = 1 + CMP r0, #3 + BCC %FT20 ; r0 = 2 + BEQ %FT30 ; R0 = 3 + CMP r0, #5 + BCC %FT40 ; R0 = 4 + BEQ %FT50 ; R0 = 5 + + ; R0 > 5, so illegal value + + ADR r0, ErrorBlock_BadReadSysInfo + [ International + Push "lr" + BL TranslateError + Pull "lr" + ] + ORR lr, lr, #V_bit + ExitSWIHandler + + MakeErrorBlock BadReadSysInfo + +; ReadSysInfo(0) - return configured screensize in r0 + +00 + Push "r1, r2, lr" + MOV r0, #ReadCMOS + MOV r1, #ScreenSizeCMOS + SWI XOS_Byte + AND r0, r2, #&7F ; top bit is reserved + MOV r10, #0 + LDR r10, [r10, #Page_Size] + MUL r0, r10, r0 + BL MassageScreenSize ; adjust for min and max or default values + Pull "r1, r2, lr" + ExitSWIHandler + +; ReadSysInfo(1) - returns configured mode/wimpmode in r0 +; configured monitortype in r1 +; configured sync in r2 +; (all de-autofied) + +10 + Push "r3-r5, lr" + BL Read_Configd_Sync + MOV r2, r0 + [ ModeSelectors + LDR r1, =VduDriverWorkSpace+CurrentMonitorType ; read current monitortype + LDR r1, [r1] + | + BL Read_Configd_MonitorType + MOV r1, r0 + ] + BL Read_Configd_Mode + CMP r0, #-1 ; if none of the three are auto, don't bother with translation + CMPNE r1, #-1 + CMPNE r2, #-1 + BNE %FT15 + BL TranslateMonitorLeadType ; issue service or work it out ourselves + CMP r0, #-1 ; if mode auto + MOVEQ r0, r3 ; then replace with default + CMP r1, #-1 ; if monitortype auto + MOVEQ r1, r4 ; then replace with default + CMP r2, #-1 ; if sync auto + MOVEQ r2, r5 ; then replace with default +15 + Pull "r3-r5, lr" + ExitSWIHandler + +; ReadSysInfo(2) +; +; in: r0 = 2 +; +; out: r0 = hardware configuration word 0 +; bits 0-7 = special functions chip type +; 0 => none +; 1 => IOEB +; bits 8-15 = I/O control chip type +; 0 => IOC +; 1 => IOMD +; bits 16-23 = memory control chip type +; 0 => MEMC1/MEMC1a +; 1 => IOMD +; bits 24-31 = video control chip type +; 0 => VIDC1a +; 1 => VIDC20 +; r1 = hardware configuration word 1 +; bits 0-7 = I/O chip type +; 0 => absent +; 1 => 82C710/711 or SMC'665 or similar +; bits 8-31 reserved (set to 0) +; r2 = hardware configuration word 2 +; bits 0-7 = LCD controller type +; 0 => absent +; 1 => present (type 1) eg A4 portable +; 2 => present (type 2) eg Stork portable + [ MorrisSupport +; bits 8-15 = IOMD variant +; 0 => IOMD +; 1 => IOMDL ie ARM7500 (Morris) +; bits 16-23 = VIDC20 variant +; 0 => VIDC20 +; 1 => VIDC2L ie ARM7500 (Morris) +; bits 24-31 reserved (set to 0) + | +; bits 8-31 reserved (set to 0) + ] +; r3 = word 0 of unique machine ID, or 0 if unavailable +; r4 = word 1 of unique machine ID, or 0 if unavailable + +; Bits in IOSystemType + +IOST_IOEB * 1 ; On IOMD systems this really means IOMD. +IOST_82C710 * 2 +IOST_LC * 4 +IOST_82C711 * 8 +IOST_37C665 * 16 + [ MorrisSupport +IOST_7500 * 32 ;Running on ARM7500 (Morris) so actually IOMDL and VIDC2L +IOST_BATMAN * 64 ;Stork keyboard/battery controller seems to be present + ] +20 + MOV r0, #0 + LDR r3, [r0, #RawMachineID+0] + LDR r4, [r0, #RawMachineID+4] + MOV r3, r3, LSR #8 ; lose first 8 bits + ORR r3, r3, r4, LSL #24 ; and put bits 0..7 of r3 into bits 24..31 of r2 + MOV r4, r4, LSL #8 ; lose CRC bits + MOV r4, r4, LSR #16 ; and move the rest down to the bottom + LDRB r0, [r0, #IOSystemType] + + ANDS r2, r0, #IOST_LC + MOVNE r2, #1 ; make r2 0 or 1 + [ MorrisSupport + TST r0, #IOST_BATMAN + MOVNE r2, #2 ;NE, its a Stork portable + TST r0, #IOST_7500 + ORRNE r2, r2, #&00000100 ;NE, Morris based machine with IOMDL + ORRNE r2, r2, #&00010000 ;NE, and VIDC2L + ] + ANDS r1, r0, #IOST_82C710 :OR: IOST_82C711 :OR: IOST_37C665 + MOVNE r1, #1 ; make r1 0 or 1 + + [ IO_Type = "IOMD" + [ VIDC_Type = "VIDC20" + LDR r0, =&01010100 + | + LDR r0, =&00010100 + ] + | + ASSERT IOST_IOEB = 1 + AND r0, r0, #IOST_IOEB ; and r0 0 or 1 + [ VIDC_Type = "VIDC20" + ORR r0, r0, #&01000000 + ] + ] + ExitSWIHandler + +; ReadSysInfo(3) +; +; in: r0 = 3 +; +; out: r0 = I/O chip base features mask 710 711 665 +; Bits 0..3 Base IDE type 1 1 1 +; Bits 4..7 Base FDC type 1 1 1 +; Bits 8..11 Base parallel type 1 1 1 +; Bits 12..15 Base 1st serial type 1 1 1 +; Bits 16..19 Base 2nd serial type 0 1 1 +; Bits 20..23 Base Config type 1 2 3 +; Bits 24..31 Reserved 0 0 0 +; +; r1 = I/O chip extra features mask 710 711 665 +; Bits 0..3 IDE extra features 0 0 0 +; Bits 4..7 FDC extra features 0 0 0 +; Bits 8..11 parallel extra features 0 0 1 +; Bits 12..15 1st serial extra features 0 0 1 +; Bits 16..19 2nd serial extra features 0 0 1 +; Bits 20..23 config extra features 0 0 0 +; Bits 24..31 Reserved 0 0 0 +; +; r2-r4 undefined (reserved for future expansion) +; + +30 + MOV r0, #0 ; used as index and as default value + LDRB r1, [r0, #IOSystemType] + TST r1, #IOST_82C710 + LDRNE r0, =&00101111 + MOVNE r1, #0 + TST r1, #IOST_82C711 + LDRNE r0, =&00211111 + MOVNE r1, #0 + TST r1, #IOST_37C665 + LDRNE r0, =&00311111 + LDRNE r1, =&00011100 + MOV r2, #0 + MOV r3, #0 + MOV r4, #0 + ExitSWIHandler + +; OS_ReadSysInfo 4 (SWI &58) +; +; On entry: r0 = 4 (reason code) +; +; On exit: r0 = LSW of Ethernet Network Address (or 0) +; r1 = MSW of Ethernet Network Address (or 0) +; +; Use: Code loaded from the dedicated Network Expansion Card or +; from a normal Expansion Card should use the value returned +; by this call in preference to a locally provided value. + +40 + MOV r0, #0 + LDRB r1, [ r0, #RawMachineID ] ; The family byte + TEQ r1, #&81 ; Is this a custom part? + BNE ExitNoEthernetAddress + LDR r1, [ r0, #RawMachineID+4 ] ; Acorn's ID and part# + [ True + BIC r1, r1, #&FF000000 ; Remove the CRC + LDR r0, =&0050A4 ; Acorn's ID is &005 + | ; Version for no checking of Manufacture's ID + MOV r1, r1, LSL #20 + MOV r1, r1, LSR #20 ; Remove CRC and ID + LDR r0, =&0A4 + ] + TEQ r1, r0 ; Is this one of our chips? + BNE ExitNoEthernetAddress + MOV r0, #0 + LDR r0, [ r0, #RawMachineID ] + MOV r0, r0, LSR #8 ; Lose family byte + LDR r1, =&0000A4100000 ; Base Ethernet address + ADD r0, r1, r0 ; Add Dallas part to base + MOV r1, #0 ; Top 16 bits are zero + ExitSWIHandler + +ExitNoEthernetAddress + MOV r0, #0 + MOV r1, #0 + ExitSWIHandler + +; OS_ReadSysInfo 5 +; +; On entry: r0 = 5 (reason code) +; +; On exit: r0 = LSW of Raw data from Dallas Chip +; r1 = MSW of Raw data from Dallas Chip + +50 + MOV r0, #0 + LDR r1, [r0, #RawMachineID+4] + LDR r0, [r0, #RawMachineID+0] + ExitSWIHandler + + LTORG + + END diff --git a/s/ModHand b/s/ModHand new file mode 100644 index 0000000000000000000000000000000000000000..90a9883615aec83552a8848c97cc7bd445f8731d --- /dev/null +++ b/s/ModHand @@ -0,0 +1,2784 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + TTL => ModHand - the Relocatable Module Handler + +ExtraRMANeeded * 24*1024 ; Amount you get extra on top of what you configured + + +; Test version, incorporating multiple incarnation attempt + +; The module handler needs to know the structure of the HPD, and nodes. +; See RMTidy in particular. + +;************************************************************** +; +; Module chain structure: ModuleList points at a (singly-linked) list of +; nodes with following fields: + + ^ 0 +Module_chain_Link # 4 ; the link to the next module info block +Module_code_pointer # 4 ; pointer to the module. +Module_Hardware # 4 ; hardware base for podules; 0 for soft loaders +Module_incarnation_list # 4 ; pointer to list of incarnation specifiers +Module_ROMModuleNode # 4 ; pointer to ROM module node if in ROM (main, podule, extn), else zero + +ModInfo * @ + +; The incarnation list is a list of sub-nodes, one for each incarnation. + + ^ 0 +Incarnation_Link # 4 ; link to next incarnation +Incarnation_Workspace # 4 ; 4 private bytes for this life +Incarnation_Postfix # 0 ; postfix string starts here + +; Incarnations are distinguished by their postfix, which is separated +; from the module name by a special character: + +Postfix_Separator * "%" + +;************************************************************** + +; Handler initialisation. +; registers preserved + +; ROM module descriptor format + + ^ 0 +ROMModule_Link # 4 ; pointer to next node +ROMModule_Name # 4 ; pointer to module name (either directly in ROM, or in an RMA block) +ROMModule_BaseAddress # 4 ; start of module, if directly accessible +ROMModule_Version # 4 ; BCD version number, decimal point between bits 15,16 eg "1.23" => &00012300 +ROMModule_PoduleNumber # 4 ; podule number (0..3 = normal podule, -1 = main ROM, -2..-n = extension ROM) +ROMModule_ChunkNumber # 4 ; chunk number if in podule or extension ROM, unused (?) if in main ROM +ROMModule_OlderVersion # 4 ; pointer to node holding the next older version of this module, 0 if none +ROMModule_NewerVersion # 4 ; pointer to node holding the next newer version of this module, 0 if none +ROMModule_CMOSAddrMask # 4 ; CMOS address of frugal bit (bits 0..15) and bit mask (16..23) + ; and 'initialised' flag in bit 24 (bits 25..31 = 0) +ROMModule_Initialised * ROMModule_CMOSAddrMask + 3 +ROMModule_Size # 4 ; size of module +ROMModule_NodeSize # 0 + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +UnplugCMOSTable ; in reverse order + = Unplug17CMOS + = Unplug16CMOS, Unplug15CMOS + = Unplug14CMOS, Unplug13CMOS + = Unplug12CMOS, Unplug11CMOS + = Unplug10CMOS, Unplug9CMOS + = Unplug8CMOS, Unplug7CMOS + = FrugalCMOS+1, FrugalCMOS+0 + = MosROMFrugalCMOS+3, MosROMFrugalCMOS+2 + = MosROMFrugalCMOS+1 +UnplugCMOSTableEnd ; used for backwards indexing + = MosROMFrugalCMOS+0 + = 0 + ALIGN + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +ModuleInit ENTRY "r0-r12" ; call here on system startup + + MOV r0, #HeapReason_Init ; first initialise the heap + MOV r1, #RMAAddress + LDR r3, [r1, #:INDEX: hpdend] ; saved for us during init. + SWI XOS_Heap + +; first initialise the podule manager - this must be the second module (ie the 1st after UtilityModule) + + ADRL r6, SysModules_Info+4 + LDR r1, [r6, #-4] + ADD r1, r6, r1 + LDR r14, [r1, #-4] + TEQ r14, #0 + MOVNE r0, #ModHandReason_AddArea + SWINE XOS_Module + +; now for each module in the main ROM, create a node for it + + ASSERT ROMModule_Link = 0 + + LDR r9, =ROMModuleChain ; pointer to 'previous' node + MOV r8, #0 ; initial head ptr is zero + STR r8, [r9] ; set up null list + MOV r3, #-1 ; podule -1 is main ROM + MOV r10, #0 ; chunk number 0 to start +10 + LDR r7, [r6, #-4] ; get size of this module + TEQ r7, #0 ; if zero + BEQ %FT20 ; then no more main rom modules + + LDR r4, [r6, #Module_Title] ; r4 = offset to module name + ADD r4, r6, r4 ; r4 -> module name + LDR r5, [r6, #Module_HelpStr] ; r5 = help offset + TEQ r5, #0 ; if no help string + ADDEQ r5, r6, #Module_HelpStr ; then use help offset as string (null string) + ADDNE r5, r6, r5 ; otherwise point to help string + + ADR r11, UnplugCMOSTable + SUBS r14, r10, #FirstUnpluggableModule ; subtract number of first module that has an unplug bit + MOVCS r1, r14, LSR #3 ; get byte number + ANDCS r14, r14, #7 ; get bit number + ADDCS r14, r14, #16 ; bit mask stored in bits 16 onwards + RSBCSS r1, r1, #(UnplugCMOSTableEnd-UnplugCMOSTable) ; invert table offset, and check in range + LDRCSB r11, [r11, r1] ; load table value if in range + MOVCS r12, #1 + ORRCS r11, r11, r12, LSL r14 ; merge with bit mask + MOVCC r11, #0 ; otherwise zero + + BL AddROMModuleNode + BVS %FT50 ; if failed then can't add any more ROMs! + + MOV r9, r2 ; this node is now previous one + ADD r6, r6, r7 ; go on to next module + ADD r10, r10, #1 ; chunk number +=1 + B %BT10 + +; now do podule ROMs + +20 + MOV r3, #0 ; start at podule 0 +21 + MOV r10, #0 ; for each podule start at chunk 0 + CMP r3, #-1 + MOVGT r12, #0 ; if real podule then start at CMOS bit number 0 for this podule + ; else carry on from where we're at +22 + MOV r0, r10 + SWI XPodule_EnumerateChunksWithInfo + BVS %FT40 ; bad podule or some such + CMP r0, #0 ; no more chunks? + BEQ %FT45 ; then step to next podule + CMP r2, #OSType_Module + MOVNE r10, r0 + BNE %BT22 + +; now claim a block to copy module title into + + MOV r7, r1 ; pass size in r7 + Push "r0, r3, r4" + MOV r3, #0 +23 + LDRB r14, [r4, r3] ; find length of title string + ADD r3, r3, #1 ; increment length (include zero at end) + TEQ r14, #0 + BNE %BT23 + + BL ClaimSysHeapNode + Pull "r0, r3, r14" ; restore chunk no., podule no., old ptr to title + BVS %FT50 ; if error then no more ROMs (doesn't matter that error ptr is naff) + + MOV r4, r2 ; save pointer to block +24 + LDRB r1, [r14], #1 ; now copy string into block + STRB r1, [r2], #1 + TEQ r1, #0 + BNE %BT24 + + MOV r14, #(1 :SHL: 16) ; bit mask ready to shift + CMP r3, #-1 + BLT %FT30 + +; doing podule ROM + + [ IO_Type = "IOMD" + + ASSERT ?PoduleFrugalCMOS = 8 ; ensure we're using the correct Hdr:CMOS + CMP r12, #7 ; if bit number <= 7 + CMPLS r3, #8 ; then if podule number <= 8 + ADDCC r11, r3, #PoduleFrugalCMOS ; then use one of the 8 PoduleFrugalCMOS bytes + MOVEQ r11, #NetworkFrugalCMOS ; elif podule number = 8 then use network card CMOS + MOVHI r11, #0 ; otherwise no CMOS + ORRLS r11, r11, r14, LSL r12 ; OR in bit mask + B %FT36 + | + ASSERT ?PoduleFrugalCMOS >= 4 + CMP r3, #4 ; if podule number < 4 + CMPCC r12, #8 ; and bit number < 8 + ADDCC r11, r3, #PoduleFrugalCMOS ; then compute CMOS address + ORRCC r11, r11, r14, LSL r12 ; and OR in bit mask + ] + B %FT35 + +; doing extension ROM +30 + CMP r12, #16 ; 2 bytes of CMOS for extension ROMs + MOVCC r1, #ExtnUnplug1CMOS ; form CMOS address in r1 + ADDCC r1, r1, r12, LSR #3 + ANDCC r11, r12, #7 ; get bit mask + ORRCC r11, r1, r14, LSL r11 ; and OR in +35 + MOVCS r11, #0 ; if out of range then no CMOS +36 + ADD r12, r12, #1 ; increment bit + BL AddROMModuleNode + BVS %FT50 + + MOV r10, r0 ; go onto next chunk + MOV r9, r2 ; this node is now previous one + B %BT22 + +40 + CMP r3, #0 ; are we doing extension ROMs + BMI %FT50 ; if so, then stop if we get an error +45 + TEQ r3, #0 ; if doing extension ROMs + SUBMI r3, r3, #1 ; then go backwards + BMI %BT21 + ADD r3, r3, #1 ; go onto next podule + CMP r3, #16 ; more podules than you could ever fit + MOVEQ r3, #-2 ; if got to end, try extension ROMs + MOVEQ r12, #0 ; start by using bit 0 of CMOS + B %BT21 + +; now go down ROM module chain, initialising things + +50 + LDR r12, =ROMModuleChain + LDR r12, [r12] +55 + TEQ r12, #0 ; if no more modules + BEQ %FT90 ; then skip + + LDR r3, [r12, #ROMModule_CMOSAddrMask] ; get CMOS for LOCATION version + ANDS r2, r3, #&FF + MOVNE r1, r2 + MOVNE r0, #ReadCMOS ; if there is a CMOS address + SWINE XOS_Byte ; then read it + TST r2, r3, LSR #16 ; test bit + BNE %FT80 ; [LOCATION unplugged, so don't initialise here] + + MOV r11, r12 ; start with current one + +; now find the newest version that isn't unplugged + +; first find the newest version + +60 + LDR r14, [r11, #ROMModule_NewerVersion] + TEQ r14, #0 ; if there is a newer version + MOVNE r11, r14 ; then link to it + BNE %BT60 ; and loop + +; now work backwards until we find a version that isn't unplugged - there must be one, since LOCATION version is not unplugged + +65 + TEQ r11, r12 ; back to LOCATION version? + BEQ %FT68 ; [yes, so use that version] + LDR r3, [r11, #ROMModule_CMOSAddrMask] ; get CMOS for CODE version + ANDS r2, r3, #&FF + MOVNE r1, r2 + MOVNE r0, #ReadCMOS ; if there is a CMOS address + SWINE XOS_Byte ; then read it + TST r2, r3, LSR #16 ; test bit + LDRNE r11, [r11, #ROMModule_OlderVersion] ; CODE is unplugged, so try next older version + BNE %BT65 + +68 + LDR r7, [r12, #ROMModule_PoduleNumber] ; get podule number (for LOCATION version) + CMP r7, #-1 ; is it an extension ROM + BGE %FT70 ; if not then initialise newer one + +; it's an extension ROM, so only initialise if it's the newest, and hasn't yet been initialised + + TEQ r11, r12 + LDREQB r10, [r11, #ROMModule_Initialised] ; only initialise if this is zero and r11=r12 + TEQEQ r10, #0 + BNE %FT80 ; don't initialise + +; not an extension ROM, so initialise the newest version (r11) of this module + +70 + [ DebugROMInit + SWI XOS_WriteS + = "About to initialise module " + LDR r0, [r11, #ROMModule_Name] + SWI XOS_Write0 + SWI XOS_NewLine + ] + BL InitialiseROMModule + [ DebugROMErrors ; print errors in ROM module init for debugging + BVC %FT80 + SWI XOS_WriteS + = "Error in ROM module init: ",0 + ALIGN + ADDVC r0, r0, #4 + SWIVC XOS_Write0 + SWIVC XOS_NewLine + ] +80 + LDR r12, [r12, #ROMModule_Link] + B %BT55 + +90 + MOV r1, #RMASizeCMOS + MOV r0, #ReadCMOS + SWI XOS_Byte + MOV r0, #0 + LDR r0, [r0, #Page_Size] + MUL r3, r0, r2 + ADD r3, r3, #ExtraRMANeeded + MOV r0, #ModHandReason_Claim + SWI XOS_Module + MOV r0, #ModHandReason_Free + SWI XOS_Module + EXIT + +;****************************************************************************************************** +; +; InitialiseROMModule - Initialise a ROM module +; +; in: r11 -> ROM module node for CODE version +; r12 -> ROM module node for LOCATION version +; +; out: All registers preserved +; + +InitialiseROMModule ENTRY "r0-r12" + MOV r14, #1 + STRB r14, [r11, #ROMModule_Initialised] ; indicate it's been initialised + LDR r2, [r11, #ROMModule_ChunkNumber] + LDR r3, [r11, #ROMModule_PoduleNumber] + LDR r4, [r11, #ROMModule_Name] + LDR r6, [r11, #ROMModule_BaseAddress] + LDR r7, [r12, #ROMModule_PoduleNumber] + ADRL r1, crstring + MOV lr, pc ; ADRS lr, %FT10 + ADD lr, lr, #%FT20-%FT10 ; ADRS lr, %FT20 +10 + Push "r0-r7,r9,lr" + LDR r1, [r11, #ROMModule_Size] + MOV r5, r11 ; r5 -> ROM module node + B APMInitEntry +20 + STRVS r0, [sp] ; if error, preserve r0 + EXIT + +;****************************************************************************************************** +; +; AddROMModuleNode - Create a ROM module node and link it with the chain +; +; in: R3 = podule number +; R4 -> module name +; R5 -> module help string +; R6 -> module base if directly executable, otherwise zero +; R7 = module size +; R8 = 0 +; R9 -> previous node +; R10 = chunk number +; R11 = CMOS address (in bits 0..15) and bit mask (in bits 16..23) for unplugging (0 if none) +; +; out: R2 -> node created +; All other registers preserved, except if error (when R0 -> error) +; + +AddROMModuleNode ENTRY "r0,r1,r3-r12" + MOV r3, #ROMModule_NodeSize ; claim a rom module node + BL ClaimSysHeapNode ; r0,r1 corrupted, r2 -> block + STRVS r0, [stack] + EXIT VS + + STR r8, [r2, #ROMModule_Link] ; set link for this node to 0 + STR r7, [r2, #ROMModule_Size] ; store size in node + STR r4, [r2, #ROMModule_Name] ; store pointer to title string + STR r6, [r2, #ROMModule_BaseAddress] ; store base address + MOV r0, r5 + BL GetVerNoFromHelpString ; read version number in BCD into r1 + STR r1, [r2, #ROMModule_Version] ; store version number + LDR r3, [stack, #2*4] ; reload podule number + STR r3, [r2, #ROMModule_PoduleNumber] ; store podule number + STR r10, [r2, #ROMModule_ChunkNumber] ; store chunk number + STR r11, [r2, #ROMModule_CMOSAddrMask] ; store CMOS address and mask + +; now check if module is a copy of one already on the list + + MOV r10, #0 ; next oldest node + MOV r11, #0 ; next newest node + CMP r3, #-1 ; if in main ROM, no need to look for duplicates + BEQ %FT40 + + MOV r1, r4 ; make r1 -> additional module's name + MOV r4, #0 ; zero terminator for Module_StrCmp + MOV r12, #0 ; search from start of chain + BL FindROMModule + TEQ r12, #0 ; did we find it? + BEQ %FT40 ; no, then module is unique + + TEQ r6, #0 ; set r6 to 1 if extra is directly executable, otherwise 0 + MOVNE r6, #1 + CMP r3, #-1 ; set r3 to 1 if extra is an extension ROM, otherwise 0 + MOVGE r3, #0 + MOVLT r3, #1 + LDR r1, [r2, #ROMModule_Version] ; reload version number of extra node + BL CompareVersions ; compare r2 version with r12 version + BCC %FT30 ; extra one is older than this one, so search down older chain + +; extra one is newer than this one, so search down newer chain + +20 + MOV r10, r12 ; old = this + LDR r12, [r12, #ROMModule_NewerVersion] ; this = newer(this) + MOVS r11, r12 ; new = this + BEQ %FT40 ; if no newer then that's it! + BL CompareVersions + BCS %BT20 + +; extra one is older than this one, so search down older chain + +30 + MOV r11, r12 ; new = this + LDR r12, [r12, #ROMModule_OlderVersion] ; this = older(this) + MOVS r10, r12 ; old = this + BEQ %FT40 + BL CompareVersions + BCC %BT30 + +40 + STR r10, [r2, #ROMModule_OlderVersion] ; older(extra)=old + STR r11, [r2, #ROMModule_NewerVersion] ; newer(extra)=new + TEQ r10, #0 ; if old <> 0 + STRNE r2, [r10, #ROMModule_NewerVersion] ; then newer(old)=extra + TEQ r11, #0 ; if new <> 0 + STRNE r2, [r11, #ROMModule_OlderVersion] ; then older(new)=extra + + STR r2, [r9] ; point previous node at this one + CLRV + EXIT + +CompareVersions ENTRY + LDR r14, [r12, #ROMModule_Version] ; r14 = version(this) + CMP r1, r14 + EXIT NE ; exit with this condition codes, unless equal + LDR r14, [r12, #ROMModule_BaseAddress] + TEQ r14, #0 ; set r14 to 1 if this one is directly executable, otherwise 0 + MOVNE r14, #1 + CMP r6, r14 + EXIT NE ; directly executables are "newer" + LDR r14, [r12, #ROMModule_PoduleNumber] + CMP r14, #-1 ; set r14 to 1 if ext. ROM, otherwise 0 + MOVGE r14, #0 + MOVLT r14, #1 + CMP r3, r14 ; extension ROMs are "newer" than anything else + EXIT ; if equal in all other respects, the later one is "newer" + +;****************************************************************************************************** +; +; FindROMModule - Find a named module in the ROM module list +; +; in: R1 -> name to match +; R4 = potential additional termintor for R1 string +; R12 -> node before 1st node to be checked (0 => search from start) +; +; out: R12 -> found node, or 0 if no match +; If match, then R1 -> terminator of R1 string, otherwise preserved +; All other registers preserved +; + +FindROMModule ENTRY + TEQ r12, #0 ; if zero passed in on entry + LDREQ r12, =ROMModuleChain ; then search from start of chain +10 + LDR r12, [r12, #ROMModule_Link] ; go to next module + TEQ r12, #0 ; any more modules? + EXIT EQ ; no, then exit + Push "r1, r3" + LDR r3, [r12, #ROMModule_Name] ; point to name of module on chain + BL Module_StrCmp ; compare names + STREQ r1, [sp] ; if match, then patch stacked r1 + Pull "r1, r3" + BNE %BT10 ; if different then try next one + EXIT + +; start of module handler SWI + + GBLA mhrc +mhrc SETA 0 + + MACRO +$l ModuleDispatchEntry $entry +$l B Module_$entry + ASSERT ModHandReason_$entry = mhrc +mhrc SETA mhrc + 1 + MEND + +ModuleHandler ROUT + + CMP r0, #(NaffSWI - (.+12))/4 ; Range check + ADDLO pc, pc, r0, LSL #2 ; dispatch + B NaffSWI + + ModuleDispatchEntry Run + ModuleDispatchEntry Load + ModuleDispatchEntry Enter + ModuleDispatchEntry ReInit + ModuleDispatchEntry Delete + ModuleDispatchEntry RMADesc + ModuleDispatchEntry Claim + ModuleDispatchEntry Free + ModuleDispatchEntry Tidy + ModuleDispatchEntry Clear + ModuleDispatchEntry AddArea + ModuleDispatchEntry CopyArea + ModuleDispatchEntry GetNames + ModuleDispatchEntry ExtendBlock + ModuleDispatchEntry NewIncarnation + ModuleDispatchEntry RenameIncarnation + ModuleDispatchEntry MakePreferred + ModuleDispatchEntry AddPoduleModule + ModuleDispatchEntry LookupName + ModuleDispatchEntry EnumerateROM_Modules + ModuleDispatchEntry EnumerateROM_ModulesWithInfo + +NaffSWI ; Set V and return + ADR R0, ErrorBlock_BadModuleReason + [ International +BumDealInModule_Translate + Push "lr" + BL TranslateError + Pull "lr" + ] +BumDealInModule + B SLVK_SetV + + MakeErrorBlock BadModuleReason + +;************************************************************* + +Module_Run ROUT + TEQP PC, #SVC_mode ; interrupts on + Push "R9, lr" + BL Load_Module + BVS LoadFailed + ; BL EnvStringSkipName - done in load +EnterIt + ; R9 now ptr to node, R10 ptr to command string to set up. + ; Enters preferred incarnation. + + LDR R12, [R9, #Module_incarnation_list] + ADD R12, R12, #Incarnation_Workspace + + LDR R9, [R9, #Module_code_pointer] + LDR R11, [R9, #Module_Start] + TEQ R11, #0 + Pull "R9, lr", EQ + ExitSWIHandler EQ + + Push "R1-R3" + MOV R1, R10 + MOV R0, #FSControl_StartApplication + MOV R2, R9 + LDR R3, [R9, #Module_Title] ; prefix with module title + ADD R3, R3, R9 + + SWI XOS_FSControl + BVS CantGoIntoModule + + LDR stack, =SVCSTK + MOV R0, R10 + TEQP pc, #0 + MOV r0, r0 ; NOP because we've changed mode + + TST R11, #ARM_CC_Mask ; check for B startit, etc. + MOVNE R11, #0 + ADD PC, R9, R11 + +CantGoIntoModule + Pull "R1-R3" +LoadFailed + Pull "R9, lr" + B BumDealInModule + +;************************************************************* + +Module_Load ROUT + TEQP PC, #SVC_mode ; interrupts on + Push "R9, lr" + BL Load_Module + Pull "R9, lr" + B SLVK_TestV + +;************************************************************* + +Module_Enter ROUT + Push "R9, lr" ; ready for EnterIt + Push "R0-R4" + BL lookup_commoned + + STRVS R0, [stack] + Pull "R0-R4, R9, lr", VS + BVS BumDealInModule + + BLGT PreferIncarnation + Pull "R0-R4" + MOV R10, R2 ; envstring pointer + B EnterIt + +;************************************************************* + +Module_ReInit ROUT + Push "R0-R4, R9, lr" + + BL lookup_commoned + BVS %FT01 + + ADDEQ R3, R9, #Module_incarnation_list + LDREQ R12, [R9, #Module_incarnation_list] + + ; R12 -> incarnation node, R3 -> previous incarnation + + MOV R10, #1 ; fatal die + BL CallDie + BVS %FT03 + + SUB R10, R1, #1 + BL EnvStringSkipName + + BL CallInit + BLVS LoseModuleSpace_if_its_the_only_incarnation + STRVC R12, [R3, #Incarnation_Link] +03 STRVS R0, [stack] + Pull "R0-R4, R9, lr" + B SLVK_TestV + + +01 LDR R11, [R0] + LDR R2, =ErrorNumber_RMNotFound + CMP R11, R2 + BEQ %FT02 +05 + SETV + B %BT03 + +02 MOV R0, #0 + BL AddModuleIfInROM + B %BT03 + +;************************************************************* + +Module_Delete ROUT + Push "R0-R4, R9, lr" + BL lookup_commoned + BVS %FT01 + + ADDEQ R3, R9, #Module_incarnation_list + LDREQ R12, [R9, #Module_incarnation_list] + + ; R12 -> incarnation node, R3 -> previous incarnation + + BL KillIncarnation +01 STRVS R0, [stack] + Pull "R0-R4, R9, lr" + B SLVK_TestV + +;************************************************************* + +Module_Free ROUT +Module_RMADesc + Push "R0, R1, lr" + + SUB R0, R0, #(ModHandReason_RMADesc-HeapReason_Desc) + ASSERT HeapReason_Desc-HeapReason_Free=ModHandReason_RMADesc-ModHandReason_Free + MOV R1, #RMAAddress + SWI XOS_Heap + STRVS R0, [stack] + Pull "R0, R1, lr" + B SLVK_TestV + +;************************************************************* + +Module_Claim ROUT + Push "R0, R1, lr" + BL RMAClaim_Chunk + STRVS R0, [stack] + Pull "R0, R1, lr" + B SLVK_TestV + +;************************************************************* +; Garbage collect the RMA. We know there's always one module, +; and some RMA space. + + [ RMTidyDoesNowt ; on Medusa we do nothing, because we would always fail + ; due to FSLock being Captain Scarlet +Module_Tidy * SLVK + | +Module_Tidy ROUT + Push "R0-R6, R9, lr" + + TEQP PC, #SVC_mode + + MOV r0, #0 + LDR r0, [r0, #Curr_Active_Object] + MOV r1, #RMAAddress + LDR r2, [r1, #:INDEX:hpdend] + SUBS r0, r0, r1 + CMPGT r2, r0 + ADRGTL r0, ErrorBlock_CantKill + [ International + BLGT TranslateError + | + SETV GT + ] + + BLVC Genocide ; warn all of impending calamity + BVS ExitRMTidy + +; now for the great adventure. R2 is old contents of ModuleList +; First build a list of block addresses, together with address of pointer to +; block, in ascending order. + + LDR R2, =ScratchSpace + STR R9, [R2], #4 ; save original module list + MOV R3, R2 + +; in loop, R0 is block address, R1 is pointer to pointer to block +; R2 is ptr to list start +; R3 is list limit + +01 ADD R1, R9, #Module_code_pointer + LDR R0, [R1] + BL %FT10 ; insert pair + + LDR R1, [R9, #Module_incarnation_list] +02 ADD R1, R1, #Incarnation_Workspace + LDR R0, [R1] + CMP R0, #0 + BLNE %FT10 ; insert workspace block if there + LDR R1, [R1, #-Incarnation_Workspace] + CMP R1, #0 + BNE %BT02 + + LDR R9, [R9, #Module_chain_Link] ; next module + CMP R9, #0 + BNE %BT01 + +; Now iterate over claimed blocks, to discard non-heap pointers. + + MOV R5, R2 ; currblock ptr + +; if hpdfree <> hpdsize then +; doblock (hpdsize, hpdfree=Nil -> hpdbase, hpdfree) + + MOV R12, #RMAAddress + LDR R4, [R12, #:INDEX: hpdfree] + CMP R4, #Nil + ADDNE R4, R4, #:INDEX: hpdfree ; convert to heapstart offset + + CMP R4, #hpdsize + BEQ %FT04 + MOV R0, #hpdsize + CMP R4, #Nil + LDREQ R1, [R12, #:INDEX: hpdbase] + MOVNE R1, R4 + BL ScanAllocBlock + CMP R4, #Nil + BEQ BlocksScanned + +; while hpdfree <> Nil +; doblock (hpdfree+fresize, step(hpdfree)=Nil -> hpdbase, hpdfree) + +04 ADD R4, R4, R12 + LDR R1, [R4, #frelink] + LDR R0, [R4, #fresize] + SUB R4, R4, R12 + + ADD R0, R0, R4 + CMP R1, #Nil + ADDNE R4, R4, R1 + MOVNE R1, R4 + LDREQ R1, [R12, #:INDEX: hpdbase] + BL ScanAllocBlock + BNE %BT04 + +BlocksScanned + MOV R3, R5 ; new list end + +; copy blocks, relocate ptrs +; R2, R3 list limits +; R12 heap start + + ADD R0, R12, #hpdsize ; get addr for first block +StripBlocks + CMP R2, R3 + BEQ %FT09 ; nowt to copy + LDR R1, [R2], #8 + CMP R1, #0 + BEQ StripBlocks + LDR R4, [R1] ; block size + CMP R1, R0 + ADDEQ R0, R4, R0 + BEQ StripBlocks + +; R1 address of first block, R0 address to copy to - gopher it! +; R4 size + LDR R5, [R2, #-4] ; pointer to + ADD R0, R0, #4 + STR R0, [R5] ; relocate ptr + SUB R0, R0, #4 + +CopyBlock + LDR R5, [R1], #4 + STR R5, [R0], #4 + SUBS R4, R4, #4 + BGT CopyBlock + B StripBlocks + +09 +; Update Hpd + SUB R0, R0, R12 ; convert to offset + STR R0, [R12, #:INDEX: hpdbase] + + MOV R0, #Nil + STR R0, [R12, #:INDEX: hpdfree] ; no free list. + + ; for restarting, we need + ; R1 -> prevmod to R9 + ; R9 -> the whinger, R12 -> incarnation list, R2 stop point + ; R4 -> dead module list + ; R3 -> previnc + + MOV R9, #Module_List ; "module" that's linked at end + LDR R4, =ScratchSpace + LDR R4, [R4] ; dead list + MOV R2, #0 ; persuade it to step module + MOV R12, #0 ; immediately. + BL RestartModuleStructure + BVS ExitRMTidy + + MOV R0, #1 + MOV R1, #-16*1024*1024 + SWI XOS_ChangeDynamicArea + CLRV + +ExitRMTidy + STRVS R0, [stack] + Pull "R0-R6, R9, lr" + B SLVK_TestV + +;------------------------------------------------------------------------- +; RMTidy support routines + +; Insertion routine. (R0, 1) is pair to insert, R2 list start, R3 list end. +; Uses R10, 11, 4 + +10 MOV R11, R2 ; take curr posn ptr + + SUB R0, R0, #4 ; genuine internal heap pointer value +11 CMP R11, R3 ; list ended? + BEQ %FT13 + LDR R4, [R11], #8 + CMP R4, R0 ; or right posn? + BLO %BT11 + + SUB R11, R11, #8 ; where we will store new entry to + SUB R4, R3, #4 ; R4 is OS_Word to move from. +12 LDR R10, [R4], #-4 ; now copy between R11 and R3 up 8. + STR R10, [R4, #12] + CMP R4, R11 + BHS %BT12 + +13 ADD R3, R3, #8 ; update list end + STMIA R11, {R0, R1} ; new entry in + ADD R0, R0, #4 ; and back to link. + MOV PC, lr + +;------------------------------------------------------------------- +ScanAllocBlock ROUT + ; R0 block start + ; R1 block end + ; R12 heap start + ; R3 list end + ; R5 current list entry + + ; poke out list entries that aren't proper heap pointers + + Push "R0, R1, R7, R8" + MOV R8, #0 + ADD R0, R0, R12 ; convert to addressi + ADD R1, R1, R12 + +01 CMP R5, R3 + BGE %FT02 + LDR R7, [R5], #8 + + CMP R7, R0 ; while entry at R5 LT R0 pokeout + STRLT R8, [R5, #-8] + BLT %BT01 + + SUBGT R5, R5, #8 + + LDR R7, [R0] + ADD R0, R0, R7 ; next block + CMP R0, R1 ; step block until end + BLT %BT01 +02 + Pull "R0, R1, R7, R8" + MOVS PC, lr + + LTORG + +;----------------------------------------------------------------------------- + +Genocide ROUT ; non-fatally kill de lot of em, stiff the module chain + ; corrupts R1-R5, R9, R10, R12 + ; returns R9 = original module chain + + Push "lr" + MOV R4, #0 ; chain so far + +FindChainEnd + MOV R1, #Module_List ; prevnode + LDR R9, [R1, #Module_chain_Link] ; currnode + CMP R9, #0 + BNE %FT01 + MOV R9, R4 + Pull "PC" + +01 LDR R11, [R9, #Module_chain_Link] ; lastnode? + CMP R11, #0 + MOVNE R1, R9 ; step chain + MOVNE R9, R11 + BNE %BT01 + + LDR R2, [R9, #Module_incarnation_list] ; keep chain head + ADD R3, R9, #Module_incarnation_list +02 LDR R12, [R3, #Incarnation_Link] ; currinc + CMP R12, #0 + BNE %FT03 + STR R12, [R1, #Module_chain_Link] ; remove from chain + STR R2, [R9, #Module_incarnation_list] ; replace incarnations + STR R4, [R9, #Module_chain_Link] ; make into dead head + MOV R4, R9 + B FindChainEnd + +03 MOV R10, #0 ; not fatal indicator + [ {FALSE} ; debug RMTidy + Push "r0" + LDR r0, [r9, #Module_code_pointer] + LDR r14, [r0, #Module_Title] + ADD r0, r0, r14 + SWI XOS_WriteS + = "RMTidy: killing '", 0 + ALIGN + SWI XOS_Write0 + SWI XOS_WriteS + = "'", 10, 13, 0 + ALIGN + Pull "r0" + ] + BL CallDie + BVC %BT02 + +; Copy the error in case overwritten + + MOV R5,R0 ; Error block + LDR R0,=GeneralMOSBuffer ; R0-> stashed error + LDR LR,[R5],#4 + STR LR,[R0],#4 ; Copy error number +05 LDRB LR,[R5],#1 + STRB LR,[R0],#1 + CMP LR,#' ' ; End of string? + BGE %BT05 ; No then more + LDR R0,=GeneralMOSBuffer ; R0-> stashed error + SETV + + MOV R5, R12 + MOV R12, R2 + MOV R2, R5 ; r12 now incarnation to start, R2 stop point + BL RestartModuleStructure + ; somebody winged, so try and restore consistency before error. + Pull "PC" + +;------------------------------------------------------------------------------ + +RestartModuleStructure ROUT + + ; R1 -> prevmod to R9 + ; R9 -> the whinger, R12 -> incarnation list, R2 stop point + ; R4 -> dead module list + ; R3 -> previnc + + Push "R0, lr" + +11 CMP R2, R12 + BNE %FT12 ; more incarnations to do + + CMP R4, #0 + Pull "R0, PC", EQ, ^ + + MOV R1, R9 +14 MOV R9, R4 + LDR R4, [R4, #Module_chain_Link] + MOV R2,#0 ; indicate reinit all incarnations + LDR R12, [R9, #Module_incarnation_list] + STR R2, [R9, #Module_incarnation_list] + ADD R3, R9, #Module_incarnation_list ; previnc ptr + + STR R2, [R9, #Module_chain_Link] ; relink next + STR R9, [R1, #Module_chain_Link] + B %BT11 ; start incarnations + +12 LDR R11, [R12, #Incarnation_Link] ; get next in case problems + ADRL R10, crstring ; no environment + BL CallInit ; frees node if error + BVC %FT15 + + STR R0, [stack] + LDR R0, [stack, #4] + ORR R0, R0, #V_bit + STR R0, [stack, #4] + Push "R2" + MOV R2, R1 ; prevnode + BL LoseModuleSpace_if_its_the_only_incarnation + Pull "R2" + + CMP R9, #0 ; did we just discard that module? + BEQ %BT14 ; yup - next one + +15 LDRVC R0, [R3, #Incarnation_Link] + STRVC R0, [R12,#Incarnation_Link] + STRVC R12, [R3, #Incarnation_Link] + MOVVC R3, R12 + + MOV R12, R11 + B %BT11 ; next incarnation + ] ; endif <RMTidyDoesNowt> + +;**************************************************************************** + +Module_Clear ENTRY "r0-r3" + TEQP pc, #SVC_mode ; interrupts on + MOV r3, #0 ; position in chain + +; now find entry in chain to kill : one with successor = R3 + +MHC_GetEndOne + MOV r2, #Module_List ; prevnode for killing + LDR r0, [r2, #Module_chain_Link] + CMP r0, r3 + PullEnv EQ + ExitSWIHandler EQ +MHC_StepOn + LDR r1, [r0, #Module_chain_Link] + CMP r1, r3 + MOVNE r2, r0 + MOVNE r0, r1 + BNE MHC_StepOn + + LDR r11, [r0, #Module_ROMModuleNode] ; don't kill if it's a ROM module (note that this would also + CMP r11, #1 ; account for squeezed ROM modules, so the invincible bit in the + LDRCC r11, [r0, #Module_code_pointer] ; die entry is not strictly necessary any more, but never mind!) + LDRCC r11, [r11, #Module_Die] ; Check for invincible module + CMPCC r11, #&80000000 ; (die entry has top bit set) + MOVCS r3, r0 ; step if not about to delete + ; - don't assassinate ROM modules. + BLCC KillAndFree + BVC MHC_GetEndOne + + LDR r3, [r2, #Module_chain_Link] + STR r0, [stack] + LDR r0, [stack, #4*4] + ORR r0, r0, #V_bit + STR r0, [stack, #4*4] + B MHC_GetEndOne + +;************************************************************* +; AddArea: +; Entry; R1 -> module in memory to add, leaving it in place. +; Return: registers preserved, V set if problem +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Module_AddArea ROUT + Push "R9, lr" + TEQP PC, #SVC_mode ; interrupts on + ADRL R10, crstring ; null environment + BL ModuleIn_CheckForDuplicate ; altentry to Load_Module + Pull "R9, lr" + B SLVK_TestV + +;************************************************************* +; CopyArea +; R1 -> area of memory to add to the module list, +; copying into the RMA +; R2 = size of the area. + +Module_CopyArea ROUT + Push "R0-R5, R9, lr" + TEQP PC, #SVC_mode + + ; R1 address, R2 size + BL CheckHeader + BVS AreaFail + + MOV R10, R1 + + LDR R1, [R10, #Module_Title] + ADD R1, R1, R10 + BL LookUp_Module ; check for duplicate + BLNE KillAndFree + STRVS R0, [stack] + Pull "R0-R5, R9, lr", VS + BVS SLVK_TestV + +; R10 points at area + LDR R3, [stack, #4*2] ; get size back + BL RMAClaim_Chunk + ADRVSL R0, ErrorBlock_MHNoRoom + [ International + BLVS TranslateError + ] + BVS AreaFail + + MOV R9, R2 ; new module pointer + +; copy R3 bytes from R10 to R2 +01 LDR R1, [R10], #4 + STR R1, [R2], #4 + SUBS R3, R3, #4 + BHI %BT01 ; was BPL, which is wrong! + + ADRL R10, crstring ; no environment string + MOV R11, #0 ; not podular + BL LinkAndInit + +AreaFail + STRVS R0, [stack] + Pull "R0-R5, R9, lr" + B SLVK_TestV + +;************************************************************* +; Enumerate modules +; Entry: R0 Reason code +; R1 module number +; R2 incarnation number +; Exit: R1, R2 updated to refer to next existing module +; R3 -> module code +; R4 private word contents +; R5 -> postfix string + +Module_GetNames ROUT + TEQP PC, #SVC_mode ; interrupts on + MOV R11, R1 + MOV R12, R2 + MOV R10, #Module_List +01 LDR R10, [R10, #Module_chain_Link] + CMP R10, #0 + BEQ %FT10 ; no more modules + SUBS R11, R11, #1 + BPL %BT01 + LDR R3, [R10, #Module_code_pointer] + ADD R10, R10, #Module_incarnation_list +02 LDR R10, [R10, #Incarnation_Link] + CMP R10, #0 + BEQ %FT11 ; no more incarnations + SUBS R12, R12, #1 + BPL %BT02 + LDR R4, [R10, #Incarnation_Workspace] + ADD R5, R10, #Incarnation_Postfix + LDR R10, [R10, #Incarnation_Link] +20 CMP R10, #0 + ADDNE R2, R2, #1 + MOVEQ R2, #0 + ADDEQ R1, R1, #1 + ExitSWIHandler + +10 ADR R0, ErrorBlock_NoMoreModules + [ International + B BumDealInModule_Translate + | + B BumDealInModule + ] + MakeErrorBlock NoMoreModules + +11 CMP r2, #0 + LDREQ r4, =&DEADDEAD + MOVEQ r10, #0 + BEQ %BT20 ; fudge for modules that go bang in init/die + ADR R0, ErrorBlock_NoMoreIncarnations + [ International + B BumDealInModule_Translate + | + B BumDealInModule + ] + MakeErrorBlock NoMoreIncarnations + LTORG + +;************************************************************* + +Module_ExtendBlock ROUT + Push "R0, r1, R3, lr" + + ADD R3, R3, #15 + BIC R3, R3, #15 + + MOV R0, #HeapReason_ExtendBlock + BL DoRMAHeapOpWithExtension + + STRVS R0, [stack] + Pull "R0, r1, R3, lr" + B SLVK_TestV + +;************************************************************* +; New Incarnation +; R1 -> module%newpostfix + +Module_NewIncarnation ROUT + Push "R0-R4, R9, lr" + TEQP PC, #SVC_mode + BL LookUp_Module + BEQ CheckTheROM + CMP R12, #0 + BEQ Incarnation_needed + BGT Incarnation_exists + MOV R9, R0 ; node pointer + MOV R0, R1 ; postfix + MOV R10, R1 + BL EnvStringSkipName ; envstring ptr in R10 + BL Add_Incarnation +01 STRVS R0, [stack] + Pull "R0-R4, R9, lr" + B SLVK_TestV + +CheckTheROM + MOV R0, #Postfix_Separator ; passed string must have postfix + BL AddModuleIfInROM + B %BT01 + +Incarnation_needed + Pull "R0-R4, R9, lr" + ADR R0, ErrorBlock_PostfixNeeded + [ International + B BumDealInModule_Translate + | + B BumDealInModule + ] + MakeErrorBlock PostfixNeeded + +Incarnation_exists + Pull "R0-R4, R9, lr" + ADR R0, ErrorBlock_IncarnationExists + [ International + B BumDealInModule_Translate + | + B BumDealInModule + ] + MakeErrorBlock IncarnationExists + +;************************************************************* +; Rename Incarnation +; R1 -> current module title +; R2 -> new postfix. + +Module_RenameIncarnation ROUT + Push "R0-R4, R9, lr" + BL lookup_commoned + BVS %FT01 + +; R12 -> incarnation node (0 for not specified) +; R3 -> previous incarnation + + MOV R11, R12 + MOV R0, R9 ; check incarnation + LDR R1, [stack, #4*2] ; not already there + [ Fix12 + Push R3 ; preserve pointer to + BL FindIncarnation + Pull R3 ; previous incarnation + | + BL FindIncarnation + ] + BNE %FT03 ; already exists + MOV R12, R11 + + CMP R12, #0 + ADDEQ R3, R9, #Module_incarnation_list + LDREQ R12, [R9, #Module_incarnation_list] + MOV R11, R3 + + ADD R1, R12, #Incarnation_Postfix + BL %FT10 ; old postfix length -> R0 + MOV R10, R0 + LDR R1, [stack, #4*2] ; new postfix + BL %FT10 ; new length - > R0 + SUB R3, R0, R10 + + MOV R2, R12 ; incarnation node + MOV R0, #HeapReason_ExtendBlock + BL DoSysHeapOpWithExtension + BVS %FT01 + + STR R2, [R11, #Incarnation_Link] ; relink + ADD R2, R2, #Incarnation_Postfix + LDR R1, [stack, #4*2] +02 LDRB R0, [R1], #1 + CMP R0, #" " + MOVLE R0, #0 + STRB R0, [R2], #1 + BGT %BT02 +01 STRVS R0, [stack] + Pull "R0-R4, R9, lr" + B SLVK_TestV + +03 ADR R0, ErrorBlock_IncarnationExists + [ International + Push "LR" + BL TranslateError + Pull "LR" + | + SETV + ] + B %BT01 + +10 MOV R0, #0 +11 LDRB R3, [R1, R0] + CMP R3, #" " + ADDGT R0, R0, #1 + BGT %BT11 + MOV PC, lr + +;************************************************************* +; MakePreferred +; R1 -> name + +Module_MakePreferred ROUT + Push "R0-R4, R9, lr" + BL lookup_commoned + BVS %FT01 + BLGT PreferIncarnation ; only prefer it if found! +01 + [ Fix13 + STRVS R0, [sp, #0] + ] + Pull "R0-R4, R9, lr" + B SLVK_TestV + +;************************************************************* +; AddPoduleModule +; +; in: R1 -> envstring +; R2 = chunk number +; R3 = podule number +; +; out: All registers preserved + +Module_AddPoduleModule ENTRY + TEQP pc, #SVC_mode ; interrupts on + BL APMEntry + PullEnv + B SLVK_TestV + +APMEntry ENTRY "r0-r7,r9" + MOV r0, r2 + SWI XPodule_EnumerateChunksWithInfo ; out: r1=size, r2=type, r4->name, r5->help string, r6=module address if in ROM + BVS %FT99 + CMP r2, #OSType_Module + BNE %FT98 + + MOV r7, r3 + MOV r5, #0 ; indicate not a ROM module (although strictly speaking, it is!) +APMInitEntry + Push "r1" ; size + MOV r1, r4 + BL LookUp_Module ; check for duplicate + BLNE KillAndFree + Pull "r3" ; get size back + BVS %FT99 + + MOVS r1, r6 ; if module address non-zero, then it's a directly executable ext. ROM + BNE %FT10 ; and don't claim a block, or read the chunk + + BL RMAClaim_Chunk + BVS %FT99 + LDR r0, [stack, #4*2] + LDR r3, [stack, #4*3] + SWI XPodule_ReadChunk + MOV r1, r2 ; r1 = address of module +10 + LDR r2, [r1, #-4] ; r2 = size + BLVC CheckHeader + BVS %FT97 ; free space too (doesn't matter that it fails for extension ROM) + + MOV r9, r1 + LDR r10, [stack, #4] ; envptr + + MOVS r3, r7 ; if not a podule (r7 < 0) + MOVMI r11, #0 ; then use hardware address zero + BMI %FT20 + Push "r1" ; else compute hardware address from 'fake' podule number + SWI XPodule_HardwareAddresses ; get raw hardware address for podule r3 into r0 (r1 = combined) + Pull "r1" + BVS %FT97 + MOV r11, r0 ; move into r11 +20 + BL LinkAndInit + STRVC r5, [r9, #Module_ROMModuleNode] ; store zero or pointer to ROM module node (if no error in init) +99 + STRVS r0, [stack] + EXIT + +98 + ADR r0, ErrorBlock_ChunkNotRM + [ International + BL TranslateError + ] +96 + SETV + B %BT99 + MakeErrorBlock ChunkNotRM + +97 + MOV r2, r1 ; free claimed RMA space + MOV r1, #RMAAddress + Push "r0" + MOV r0, #HeapReason_Free + SWI XOS_Heap + Pull "r0" + B %BT96 + + LTORG + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; LookupName +; Take module name, return info on it suitable for use with Enumeration +; (e.g. to get all incarnations of it) +; In : R1 -> name +; Out: R1 module number \ of THIS module; first enumerate +; R2 incarnation number / call will give back this module +; R3 -> module code +; R4 private word contents +; R5 -> postfix string + +Module_LookupName ROUT + Push "R0-R4, R9, lr" + BL lookup_commoned + BVC %FT01 + STR R0, [stack] + Pull "R0-R4, R9, lr" + B SLVK_SetV + +01 MOV R1, #0 ; module number + MOV R0, #Module_List + +; R9 -> module chain node +; R12 -> incarnation node (0 for not specified, -1 for not found) + + LDREQ R12, [R9, #Module_incarnation_list] ; preferred inc. + +02 LDR R0, [R0] + CMP R0, R9 + ADDNE R1, R1, #1 + BNE %BT02 + ADD R0, R0, #Module_incarnation_list + MOV R2, #0 +03 LDR R0, [R0] + CMP R0, R12 + ADDNE R2, R2, #1 + BNE %BT03 + LDR R3, [R9, #Module_code_pointer] + LDR R4, [R12, #Incarnation_Workspace] + ADD R5, R12, #Incarnation_Postfix + LDR r0, [sp], #5*4 ; Load r0, skip r1-r4 + Pull "R9, lr" + ExitSWIHandler + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; EnumerateROM_Modules and EnumerateROM_ModulesWithInfo +; +; In : R1 = module number +; R2 = -1 => ROM +; = other => Podule R2 +; +; Out: R1 = incremented: next call will return next module +; R2 = preserved +; R3 -> name +; R4 = -1 => unplugged +; = 0 => inserted but not currently in the module chain +; = 1 => active +; = 2 => running +; R5 = chunk number of podule RM +; If R0 = ModHandReason_EnumerateROM_ModulesWithInfo then +; R6 = BCD version number of module (decimal point between top and bottom half-words) + +Module_EnumerateROM_Modules ROUT +Module_EnumerateROM_ModulesWithInfo ROUT + LDR r12, =ROMModuleChain + MOV r10, r1 ; module count +10 + LDR r12, [r12, #ROMModule_Link] ; follow link to next module + TEQ r12, #0 ; if no more modules + ADREQL r0, ErrorBlock_NoMoreModules + [ International + Push "lr",EQ + BLEQ TranslateError + Pull "lr",EQ + ] + BEQ SLVK_SetV ; then report error + LDR r11, [r12, #ROMModule_PoduleNumber] + CMP r2, #-1 ; if searching for podule -1, then this one must be ">=" + BEQ %FT30 + BGT %FT20 ; searching from normal podules onwards + +; searching from extension ROMs onwards + + CMP r11, r2 ; so if r11 > r2 then not there yet + BGT %BT10 + +; searching from normal podules onwards + +20 + CMP r11, #-1 ; if found one is extension ROM + BLT %FT30 ; then will be OK + CMP r11, r2 ; else is only OK if r11 >= r2 + BLT %BT10 +30 + CMP r11, r2 ; check for equality + MOVNE r1, #0 ; if not correct podule then this is the one to return + BNE %FT50 + + SUBS r10, r10, #1 ; decrement module count + BCS %BT10 ; not there yet, so go back +50 + Push "r0-r2, lr" + LDR r10, [r12, #ROMModule_CMOSAddrMask] ; get CMOS address and mask + ANDS r2, r10, #&FF ; extract address + MOVNE r1, r2 ; if there is a CMOS address + MOVNE r0, #ReadCMOS + SWINE XOS_Byte ; then read it + TST r2, r10, LSR #16 ; test bit + Pull "r0-r2" + Push "r8, r9" + MOVNE r4, #-1 ; indicate unplugged + BNE %FT90 + +; not unplugged, so check for module in module list + + MOV r4, #Module_List +60 + LDR r4, [r4, #Module_chain_Link] + TEQ r4, #0 ; module not active + BEQ %FT90 + LDR r11, [r4, #Module_ROMModuleNode] ; get active module's pointer to ROM module node + TEQ r11, r12 ; if it matches + BNE %BT60 + LDR r10, [r4, #Module_code_pointer] ; get pointer to code + MOV r11, #0 + LDR r11, [r11, #Curr_Active_Object] + LDR r4, [r10, #-4] ; node size of code + ADD r4, r4, r10 + CMP r11, r10 + CMPCS r4, r11 + MOVHI r4, #2 ; indicate running + MOVLS r4, #1 ; indicate just active +90 + LDR r2, [r12, #ROMModule_PoduleNumber] ; reload podule number + CMP r2, #-1 ; if not main ROM + LDRNE r5, [r12, #ROMModule_ChunkNumber] ; then load chunk number + LDR r3, [r12, #ROMModule_Name] ; load pointer to name + ADD r1, r1, #1 ; move module number onto next one + TEQ r0, #ModHandReason_EnumerateROM_ModulesWithInfo + LDREQ r6, [r12, #ROMModule_Version] + Pull "r8, r9, lr" ; restore registers + ExitSWIHandler ; and exit + +;************************************************************* +; Support routines. +; +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Load_Module +; takes filename pointer in R1, and loads and initialises the given file. +; Returns R9 as a pointer to the node claimed +; and V/current error set if fails + +Load_Module ROUT + + Push "R0-R5, lr" + + MOV r0, #OSFile_ReadInfo + SWI XOS_File + BVS modfailxit ; return FileSwitch error + CMP r0, #object_file + BNE HeNotFile + + BIC R2, R2, #&FF ; low byte ignored by me. + CMP R2, #Module_LoadAddr + BNE NotAModule + +; it's a module, so try and claim. + MOV R10, R1 ; keep string pointer + MOV R3, R4 ; size of vector needed + BL RMAClaim_Chunk + BVS modfailxit + +02 MOV R9, R2 ; keep a copy of node ptr. + MOV R1, R10 + MOV R0, #OSFile_Load + MOV R3, #0 ; load to R2 posn + SWI XOS_File + BVS modfailxit ; return FileSwitch error + +50 MOV R11, #0 ; not loaded from hardware. + +; R9 address, R9!-4 size + MOV R1, R9 + LDR R2, [R9, #-4] + BL CheckHeader + BVS Duplicate_Immortal ; actually means naff header field + +; now we've got it, see if any other modules have the same name. + + LDR R1, [R9, #Module_Title] + ADD R1, R1, R9 + BL LookUp_Module + BEQ %FT01 ; no module at all + CMP R12, #0 + BNE nopostfixwanted ; postfix given: bad name + BL KillAndFree + BVS Duplicate_Immortal + +; now claim a link +; R9 module pointer, R10 environment + +01 BL EnvStringSkipName + BL LinkAndInit ; takes R2 prevnode from lookup + + STRVS R0, [stack] + Pull "R0-R5, pc" + +Duplicate_Immortal ; free space claimed for loading + STR R0, [stack] + MOV R2, R9 + MOV R0, #HeapReason_Free + MOV R1, #RMAAddress + SWI XOS_Heap + Pull "R0-R5, lr" + ORRS PC, lr, #V_bit + + MakeErrorBlock MHNoRoom + +nopostfixwanted + ADR R0, ErrorBlock_ModulePostfix + [ International + BL TranslateError + ] + B modfailxit + + MakeErrorBlock ModulePostfix + + MakeErrorBlock NotMod + +NotAModule + ADR R0, ErrorBlock_NotMod + [ International + BL TranslateError + ] +modfailxit + STR R0, [stack] + Pull "R0-R5, lr" + ORRS PC, lr, #V_bit + +HeNotFile + MOV r2, r0 + MOV r0, #OSFile_MakeError + SWI XOS_File + B modfailxit + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; ModuleIn_CheckForDuplicate +; Altentry to Load_Module for AddArea: module already in, initialise it. + +ModuleIn_CheckForDuplicate + Push "R0-R5, lr" + MOV R9, R1 ; move module ptr to handy place + B %BT50 + +;************************************************************* +; AddModuleIfInROM +; in: R1 -> name +; R0 = Postfix_Separator => called from AddNewIncarnation when module is not active +; find newest version in ROM, and initialise it in its own location (even if unplugged) +; then rename the base incarnation of it to specified postfix +; +; = 0 => called from ReInit when module is not active +; plug in all versions of module, and initialise newest one in its own location +; +; out: R5-R8 preserved +; Other registers may be corrupted +; + +AddModuleIfInROM ENTRY "r5-r8" + MOV r4, r0 + MOV r12, #0 ; search entire ROM set + MOV r7, r1 ; save pointer to beginning of name + BL FindROMModule + TEQ r12, #0 + BNE %FT10 + BL MakeNotFoundError ; in: r1 -> module name 'foo' + ; out: r0 -> "Module 'foo' not found" error, V=1 + EXIT + +10 + MOV r6, r1 ; save pointer to terminator of module name +15 + LDR r14, [r12, #ROMModule_OlderVersion] ; find oldest version + TEQ r14, #0 + MOVNE r12, r14 + BNE %BT15 + +20 + TEQ r4, #0 ; if doing AddIncarnation rather than ReInit + BNE %FT30 ; then don't plug module in + MOV r5, #&FF ; set up byte mask (and indicate found) + LDR r1, [r12, #ROMModule_CMOSAddrMask] + AND r3, r5, r1, LSR #16 ; get bit mask + ANDS r1, r1, r5 + BEQ %FT30 ; if no CMOS, then look for another module + MOV r0, #ReadCMOS + SWI XOS_Byte + EXIT VS + TST r2, r3 ; test if module unplugged + BEQ %FT30 ; if not, then don't write to CMOS (so RMReInit works when FSLock enabled) + BIC r2, r2, r3 ; otherwise clear bit + MOV r0, #WriteCMOS + SWI XOS_Byte + EXIT VS +30 + LDR r14, [r12, #ROMModule_NewerVersion] + TEQ r14, #0 + MOVNE r12, r14 + BNE %BT20 + + TEQ r4, #0 ; if AddIncarnation then check that name terminator is "%" + LDRNEB r14, [r6], #1 ; load next character (and skip it) + TEQNE r14, #Postfix_Separator + BEQ %FT40 + ADRL r0, ErrorBlock_PostfixNeeded + [ International + BL TranslateError + | + SETV + ] + EXIT + +40 + MOV r11, r12 + BL InitialiseROMModule ; in both cases initialise newest version + ; (in AddIncarnation case it may still be unplugged) + EXIT VS + + TEQ r4, #0 ; if ReInit then we've finished (V=0 from above) + EXIT EQ + + SUB r8, r6, r7 ; length of module name including '%' + ADD r8, r8, #4+1+3 ; allow for 'Base<0>' and round up to whole number of words + BIC r8, r8, #3 + SUB stack, stack, r8 + + MOV r0, stack +50 + LDRB r14, [r7], #1 ; copy name, including '%' + STRB r14, [r0], #1 + TEQ r7, r6 + BNE %BT50 + + ADR r1, base_postfix +60 + LDRB r14, [r1], #1 ; copy 'Base<0>' + STRB r14, [r0], #1 + TEQ r14, #0 + BNE %BT60 + + MOV r0, #ModHandReason_RenameIncarnation + MOV r1, stack ; pointer to '<module>%Base<0>' + MOV r2, r6 ; pointer to 'newinc' + SWI XOS_Module + ADD stack, stack, r8 ; junk name + EXIT + +;************************************************************* +; LinkAndInit : +; module pointer in R9 +; module list position in R2 : added at end if posn not found +; environment string pointer in R10 +; "hardware" in R11 +; returns module node pointer in R9 + +LinkAndInit ENTRY "r2, r3" + MOV r3, #ModInfo + BL ClaimSysHeapNode + EXIT VS + + STR r9, [r2, #Module_code_pointer] + STR r11, [r2, #Module_Hardware] + MOV r9, r2 ; keep node pointer + + MOV r0, #0 + STR r0, [r2, #Module_ROMModuleNode] ; assume not a ROM module + STR r0, [r2, #Module_incarnation_list] ; terminate list + ADR r0, base_postfix + BL Add_Incarnation ; add Base incarnation + BVS %FT01 + + Pull "r2" + ADR r0, Module_List +05 + LDR r1, [r0] + CMP r1, #0 + CMPNE r0, r2 + MOVNE r0, r1 + BNE %BT05 + +; add module to chain end - give ROM modules priority. + + STR r1, [r9, #Module_chain_Link] + STR r9, [r0, #Module_chain_Link] + Pull "r3, pc" ; V clear from EQ compare with 0 + +01 + Push "r0" + LDR r2, [r9, #Module_code_pointer] + MOV r1, #RMAAddress + MOV r0, #HeapReason_Free + SWI XOS_Heap + MOV r2, r9 ; node pointer + BL FreeSysHeapNode + Pull "r0, r2, r3, lr" + ORRS pc, lr, #V_bit + +base_postfix + = "Base",0 ; postfix used for 1st incarnation + ALIGN + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Add_Incarnation +; takes postfix pointer in R0 (terminated by <= space +; module node pointer in R9 +; envstring in R10 +; Adds an incarnation node, reinitialises the module + +Add_Incarnation ROUT + Push "R0-R3, lr" + + MOV R3, #Incarnation_Postfix ; node size needed +01 LDRB R1, [R0], #1 + ADD R3, R3, #1 + CMP R1, #" " + BGT %BT01 + BL ClaimSysHeapNode + STRVS R0, [stack] + Pull "R0-R3, PC", VS + + LDR R0, [stack] + ADD R3, R2, #Incarnation_Postfix +02 LDRB R1, [R0], #1 + CMP R1, #" " + STRGTB R1, [R3], #1 + BGT %BT02 + MOV R1, #0 + STRB R1, [R3] + + MOV R3, #0 + STR R3, [R2, #Incarnation_Workspace] ; zero private word + MOV R12, R2 + BL CallInit +; BLVS FreeIncarnation done by CallInit + STRVS R0, [stack] + + LDRVC R3, [R9, #Module_incarnation_list] + STRVC R3, [R2, #Incarnation_Link] + STRVC R2, [R9, #Module_incarnation_list] + Pull "R0-R3, PC" + +;************************************************************* +CallInit ROUT +; take R9 -> module node +; R12 -> incarnation node +; R10 -> envstring +; set R11 appropriately +; initialise module with R10 given + + Push "R0-R6, R11, R12, lr" + + [ SqueezeMods + BL CheckForSqueezedModule ; unsqueeze module if squeezed + BVS %FT02 + ] + + ; see if we need to set up a module swi node + + BL CheckForSWIEntries + LDR R12, [stack, #4*(6+2)] + BNE %FT03 + + ; the module really does have a SWI chunk. Add node to hashtable. + + MOV R4, R0 + MOV R11, R1 + MOV R3, #ModSWINode_Size + BL ClaimSysHeapNode + BVS %FT02 + STR R9, [R2, #ModSWINode_MListNode] + STR R4, [R2, #ModSWINode_CallAddress] + STR R11, [R2, #ModSWINode_Number] + ModSWIHashvalOffset R11 + LDR R6, [R11, #ModuleSWI_HashTab]! ; link into table. + STR R6, [R2, #ModSWINode_Link] + STR R2, [R11] + +03 ; now prepared to look at module + + LDR R3, [R9, #Module_code_pointer] + + LDR R4, [R3, #Module_Init] + CMP R4, #0 + Pull "R0-R6, R11, R12, PC", EQ ; V clear + + ADD R12, R12, #Incarnation_Workspace + MOV R11, #0 + ADD R5, R9, #Module_incarnation_list - Incarnation_Link +01 LDR R5, [R5, #Incarnation_Link] + CMP R5, #0 ; count incarnations + ADDNE R11, R11, #1 + BNE %BT01 + CMP R11, #0 + LDREQ R11, [R9, #Module_Hardware] + + ; R11, R12 now set: initialise + + MOV lr, PC ; pseudo BL + ADD PC, R3, R4 ; call 'im + + Pull "R0-R6, R11, R12, lr", VC + BICVCS PC, lr, #V_bit + +02 LDR R12, [stack, #4*(6+2)] + BL FreeIncarnation + BL FreeSWIEntry + STR R0, [stack] + Pull "R0-R6, R11, R12, PC" ; V set return + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Enter with module pointer in R1 +; " size in R2 + +CheckHeader ROUT + Push "R3, lr" + LDR R3, [R1, #Module_HC_Table] + BL %FT11 + LDR R3, [R1, #Module_HelpStr] + BL %FT11 + LDR R3, [R1, #Module_Title] + BL %FT11 + LDR R3, [R1, #Module_Service] + BL %FT10 + LDR R3, [R1, #Module_Die] + BIC R3, R3, #&80000000 ; ignore top-bit (means cannot be RMCleared) + BL %FT10 + LDR R3, [R1, #Module_Init] + TST R3, #&80000000 + BLEQ %FT10 ; only check init offset if an unsqueezed module + Pull "R3, lr" + BICS PC, lr, #V_bit + +10 TST R3, #3 + BNE %FT99 +11 CMP R3, R2 + MOVLO PC, lr +99 + Pull "R3, lr" + ADR R0, ErrorBlock_BadRMHeaderField + [ International + Push "lr" + BL TranslateError + Pull "lr" + ] + ORRS PC, lr, #V_bit + MakeErrorBlock BadRMHeaderField + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Enter with module node pointer in R9 +; Sets R12 to module code pointer, R0 SWI code offset, R1 to SWI number +; Only returns SWIs extant if no incarnations of module yet + +CheckForSWIEntries ROUT + LDR R12, [R9, #Module_incarnation_list] + CMP R12, #0 + LDREQ R12, [R9, #Module_code_pointer] + LDREQ R1, [R12, #Module_SWIChunk] + BICEQ R1, R1, #Auto_Error_SWI_bit + TSTEQ R1, #Module_SWIChunkSize-1 + TSTEQ R1, #&FF000000 + MOVNE PC, lr ; naff chunk number. + CMP R1, #0 + LDRNE R0, [R12, #Module_SWIEntry] + CMPNE R0, #0 + BEQ %FT01 + TST R0, #3 + MOVNE PC, lr + Push "R5" + LDR R5, [R12, #-4] + CMP R5, R0 + Pull "R5" +01 BICLSS PC, lr, #Z_bit ; NE return + ADD R0, R0, R12 + ORRS PC, lr, #Z_bit ; EQ for success + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Takes R9 pointer to module node; frees any module SWI hashtab node + +FreeSWIEntry ROUT + Push "R0-R4, R12, lr" + BL CheckForSWIEntries + Pull "R0-R4, R12, PC", NE, ^ + MOV R3, R1 ; copy of SWIno + ModSWIHashval R1 + LDR R2, [R1], #-ModSWINode_Link + + ; R1 predecessor, R2 currnode, R0 call address, R3 SWIno + ; look down chain until find right call address and number +01 CMP R2, #0 + Pull "R0-R4, R12, PC", EQ, ^ + LDR R4, [R2, #ModSWINode_CallAddress] + CMP R4, R0 + LDREQ R4, [R2, #ModSWINode_Number] + CMPEQ R4, R3 + MOVNE R1, R2 + LDRNE R2, [R2, #ModSWINode_Link] + BNE %BT01 + LDR R4, [R2, #ModSWINode_Link] + STR R4, [R1,#ModSWINode_Link] + BL FreeSysHeapNode + Pull "R0-R4, R12, PC",,^ + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +FreeIncarnation ROUT + ; copy error, free any workspace, incarnation link. + ; R12 incarnation pointer + Push "R0-R2, lr" + BL Module_CopyError + STR R0, [stack] + LDR R2, [R12, #Incarnation_Workspace] + CMP R2, #0 + MOV R0, #HeapReason_Free + MOV R1, #RMAAddress + SWINE XOS_Heap + MOV R2, R12 + BL FreeSysHeapNode + Pull "R0-R2, PC",,^ + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; KillAndFree: +; R0 -> module +; R2 -> prevmodule +; Kills all incarnations, frees all space. + +KillAndFree ROUT + Push "R2, R3, R9, R12, lr" + MOV R9, R0 + ADDS R3, R9, #Module_incarnation_list ; ensure V clear +01 LDR R12, [R9, #Module_incarnation_list] + BL KillIncarnation + Pull "R2, R3, R9, R12, PC", VS + CMP R9, #0 + BNE %BT01 ; more incarnations yet + Pull "R2, R3, R9, R12, PC" + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; KillIncarnation +; R9 module ptr +; R12 incarnation ptr +; R3 previous incarnation +; R2 previous module +; Exit: R9 zeroed if module completely gone +; +KillIncarnation ROUT + Push "R0-R2, R10, lr" + MOV R10, #1 ; fatal die + CMP r12, #0 ; fudge for 0 incarnations: + BLNE CallDie ; tidy up anyway + STRVS R0, [stack] + Pull "R0-R2, R10, PC", VS + + MOV R2, R12 + BL FreeSysHeapNode ; free incarnation node +01 LDR R0, [R9, #Module_incarnation_list] + CMP R0, #0 ; last incarnation? + LDREQ R2, [stack, #2*4] + BLEQ DelinkAndFreeModule + MOVEQ R9, #0 + Pull "R0-R2, R10, PC",,^ + +LoseModuleSpace_if_its_the_only_incarnation + Push "R0-R2, R10, lr" + B %BT01 + +;************************************************************* +; CallDie +; take R9 -> module node +; R12 -> incarnation node +; R3 -> previous incarnation +; R10 = fatality +; check against CAO +; delink incarnation, issue die, deal with workspace. + +CallDie ROUT + Push "R0-R6, R11, R12, lr" + + MOV R11, #0 + LDR R11, [R11, #Curr_Active_Object] + + ; check killability + + LDR R0, [R9, #Module_code_pointer] + BL %FT10 ; is_CAO? + BLT %FT04 ; code block is CAO + + ; check if workspace block could be CAO: may have handler in there + + LDR R0, [R12, #Incarnation_Workspace] + BL %FT20 ; check block before getting size + BVS ModuleIsntCAO ; not heap block - we don't + BL %FT10 ; know what's going on. + BGE ModuleIsntCAO ; not CAO + +04 CMP R10, #0 ; fatal? + BNE CantKill + LDR R0, [R12, #Incarnation_Workspace] + BL %FT20 + BVS ModuleIsntCAO ; soft die of non-heap module OK +CantKill + ADR R0, ErrorBlock_CantKill + [ International + BL TranslateError + ] +01 STR R0, [stack] + LDR R3, [stack, #4*3] + LDR R12, [stack, #4*(6+2)] + STR R12, [R3, #Incarnation_Link] ; relink + Pull "R0-R6, R11, R12, lr" + ORRS PC, lr, #V_bit + MakeErrorBlock CantKill + +ModuleIsntCAO + MOV R11, #0 ; set R11 to incarnation number. + LDR R0, [R9, #Module_incarnation_list] +03 CMP R0, R12 + ADDNE R11, R11, #1 + LDRNE R0, [R0, #Incarnation_Link] + BNE %BT03 + + LDR R0, [R12, #Incarnation_Link] + STR R0, [R3, #Incarnation_Link] ; delink + ADD R12, R12, #Incarnation_Workspace + LDR R1, [R9, #Module_code_pointer] + LDR R0, [R1, #Module_Die] + BIC R0, R0, #&80000000 ; knock out invincibility bit + CMP R0, #0 ; WARNING: don't try to combine these 2 instructions in a BICS, V is used below + MOV lr, PC + ADDNE PC, R1, R0 ; call. + BVS %BT01 + BL FreeSWIEntry + + CMP R10, #0 ; soft die? + BEQ %FT02 + + LDR R12, [stack, #4*(6+2)] + LDR R2, [R12, #Incarnation_Workspace] + CMP R2, #0 + MOVNE R1, #RMAAddress + MOVNE R0, #HeapReason_Free + SWINE XOS_Heap + MOV R0, #0 + STR R0, [R12, #Incarnation_Workspace] ; orgone +02 + Pull "R0-R6, R11, R12, lr" + BICS PC, lr, #V_bit + +; check if block @ R0 contains address R11 +10 LDR R1, [R0, #-4] + ADD R1, R1, R0 + CMP R0, R11 + CMPLS R11, R1 + MOV PC, lr ; return LT for Yes + +; check block @ R0 is a valid RMA heap block +20 + Push "R0-R3, lr" + MOV R2, R0 + MOV R0, #HeapReason_ExtendBlock + MOV R1, #RMAAddress + MOV R3, #0 + SWI XOS_Heap + Pull "R0-R3, PC" ; V set if not. + +;************************************************************* +; DelinkAndFreeModule +; R9 -> Module +; R2 -> prevmodule + +DelinkAndFreeModule ROUT + Push "R0-R2, lr" + +; loop here to find predecessor; make death re-entrant + MOV R0, #Module_List +01 + LDR R1, [R0, #Module_chain_Link] + CMP R1, R9 + MOVNE R0, R1 + BNE %BT01 + + LDR R1, [R9, #Module_chain_Link] + STR R1, [R0, #Module_chain_Link] ; delinked + + LDR R2, [R9, #Module_code_pointer] + MOV R1, #RMAAddress + MOV R0, #HeapReason_Free + SWI XOS_Heap + + MOV R2, R9 + BL FreeSysHeapNode + + Pull "R0-R2, PC",,^ + +;************************************************************************* +; common lookup for reinit, enter, die + +lookup_commoned ROUT + BIC lr, lr, #I_bit + TEQP PC, #SVC_mode + Push "lr" + BL LookUp_Module ; node ptr in R0 + BEQ %FT01 ; not found + CMP R12, #0 + BLT %FT02 ; incarnation not found + MOV R9, R0 + Pull "PC" +01 + ADR R0, ErrorBlock_RMNotFound + Push "r1-r6" + MOV r3, #0 + LDR r3, [r3, #IRQsema] + CMP r3, #0 + BNE %FT03 + [ International + MOV R4, R1 + BL TranslateError_UseR4 + Push "r0" + | + BL GetOscliBuffer + Push r5 + LDR r2, [r0], #4 + STR r2, [r5], #4 + BL rmecopystr +copynfrmname + LDRB r2, [r1], #1 + CMP r2, #32 + STRGTB r2, [r5], #1 + BGT copynfrmname + + BL rmecopystr + STRB r2, [r5] ; terminate + ] + Pull "r0-r6" + + +03 + Pull "lr" + ORRS PC, lr, #V_bit + MakeErrorBlock RMNotFound +02 + ADR R0, ErrorBlock_IncarnationNotFound + [ International + BL TranslateError + ] + B %BT03 + MakeErrorBlock IncarnationNotFound + +MakeNotFoundError ; r1 -> module name + Push lr + B %BT01 + +;************************************************************* +; Lookup_Module +; Entry: R1 -> module name +; Exit: R0 -> module chain node (0 for not found) +; R1 -> postfix of name +; R12 -> incarnation node (0 for not specified, -1 for not found) +; R2 -> previous module for potential delinking +; R3 -> previous incarnation " " " +; NE for found/EQ for not + + +LookUp_Module ROUT + Push "R4, R5, lr" + TEQP PC, #SVC_mode ; interrupts on + LDR R2, =Module_List +01 LDR R0, [R2, #Module_chain_Link] + CMP R0, #0 + Pull "R4, R5, PC", EQ ; return if not found + LDR R4, [R0, #Module_code_pointer] + LDR R3, [R4, #Module_Title] + ADD R3, R3, R4 ; got ptr to title + MOV R4, #Postfix_Separator ; allowed terminator for StrCmp + BL Module_StrCmp ; compare with abbreviation. + MOVNE R2, R0 + BNE %BT01 ; loop if not found + LDRB R4, [R1], #1 ; get terminator + CMP R4, #Postfix_Separator + BEQ %FT02 + + ; now a quick fudge to spot recursive ModHand calls during module death. + LDR R12, [R0, #Module_incarnation_list] + CMP R12, #0 + MOVEQ R12, #-1 ; no incarnations! + MOVNE R12, #0 ; no postfix/incarnation specified + CMP PC, #0 + Pull "R4, R5, PC" ; back with NE + +02 LDRB R4, [R1] + CMP R4, #" " + Pull "R4, R5, lr", LE + ORRLES PC, lr, #Z_bit ; not found: naff postfix + Push "R1" ; updated value to return + BL FindIncarnation + MOVEQ R12, #-1 ; failed to find postfix. + CMP PC, #0 ; force NE + Pull "R1, R4, R5, PC" ; back with NE + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; FindIncarnation +; R0 is node pointer, need to loop to find incarnation ($R1) +; Return EQ if not found, +; NE => R12 -> incarnation, R3 -> previnc + +FindIncarnation ROUT + Push "lr" + ADD R3, R0, #Module_incarnation_list ; previnc +03 LDR R12, [R3, #Incarnation_Link] + CMP R12, #0 + Pull "PC", EQ ; failed to find postfix. + [ Fix9 + Push "R3,R4" + ADD R3, R12, #Incarnation_Postfix + MOV R4, #0 ; no special terminator + BL Module_StrCmp + Pull "R3,R4" + | + Push "R3" + ADD R3, R12, #Incarnation_Postfix + BL Module_StrCmp + Pull "R3" + ] + MOVNE R3, R12 + BNE %BT03 + CMP PC, #0 ; force NE + Pull "PC" + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; Module_StrCmp +; +; Do a string comparison, given pointers in R1, R3. +; Ignore case, allow $R1 to be an abbreviation of $R3 +; Strings are terminated by ctrl-char, or ASC(R4) for $R1 +; +; out: EQ => match found, R1 -> terminator of R1 string +; NE => match not found, R1 preserved +; R3 corrupted in all cases +; + +Module_StrCmp ENTRY "r1,r2,r5-r7" + MOV r2, #0 +01 + LDRB r7, [r1], #1 + LDRB r5, [r3], #1 + CMP r7, r4 + CMPNE r7, #32 + CMPLE r5, #32 + BLE %FT02 + UpperCase r7, r6 + UpperCase r5, r6 + CMP r7, r5 + ADDEQ r2, r2, #1 + BEQ %BT01 + CMP r2, #0 + MOV r2, #Z_bit + TEQP r2, pc ; invert EQ/NE + CMPEQ r7, #"." ; success if abbreviation + EXIT NE + CMP r5, #" " ; reject abbreviation + EXIT LT ; after full match + ADD r1, r1, #1 +02 + SUB r1, r1, #1 + CMP r2, #0 ; reject 0-length match + MOV r2, #Z_bit + TEQP r2, pc ; invert EQ/NE + STREQ r1, [stack] ; r1 -> terminator + EXIT ; return with success + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +EnvStringSkipName ROUT + Push "R0" +01 LDRB R0, [R10], #1 + CMP R0, #" " + BGT %BT01 +02 LDREQB R0, [R10], #1 + CMP R0, #" " + BEQ %BT02 + SUB R10, R10, #1 + Pull "R0" + MOV PC, lr + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; PreferIncarnation +; R9 -> module node +; R12 -> incarnation node +; R3 -> previous incarnation +PreferIncarnation + Push "R0" + LDR R0, [R12, #Incarnation_Link] + STR R0, [R3, #Incarnation_Link] + LDR R0, [R9, #Module_incarnation_list] + STR R0, [R12, #Incarnation_Link] + STR R12, [R9, #Module_incarnation_list] + Pull "R0" + MOV PC, R14 + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Module_CopyError ROUT +; grab an oscli buffer for the error, +; rather than having a permanent module buffer + Push "R0, R2, R5, R6, lr" + BL GetOscliBuffer + + STR R5, [stack] + LDR R2, [R0], #4 + STR R2, [R5], #4 +01 LDRB R2, [R0], #1 + STRB R2, [R5], #1 + CMP R2, #0 + BNE %BT01 + Pull "R0, R2, R5, R6, PC" + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Claim chunk from RMA : increase RMA if can, +; force size to multiple of 16 -4 to keep alignment OK + +RMAClaim_Chunk ROUT + MOV R0, #HeapReason_Get + Push "R0, R3, lr" + + ADD R3, R3, #15+4 ; now force size to 16*n-4 + BIC R3, R3, #15 ; so heap manager always has + SUB R3, R3, #4 ; 4-word aligned blocks + + B IntoRMAHeapOp + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +DoRMAHeapOpWithExtension + Push "R0, R3, lr" + +IntoRMAHeapOp + MOV R1, #RMAAddress + SWI XOS_Heap + Pull "R0, R3, PC", VC + + LDR r14, [r0] ; look at error number + TEQ r14, #ErrorNumber_HeapFail_Alloc + STRNE r0, [stack] + Pull "r0, r3, PC", NE ; can only retry if ran out of room + + Push r3 ; in case extension + LDR r1, [stack, #4] + CMP r1, #HeapReason_ExtendBlock + BNE notRMAextendblock + Push "r5, r6" + LDR r1, [r2, #-4] ; pick up block size + ADD r5, r1, r2 ; block end +4 + SUB r5, r5, #4 ; TMD 02-Aug-93: block size includes size field (optimisation was never taken) + MOV r6, #RMAAddress + LDR r6, [r6, #:INDEX:hpdbase] + ADD r6, r6, #RMAAddress ; free space + CMP r5, r6 ; does block butt against end? + ADDNE r3, r3, r1 ; max poss size needed + Pull "r5, r6" + + ; note that this doesn't cope well with a block at the end preceded by a + ; free block, but tough. + +notRMAextendblock + MOV r1, #RMAAddress + LDR R0, [R1, #:INDEX: hpdbase] + LDR R1, [R1, #:INDEX: hpdend] + SUB R1, R1, R0 ; bytes free + SUB R1, R3, R1 ; bytes needed + + Pull r3 + ADD R1, R1, #8 ; safety factor + + MOV R0, #1 ; try and expand RMA. + SWI XOS_ChangeDynamicArea + Pull "R0" ; heap reason code back + MOV R1, #RMAAddress + SWIVC XOS_Heap +01 + ADRVSL R0, ErrorBlock_MHNoRoom + [ International + Push "LR",VS + BLVS TranslateError + Pull "LR",VS + ] + Pull "r3, PC" + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Data + +crstring = 13 + ALIGN + +;***************************************************************************** +; *Unplug code. + +Unplug_Code ENTRY "r7-r9" + CMP r1, #0 + BNE ZapTheModule + +; If name not given, list unplugged modules + +; MOV r1, #0 ; start with module 0 (r1 is already zero indicating no parameters to command!) + MOV r2, #-1 ; start with main ROMs + MOV r7, #0 ; flag indicating whether we've had any unplugged modules already +10 + MOV r0, #ModHandReason_EnumerateROM_ModulesWithInfo + SWI XOS_Module + BVS %FT30 ; no more, so finish off + CMP r4, #-1 ; is it unplugged? + BNE %BT10 ; no, then go for another one + + MOV r8, r1 ; save module and podule numbers + MOV r9, r2 + TEQ r7, #0 ; if already printed header message + BNE %FT20 ; then skip + [ International + BL WriteS_Translated + = "Unp:Unplugged modules are:", 10, 13, 0 + ALIGN + | + ADR r0, AreUnpluggedMessage + SWI XOS_Write0 + ] + EXIT VS + MOV r7, #1 +20 + MOV r0, r3 + SWI XOS_Write0 + EXIT VS + CMP r2, #-1 + BEQ %FT25 ; if a main ROM, then no blurb after name (and V=0) + [ International + MOV r4, r2 + | + ADRGT r4, podbra ; is a podule module + ADRLT r4, extnbra ; is an extn rom module + ] + MVNLT r2, r2 ; so invert number + SUB r0, r0, r3 ; length of module name + RSB r0, r0, #24 ; number of spaces to pad out to column 24 (may be -ve) +21 + SWI XOS_WriteI + " " ; always print at least one space + EXIT VS + SUBS r0, r0, #1 + BGT %BT21 + [ :LNOT: International + MOV r0, r4 + SWI XOS_Write0 + EXIT VS + ] + SUB sp, sp, #3*4 ; make buffer on stack + MOV r0, r2 + MOV r1, sp + MOV r2, #3*4 + SWI XOS_ConvertCardinal4 + [ International + CMP r4,#-1 + MOV r4,r0 ; r4 -> number + BLT %FT23 + BL WriteS_Translated_UseR4 + = "Podule:(Podule %0)",0 + ALIGN + B %FT24 +23 + BL WriteS_Translated_UseR4 + = "Extn:(Extn ROM %0)",0 + ALIGN +24 + ADD sp, sp, #3*4 ; restore stack + | + SWIVC XOS_Write0 + ADD sp, sp, #3*4 ; restore stack + SWIVC XOS_WriteI + ")" + ] +25 + SWIVC XOS_NewLine + MOVVC r1, r8 ; restore module and podule number + MOVVC r2, r9 + BVC %BT10 + EXIT + +30 + CMP r7, #0 ; NB will clear V in any case + [ International + BNE %FT31 + BL WriteS_Translated + = "NoUnp:No modules are unplugged", 10, 13, 0 + ALIGN +31 + EXIT + | + ADREQ r0, NoUnpluggedMessage + SWIEQ XOS_Write0 + EXIT ; exit with V=0 unless error in Write0 + +AreUnpluggedMessage + = "Unplugged modules are:", 10, 13, 0 +NoUnpluggedMessage + = "No modules are unplugged", 10, 13, 0 +podbra + = "(" +rommposp + = "Podule ", 0 +extnbra + = "(" +rommposer + = "Extn ROM ", 0 + ALIGN + ] + +ZapTheModule + MOV r9, #0 ; indicate unplug, not insert +UnplugInsertEntry + MOV r12, #0 ; search from start of chain + MOV r7, r0 ; name pointer + MOV r4, #0 ; no extra terminator + MOV r5, #0 ; indicate no versions found yet + + MOV r6, #0 ; indicate no version found that was initialised + MOV r1, r7 + BL SkipToSpace ; leaves r1 pointing to 1st space or control char + BL SkipSpaces ; leaves r1 -> 1st non-space, r0 = 1st non-space char + CMP r0, #&7F + CMPNE r0, #" " ; if a ctrl char, then + MOVLS r8, #&80000000 ; indicate to unplug all versions + BLS %FT40 + CMP r0, #"-" + ADDEQ r1, r1, #1 + MOVEQ r8, #-1 + MOVNE r8, #1 + MOV r0, #1 :SHL: 31 ; check terminator is control char or space + SWI XOS_ReadUnsigned + EXIT VS + MUL r8, r2, r8 ; apply sign +40 + MOV r1, r7 + BL FindROMModule + TEQ r12, #0 + BEQ %FT60 ; no versions of this module found, so report error + +42 + LDR r14, [r12, #ROMModule_OlderVersion] ; find oldest version of this module + TEQ r14, #0 + MOVNE r12, r14 + BNE %BT42 + +45 + TEQ r8, #&80000000 ; if not doing any old podule + LDRNE r14, [r12, #ROMModule_PoduleNumber] + TEQNE r14, r8 ; and podule number doesn't match + BNE %FT50 ; then skip this one + + LDRB r14, [r12, #ROMModule_Initialised] ; if this version of CODE was initialised then keep pointer to it + TEQ r14, #0 + MOVNE r6, r12 ; save pointer to it + MOV r5, #&FF ; set up byte mask (and indicate found) + LDR r1, [r12, #ROMModule_CMOSAddrMask] + AND r3, r5, r1, LSR #16 ; get bit mask + ANDS r1, r1, r5 + BEQ %FT50 ; if no CMOS, then look for another module + MOV r0, #ReadCMOS + SWI XOS_Byte + EXIT VS + TEQ r9, #0 + ORREQ r2, r2, r3 ; set unplug bit + BICNE r2, r2, r3 ; or clear it as appropriate + MOV r0, #WriteCMOS + SWI XOS_Byte + EXIT VS +50 + LDR r14, [r12, #ROMModule_NewerVersion] ; go to next newer version + TEQ r14, #0 + MOVNE r12, r14 + BNE %BT45 + +60 + TEQ r5, #0 ; if we've seen any versions, then don't report error + BNE %FT70 + ADR r0, ErrorBlock_RMNotFoundInROM + [ International + BL TranslateError + | + SETV + ] + EXIT + +70 + CMP r9, #1 ; if doing unplug not insert + CMPNE r6, #0 ; and we found a match on an initialised version (else V=0) + [ 1 = 1 +;RCM's fix for MED-04173 + EXIT EQ + +; see if module is active, by checking for module in module list + MOV r0, #Module_List +60 + LDR r0, [r0, #Module_chain_Link] + TEQ r0, #0 ; module not active + BEQ %FT90 + LDR r1, [r0, #Module_ROMModuleNode] ; get active module's pointer to ROM module node + TEQ r1, r12 ; if it matches + BNE %BT60 + + MOV r0, #ModHandReason_Delete ; then tell him he's dead + LDR r1, [r6, #ROMModule_Name] + SWI XOS_Module +90 + | + MOVNE r0, #ModHandReason_Delete ; then tell him he's dead + LDRNE r1, [r6, #ROMModule_Name] + SWINE XOS_Module + ] + EXIT + +RMInsert_Code ALTENTRY + MOV r9, #1 ; indicate insert, not unplug + B UnplugInsertEntry + + MakeErrorBlock RMNotFoundInROM + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + END diff --git a/s/MoreComms b/s/MoreComms new file mode 100644 index 0000000000000000000000000000000000000000..0a55cdce6e91028bb4e3368ee99df6a4c64a27ed --- /dev/null +++ b/s/MoreComms @@ -0,0 +1,531 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + TTL => MoreComms + +Error_Code ROUT + ; Use MessageTrans to construct an error block by substituting the error text into + ; an error + + Push "r7,r8,lr" + + ASSERT ?Error_CodeTag <= 8 + ADR lr, Error_CodeTag + LDMIA lr, {r1,r2} + Push "r1,r2" + + MOV r1, r0 ; pointer + MOV r0, #0 ; base + SWI XOS_ReadUnsigned + Push "r2" + + MOV r0, sp ; Error block + BL TranslateError_VClear + + ; If error number's changed don't substitute + LDR r3, [r0] + TEQ r3, r2 + BNE %FT90 + + ; GSTrans the text into the error buffer + MOV r3, r0 + MOV r0, r1 + ADD r1, r3, #4 + MOV r2, #252 + SWI XOS_GSTrans + + ; Ensure 0-terminated + MOV r0, #0 + CMP r2, #252 + MOVHI r2, #252 + STRB r0, [r1, r2] + + MOV r0, r3 +90 + ADD sp, sp, #12 + Pull "r7,r8,lr" + ORRS pc, lr, #V_bit + +Error_CodeTag DCB "ErrSub", 0 + + LTORG + +Eval_Code ROUT + Push "lr" + LDR R1, =GeneralMOSBuffer + MOV R2, #256 + SWI XOS_EvaluateExpression + Pull "PC", VS + [ :LNOT: International + SWI XOS_WriteS + = "Result is a",0 + ALIGN + Pull "PC", VS + CMP R1, #0 + ADREQ R0, %FT01 + ADRNE R0, %FT02 + SWI XOS_Write0 + Pull "PC", VS + SWI XOS_WriteS + = ", value : ",0 + ALIGN + Pull "PC", VS + | + Push "r4" + CMP R1, #0 + ADREQ R0, %FT01 + ADRNE R0, %FT02 + BL FindToken + MOV R4,R0 + BL WriteS_Translated_UseR4 + = "Result:Result is %0, value :",0 + ALIGN + Pull "r4" + + ] + LDREQ R1, =GeneralMOSBuffer + MOVEQ R0, R2 + MOVEQ R2, #256 + SWIEQ XOS_BinaryToDecimal + MOV R5, #-1 +03 ADD R5, R5, #1 + CMP R5, R2 + BEQ %FT04 + LDRB R0, [R1, R5] + CMP R0, #&7F + MOVEQ R0, #"?"-"@" ; preversion!! + CMP R0, #31 + ADDLE R0, R0, #"@" + SWILE XOS_WriteI+"|" + Pull "PC", VS + CMP R0, #"|" + CMPNE R0, #"""" + CMPNE R0, #"<" + SWIEQ XOS_WriteI+"|" + SWIVC XOS_WriteC + BVC %BT03 + +04 SWIVC XOS_NewLine + Pull "PC" + + [ International +01 + = "Integer:an integer",0 +02 + = "String:a string",0 + | +01 + = "n integer",0 +02 + = " string",0 + ] + + ALIGN + +;**************************************************************************** +; Coupla utility commands + +Time_Code ROUT + Push "lr" + LDR R1, =GeneralMOSBuffer + MOV R0, #0 + STRB R0, [R1] + MOV R0, #14 + SWI XOS_Word + MOVVC R0, R1 + MOVVC R1, #24 + SWIVC XOS_WriteN + SWIVC XOS_NewLine + Pull "PC" + + +Ignore_Code ROUT + Push "lr" + MOVS R4, R1 + MOV R1, R0 + MOV R0, #10+ (1:SHL:30) + SWINE XOS_ReadUnsigned + Pull "PC", VS + MOV R6, R2 ; maybe number + BL CheckEOL + BNE %FT01 + + CMP R4, #0 + MOV R0, #&B6 + MOVEQ R1, #255 + MOVNE R1, #0 + MOV R2, #0 + SWI XOS_Byte + MOV R0, #6 + MOV R1, R6 + SWINE XOS_Byte + Pull "PC" + +01 ADRL R0, ErrorBlock_BadNumb + [ International + BL TranslateError + | + SETV + ] + Pull "PC" + +;***************************************************************************** + +ROMModules_Code ENTRY + [ International + BL GSWriteS_Translated + = "ROMMTitle:No. Position|IModule Name|I|IVersion|IStatus|M|J",0 + EXIT VS + | + ADRL r0, romm_helpstr + MOV r1, #0 + SWI XOS_PrettyPrint + EXIT VS + ] + MOV r1, #0 + MOV r2, #-1 +01 + SWI XOS_ReadEscapeState + PullEnv CS + BCS AckEscape + MOV r0, #ModHandReason_EnumerateROM_ModulesWithInfo + SWI XOS_Module + EXITS VS ; exit V clear + +; R1 = module number +1 +; R2 = podule number +; R3 -> name +; R4 = status (-1 unplugged, 0 dormant, 1 active, 2 running) +; R5 = chunk number +; R6 = version number + +; Copy info into buffer and prettyprint + + MOV r5, r1 ; save r1 and r2 for next call to OS_Module + MOV r10, r2 + MOV r0, r1 + LDR r1, =GeneralMOSBuffer + MOV r2, #256 + SWI XOS_ConvertCardinal2 + SUB r12, r1, r0 ; characters in buffer +02 + CMP r12, #3 ; tab out to 3 characters + SWICC XOS_WriteI+" " + EXIT VS + ADDCC r12, r12, #1 + BCC %BT02 + MOV r0, #" " + BL %FT20 ; add space + CMP r10, #-1 + [ International + ADREQL r0, rommpossysrom + ADRLTL r0, rommposextrom + ADRGTL r0, rommpospodule + BL FindToken + | + ADREQL r0, rommpossr + ADRLTL r0, rommposer + ADRGTL r0, rommposp + ] + BL %FT21 ; add string + MOVGT r0, r10 ; if normal podule then use plain number (flags still set from CMP) + MVNLT r0, r10 ; if extension ROM then NOT it (-2 => 1, -3 => 2 etc) + SWINE XOS_ConvertCardinal1 + MOV r0, #TAB + BL %FT20 ; tab to col. 16 + MOV r0, r3 + BL %FT21 ; copy name in + MOV r3, r0 ; string length + MOV r0, #TAB +03 + CMP r3, #24 + ADDCC r3, r3, #8 + BLCC %FT20 + BCC %BT03 + + MOV r11, #"0" + TST r6, #&F0000000 ; 1st digit of integer part + ORRNE r0, r11, r6, LSR #28 + BLNE %FT20 + MOV r6, r6, LSL #4 + TSTEQ r6, #&F0000000 ; 2nd digit of integer part + ORRNE r0, r11, r6, LSR #28 + BLNE %FT20 + MOV r6, r6, LSL #4 + TSTEQ r6, #&F0000000 ; 3rd digit of integer part + ORRNE r0, r11, r6, LSR #28 + BLNE %FT20 + MOV r6, r6, LSL #4 + ORR r0, r11, r6, LSR #28 ; 4th digit of integer part + BL %FT20 + MOV r0, #"." + BL %FT20 + MOV r6, r6, LSL #4 + ORR r0, r11, r6, LSR #28 ; 1st digit of decimal part + BL %FT20 + MOV r6, r6, LSL #4 + ORR r0, r11, r6, LSR #28 ; 2nd digit of decimal part + BL %FT20 + MOVS r6, r6, LSL #4 ; only print 3rd and 4th digits of decimal part if non-zero + ORRNE r0, r11, r6, LSR #28 + BLNE %FT20 + MOVS r6, r6, LSL #4 + ORRNE r0, r11, r6, LSR #28 + BLNE %FT20 + MOV r0, #TAB + BL %FT20 + + CMP r4, #0 + [ International + ADRMIL r0, rommstatu + ADREQL r0, rommstatd + ADRGTL r0, rommstata + BL FindToken + | + ADRMIL r0, rommstu + ADREQL r0, rommstd + ADRGTL r0, rommsta + ] + CMP r4, #2 + [ International + ADREQL r0, rommstatr + BLEQ FindToken + | + ADREQL r0, rommstr + ] + BL %FT21 + MOV r0, #13 + BL %FT20 + MOV r0, #0 + BL %FT20 + LDR r0, =GeneralMOSBuffer + MOV r1, #0 + SWI XOS_PrettyPrint + EXIT VS + MOV r1, r5 + MOV r2, r10 + B %BT01 + +; R1 buffer ptr, R2 bufflen left + +20 + SUBS r2, r2, #1 + STRPLB r0, [r1], #1 + MOVS pc, lr +21 + Push "r0, lr" + MOV r12, r0 +22 + LDRB r0, [r12], #1 + CMP r0, #TokenEscapeChar + BEQ %FT23 + CMP r0, #0 + [ International + CMPNE r0, #10 + ] + BLNE %BT20 + BNE %BT22 + Pull "r0, lr" + SUB r0, r12, r0 ; length of string + SUB r0, r0, #1 + MOVS pc, lr + +23 + BL %BT20 + LDRB r0, [r12], #1 + BL %BT20 + B %BT22 + + [ International +rommpossysrom + = "SYSROM:System ROM", 0 +rommposextrom + = "EXTROM:Extn ROM", 0 +rommpospodule + = "PODROM:Podule", 0 + +rommstata + = "Active:Active", 0 + +rommstatd + = "Dormant:Dormant", 0 + +rommstatu + = "Unplugged:Unplugged", 0 + +rommstatr + = "Running:Running",0 + + ALIGN + ] + +;***************************************************************************** + +RMEnsure_Code ENTRY "r0, r1" + MOV r1, r0 ; name pointer + MOV r0, #ModHandReason_LookupName + SWI XOS_Module + MOVVS r10, r0 ; module handler will build a nice error + BVS RMEDoCommand ; module not found + LDR r0, [stack] ; now find version number +01 + LDRB r6, [r0], #1 + CMP r6, #" " + BNE %BT01 + BL RMEGetVerNo + MOV r6, r1 + LDR r0, [r3, #Module_HelpStr] + TEQ r0, #0 + BEQ RMEDoCommand ; no help string, so do command + ADD r0, r0, r3 + BL GetVerNoFromHelpString + CMP r1, r6 + EXIT GE + MOV r10, #0 +RMEDoCommand + Pull "r0, r1" + CMP r1, #2 + BEQ BuildRMEnsureError +04 + LDRB r1, [r0], #1 + CMP r1, #" " + BNE %BT04 +05 + LDRB r1, [r0], #1 + CMP r1, #" " + BEQ %BT05 +06 + LDRB r1, [r0], #1 + CMP r1, #" " + BNE %BT06 + SUB r0, r0, #1 +03 + SWI XOS_CLI + Pull PC + +BuildRMEnsureError + MOVS r0, r10 + Pull lr, NE + ORRNES pc, lr, #V_bit + ADR r0, ErrorBlock_ModuleTooOld + [ International + LDR r4,[r3, #Module_Title] + ADD r4,r4,r3 + BL TranslateError_UseR4 + Pull "LR" + ORRS PC,LR,#V_bit + | + BL GetOscliBuffer + MOV r10, r5 + LDR r2, [r0], #4 + STR r2, [r5], #4 + BL rmecopystr + MOV r6, r0 + + LDR r2, [r3, #Module_Title] ; r3 still module pointer + ADD r0, r2, r3 + BL rmecopystr + MOV r0, r6 + BL rmecopystr + STRB r2, [r5] ; terminate + B BuildRMEnsureError + ] + +rmecopystr + LDRB r2, [r0], #1 + CMP r2, #32 + STRGEB r2, [r5], #1 + BGE rmecopystr + MOV pc, lr + + MakeErrorBlock ModuleTooOld + +; ************************************************************************* +; +; RMEGetVerNo - Read version number from a string +; +; in: R0 -> string +; +; out: R0, R4, R5, R12 corrupted +; R1 = version number in BCD with the decimal point between bits 15 and 16 +; eg "2.34" => &00023400, "5.6789" => &00056789, "17" => &00170000 +; only the last 4 digits of the integer part, and the first 4 decimal places are stored +; + +RMEGetVerNo ENTRY + MOV r1, #0 +10 + LDRB r12, [r0], #1 + CMP r12, #" " + BEQ %BT10 +11 + SUB r12, r12, #"0" + CMP r12, #9 + ORRLS r1, r12, r1, LSL #4 ; just keep nibbles - we only need the + LDRLSB r12, [r0], #1 ; result to be ordered, not continous + BLS %BT11 + MOV r5, #0 + CMP r12, #"."-"0" + BNE %FT13 + MOV r4, #16 +12 + SUBS r4, r4, #4 + BMI %FT13 + LDRB r12, [r0], #1 + SUB r12, r12, #"0" + CMP r12, #9 + ORRLS r5, r5, r12, LSL r4 + BLS %BT12 +13 + ORR r1, r5, r1, LSL #16 + EXIT + +; ************************************************************************* +; +; GetVerNoFromHelpString - Read version number from a module help string +; +; in: R0 -> module help string +; +; out: R1 = version number in BCD with the decimal point between bits 15 and 16 +; eg "2.34" => &00023400, "5.6789" => &00056789, "17" => &00170000 +; only the last 4 digits of the integer part, and the first 4 decimal places are stored +; All other registers preserved +; + +GetVerNoFromHelpString ENTRY "r0, r4, r5, r12" + MOV r5, #0 ; char count +10 + LDRB r1, [r0], #1 + CMP r1, #0 ; check character + EXIT EQ ; if end of string then no version number so return zero + ADD r5, r5, #1 + CMP r1, #TAB + ADDEQ r5, r5, #7 + BICEQ r5, r5, #7 + CMP r5, #16 ; hit verno col yet? + BLT %BT10 +20 + LDRB r1, [r0], #1 + CMP r1, #TAB + CMPNE r1, #31 ; if a control character (except TAB) + MOVLT r1, #0 ; then no version number so return zero + EXIT LT + SUB r1, r1, #"0" + CMP r1, #9 ; if not a digit + BHI %BT20 ; then try next character + SUB r0, r0, #1 ; was a digit so go back to it + BL RMEGetVerNo ; read version number from here + EXIT + + END diff --git a/s/MoreSWIs b/s/MoreSWIs new file mode 100644 index 0000000000000000000000000000000000000000..b82d60853710192d5f375adafdbc8c026f4ab5ba --- /dev/null +++ b/s/MoreSWIs @@ -0,0 +1,1147 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + TTL => MoreSWIs + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SubstituteArgs +; in: R0 -> arglist (space delimited args, terminated by 10,13,0) +; top bit set => don't append unused part of line +; R1 -> buffer +; R2 = bufflen +; R3 -> string to mangle +; R4 = no of chars in $R3 +; out: R2 = no of chars in buffer + +XOS_SubstituteArgs_code ROUT + + TEQP PC, #SVC_mode ; enable IRQs + + Push "R0-R8, lr" + BIC r0, r0, #&80000000 + ADD R8, R4, R3 + +; try and get parameter positions. +; Items starting with " can have spaces in + + MOV R6, #0 ; parameter number + LDR R12, =MacExStartPtrs + LDR R4, =MacExEndPtrs +35 LDRB R5, [R0], #1 + CMP R5, #" " + BEQ %BT35 + MOV R2, #" " + CMP R5, #"""" + MOVEQ R2, #"""" ; quoted param + CMP r6, #10 ; "rest of line" item? + MOVEQ r2, #-1 ; terminate on EOL only + SUB R0, R0, #1 + STR R0, [R12, R6, LSL #2] + CMP r5, #"""" + ADDEQ R0, R0, #1 +36 LDRB R5, [R0], #1 + BL suba_chktrm + CMPNE R5, R2 + BNE %BT36 + CMP R5, #"""" + LDREQB R5, [R0] + CMPEQ R5, #"""" ; check for "" in string + ADDEQ R0, R0, #1 + BEQ %BT36 + CMP R2, #"""" + SUBNE R0, R0, #1 + STR R0, [R4, R6, LSL #2] + ADD R6, R6, #1 + CMP R6, #11 ; Parameters 0-9 and a "rest" set. + BNE %BT35 + +; Keep track of highest param used, so can tack any unused stuff on end. +; R3 points at string to get chars from +; R12 at start ptrs +; R4 at end ptrs + + MOV R6, #0 ; count. + MOV R7, #0 ; highest param used. + LDR R2, [stack, #4*2] +37 BL suba_getchar + BEQ %FT41 + CMP R5, #"%" + BEQ %FT44 +38 BL suba_addchar + B %BT37 + +PCnotparm + ADD R5, R5, #"0" + MOV R11, R5 + MOV R5, #"%" + BL suba_addchar + MOV R5, R11 + B %BT38 + +44 BL suba_getchar + MOVEQ R5, #"%" + BEQ %FT40 + CMP R5, #"%" + BEQ %BT38 + CMP R5, #"*" + BEQ DoStarParams + SUBS R5, R5, #"0" + BMI PCnotparm + CMP R5, #9 + BGT PCnotparm + +; itsa parameter! Get ptrs from R12, R4 + CMP R5, R7 + ADDGE R7, R5, #1 + LDR R11, [R4, R5, LSL #2] +CopyToR11FromParamR5 + LDR R10, [R12, R5, LSL #2] ; start ptr +39 LDRB R5, [R10], #1 + CMP R10, R11 + BGT %BT37 + BL suba_addchar + B %BT39 + +DoStarParams ; had %* : find limits to copy between + BL suba_getchar + BEQ PCStarTerminates + SUBS R5, R5, #"0" + BMI PCStarNoDigit + CMP R5, #9 + MOVLE R7, #11 ; flag * used + LDRLE R11, [R4, #10*4] ; always to EOL + BLE CopyToR11FromParamR5 +PCStarNoDigit + ADD R5, R5, #"0" + MOV R11, R5 + MOV R5, #"%" + BL suba_addchar + MOV R5, #"*" + BL suba_addchar + MOV R5, R11 + B %BT38 + +PCStarTerminates + MOV R5, #"%" + BL suba_addchar + MOV R5, #"*" +40 BL suba_addchar +41 CMP r7, #11 + LDREQ r12, [r4, #10*4] ; no more to copy + BEQ %FT42 + LDR r0, [stack] + CMP r0, #0 + LDRPL R12, [R12, R7, LSL #2] ; ptr to rest of command line : copy + LDRMI r12, [r4, #10*4] ; caller wants no appending. +42 LDRB R5, [R12], #1 + BL suba_addchar + BL suba_chktrm + BNE %BT42 + + STR R6, [stack, #4*2] + Pull "R0-R8, lr" + ExitSWIHandler + +suba_addchar + ADD R6, R6, #1 + CMP R6, R2 + STRNEB R5, [R1], #1 + MOVNES PC, lr + + ADRL R0, ErrorBlock_BuffOverflow + [ International + BL TranslateError + ] + STR R0, [stack] + Pull "R0-R8, lr" + B SLVK_SetV + +suba_getchar + CMP R3, R8 + LDRNEB R5, [R3], #1 + MOV PC, lr + +suba_chktrm + CMP R5, #13 + CMPNE R5, #10 + CMPNE R5, #0 + MOV PC, lr + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Take R0 as pointer to null-terminated string, print it +; with line breaks before words that won't fit on the current line. +; CR forces a newline. TAB=tab to next column of 8. CHR$31 = hard space +; <27,n> => substitute nth dictionary entry: +; dictionary is pointed at by r1, consists of a list of null-terminated +; strings, with preceding length bytes. +; 0th dictentry => use string at r2. + +XOS_PrettyPrint_code ROUT + +; Inside here, r1 is the current string pointer +; R3 is the linelength to format to +; R4 is the current position in the line. +; r6 is the return addr in word counting +; r7 is the r1 restore value in reading word length +; r8 is used in dictionary selection in getbytepp +; r9 is the stack restoration level for exiting. +; r11 is the dictionary pointer (0 means use MOS dict) +; r12 is the special token pointer + + TEQP PC, #SVC_mode + + Push "r0-r9, lr" + + BL ReadWindowWidth ; read linelength + MOV R3, R0 + MOV R0, #165 ; read output cursor + SWI XOS_Byte + ORR R4, R1, #&80000000 ; no leading space even if in line. + LDMFD stack, {r1, r11, r12} ; reload strptr, dictptr, tokptr + CMP r11, #0 + ADREQL r11, MOSdictionary + MOV r9, stack + +; loop over all words +01 BL getwordlength + CMP R2, #0 + BLEQ getbytepp + BEQ %FT21 ; null word - test for done + + CMP R4, #0 + ADDGT R2, R2, #1 ; allow for separator + ADD R0, R2, R4 + BIC R0, R0, #&80000000 ; clear R4 flag + CMP R0, R3 + BLE %FT10 + CMP R4, #0 + SUBGT R2, R2, #1 ; remove leading space length + MOV R4, #0 ; if word too long to fit, do newline + SWI XOS_NewLine + BVS exitpp + +10 CMP R4, #0 + BIC R4, R4, #&80000000 ; clear "no leading space" flag + ADD R4, R4, R2 + SUBGT R2, R2, #1 + SWIGT XOS_WriteI+" " ; output separator if not 1st on line + BVS exitpp + +04 BL getbytepp + CMP R0, #31 ; hard space? + MOVEQ R0, #" " + SWI XOS_WriteC + BVS exitpp + SUBS R2, R2, #1 + BNE %BT04 + +21 CMP R0, #13 + MOVEQ R4, #0 + SWIEQ XOS_NewLine + BVS exitpp + + CMP R0, #TAB + BEQ %FT20 + CMP R0, #0 + BNE %BT01 + +exitpp MOV stack, r9 + STRVS r0, [stack] + Pull "r0-r9,lr" + B SLVK_TestV + +; TAB had: align to next multiple of 8 +20 BIC R4, R4, #&80000000 + ; first want to get next word length, to see if it's worth doing + ADD R5, R4, #8 + BIC R5, R5, #7 + SUB R5, R5, R4 ; spaces for this tab + +24 BL getwordlength + CMP R2, #0 + BNE %FT23 ; got the word + BL getbytepp + CMP R0, #13 + BEQ %BT21 ; TAB, CR - whalley! + CMP R0, #TAB + SUBNE R5, R5, #1 ; leading spaces, junk ignored + ADDEQ R5, R5, #8 ; multiple tabs OK tho. + CMP r0, #0 ; terminator? + BNE %BT24 ; only case to allow zero-length word + SUB r1, r1, #1 ; we know this rewinds OK + +23 ADD R0, R4, R5 + ADD R0, R0, R2 + CMP R0, R3 + MOVGT R0, #13 ; next tab stop too far : newline + BGT %BT21 +22 SWI XOS_WriteI+" " + BVS exitpp + ADD R4, R4, #1 + SUBS r5, r5, #1 + BNE %BT22 + ORR R4, R4, #&80000000 ; set top bit to disable leading space + B %BT01 + +getwordlength + MOV r6, lr + MOV r10, r9 ; first copy context + MOV r2, stack + MOV r7, r1 +copycontextpp + CMP r9, r2 + LDRNE r0, [r9, #-4]! + Push r0, NE + BNE copycontextpp + + MOV r2, #0 ; word length +02 BL getbytepp + CMP R0, #31 + CMPNE R0, #" "+1 + ADDGE r2, r2, #1 + BGE %BT02 + MOV r1, r7 + MOV stack, r9 + MOV r9, r10 + MOV pc, r6 + +getbytepp LDRB r0, [r1], #1 + CMP r0, #TokenEscapeChar + BEQ gettokenpp + CMP r0, #0 + MOVNES pc, lr + CMP stack, r9 + MOVHSS pc, lr + Pull r1 ; back to previous token + B getbytepp + +gettokenpp + LDRB r0, [r1], #1 ; tokno + Push r1 ; save context + CMP r0, #0 + MOVEQ r1, r12 + BEQ getbytepp + MOV r1, r11 +gtoklp SUBS r0, r0, #1 + LDRNEB r8, [r1] + ADDNE r1, r1, r8 + BNE gtoklp + ADD r1, r1, #1 + B getbytepp + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +ReadWindowWidth ROUT ; read "number of chars printable after Newline + ; before we're on the next line" + MOV R0, #VduExt_WindowWidth +ReadVduVarForSam + Push "R0, R1, lr" ; R1 reserves space + MOV R0, #-1 + STR R0, [stack, #4] ; overwrite R1 value + MOV R0, sp + MOV R1, sp + SWI XOS_ReadVduVariables + Pull "R0, R14, PC" + +;***************************************************************************** +; R0 -> envstring, R1 -> 5 byte time + +WriteEnv_SWICode ROUT ; for debugger use + CMP R0, #0 + BEQ %FT01 + LDR R10, =EnvString + MOV R11, R0 +02 LDRB R12, [R11], #1 + CMP R12, #" " + MOVLT R12, #0 + STRB R12, [R10], #1 + BGE %BT02 + +01 CMP R1, #0 + ExitSWIHandler EQ + LDR R10, =EnvTime + MOV R11, #4 +03 LDRB R12, [R1, R11] + STRB R12, [R10, R11] + SUBS R11, R11, #1 + BPL %BT03 + ExitSWIHandler + +;***************************************************************************** + +; LET RdArgs() BE +; R0 ptr to key defn string +; R1 ptr to command line to decode +; R2 ptr to workspace +; R3 size of workspace +; Returns R3 size left + +; Flags used in initial args decoding + +AFlag * 1:SHL:8 ; flags shifted up a byte; avoid looking like chars. +KFlag * 1:SHL:9 +SFlag * 1:SHL:10 +EFlag * 1:SHL:11 +GFlag * 1:SHL:12 +UnsetFlag * 1:SHL:31 +PresentFlag * -1 :AND::NOT:UnsetFlag +AbsentFlag * 0 + +; Type flags + +EndType * 0 +FlagType * 1 +KeywordType * 2 +ItemType * 3 + +RdArgs_SWICode ROUT + + TEQP PC, #SVC_mode + + Push "R4, R8, R9, lr" + MOV R10, R2 ; R10 points at next available word + MOV R12, R0 +01 MOV R11, #UnsetFlag + SUBS R3, R3, #4 + BMI %FT99 ; insufficient space + STR R11, [R10], #4 +02 LDRB R11, [R12], #1 + CMP R11, #"/" + BNE %FT03 + LDRB R11, [R12], #1 + UpperCase R11, R9 + CMP R11, #"A" + MOVEQ R11, #AFlag + CMP R11, #"K" + MOVEQ R11, #KFlag + CMP R11, #"S" + MOVEQ R11, #SFlag + CMP R11, #"E" + MOVEQ R11, #EFlag + CMP R11, #"G" + MOVEQ R11, #GFlag + CMP R11, #256 + LDRGE R9, [R10, #-4] + ORRGE R9, R11, R9 + STRGE R9, [R10, #-4] +03 + CMP R11, #"," + BEQ %BT01 + CMP R11, #" " + BGE %BT02 + +; Initialisation complete: all flags set, R10 implies number of args. + MOV R8, R10 + +10 BL RdItem + BVS %FT90 + CMP R12, #KeywordType + BNE %FT11 + ADD R11, R2, R4, LSL #2 ; keyword ptr + BL RdItem + BVS %FT90 + CMP R12, #ItemType + BNE %FT98 + BL SetKeyword + BVS %FT90 + B %BT10 + +11 CMP R12, #ItemType + BNE %FT12 + +; next positional arg := itemptr + + MOV R11, R2 +20 CMP R11, R8 + BEQ %FT98 ; no more positional args + LDR R12, [R11], #4 + TST R12, #UnsetFlag + BEQ %BT20 + TST R12, #KFlag :OR: SFlag + BNE %BT20 + SUB R11, R11, #4 + BL SetKeyword + BVS %FT90 + B %BT10 + +12 CMP R12, #EndType + BNE %BT10 + +; postscan to check all /a args set. + MOV R12, R2 +30 CMP R12, R8 + BEQ %FT31 + LDR R11, [R12], #4 + TST R11, #UnsetFlag + BEQ %BT30 + TST R11, #AFlag + BNE %FT98 ; bum args error + MOV R11, #AbsentFlag + STR R11, [R12, #-4] ; force "not present" + B %BT30 + +31 + Pull "R4, R8, R9, lr" + ExitSWIHandler + +98 ADR R0, ErrorBlock_BadParameters + [ International + BL TranslateError + ] + B %FT90 + +99 ADRL R0, ErrorBlock_BuffOverflow + [ International + BL TranslateError + ] +90 + Pull "R4, R8, R9, lr" + B SLVK_SetV + + MakeErrorBlock BadParameters + MakeErrorBlock ArgRepeated + ALIGN + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; RdItem: strips next item from command line +; In: R1 -> cmd line +; Out: R1 updated +; R12 contains type +; R4 contains ptr for Item, argno for Flag/Keyword +; VS means buffer full +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +RdItem ROUT + Push "R1, R7, R8, lr" + MOV R8, #0 ; not demanding new arg +01 LDRB R12, [R1], #1 + CMP R12, #" " + BEQ %BT01 + MOVLT R12, #EndType + Pull "R1, R7, R8, lr", LT + BICLTS PC, lr, #V_bit + + CMP R12, #"""" + BEQ ohnoitsquotedargumentsagain + + CMP R12, #"-" ; options? + BNE %FT02 ; nope - boring item +05 BL GetArg + LDRVS R1, [stack] + BVS %FT02 ; not recognised - boring item + STR R1, [stack] ; new restore value. + Push PC ; save EQ/NE + LDR R12, [R2, R4, LSL #2] + TST R12, #UnsetFlag + ADREQ R0, ErrorBlock_ArgRepeated + [ International + BLEQ TranslateError + ] + ADDEQ stack, stack, #4 ; discard PC + Pull "R1, R7, R8, lr", EQ + ORREQS PC, lr, #V_bit + + ANDS R12, R12, #SFlag + MOVEQ R12, #KeywordType + ADDEQ stack, stack, #4 ; discard PC + Pull "R1, R7, R8, lr",EQ + BICEQS PC, lr, #V_bit + + MOV R12, #PresentFlag + STR R12, [R2, R4, LSL #2] + +; now deal with flag elision: if nextchar valid keyword char, rescan + Pull R12 + TST R12, #Z_bit + BEQ %FT20 ; GetArg returned NE, so not single char abbr + Push "R2, R3" + LDRB R2, [R1] + BL CheckR2OKChar + Pull "R2, R3" + MOVEQ R8, #1 ; MUST get another arg + BEQ %BT05 +20 MOV R12, #FlagType + Pull "R1, R7, R8, lr" + BICS PC, lr, #V_bit + +02 CMP R8, #0 + ADRNE R0, ErrorBlock_BadParameters + [ International + BLNE TranslateError + ] + Pull "R1, R7, R8, lr", NE + ORRNES PC, lr, #V_bit + + ; copy arg until <" " + + MOV R7, #" " + SUB R1, R1, #1 +06 MOV R4, R10 +03 LDRB R12, [R1], #1 + CMP R12, R7 + CMPNE R12, #" "-1 + BLE %FT04 +10 + SUBS R3, R3, #1 + STRPLB R12, [R10], #1 + BPL %BT03 +23 + ADRL R0, ErrorBlock_BuffOverflow + [ International + BL TranslateError + ] + Pull "R1, R7, R8, lr" + ORRS PC, lr, #V_bit ; overflow + +04 CMP R7, #"""" + BNE %FT07 + CMP R12, #"""" + BNE %FT08 + LDRB R12, [R1], #1 + CMP R12, #"""" + BEQ %BT10 +07 MOV R12, #0 ; terminate + SUBS R3, R3, #1 + BMI %BT23 + STRB R12, [R10], #1 + MOV R12, #ItemType + SUB R1, R1, #1 + STR R1, [stack] + Pull "R1, R7, R8, lr" + BICS PC, lr, #V_bit + +ohnoitsquotedargumentsagain + MOV R7, #"""" + B %BT06 + +08 ADRL R0, ErrorBlock_BadString + [ International + BL TranslateError + ] + Pull "R1, R7, R8, lr" + ORRS PC, lr, #V_bit + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; GetArg +; Look through keys: allow only full match on first pass, then +; single char abbreviation on second pass +; Return V set if not key, EQ if single letter abbreviation +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +GetArg ROUT +; In: R0 ptr to keystring +; R1 ptr to potential option. +; Out: VS if nomatch or +; R1 updated +; R4 argument number + + Push "R0-R3, R5-R6, lr" + MOV R6, #-1 ; pass number +20 MOV R4, #0 + +01 LDRB R2, [R0], #1 + CMP R2, #" " + BEQ %BT01 + +02 BL CheckR2OKChar + BNE %FT03 ; matched in full + LDRB R3, [R1], #1 + UpperCase R2, R5 + UpperCase R3, R5 + CMP R2, R3 + LDREQB R2, [R0], #1 + BEQ %BT02 + + CMP R6, #0 + BLT %FT04 + +; 2nd pass: allow abbreviation +; IF single char abbreviation THEN success ELSE skip + LDR R2, [stack, #4] + SUB R2, R1, R2 ; length of match+1 + CMP R2, #2 + SUBEQ R1, R1, #1 + BEQ %FT13 ; success + +; skip to next keyword +04 LDRB R2, [R0], #1 + CMP R2, #" " + BLT %FT05 + CMP R2, #"," + ADDEQ R4, R4, #1 + CMPNE R2, #"=" + BNE %BT04 + LDR R1, [stack, #4] + B %BT01 + +03 ; NE on first pass: check input string terminated OK + LDRB R2, [R1] ; check for end of input word + BL CheckR2OKChar + BNE %FT13 ; yaay! full & correct match + SUB R0, R0, #1 + B %BT04 + +05 ADDS R6, R6, #1 + LDMLEFD stack, {R0, R1} + BLE %BT20 + Pull "R0-R3, R5-R6, lr" + ORRS PC, lr, #V_bit ; back with failure + +13 STR R1, [stack, #4] + MVN R0, #V_bit + TSTP R0, PC ; clrV (just) + Pull "R0-R3, R5-R6, PC" ; back with success + +CheckR2OKChar ROUT + CMP R2, #"A" + RSBGES R3, R2, #"Z" + ORRGES PC, lr, #Z_bit + CMP R2, #"a" + RSBGES R3, R2, #"z" + ORRGES PC, lr, #Z_bit + CMP R2, #"0" + RSBGES R3, R2, #"9" + ORRGES PC, lr, #Z_bit + CMP R2, #"_" + BICNES PC, lr, #Z_bit + ORRS PC, lr, #Z_bit + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +SetKeyword ROUT +; R11 ptr at keyword flags +; R4 ptr to value + Push "R0-R2, R5, R6, lr" + LDR R0, [R11] + TST R0, #EFlag :OR: GFlag + STR R4, [R11] ; result will always be here anyway + BEQ %FT01 + SUB R5, R10, R4 ; length of value + ADD R3, R3, R5 ; increase free space + ADD R2, R5, #11 ; round up to nearest word, then 1 + BIC R2, R2, #3 + + STR stack, [stack, -R2]! ; reserve stack frame + + ADD R2, stack, #4 ; input value ptr +03 LDRB R6, [R4, R5] + STRB R6, [R2, R5] + SUBS R5, R5, #1 + BPL %BT03 ; copy the value + + TST R0, #EFlag + MOV R0, R2 + BNE %FT02 + ADD R1, R4, #2 ; free space pointer + SUBS R3, R3, #2 + MOV R2, R3 + BMI %FT04 + ORR R2, R2, #1:SHL:31 + SWI XOS_GSTrans +05 SUB R3, R3, R2 + ADD R10, R1, R2 ; update freespace pointer + STRB R2, [R1, #-2] + MOV R2, R2, LSR #8 + STRB R2, [R1, #-1] + BCS %FT04 + +90 LDR stack, [stack, #0] ; unwind frame (and don't let AAsm use + STRVS R0, [stack] ; postindexed!!!) + Pull "R0-R2, R5, R6,lr" + BICVCS PC, lr, #V_bit + ORRS PC, lr, #V_bit + +04 ADRL R0, ErrorBlock_BuffOverflow + [ International + BL TranslateError + | + SETV + ] + B %BT90 + +02 ADD R1, R4, #3 ; free space pointer + SUBS R3, R3, #3 ; adjust for type (1 byte) + length (2 bytes) + BMI %BT04 + MOV R2, R3 + SWI XOS_EvaluateExpression + BVS %BT90 + TEQ R1, #0, 2 ; if non-zero, then string, so update length + MOVNE R14, #1 ; set type byte to definitely non-zero + STRNEB R14, [R4] + BNE %BT05 ; (C=0 so no buffer overflow, V=0 from SWI) + STRB R1, [R4] ; set type byte to zero (=> integer) + SUBS R3, R3, #5 + BMI %BT04 + STRB R2, [R4, #1] + MOV R2, R2, LSR #8 + STRB R2, [R4, #2] + MOV R2, R2, LSR #8 + STRB R2, [R4, #3] + MOV R2, R2, LSR #8 + STRB R2, [R4, #4] + ADD R10, R4, #5 + B %BT90 + +01 + Pull "R0-R2, R5, R6,lr" + BICS PC, lr, #V_bit + + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; ReadRAMFSLimits +; Return R0 start, R1 end (i.e. 1st byte out of area) + +ReadRAMFSLimits_Code ROUT + [ NewStyle_RAMDisc + Push "lr" + MOV r0, #ChangeDyn_RamFS + SWI XOS_ReadDynamicArea ; out: r0 = base, r1 = current size + Pull "lr" + ADDVC r1, r1, r0 ; if no error, make r1 -> after end + ORRVS lr, lr, #V_bit ; if error, then set V_bit on return + | + MOV R0, #RAMDiscAddress + MOV R1, #0 + LDR R1, [R1, #RAMDiscSize] + ADD R1, R1, R0 + ] + ExitSWIHandler + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; ExitAndDie +; r0-r2 parameters for Exit +; r3 pointer to module name + +TerminateAndSodOff ROUT + + Push "r0-r2" + MOV r10, #0 + STR r10, [r10, #Curr_Active_Object] + MOV r1, r3 + MOV r0, #ModHandReason_Delete + SWI XOS_Module + Pull "r0-r2" + SWI XOS_Exit + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; AddCallBack entry to callback vector +; r0 address to call +; r1 workspace ptr + +AddCallBack_Code ROUT + + Push "r0-r3, lr" + MOV r3, #12 + BL ClaimSysHeapNode + BVS %FT99 + Pull "r0, r1" + MOV r10, #0 + TEQP PC, #SVC_mode+I_bit ; IRQs off while holding context. + LDR r3, [r10, #CallBack_Vector] + [ True + STR r3, [r2, #0] + STMIB r2, {r0, r1} + STR r2, [r10, #CallBack_Vector] + Pull "r2, r3, lr" + | + STR r3, [r2], #4 + STMIA r2, {r0, r1} + SUB r2, r2, #4 + STR r2, [r10, #CallBack_Vector] + Pull "r2, r3, lr" + MOV r10, #0 + ] + LDRB r11, [r10, #CallBack_Flag] + ORR r11, r11, #CBack_VectorReq + STRB r11, [r10, #CallBack_Flag] + B SLVK + +99 STR r0, [stack] + Pull "r0-r3, lr" + B SLVK_SetV + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; RemoveCallBack - Entry for SWI OS_RemoveCallBack +; +; Removes an entry on the callback vector before it has been called +; +; in: r0 = address that would have been called +; r1 = workspace ptr +; +; out: - +; + +RemoveCallBack ROUT + Push "r2-r4" + MOV r10, PC ; save old I bit +10 + TEQP PC, #SVC_mode+I_bit ; disable IRQs while looking at list + MOV r11, #0 + LDR r2, [r11, #CallBack_Vector]! ; r11 -> prev, r2 -> this +20 + TEQ r2, #0 + Pull "r2-r4", EQ + ExitSWIHandler EQ + + LDMIA r2, {r3,r4,r12} ; r3 -> next, r4 = addr, r12 = ws + TEQ r4, r0 ; check if correct address + TEQEQ r12, r1 ; and correct ws ptr + MOVNE r11, r2 ; if not, then prev:=this + MOVNE r2, r3 ; and this:=next + BNE %BT20 ; and loop + + STR r3, [r11] ; prev.link := next + TEQP r10, #0 ; safe now to restore IRQ status + + Push "r0, r1, lr" ; now free this node + BL FreeSysHeapNode ; and then start again (NB we must + ; restart from head of list again, as + ; enabling IRQs could have changed list + STRVS r0, [sp, #0] + Pull "r0, r1, lr" + BVC %BT10 + + Pull "r2-r4" ; had an error while releasing block + ORR lr, lr, #V_bit + ExitSWIHandler + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; SWI OS_Confirm + +; If pointer visible, change pointer shape and look at mouse keys too. +; Flush mouse buffer first. +; Wait until key pressed. +; Returns: (lowercased) character in r0 (if mouse scanned, LH button = 'y', +; other buttons = 'n') +; C set for Escape condition +; EQ set if r0 = 'y' + +confirm_yn DCB "YesNo:yn",0 ; Token to lookup message for Yes/No +ptr_confirm DCB "ptr_confirm",0 ; Wimp's confirm pointer sprite shape +confirm_scale DCD 1,1,1,1 ; Scaling factor for sprite op +Confirm_Code ROUT + TEQP pc, #SVC_mode ; enable IRQs + Push "r0-r7, lr" + +; Lookup the symbols for Y/N + + ADR r0, confirm_yn + BL FindToken ; Lookup in messages, use default if error + LDRB r1, [r0], #1 ; Y character + LDRB r2, [r0], #1 ; N character + ORR r1, r1, r2, LSL #8 + Push "r1" ; Y=[sp], N=[sp+1] + +; Save current pointer selected + + MOV r0, #106 + MOV r1, #255 ; read pointer state + SWI XOS_Byte + BVS confirm_error + BIC r2, r1, #&80 + MOV r10, r1 + TST r10, #15 ; Pointer enabled? + BEQ confirm_waitloop ; Jump if not + +; Find Wimp's "ptr_confirm" sprite, searching first RMA then ROM + + SWI XWimp_BaseOfSprites + MOVVS r10, #0 ; If error then don't use mouse + BVS confirm_waitloop ; And jump to poll keyboard + + MOV r11, r0 ; Save -> ROM sprites, r1 -> RMA sprites + ADR r2, ptr_confirm ; -> sprite name + MOV r0, #&128 ; Read sprite info + SWI XOS_SpriteOp + BVC %FT10 ; Jump if sprite in RMA + + ADR r2, ptr_confirm ; -> sprite name + MOV r1, r11 ; -> ROM sprites + MOV r0, #&128 ; Read sprite info + SWI XOS_SpriteOp + MOVVS r10, #0 ; If error then don't use mouse + BVS confirm_waitloop ; And jump to poll keyboard + +; Set pointer shape from the sprite area found (r1) + +10 MOV r7, #0 ; No pixel translation + ADR r6, confirm_scale ; pointer scaling factor (1:1) + MOV r5, #0 ; y hot spot offset + MOV r4, #0 ; x hot spot offset + MOV r3, #&23 ; No palette, shape 3 + ADR r2, ptr_confirm ; -> sprite name + MOV r0, #&124 ; Set pointer shape + SWI XOS_SpriteOp ; Ignore errors + + MOV r0, #21 + MOV r1, #9 + SWI XOS_Byte ; flush mouse buffer + + MOV r0, #&C4 + MOV r1, #0 + MOV r2, #255 + SWI XOS_Byte ; read current repeat rate. + MOV r0, #0 + LDR r0, [r0, #MetroGnome] + ADD r11, r1, r0 ; time to wait for + +confirm_mouserepeat + SWI XOS_Mouse + CMP r2, #0 ; any buttons down? + BEQ confirm_waitloop + + CMP r3, r11 + BMI confirm_mouserepeat + +confirm_waitloop + MOV r0, #129 + MOV r1, #1 + MOV r2, #0 + SWI XOS_Byte ; scan for key + BVS confirm_error + CMP r2, #255 + BNE confirm_gotkey + + TST r10, #15 + BEQ confirm_waitloop ; no mouse scan wanted. + + SWI XOS_Mouse + BVS confirm_error + CMP r2, #0 + BEQ confirm_waitloop + + TST r2, #4 ; LH button? + LDRNEB r1, [sp] ; Yes + LDREQB r1, [sp, #1] ; No + +confirm_gotkey + CMP r2, #&1B ; ESCAPE or normal char read ? + ORREQ r11, r1, #&100 + MOVNE r11, r1 + LowerCase r11, r1 + + TSTS r10, #15 ; Was pointer changed? + MOV r1, r10 + MOV r0, #106 + SWINE XOS_Byte ; Yes then restore shape + + Pull "r10" ; r10=YN + AND r10, r10, #&ff ; Retain Y byte + Pull "r0-r7, lr" + BIC lr, lr, #C_bit :OR: Z_bit ; SKS. Punter lr has VClear + AND r0, r11, #&FF + TST r11, #&100 ; ESCAPE condition ? (SKS) + ORRNE lr, lr, #C_bit + CMP r0, r10 + ORREQ lr, lr, #Z_bit + B SLVK + +confirm_error + ADD sp, sp, #4 ; Drop YN + STR r0, [stack] + Pull "r0-r7, lr" + B SLVK_SetV + + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r0 = continuation crc (0 to start) +; r1 -> start of core +; r2 -> end of core +; r3 = increment (typically 1, 2 or 4), but can be -ve + +; Out r0 = crc so far + +CRC_Code ROUT + + [ {TRUE} + TEQP pc, #SVC_mode ; Could take a long time + + Push "r3, r14" + TEQ r3, #0 ; is increment 0? - if so, it's silly + BEQ %FT80 ; so return error, rather than going on forever + + MOV r10, r1 + MOV r12, #&A000 ; CRC EOR pattern = &A001 + ORR r12, r12, #&0001 +10 + CMP r10, r2 ; Finished ? + BEQ %FA90 ; Must be exact end, allows -ve offset + + LDRB r14, [r10], r3 + EOR r0, r0, r14 ; EOR the data with current crc lo + CMP r10, r2 ; length might be odd so check again + MOVEQ r11, #8 ; if equal then only do 8 bits + BEQ %FT20 + + LDRB r14, [r10], r3 + EOR r0, r0, r14, LSL #8 ; EOR the data with current crc hi + MOV r11, #16 ; do 16 bits + +20 + MOVS r0, r0, LSR #1 ; acc >>= 1; CS/CC + EORCS r0, r0, r12 ; CS -> eor, CC -> ok + SUBS r11, r11, #1 ; 8 bits per byte + BNE %BT20 + B %BT10 + +80 + ADRL r0, ErrorBlock_BadParameters ; return "Bad parameters" error + [ International + BL TranslateError + ] + Pull "r3, r14" + B SLVK_SetV + +90 + Pull "r3, r14" + ExitSWIHandler + | + TEQP pc, #SVC_mode ; Could take a long time + + Push "r3, r4, lr" + MOV r10, r1 + MOV r12, #&A000 ; CRC EOR pattern = &A001 + ORR r12, r12, #&0001 + MOV r14, #1 ; A single bit to be shifted + +10 CMP r10, r2 ; Finished ? + BEQ %FA90 ; Must be exact end, allows -ve offset + + LDRB r4, [r10], r3 + MOV r11, #0 ; Go round the bits + +20 TST r4, r14, LSL r11 ; Is data bit = carry ?; NE/EQ + BEQ %FT30 + + MOVS r0, r0, LSR #1 ; acc >>= 1; CS/CC + EORCC r0, r0, r12 ; NE, CC -> eor, NE, CS -> ok + B %FT40 + +30 MOVS r0, r0, LSR #1 ; acc >>= 1; CS/CC + EORCS r0, r0, r12 ; EQ, CS -> eor, EQ, CC -> ok + +40 ADD r11, r11, #1 ; 8 bits per byte + CMP r11, #8 + BLO %BT20 + + B %BT10 + +90 Pull "r3, r4, lr" + ExitSWIHandler + ] + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + END diff --git a/s/Morris b/s/Morris new file mode 100644 index 0000000000000000000000000000000000000000..94d04b9b668760149d205039a786970023501f8a --- /dev/null +++ b/s/Morris @@ -0,0 +1,105 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > Morris + +; +; ROM entry code for RISC OS Black +; + +MorrisHeaderCodeSize * (24*4) ;Code occupies less than this, we pad to this boundary so POST code + ;has a nicely defined place for its romsize and code entry points + [ 1 = 1 +; VECTOR AREA: + + LDR pc, .+ResetIndirection + LDR PC, UNDEF_VEC + LDR PC, SWI_VEC + LDR PC, PREF_VEC + LDR PC, DATA_VEC + LDR PC, RES_VEC ; addr. exn not generated + LDR PC, IRQ_VEC + LDR PC, FIQ_VEC + + ! 0, "*** WARNING *** assembling Morris code" + +; The above 8 instructions will operate as expected in 32-bit ROM mode, +; or in 16-bit ROM mode with a 16-bit ROM used. In 16-bit ROM mode, and +; with 32-bit wide ROMs in use, they will instead be intepreted as 4 +; NV-condition instructions (exact meaning not determined and should be +; irrelevant) which should do nothing and so allow control to drop +; through to this point, still in 16-bit mode. Force IOMD into 32-bit +; ROM mode for bank 0. The following instruction sequence has been +; produced in 16-in-32 form by extracting hex values from a listing... + + DCD &0000B632, &0000E3A0 ; 20: MOV R11, #IO+IOMDREGS - point at IOMD + DCD &00000000, &0000E3A0 ; 24: MOV R0, #&0 - ROMCR:32b,slow,218.75us,no burst + DCD &00000080, &0000E5CB ; 28: STRB R0,[R11,#ROMCR0] - switch mode + DCD &0000F000, &0000E3A0 ; 2C: MOV PC, #0 - jump to 0 (this instr pre-fetched) + | +; +; Kludged to cope with Morris Bugs +; + + ! 0,"<><><><><><><> This kernel version will not softload on a Risc PC <><><><><><><>" + + DCD &E3A0F010 + DCD &FFFFE3A0 + + DCD &E59FF034 + DCD &E59FF034 + + DCD &E59FF034 + DCD &E59FF034 + + DCD &E59FF034 + DCD &E59FF034 + + DCD &E3A0B632 + DCD &E3A0E3A0 ; 20: MOV R11, #IO+IOMDREGS - point at IOMD + + DCD &E3A00000 + DCD &E3A0E3A0 ; 24: MOV R0, #&0 - ROMCR:32b,slow,218.75us,no burst + + DCD &E5CB0080 + DCD &E3A0E5CB ; 28: STRB R0,[R11,#ROMCR0] - switch mode + + DCD &E59FF0F4 + DCD &E5CBE59F ; 2C: MOV PC, #0 - jump to 0 (this instr pre-fetched) + ] +; vector absolute targets for use from physical vector instructions + + + +UNDEF_VEC DCD UndInstInReset-ROM +SWI_VEC DCD SWIInReset -ROM +PREF_VEC DCD PrefAbInReset -ROM +DATA_VEC DCD DataAbInReset -ROM +RES_VEC DCD AddrExInReset -ROM +IRQ_VEC DCD IRQInReset -ROM +FIQ_VEC DCD FIQInReset -ROM + +UndInstInReset +SWIInReset +PrefAbInReset +DataAbInReset +AddrExInReset +IRQInReset +FIQInReset + SUB pc, pc, #8 + + ASSERT .-ROM <= MorrisHeaderCodeSize + % MorrisHeaderCodeSize-(.-ROM) + + END diff --git a/s/MsgCode b/s/MsgCode new file mode 100644 index 0000000000000000000000000000000000000000..19ece4fecb88e029fc243aef303acc583b37bf00 --- /dev/null +++ b/s/MsgCode @@ -0,0 +1,332 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; Kernel.Messages +; +; This file deals with translating text and errors in an international +; kernel. +; +; +; TranslateError +; Entry: +; R0 = Pointer to error block (Error number followed by token:default). +; Exit +; R0 = pointer to error block to use. +; If the error semaphore is set a pointer to the original block is +; returned. +; V Set. +; +TranslateError_VClear ROUT + Push "r4,LR" + MOV r4,#0 + BL TranslateError_UseR4 + Pull "r4,PC",,^ + +TranslateError ROUT + Push "r4,LR" + MOV r4,#0 + BL TranslateError_UseR4 + Pull "r4,PC" + +TranslateError_UseR4 + Push "R8,LR" + + MOV R8,#0 + LDRB R8, [R8, #ErrorSemaphore] + CMP R8,#0 + Pull "R8,LR",NE + ORRNES PC,LR,#V_bit + + MOV R8,LR + [ {TRUE} + ORR LR, LR, #SVC_mode ; SVC mode, preserve IRQ state + TEQP PC, LR + | + TEQP PC,#SVC_mode + ] + MOV R0,R0 + Push "R0-R7,LR" + + MOV R2,#0 + MOV R1,#-1 ; We are looking up an error, don't bother + STRB R1, [R2, #ErrorSemaphore] ; translating other errors. + + ADR R1,KernelMessagesBlock+4 + MOV R5,#0 + MOV R6,#0 + MOV R7,#0 + SWI XMessageTrans_ErrorLookup + LDR R14,[R0] + LDR R1,[SP] + LDR R1,[R1] + CMP R14,R1 + STREQ R0,[SP] + + MOV R1,#0 + STRB R1, [R1 ,#ErrorSemaphore] ; Clear error semaphore + + Pull "R0-R7,LR" ; Exit with new block and V set. + + TEQP PC,R8 ; Back to original mode. + MOV R0,R0 + Pull "R8,LR" + ORRS PC,R14,#V_bit ; original R0. + +;---------------------------------------------------------------------------------------- +; +;WriteS_Translated +;Entry: +; R14 -> Token. +;*NOTE* +; MUST BE TOKEN:DEFAULT +; +;Exit: +; Message printed +; Returns to word after end of token. +; +WriteS_Translated ROUT + Push "r0-r7,LR" + MOV r4,#0 + B Int_WriteS_Translated_UseR4 + +WriteS_Translated_UseR4 + + Push "r0-r7,LR" + +Int_WriteS_Translated_UseR4 + BIC r1,LR,#3 ; r1 -> Token. + BIC r1,r1,#2_111111 :SHL: 26 + MOV r0,#0 + LDR r0,[r0,#KernelMessagesBlock] + CMP r0,#0 ; If no messages file, try the global one. + ADRNE r0,KernelMessagesBlock+4 + MOV r2,#0 ; Use message in place. + MOV r3,#0 + MOV r5,#0 + MOV r6,#0 + MOV r7,#0 ; No arguments. + SWI XMessageTrans_Lookup + BVC %FT01 + + MOV R2,R1 ; MessageTrans not present or token not found. +00 + LDRB r0,[r2],#1 ; Skip to after ":" + CMP r0,#":" + BNE %BT00 + +; Now +; r1 -> terminator +; r2 -> message +; Print the message. + +01 + LDRB r0,[r2],#1 ; Print all characters of message + CMP r0,#" " + BLT %FT02 + CMP r0,#"%" + SWINE XOS_WriteC + BNE %BT01 + + LDRB r0,[r2],#1 ; Found a % + CMP r0,#" " + BLT %FT02 ; Trailing % sign! + CMP r0,#"0" + SWINE XOS_WriteI+"%" + SWINE XOS_WriteC + BNE %BT01 ; Just in case it isn't %0 + + CMP r4,#0 ; r4 = original parameter + BEQ %BT01 + +11 + LDRB R0,[R4],#1 + CMP R0,#" " + SWIGE XOS_WriteC + BGE %BT11 + B %BT01 + ; Now skip to end of token. +02 + LDR r1,[sp,#8*4] ; Get original token pointer + BIC r1,r1,#3 ; r1 -> Token. + BIC r1,r1,#2_111111 :SHL: 26 +03 + LDRB r0,[r1],#1 + CMP r0,#32 + BGE %BT03 ; Skip to control character. +04 + CMP r0,#0 ; Print all control characters to terminating 0. + SWINE XOS_WriteC + LDRNEB r0,[r1],#1 + BNE %BT04 + +; r1 now points at byte after end of token. + + ADD r1,r1,#3 ; Round up to next word. + BIC r1,r1,#3 + + LDR r2,[sp,#8*4] + MOV r3,#2_111111 :SHL:26 + ORR r3,r3,#2_11 + AND r2,r2,r3 ; Just the flags and mode bits. + ORR r1,r1,r2 + ORRVS r1,r1,#V_bit + STR r1,[sp,#8*4] ; Store back as return address on stack + + Pull "r0-r7,PC",,^ ;Return. + +;---------------------------------------------------------------------------------------- +; +;GSWriteS_Translated +;Entry: +; R14 -> Token. +;*NOTE* +; MUST BE TOKEN:DEFAULT +; +;Exit: +; Message printed +; Returns to word after end of token. +; +GSWriteS_Translated ROUT + Push "r0-r7,LR" + MOV r4,#0 + B Int_GSWriteS_Translated_UseR4 + +GSWriteS_Translated_UseR4 + + Push "r0-r7,LR" + +Int_GSWriteS_Translated_UseR4 + BIC r1,LR,#3 ; r1 -> Token. + BIC r1,r1,#2_111111 :SHL: 26 + MOV r0,#0 + LDR r0,[r0,#KernelMessagesBlock] + CMP r0,#0 ; If no messages file, try the global one. + ADRNE r0,KernelMessagesBlock+4 + LDR r2,=GeneralMOSBuffer + MOV r3,#256 + MOV r5,#0 + MOV r6,#0 + MOV r7,#0 ; No arguments. + SWI XMessageTrans_GSLookup + BVC %FT01 + + MOV R2,R1 ; MessageTrans not present or token not found. +00 + LDRB r0,[r2],#1 ; Skip to after ":" + CMP r0,#":" + BNE %BT00 + +; Now +; r1 -> terminator +; r2 -> message +; Print the message using OS_PrettyPrint. + +01 + LDR r0, =GeneralMOSBuffer + MOV r1, #0 + SWI XOS_PrettyPrint + ; Now skip to end of token. +02 + LDR r1,[sp,#8*4] ; Get original token pointer + BIC r1,r1,#3 ; r1 -> Token. + BIC r1,r1,#2_111111 :SHL: 26 +03 + LDRB r0,[r1],#1 + CMP r0,#0 + BNE %BT03 ; Skip to 0. + +; r1 now points at byte after end of token. + + ADD r1,r1,#3 ; Round up to next word. + BIC r1,r1,#3 + + LDR r2,[sp,#8*4] + MOV r3,#2_111111 :SHL:26 + ORR r3,r3,#2_11 + AND r2,r2,r3 ; Just the flags and mode bits. + ORR r1,r1,r2 + ORRVS r1,r1,#V_bit + STR r1,[sp,#8*4] ; Store back as return address on stack + + Pull "r0-r7,PC",,^ ;Return. + +;---------------------------------------------------------------------------------------- +;FindToken +; +;Entry: +; R0 -> Token. +;*NOTE* +; MUST BE TOKEN:DEFAULT +; +;Exit: +; r0 -> Message, or after the : if MessageTrans is dead. +; +; +FindToken ROUT + Push "r0-r7,LR" + + MOV r1,r0 + MOV r0,#0 + LDR r0,[r0,#KernelMessagesBlock] + CMP r0,#0 ; If no messages file, try the global one. + ADRNE r0,KernelMessagesBlock+4 + MOV r2,#0 + MOV r3,#0 + MOV r4,#0 + MOV r5,#0 + MOV r6,#0 + MOV r7,#0 ; No arguments. + SWI XMessageTrans_Lookup + BVC %FT01 + + MOV R2,R1 ; MessageTrans not present or token not found. +00 + LDRB r0,[r2],#1 ; Skip to after ":" + CMP r0,#":" + BNE %BT00 +01 + STR r2,[sp] + + Pull "r0-r7,PC",,^ +;---------------------------------------------------------------------------------------- +;Write0_Translated +; +;Entry: +; R0 -> Token. +;*NOTE* +; MUST BE TOKEN:DEFAULT +; +;Exit: +; Message printed, r0->Message. +; +Write0_Translated ROUT + Push "r0,r1,LR" + BL FindToken + MOV R1,R0 +01 + LDRB R0,[R1],#1 + CMP R0,#31 + SWIGT XOS_WriteC + STRVS r0,[SP] + Pull "r0,r1,PC",VS + BGT %BT01 + + Pull "r0,r1,PC",,^ + + END + + + + + diff --git a/s/NewIRQs b/s/NewIRQs new file mode 100644 index 0000000000000000000000000000000000000000..2ed883bec2215d1723b1feac7f0c9a2b424315e4 --- /dev/null +++ b/s/NewIRQs @@ -0,0 +1,1186 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + TTL => NewIRQs + +; ***************************************************************************** +; +; Main IRQ routine: +; Push workregs,lr +; IRQsema -> TOS +; stack -> IRQsema +; call IRQ1V +; IRQs off +; TOS ->IRQsema +; process callback, pulling workregs,pc at some point +; +; ***************************************************************************** + +Initial_IRQ_Code ROUT + SUB lr, lr, #4 + Push "r0-r3, r11, r12, lr" +; ** For Pete's sake remember to change the heap manager if you change the above +; ** register list!!!!!!! And the [sp_irq, #4*6] below + [ IRQSTK - 7*4 :AND: 15 <> 0 + ! 0,"IRQ STM/LDM making extra S cycle into N" + ] + + [ CPU_Type = "ARM600" + BIC pc, pc, #&FC000000 ; get back out of shadow ROM + NOP ; (this instruction skipped) + mrs AL, r0, SPSR_all ; r0 = saved PSR + AND r1, r0, #I32_bit + F32_bit ; r1 = caller I&F flags, in ARM6 place + ORR lr, lr, r1, LSL #IF32_26Shift ; put IF in place + AND r1, r0, #&F0000003 ; r1 = caller NZCV and mode bits + ORR lr, lr, r1 ; lr = 26 bit style return addr + PSR + STR lr, [sp_irq, #4*6] ; store back into stack + + BIC r0, r0, #&1F ; clear out foreground mode bits + ORR r0, r0, #I32_bit + IRQ26_mode ; force IRQ_26 mode and I_bit set + msr AL, CPSR_all, r0 + ] + + MOV r12, #0 + LDR r0, [r12, #IRQsema] + Push r0 + STR sp_irq, [r12, #IRQsema] + MOV lr, pc + LDR pc, [r12, #IRQ1V] + +; IRQ1V called with r0-r3,r11,r12 trashable. r12=0 + +; Stu has a theory that 1N cycle can be saved by the default IRQ1V pointing +; at a location containing a branch to our code; we then do something like +; LDR R0, [R12, #IRQ1V] +; CMP R0, #OurIRQ1V +; BNE somebodysonIRQ1V +; .... fall into default IRQ1V code + + MOV r11, #0 + Pull r0 + STR r0, [r11, #IRQsema] + + LDRB r11, [r11, #CallBack_Flag] + CMP r11, #0 + Pull "r0-r3, r11, r12, pc", EQ, ^ + + TST r11, #CBack_Postpone + LDREQ lr, [sp_irq, #4*6] + TSTEQ lr, #SVC_mode :OR: I_bit + Pull "r0-r3, r11, r12, pc", NE, ^ + +; Do a CallBack: asked for, not postponed, and we're returning into user mode. + + Pull "r0-r3, r11, r12" + TEQP pc, #SVC_mode + MOVNV r0, r0 + Push "r10-r12" + TEQP pc, #IRQ_mode + MOVNV r0, r0 + Pull "r12" ; lr really + TEQP pc, #SVC_mode + MOVNV r0, r0 + MOV lr, r12 + MOV r10, #0 + LDRB r11, [r10, #CallBack_Flag] + B Do_CallBack + + LTORG + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Default IRQ1V: despatch on interrupting device + +; Now copied to RAM, together with vector entries and device tables + +DefaultIRQ1Vcode ROUT + + [ IO_Type = "IOMD" + MOV r3, #IOC ; base for IOC and IOMD + LDRB r0, [r3, #IOMD_DMAREQ] + TEQ r0, #0 + ADRNE r1, IrqDMADevnos + LDREQB r0, [r3, #IOCIRQREQB] ; if not DMA then assume IRQB until we know otherwise + ADREQ r1, IrqReqBDevnos + + [ MorrisSupport +;>>>RCM Says should we use separate Morris specific code, cos Morris doesn't support +;>>>RCM all IOMD_DMAREQ bits and non Morris machines don't have IOMD_IRQRQD. +;>>>RCM Look at use of NoInterrupt. + TEQEQ r0, #0 + LDREQB r0, [r3, #IOMD_IRQRQD] + ADREQ r1, IrqReqDDevnos + ] + TEQEQ r0, #0 + LDREQB r0, [r3, #IOCIRQREQA] ; not DMA and not IRQB so assume IRQA + ADREQ r1, IrqReqADevnos + + LDRB r0, [r1, r0] ; pick up offset in device despatcher + ADD r1, pc, r0, LSL #2 ; so table contains DevNo * 3 + LDMIA r1, {r12, pc} + | + MOV r3, #IOC + LDRB r0, [r3, #IOCIRQREQB] + CMP r0, #0 + LDREQB r0, [r3, #IOCIRQREQA] + + ADREQ r1, IrqReqADevnos + ADRNE r1, IrqReqBDevnos + LDRB r0, [r1, r0] ; pick up offset in device despatcher + + ADD r1, pc, r0, LSL #2 ; so table contains DevNo * 3 + LDMIA r1, {r12, pc} + ] + +; ******* IRQ device handlers entered with r0-r3,r11,r12,r14 trashable ******* +; r3 -> IOC +; r12 = what they asked for +; r14 = return address to MOS IRQ exit sequence + + [ IO_Type = "IOMD" + [ MorrisSupport +NoInterrupt * 27 ; Morris has IOMD's extra interrupts plus 5 of its own + | +NoInterrupt * 22 ; IOMD has 6 more interrupts for DMA + ] + | +NoInterrupt * 16 ; internal devno; when ReqA = 0! + ] + +Devices + +; Register A devices +; pbusy handler + & 0 ; R12 value + & IRQ ; call address + & 0 ; link +; ringing handler + & 0 + & IRQ + & 0 +; printer acknowledge + [ DriversInKernel + & OsbyteVars + & PrinterIRQ + & 0 + | + & 0 + & IRQ + & 0 + ] +; vsync handler + & OsbyteVars + & VsyncIRQ + & 0 +; power on reset: this can't happen, but call IRQ2V if it does. + & 0 + & IRQ + & 0 +; timer0 + & OsbyteVars + & TickOne + & 0 +; timer1 + & 0 + & IRQ + & 0 +; FIQ downgrade + & 0 + & IRQ + & 0 + +; register B devices +; PFIQ downgrade + & PFIQasIRQ_Chain - (PodDesp_Link-PodDesp_R12Val) + & PFIQasIRQ_Despatch + & 0 +; sound + & 0 + & IRQ + & 0 +; serial + [ DriversInKernel + & OsbyteVars + & RS423IRQ + & 0 + | + & 0 + & IRQ + & 0 + ] +; winnie IRQ + & 0 + & IRQ + & 0 +; Disc changed + & 0 + & IRQ + & 0 +; podule IRQ + & PIRQ_Chain - (PodDesp_Link-PodDesp_R12Val) + & PIRQ_Despatch + & 0 +; serial TX (Keyboard serial transmit register empty) + & IOC + [ Keyboard_Type = "A1A500" + & IrqTx + | + & IRQ + ] + & 0 +; serial RX (Keyboard serial receive register full) + & IOC + [ Keyboard_Type = "A1A500" + & IrqRx + | + & IRQ + ] + & 0 + + [ IO_Type = "IOMD" +; IOMD DMA devices +; DMA channel 0 + & 0 + & IRQ + & 0 +; DMA channel 1 + & 0 + & IRQ + & 0 +; DMA channel 2 + & 0 + & IRQ + & 0 +; DMA channel 3 + & 0 + & IRQ + & 0 +; Sound DMA channel 0 + & 0 + & IRQ + & 0 +; Sound DMA channel 1 + & 0 + & IRQ + & 0 + ] + + [ MorrisSupport +; register D devices +; Mouse port Rx full + & IOC + & IRQ + & 0 +; Mouse port Tx empty + & IOC + & IRQ + & 0 +; AtoD (Joystick) + & 0 + & IRQ + & 0 +; Nevent1 + & 0 + & IRQ + & 0 +; Nevent2 + & 0 + & IRQ + & 0 + ] + +; Neither A or B is interrupting, which is impossible: just call IRQ2V anyway + & 0 + & IRQ + & 0 + + +; Following tables encode the priority of the devices within each register + + GBLA DTabC +DTabC SETA 1 + +; generic IRQA bits +IrqReqAPrio0 * por_bit +IrqReqADev0 * PowerOn_DevNo + +IrqReqAPrio2 * pbusy_bit +IrqReqADev2 * PrinterBusy_DevNo + +IrqReqAPrio4 * timer1_bit +IrqReqADev4 * Timer1_DevNo + +IrqReqAPrio5 * vsync_bit +IrqReqADev5 * VSync_DevNo + +IrqReqAPrio6 * timer0_bit +IrqReqADev6 * Timer0_DevNo + +IrqReqAPrio7 * force_bit +IrqReqADev7 * FIQDowngrade_DevNo + +; Machine specific IRQB bits + + [ IO_Type = "IOC-A1" :LOR: IO_Type = "IOC-A500" +IrqReqAPrio1 * ring_bit +IrqReqADev1 * Ringing_DevNo + +IrqReqAPrio3 * pack_bit +IrqReqADev3 * PrinterAck_DevNo + ] + + [ IO_Type = "IOEB" +IrqReqAPrio1 * IOEB_battery_low_bit +IrqReqADev1 * Ringing_DevNo + +IrqReqAPrio3 * IOEB_floppy_index_bit +IrqReqADev3 * PrinterAck_DevNo + ] + + [ IO_Type = "IOMD" +IrqReqAPrio1 * 1:SHL:1 ; not used +IrqReqADev1 * Ringing_DevNo + +IrqReqAPrio3 * IOMD_floppy_index_bit +IrqReqADev3 * PrinterAck_DevNo + ] + +IrqReqADevnos + = NoInterrupt*3 + WHILE DTabC <256 + [ (DTabC:AND:IrqReqAPrio7)<>0 + = IrqReqADev7*3 + | + [ (DTabC:AND:IrqReqAPrio6)<>0 + = IrqReqADev6*3 + | + [ (DTabC:AND:IrqReqAPrio5)<>0 + = IrqReqADev5*3 + | + [ (DTabC:AND:IrqReqAPrio4)<>0 + = IrqReqADev4*3 + | + [ (DTabC:AND:IrqReqAPrio3)<>0 + = IrqReqADev3*3 + | + [ (DTabC:AND:IrqReqAPrio2)<>0 + = IrqReqADev2*3 + | + [ (DTabC:AND:IrqReqAPrio1)<>0 + = IrqReqADev1*3 + | + [ (DTabC:AND:IrqReqAPrio0)<>0 + = IrqReqADev0*3 + ] + ] + ] + ] + ] + ] + ] + ] +DTabC SETA DTabC+1 + WEND + +; generic IRQB bits +IrqReqBPrio2 * podule_FIQ_as_IRQ_bit +IrqReqBDev2 * PFIQasIRQ_DevNo + +IrqReqBPrio3 * serial_Tx_bit +IrqReqBDev3 * SerialTx_DevNo + +IrqReqBPrio4 * serial_Rx_bit +IrqReqBDev4 * SerialRx_DevNo + +IrqReqBPrio5 * podule_IRQ_bit +IrqReqBDev5 * Podule_DevNo + +IrqReqBPrio7 * serial_bit +IrqReqBDev7 * Serial_DevNo + +; Machine specific IRQB bits + + [ IO_Type = "IOC-A500" +IrqReqBPrio0 * 0 +IrqReqBDev0 * NoInterrupt + +IrqReqBPrio1 * sound_IRQ_bit +IrqReqBDev1 * Sound_DevNo + +IrqReqBPrio6 * winnie_IRQ_bit :OR: winnie_DRQ_bit +IrqReqBDev6 * WinnieIRQ_DevNo + ] + + [ IO_Type = "IOC-A1" +IrqReqBPrio0 * winnie_DRQ_bit +IrqReqBDev0 * DiscChanged_DevNo + +IrqReqBPrio1 * sound_IRQ_bit +IrqReqBDev1 * Sound_DevNo + +IrqReqBPrio6 * winnie_IRQ_bit +IrqReqBDev6 * WinnieIRQ_DevNo + ] + + [ IO_Type = "IOEB" +IrqReqBPrio0 * IOEB_ide_IRQ_bit +IrqReqBDev0 * DiscChanged_DevNo + +IrqReqBPrio1 * IOEB_sound_IRQ_bit +IrqReqBDev1 * Sound_DevNo + +IrqReqBPrio6 * IOEB_floppy_IRQ_bit +IrqReqBDev6 * WinnieIRQ_DevNo + ] + + [ IO_Type = "IOMD" +IrqReqBPrio0 * IOMD_floppy_IRQ_bit +IrqReqBDev0 * DiscChanged_DevNo + +IrqReqBPrio1 * IOMD_HardDisc_IRQ_bit +IrqReqBDev1 * Sound_DevNo + +IrqReqBPrio6 * IOMD_Network_IRQ_bit +IrqReqBDev6 * WinnieIRQ_DevNo + ] + + + +DTabC SETA 1 + +IrqReqBDevnos + = NoInterrupt*3 + + WHILE DTabC <256 + [ (DTabC:AND:IrqReqBPrio7)<>0 + = IrqReqBDev7*3 + | + [ (DTabC:AND:IrqReqBPrio6)<>0 + = IrqReqBDev6*3 + | + [ (DTabC:AND:IrqReqBPrio5)<>0 + = IrqReqBDev5*3 + | + [ (DTabC:AND:IrqReqBPrio4)<>0 + = IrqReqBDev4*3 + | + [ (DTabC:AND:IrqReqBPrio3)<>0 + = IrqReqBDev3*3 + | + [ (DTabC:AND:IrqReqBPrio2)<>0 + = IrqReqBDev2*3 + | + [ (DTabC:AND:IrqReqBPrio1)<>0 + = IrqReqBDev1*3 + | + [ (DTabC:AND:IrqReqBPrio0)<>0 + = IrqReqBDev0*3 + ] + ] + ] + ] + ] + ] + ] + ] +DTabC SETA DTabC+1 + WEND + + + [ IO_Type = "IOMD" +; Prioritised IOMD DMA device numbers + +IrqDMAPrio0 * 1:SHL:5 +IrqDMADev0 * IOMD_DMASound1_DevNo + +IrqDMAPrio1 * 1:SHL:4 +IrqDMADev1 * IOMD_DMASound0_DevNo + +IrqDMAPrio2 * 1:SHL:3 +IrqDMADev2 * IOMD_DMAChannel3_DevNo + +IrqDMAPrio3 * 1:SHL:2 +IrqDMADev3 * IOMD_DMAChannel2_DevNo + +IrqDMAPrio4 * 1:SHL:1 +IrqDMADev4 * IOMD_DMAChannel1_DevNo + +IrqDMAPrio5 * 1:SHL:0 +IrqDMADev5 * IOMD_DMAChannel0_DevNo + + +DTabC SETA 1 + +IrqDMADevnos + = NoInterrupt*3 + +; Top 2 bits are always 0 so table need only be 64 bytes + WHILE DTabC <64 + [ (DTabC:AND:IrqDMAPrio5)<>0 + = IrqDMADev5*3 + | + [ (DTabC:AND:IrqDMAPrio4)<>0 + = IrqDMADev4*3 + | + [ (DTabC:AND:IrqDMAPrio3)<>0 + = IrqDMADev3*3 + | + [ (DTabC:AND:IrqDMAPrio2)<>0 + = IrqDMADev2*3 + | + [ (DTabC:AND:IrqDMAPrio1)<>0 + = IrqDMADev1*3 + | + [ (DTabC:AND:IrqDMAPrio0)<>0 + = IrqDMADev0*3 + ] + ] + ] + ] + ] + ] +DTabC SETA DTabC+1 + WEND + + ] + + + [ MorrisSupport +; Prioritised IRQD device numbers + +IrqReqDPrio0 * 1:SHL:4 +IrqReqDDev0 * IOMD_Event2_DevNo + +IrqReqDPrio1 * 1:SHL:3 +IrqReqDDev1 * IOMD_Event1_DevNo + +IrqReqDPrio2 * 1:SHL:2 +IrqReqDDev2 * IOMD_AtoD_DevNo + +IrqReqDPrio3 * 1:SHL:1 +IrqReqDDev3 * IOMD_MouseTxEmpty_DevNo + +IrqReqDPrio4 * 1:SHL:0 +IrqReqDDev4 * IOMD_MouseRxFull_DevNo + + +DTabC SETA 1 + +IrqReqDDevnos + = NoInterrupt*3 + +; Top 3 bits are always 0 so table need only be 32 bytes + WHILE DTabC <32 + [ (DTabC:AND:IrqReqDPrio4)<>0 + = IrqReqDDev4*3 + | + [ (DTabC:AND:IrqReqDPrio3)<>0 + = IrqReqDDev3*3 + | + [ (DTabC:AND:IrqReqDPrio2)<>0 + = IrqReqDDev2*3 + | + [ (DTabC:AND:IrqReqDPrio1)<>0 + = IrqReqDDev1*3 + | + [ (DTabC:AND:IrqReqDPrio0)<>0 + = IrqReqDDev0*3 + ] + ] + ] + ] + ] +DTabC SETA DTabC+1 + WEND + + ] + + +DefaultIRQ1Vcode_end + + ASSERT DefaultIRQ1Vcode_end - DefaultIRQ1Vcode <= DefIRQ1Vspace + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Specialist despatchers for podules + + ^ 0 +PodDesp_Address # 4 ; address of IRQ status byte +PodDesp_Mask # 4 ; for use on above +PodDesp_R12Val # 4 +PodDesp_CallAddr # 4 ; address to call if ?Address AND Mask <> 0 +PodDesp_Link # 4 ; next node +PodDesp_NodeSize # 0 + + [ True + +; In r12 = PFIQasIRQ_Chain - (PodDesp_Link-PodDesp_R12Val) +; or PIRQ_Chain - (PodDesp_Link-PodDesp_R12Val) from despatcher + +PFIQasIRQ_Despatch ROUT + +PIRQ_Despatch ; All the same thing now + + | + +PFIQasIRQ_Despatch ROUT + + LDR r12, =PFIQasIRQ_Chain - (PodDesp_Link-PodDesp_R12Val) + B %FT01 + +PIRQ_Despatch ; NOROUT + + LDR r12, =PIRQ_Chain - (PodDesp_Link-PodDesp_R12Val) + ] + + +01 LDR r12, [r12, #PodDesp_Link-PodDesp_R12Val] + LDMIA r12!, {r1, r2} ; address and mask + + [ Fix11 +; TMD 09-Jun-89: Don't corrupt r0 - it's needed by the default IRQ2 routine + LDRB r1, [r1] + ANDS r1, r1, r2 + | + LDRB r0, [r1] + ANDS r0, r0, r2 + ] + BEQ %BT01 + LDMIA r12, {r12, pc} + + +Default_PIRQHandler_Node +Default_PFIQasIRQHandler_Node + & .+4 ; address we know has non-zero value! + & -1 ; mask + & 0 ; handler r12 + & IRQ ; handler code + & 0 ; null link for naff release checking + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Claim of device vectors + +; r0 = Device number +; r1 = call address +; r2 = r12 value +; r0 = PFIQ|PIRQ devno -> r3 = interrupt location +; r4 = interrupt mask + +DeviceVector_Claim ROUT + + Push "r0-r3, lr" + +01 SWI XOS_ReleaseDeviceVector ; Release until bored + BVC %BT01 + + LDR r0, [sp] + CMP r0, #NoInterrupt + BGE DV_Fail_NaffDevNo + + CMP r0, #Podule_DevNo + CMPNE r0, #PFIQasIRQ_DevNo + BEQ PoduleChainClaim + + MOV r3, #12 + BL ClaimSysHeapNode + BVS DV_Exit + LDR r0, [sp] + ADD r0, r0, r0, LSL #1 ; *3 + LDR r1, =DefaultIRQ1V-DefaultIRQ1Vcode+Devices + ADD r1, r1, r0, LSL #2 + TEQP pc, #SVC_mode+I_bit ; IRQs off for update + LDMIA r1, {r0, r3, r10} + STMIA r2, {r0, r3, r10} ; copy current head into node + LDR r10, [sp, #4*2] ; r12 value + LDR r11, [sp, #4*1] ; call address + MOV r12, r2 + STMIA r1, {r10-r12} ; copy given info into head + + +DV_Exit STRVS r0, [sp] ; Common exit for both claim + release + Pull "r0-r3, lr" + B SLVK_TestV + + +DV_Fail_NaffDevNo + ADR r0, ErrorBlock_NaffDevNo + [ International + BL TranslateError + | + SETV + ] + B DV_Exit + + MakeErrorBlock NaffDevNo + + +PoduleChainClaim + MOV r3, #PodDesp_NodeSize + BL ClaimSysHeapNode + BVS DV_Exit + MOV r10, r2 + LDMFD sp, {r0-r3} + STR r1, [r10, #PodDesp_CallAddr] + STR r2, [r10, #PodDesp_R12Val] + STR r3, [r10, #PodDesp_Address] + STR r4, [r10, #PodDesp_Mask] + CMP r0, #Podule_DevNo + LDREQ r0, =PIRQ_Chain + LDRNE r0, =PFIQasIRQ_Chain + TEQP pc, #SVC_mode+I_bit ; IRQs off for update + LDR r1, [r0] + STR r1, [r10, #PodDesp_Link] + STR r10, [r0] + B DV_Exit + +; ............................................................................. +; Release of device vectors + +; r0 = Device number +; r1 = call address +; r2 = r12 value +; r0 = PFIQ|PIRQ devno -> r3 = interrupt location (LDRB always used) +; r4 = interrupt mask + +DeviceVector_Release ROUT + + Push "r0-r3, lr" ; Ensure same regset as above + CMP r0, #NoInterrupt + BGE DV_Fail_NaffDevNo + + TEQP pc, #SVC_mode + I_bit ; IRQs off while holding context + CMP r0, #Podule_DevNo + CMPNE r0, #PFIQasIRQ_DevNo + BEQ PoduleChainRelease + + ADD r0, r0, r0, LSL #1 ; *3 + LDR r12, =DefaultIRQ1V-DefaultIRQ1Vcode+Devices + ADD r12, r12, r0, LSL #2 ; address of node + MOV r11, #-1 ; "fudge" predecessor node + +01 LDMIA r12, {r3, r10} + CMP r3, r2 + CMPEQ r10, r1 + BEQ %FT02 ; found it + MOV r11, r12 + LDR r12, [r12, #8] ; get the link + CMP r12, #0 + BNE %BT01 + +11 ADR r0, ErrorBlock_BadDevVecRel + [ International + BL TranslateError + | + SETV + ] + B DV_Exit + + MakeErrorBlock BadDevVecRel + + +02 CMP r11, #-1 + BEQ %FT03 + MOV r2, r12 + LDR r12, [r2, #8] + STR r12, [r11, #8] ; node delinked + B %FT04 + +03 LDR r2, [r12, #8] ; freeable = nextnode + LDMIA r2, {r0, r1, r3} ; copy next node into head posn + STMIA r12, {r0, r1, r3} + +04 + BL FreeSysHeapNode ; free block + B DV_Exit + + +PoduleChainRelease + CMP r0, #Podule_DevNo + LDREQ r0, =PIRQ_Chain-PodDesp_Link + LDRNE r0, =PFIQasIRQ_Chain-PodDesp_Link + +10 LDR r12, [r0, #PodDesp_Link] + CMP r12, #0 + BEQ %BT11 + LDR r11, [r12, #PodDesp_Address] + CMP r11, r3 + LDREQ r11, [r12, #PodDesp_Mask] + CMPEQ r11, r4 + LDREQ r11, [r12, #PodDesp_CallAddr] + CMPEQ r11, r1 + LDREQ r11, [r12, #PodDesp_R12Val] + CMPEQ r11, r2 + MOVNE r0, r12 + BNE %BT10 + + LDR r11, [r12, #PodDesp_Link] + STR r11, [r0, #PodDesp_Link] + MOV r2, r12 + B %BT04 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Default device owner for IRQ not recognised by system: pass to IRQ2V + +IRQ ROUT + + Push "r10, lr" + [ False + ASSERT VIDC_Type <> "VIDC20" + MOV r14, #11 + MUL r14, r0, r14 + MOV r14, r14, LSR #5 + ADR r10, irq_vtable + LDR r14, [r10, r14, LSL #2] + MOV r10, #VIDC + STR r14, [r10] + ] + MOV r10, #IrqV + BL CallVector + + Pull "r10, pc" ; return: someone will always claim it. + + [ False +irq_vtable + DCD &40000000 + &444 + DCD &40000000 + &008 + DCD &40000000 + &080 + DCD &40000000 + &088 + + DCD &40000000 + &800 + DCD &40000000 + &808 + DCD &40000000 + &880 + DCD &40000000 + &FA8 + + DCD &40000000 + &8AF + DCD &40000000 + &00F + DCD &40000000 + &0F0 + DCD &40000000 + &0FF + + DCD &40000000 + &F00 + DCD &40000000 + &F0F + DCD &40000000 + &FF0 + DCD &40000000 + &FFF + ] + +; ***************************************************************************** +; Default IRQ2V: +; r0 must still have devno*3 in it +; r12 is 0 (from vector) + +; Clear mask, clear IRQ as appropriate/possible + +; NB. a cheap way of dividing by ~3 is *11,/32: accurate for 0..31 result ... + +NOIRQ ROUT + + [ False + ASSERT VIDC_Type <> "VIDC20" + MOV r14, #11 + MUL r14, r0, r14 + MOV r14, r14, LSR #5 + ADR r10, irq_vtable + LDR r14, [r10, r14, LSL #2] + MOV r10, #VIDC + STR r14, [r10] + ] +01 SUBS r0, r0, #3 + ADDGE r12, r12, #1 + BGT %BT01 ; r12 := r0 DIV 3 + + [ MorrisSupport +; RCM 31-Jan-95 fix MED-04355, need to cope with interrupts from new Morris register + CMP R12, #IOMD_MouseRxFull_DevNo + SUBHS R12, R12, #IOMD_MouseRxFull_DevNo ;reduce to bit number 0..7 + MOVHS R0, #IOMD_IRQMSKD ; in IRQ D interrupt register + BHS %FT03 + ] + +; ** TMD 14-Feb-94 - insert code here to fix MED-02859 +; ** Old code did not cope with the DMA case here + + [ IO_Type = "IOMD" + CMP r12, #16 ; check if a DMA device + BCC %FT02 ; it's not, so skip + + SUB r12, r12, #16 ; convert to a bit number in mask + MOV r1, #1 + MOV r1, r1, LSL r12 ; convert to bit mask + LDR r0, =IOC+IOMD_DMAMSK ; point at mask register + LDRB r12, [r0] ; load mask + BIC r12, r12, r1 ; knock out bit + STRB r12, [r0] ; store back + Pull pc,,^ ; and exit, claiming vector + +02 + ] + +; ** end of insertion + + CMP r12, #8 + MOVGE r0, #IOCIRQMSKB + SUBGE r12, r12, #8 + MOVLT r0, #IOCIRQMSKA + [ MorrisSupport +03 + ] + ADD r0, r0, #IOC + MOV r1, #1 + MOV r1, r1, LSL r12 ; bit to clear + + [ :LNOT: NewClockChip ; fudge winnieDRQ on A500 + CMP r1, #winnie_IRQ_bit + CMPEQ r0, #IOCIRQMSKB + ORREQ r1, r1, #winnie_DRQ_bit ; turn both off. + ] + MOV lr, pc + TEQP pc, #IRQ_mode+I_bit+F_bit + LDRB r12, [r0] ; FIQs off for updating IOCIRQMSKA + BIC r12, r12, r1 + STRB r12, [r0] ; relevant IRQ disabled + TEQP lr, #0 ; absolute minimum FIQ disable period + + STRB r1, [r0, #IOCIRQCLRA-IOCIRQMSKA] ; Clear IRQ + Pull pc,,^ ; claim vector + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; The following bits have been appropriated from source.pmf.oseven to make +; sure Tim's old code doesn't overwrite us when he gets back! + +; SWI OS_GenerateEvent: call event vector if enabled + +GenEvent ROUT + + Push lr + TEQP pc, #SVC_mode+I_bit ; Disable IRQs. MUST call these ones + BL OSEVEN ; in SVC mode as people expect it + Pull lr + B SLVK + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Subroutine call version + +; In r0 = event type +; r1,r2 parameters + +; Out C=0 => event was enabled, or was >= 32 anyway +; C=1 => event was disabled, so vector not called + +OSEVEN ROUT + + Push lr + + CMP r0, #31 ; Events >= 32 are ALWAYS raised. SKS + ; flags are HI if so, ie. NE + LDRLSB r14, [r0, #OsbyteVars + :INDEX: EventSemaphores] + ; get semaphore for this event 0..31 + CMPLS r14, #0 ; non-zero => enabled + Pull pc, EQ ; if disabled, exit with C=1 + + Push "r0-r3, r10-r12" ; r3 excessive ??? + MOV r10, #EventV ; call event vector + BL CallVector + CLC ; indicate event enabled + Pull "r0-r3, r10-r12, pc" + +; ...................... default owner of EventV .............................. +; Call Event handler + +; In r12 = EvtHan_ws + +DefEvent ROUT + + MOV lr, pc ; link with all the bits + LDMIA r12, {r12, pc} ; call EventHandler, returns to ... + + TEQ r12, #1 + Pull pc,NE,^ + + LDRB r14, [r12, #CallBack_Flag-1] ; IRQs are still disabled + ORR r14, r14, #CBack_OldStyle + STRB r14, [r12, #CallBack_Flag-1] + Pull pc,,^ ; claim EventV + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Process timer zero IRQ device (100Hz clock) +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TickOne ROUT + + Push r14 + + MOV R0, #timer0_bit + STRB R0, [R3, #IOCIRQCLRA] ; clear timer 0 interrupt + + LDRB R0, CentiCounter ; Counter for VDU CTRL timing + SUBS R0, R0, #1 + STRCSB R0, CentiCounter ; decrement if not zero + + LDR R0, IntervalTimer +0 + ADDS R0, R0, #1 ; Increment the low 4 bytes + STR R0, IntervalTimer +0 + + LDREQB R0, IntervalTimer +4 + ADDEQ R0, R0, #1 ; and carry into 5th byte if necessary + STREQB R0, IntervalTimer +4 + + Push "R4,R12" ; R0-R3 already pushed + + TEQEQ R0, #&100 ; has interval timer crossed zero ? + MOVEQ R0, #Event_IntervalTimer ; Event ITCZ + BLEQ OSEVEN + + BL CentiSecondTick ; Notify keyboard of a centisecond + + Pull "R4,R12" + + [ :LNOT: NewClockChip + LDRB R1, SecondsDirty + TEQ R1, #0 ; if seconds dirty + BNE %FT10 ; we haven't synced yet + ] + + LDR R0, RealTime +0 ; Increment 5-byte real time + ADDS R0, R0, #1 + STR R0, RealTime +0 + LDRCSB R0, RealTime +4 + ADDCS R0, R0, #1 ; Won't wrap until 2248 and then it + STRCSB R0, RealTime +4 ; all falls over anyway + + [ :LNOT: NewClockChip + LDRB R0, CentiTime + ADD R0, R0, #1 + TEQ R0, #100 + MOVEQ R0, #0 + STRB R0, CentiTime + + LDRB R0, SecondsTime + ADDEQ R0, R0, #1 ; increment only if wrap from centisecs + TEQEQ R0, #60 + MOVEQ R0, #0 + STRB R0, SecondsTime + + B NoTickThisTime ; don't do dirty code +10 + LDRB R0, MinTick + MOV R1, #IOC + LDRB R3, [R1, #IOCControl] ; IOC control register + AND R3, R3, #rtc_minutes_bit + TEQ R3, R0 ; Look for transition + BEQ NoTickThisTime + TEQ R3, #rtc_minutes_bit ; from zero to one = minute!!! + STRB R3, MinTick ; One to zero = 30 seconds + MOV R0, #0 + STRB R0, SecondsDirty ; Mark the seconds as OK now ! + STRB R0, CentiTime ; When the minutes tick, ZERO the centiseconds! + MOVEQ R0, #30 + STRB R0, SecondsTime ; And set the seconds to 0 or 30 ! + + LDR R0, =ticksperminute ; get offset for 1 minute (60 secs) + MOVEQ R0, R0, LSR #1 ; halve it if 30 second tick + + LDR R1, RealTime +0 + ADDS R1, R1, R0 + STR R1, RealTime +0 + LDRCSB R1, RealTime +4 + ADDCS R1, R1, #1 + STRCSB R1, RealTime +4 + +NoTickThisTime + ] + + LDRB R0, TimerState ; get switch state + TEQ R0, #5 ; toggles between 5 and 10 + + LDREQ R1, TimerAlpha +0 ; either load from one + LDREQB R2, TimerAlpha +4 + + LDRNE R1, TimerBeta +0 ; or the other + LDRNEB R2, TimerBeta +4 + + ADREQ R3, TimerBeta +0 ; and point to t'other + ADRNE R3, TimerAlpha +0 + + ADDS R1, R1, #1 ; increment + ADC R2, R2, #0 ; with carry + + STR R1, [R3] ; and store back + STRB R2, [R3, #4] + + EOR R0, R0, #&0F ; 5 <-> 10 + STRB R0, TimerState + + Push R10 + + [ TickIrqReenter + MOV R10, #TickerV ; call 100Hz vector + BL CallVector ; IRQ's still disabled + + BL ProcessTickEventChain ; Re-enables IRQs + | + BL ProcessTickEventChain + + MOV R10, #TickerV ; call 100Hz vector + BL CallVector + ] + Pull "R10,PC" + +; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Process VSync IRQ device +; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +VsyncIRQ ROUT + + Push r14 + + MOV R0, #vsync_bit + STRB R0, [R3, #IOCIRQCLRA] ; Clear the vsync interrupt + + LDRB R0, CFStime ; decrement 'CFS' timer ! + SUB R0, R0, #1 + STRB R0, CFStime + + VDWS WsPtr ; Do our stuff before issuing VSYNC event + BL VsyncCall + BYTEWS WsPtr + + MOV R0, #Event_VSync ; VSYNC event number + BL OSEVEN + + LDRB R1, FlashCount + SUBS R1, R1, #1 + Pull PC, CC ; was zero, so frozen + STRNEB R1, FlashCount ; else if now non-zero, store it back + Pull PC, NE ; not time to flash yet + + LDRB R1, FlashState ; Get the state and + EORS R1, R1, #1 ; flip to the other one (setting flags) + STRB R1, FlashState + + LDREQB R2, SpacPeriod ; get appropriate new period + LDRNEB R2, MarkPeriod + STRB R2, FlashCount ; and put into counter + + VDWS WsPtr + Push R4 + BEQ dothesecondflash + +dothefirstflash + BL DoFirstFlash + Pull "R4, PC" + +dothesecondflash + BL DoSecondFlash + Pull "R4, PC" + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + END diff --git a/s/NewReset b/s/NewReset new file mode 100644 index 0000000000000000000000000000000000000000..cb1538db82f2b94542e8ad7d5ef00f656d0dd6f7 --- /dev/null +++ b/s/NewReset @@ -0,0 +1,2189 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + SUBT => NewReset + +DuffEntry * 31*1024*1024+32*1024 ; Never any memory at this address + +SoftReset * 0 ; Reset types +PowerOnReset * 1 +ControlReset * 2 + +; CMOS RAM resetting stuff: +CMOSLimit * &F0 + +; Keyboard flags + ^ 1 +CTRL_Down_Flag # 1 +SHIFT_Down_Flag # 1 +KB_There_Flag # 1 + +R_Down_Flag # 1 ; note that these 4 form one word!! +T_Down_Flag # 1 +Del_Down_Flag # 1 +Copy_Down_Flag # 1 + +KeyDataPtr # 4 + [ MorrisSupport +Port2Present # 4 + ] + + [ MEMM_Type = "ARM600" + +; On ARM600, InitKbdWs is in zero page - check it's big enough + + ASSERT @ <= ?InitKbdWs + | + +; Else use PhysRam start + +InitKbdWs * PhysRam + ] + + [ MEMM_Type <> "ARM600" +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; routine to set up a 32K chunk (for fixed areas) +; Enter with R8 = PageSize, R2 = physram offset, R3 logaddr +; R8 preserved on exit + +; This routine is not needed on ARM600, as MemSize sets up the L2PT for the static pages + +SlapIn32K + MOV R12, lr + ADRL R1, PageShifts-1 + LDRB R1, [R1, R8, LSR #12] + MOV R2, R2, LSR R1 ; DivRem R0, R2, R8, R1 + ; R2 := cam entry no + ADD R5, R3, #32*1024 +SlapInNext + BL BangCam + ADD R2, R2, #1 + ADD R3, R3, R8 + CMP R3, R5 + BNE SlapInNext + MOV PC, R12 + ] + + +; AddCamEntries +; +; in: r0 -> appropriate part of CAM map +; r1 = ap (+ CB bits in new world) +; r2 = log address +; r7 = amount of cam map to do +; r8 = PageSize +; +; out: r0, r3-r12 preserved +; r1 corrupted +; r2 updated by relevant amount + +AddCamEntries ROUT + [ ExpandedCamMap + Push "r0, lr" + MOV lr, r1 ; access privs (PPL) + MOV r1, r7 +01 + STMIA r0!, {r2, lr} ; store logaddr, PPL + ADD r2, r2, r8 ; increment address by 1 page + SUBS r1, r1, #8 ; decrement count of how much to do + BNE %BT01 + Pull "r0, pc" + | + MOV R1, #0 + CMP r2, #CursorChunkAddress + ORREQ r2, r2, #&10000000 ; appropriate PPL +01 + STR R2, [R0, R1] + ADD R1, R1, #4 + ADD R2, R2, R8 + CMP R1, R7 + BNE %BT01 + MOVS pc, lr + ] + +; GetConfiguredSize - convert CMOS address into amount of memory +; in: r0 = CMOS address +; out: r0 corrupted +; r2 = amount in bytes + +; NB this routine doesn't do screen size mangling (yet!) + +GetConfiguredSize ENTRY "r1" + MOV r1, #0 + LDR r1, [r1, #Page_Size] + ADRL lr, PageShifts-1 + LDRB r1, [lr, r1, LSR #12] ; r1 = log2 pagesize + MOV r2, #127 ; mask of value + + TEQ r0, #FontCMOS ; if fontsize + MOVEQ r1, #12 ; then in units of 4K, not pagesize + MOVEQ r2, #255 ; and use full byte + + BL Read ; read CMOS ram + AND r2, r0, r2 ; value anded with mask + MOV r2, r2, LSL r1 ; and shifted up accordingly + EXIT + +FudgeConfigureRMA + Push lr + B ConfigureRMA + +ReadCMOSAndConfigure ROUT +; R0 = index into CMOS RAM of byte with size in +; R1 = place to save amount moved +; R2 = CAM entry number to start at: updated +; R3 = LogRam Address to move memory to +; r11 PPL +; Check for memory left, move as much as poss + Push lr + BL Read ; CMOS byte -> R0 + + [ :LNOT: NewStyle_FontArea + CMP r3, #FontCacheAddress + MOVEQ r0, r0, LSL #12 ; *4K + BEQ NotScreen + ] + + AND R0, R0, #127 ; mask to same bitfield as status +ConfigureRMA + MOV R10, #0 + LDR R10, [R10, #Page_Size] + MUL R0, R10, R0 ; get size in bytes + CMP R3, #ScreenEndAdr ; screen? + BNE NotScreen + +; quick pokery for sensible screensize + + BL MassageScreenSize + SUB R3, R3, R0 ; step back. +NotScreen + MOV R5, #0 ; amount moved + CMP R0, #0 + BEQ NoMoreMemory + + [ GetPagesFromFreePool + +; r0 = amount of memory to move +; r1 = address to store size in +; (r2 = page number to start at, ignored in our method) +; r3 = address of where to put memory +; r10 = page size +; r11 = ap + CB + + MOV r6, r11 ; r6 = ap + CB + MOV r4, #FreePoolDANode + LDR r7, [r4, #DANode_Base] + LDR r8, [r4, #DANode_Size] + ADD r7, r7, r8 ; r7 -> end of free pool +1 +10 + CMP r8, r10 ; if no free memory left + BCC %FT20 ; then tidy up + SUB r7, r7, r10 ; move free pool pointer backwards + Push "r0, r1" + MOV r0, r7 + MOV r1, r3 + BL MovePageAtR0ToR1WithAccessR6 + Pull "r0, r1" + ADD r3, r3, r10 ; advance "to" pointer + SUB r8, r8, r10 ; one less page of free memory + ADD r5, r5, r10 ; one more page done + SUBS r0, r0, r10 + BNE %BT10 +20 + STR r8, [r4, #DANode_Size] + | + LDR R8, [R5, #RAMLIMIT] + +; now set R6 = first entry not to use +; R7 = end of gap " " " +; R8 = last entry we can use + + [ MEMM_Type = "ARM600" + MOV r7, #0 + LDR r6, [r7, #VideoSize] ; find out how many pages in video area + MOV r6, r6, LSR #12 ; = page number of start of skipped bit + ASSERT SoftCamMapSize = L2PTSize +4 + MOV r7, #L2PTSize + LDMIA r7, {r7, lr} ; r7 = L2PTSize, lr = SoftCamMapSize + ADD r7, r7, lr ; add sizes together + ADD r7, r7, #StaticPagesSize + UndStackSize ; + number of bytes used for other static bits + ADD r7, r6, r7, LSR #12 ; r7 = page number after static bit + MOV r8, r8, LSR #12 ; make r8 into highest page number+1 + | + CMP R8, #512*1024 + MOVEQ R6, #(512-96)*1024 + MOVEQ R7, #512*1024 + MOVNE R6, #(512-32)*1024 + [ MEMM_Type = "MEMC2" + MOVNE R7, #(512+96)*1024 ; if MEMC2, skip L2PT as well + | + MOVNE R7, #(512+64)*1024 + ] + Push "R2" + + ADRL R2, PageShifts-1 + LDRB R2, [R2, R10, LSR #12] + MOV R6, R6, LSR R2 ; DivRem R6, R6, R10, R2 + MOV R7, R7, LSR R2 + MOV R8, R8, LSR R2 + + Pull "R2" + ] + +CAMZapLoop + CMP R2, R6 ; if at gap, skip + MOVEQ R2, R7 + CMP R2, R8 ; if no more memory, give in + BEQ NoMoreMemory + ADD R5, R5, R10 + Push "R0, R1, R6" + BL BangCamUpdate + Pull "R0, R1, R6" + ADD R2, R2, #1 + ADD R3, R3, R10 + SUBS R0, R0, R10 + BGT CAMZapLoop + ] +NoMoreMemory + STR R5, [R1] + Pull "PC" + +; MassageScreenSize - called from ReadCMOSAndConfigure (above) and also from +; ReadSysInfo + +MassageScreenSize ROUT + CMP r0, #0 + BNE CmosScreenWillDo + LDR r0, [r0, #RAMLIMIT] + CMP r0, #512*1024 + MOVEQ r0, #80*1024 + MOVNE r0, #160*1024 +CmosScreenWillDo + CMP r0, #20*1024 ; ensure mode 0 gettable + ADDCC r0, r0, r10 ; if not, then add another page + BCC CmosScreenWillDo + CMP r0, #ScreenMaxSize + MOVHI r0, #ScreenMaxSize + MOV pc, lr + + LTORG + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Data tables: VIDC := mode 0, all palette black + +VIDCTAB + [ VIDC_Type = "VIDC20" + +; Program Control Register first, to clear power-down bit + + & &E0000400 ; CR: FIFO load 16 words, 1 bpp, ck/1, vclk + +; Don't bother programming all 256 palette entries, we'll be here all night +; Since we're setting up a 1 bit-per-pixel mode, just do colours 0 and 1 + + & &10000000 ; Palette address register = 0 + & &00000000 ; Colour 0 = black + & &00000000 ; Colour 1 = black + & &40000000 ; Border colour = black + & &50000000 ; Pointer colour 1 = black + & &60000000 ; Pointer colour 2 = black + & &70000000 ; Pointer colour 3 = black + +; Get a stable display up so we get stable signals + + & &800003F8 ; HCR = 76 + 88 + 96 + 640 + 96 + 28 + & &81000044 ; HSWR = 76 + & &82000098 ; HBSR = 76 + 88 + & &830000F2 ; HDSR = 76 + 88 + 96 + & &84000372 ; HDER = 76 + 88 + 96 + 640 + & &850003D8 ; HBER = 76 + 88 + 96 + 640 + 96 + & &860000F3 ; HCSR = HDSR + + & &90000137 ; VCR = 3 + 19 + 16 + 256 + 16 + 2 + & &91000002 ; VSWR = 3 + & &92000015 ; VBSR = 3 + 19 + & &93000025 ; VDSR = 3 + 19 + 16 + [ MEMC_Type = "IOMD" + [ Simulator + & &94000025 ; No displayed lines, so we don't get video FIFO u/flow when simulating + | + & &94000125 ; VDER = 3 + 19 + 16 + 256 + ] + | + & &94000125 ; VDER = 3 + 19 + 16 + 256 + ] + & &95000135 ; VBER = 3 + 19 + 16 + 256 + 16 + & &96000025 ; VCSR = VDSR + & &97000025 ; VCER = VDSR + + & &B1000001 ; SCR: sound disabled (+use 24MHz clock) + + & &C00F1003 ; EREG = comp sync, DACs on, ereg output ext lut + & &D0000305 ; FSYNREG, clk = (3+1)/(5+1) * 24MHz = 16MHz + & &F0013000 ; DCR: bus D[31:0], Hdisc ;RCM 29/9/94: changed from &F0012000 at PSwindells request + & &FFFFFFFF ; That's the lot + | + & &00000000 + & &04000000 + & &08000000 + & &0C000000 + & &10000000 + & &14000000 + & &18000000 + & &1C000000 + & &20000000 + & &24000000 + & &28000000 + & &2C000000 + & &30000000 + & &34000000 + & &38000000 + & &3C000000 + & &40000000 + & &44000000 ; Cursor -> black + & &48000000 + & &4C000000 ; Palette programmed (avoid messy screen on reset) + + & &807FC000 ; HCR Get a stable display up so we get stable signals + & &8408C000 ; HSWR + & &881B0000 ; HBSR + & &94770000 ; HBER + & &A04E0000 ; VCR + & &A4024000 ; VSWR + & &A8050000 ; VBSR + & &B44E0000 ; VBER + & &C0000100 ; SFR NB. TEST BIT !!! - also DFlynn requested value + & &E00000B2 ; CR Set 640*256, 1 bit per pixel, rate of 12MHz + ; change bottom byte to 22 for Linear Microvitecs (CS) + ; B2 for Monochrome/Philips (SS) + & &8C208000 ; HDSR + & &90708000 ; HDER + & &98258000 ; HCSR + & &9C400000 ; HIR + & &AC098000 ; VDSR + & &B0498000 ; VDER + & &B8098000 ; VCSR + & &BC498000 ; VCER +; don't mess with the stereo image registers: sound code will set them. + & &FFFFFFFF ; That's the lot + ] + + + [ MEMM_Type <> "ARM600" + GBLL ARM3_Support + ] + + [ :DEF:ARM3_Support +ARM3 CP 15 + +CR0 CN 0 +CR_ID CN 0 +CR_Flush CN 1 +CR_Control CN 2 +CR_Cacheable CN 3 +CR_Updateable CN 4 +CR_Disruptive CN 5 + +UndefVec * &00000004 + +; Default cacheable areas +; +; ROM Cacheable (&03400000..&03FFFFFF) +; I/O Not cacheable (&03000000..&033FFFFF) +; Phys RAM Not cacheable (&02000000..&02FFFFFF) +; Log RAM (screen) Not cacheable (&01E00000..&01FFFFFF) +; Log RAM (RAM Disc) Not cacheable (&01000000..&013FFFFF) +; (No point in caching RAM Disc) +; Log RAM (non-screen) Cacheable (&00000000..&01DFFFFF) +Cacheable_Default DCD 2_11111100000000000111110011111111 + +; Default updateable areas +; +; ROM/CAM Not updateable (&03800000..&03FFFFFF) +; ROM/DAG Not updateable (&03400000..&037FFFFF) +; I/O Not updateable (&03000000..&033FFFFF) +; Phys RAM Not updateable (&02000000..&02FFFFFF) +; Log RAM (screen) Not updateable (&01E00000..&01FFFFFF) +; Log RAM Updateable (&00000000..&01DFFFFF) +Updateable_Default DCD 2_00000000000000000111111111111111 + +; Default disruptive areas +; +; CAM Disruptive (&03800000..&03FFFFFF) +; DAG Not disruptive (&03400000..&037FFFFF) +; I/O Not disruptive (&03000000..&033FFFFF) +; Phys RAM Not disruptive (&02000000..&02FFFFFF) +; Log RAM Not disruptive (&00000000..&01FFFFFF) +Disruptive_Default * 2_11110000000000000000000000000000 + +UndefRet + MOVS pc, lr + ] + +VIDCPhys * &03400000 ; used to address VIDC when MMU is off + +; Entered here after RESET (or BREAK) + +; This code must be capable of being executed at a non-ROM address and with the MMU off, +; and running in 32-bit mode up until the call to MemSize. + +CONT_Break + MOV r1, #1 ; parameter passed to InitMEMC, to indicate Break not Reset + B Continue + +CONT ROUT + MOV r1, #0 ; parameter passed to InitMEMC, to indicate Reset not Break +Continue + +; First bang MEMC to ensure safety + + BL InitMEMC ; initialise MEMC CR, and turn off MMU if it's on + +; VInit etc set on ze mode change: no DMA going yet so don't set owt. + + MOV R1, #VIDCPhys ; Must ALWAYS initialise VIDC on reset or else + ADR R2, VIDCTAB ; we may get vsync interrupts that stiff us +10 LDR R0, [R2], #4 ; permanently as VIDC is in an undefined state + CMP R0, #-1 ; so have mode 0 with all black palette + STRNE R0, [R1] + BNE %BT10 + +; Now bang IOC (disable all but keyboard interrupts) + + MOV R1, #IOC + MOV R0, #&FF ; all inputs + STRB R0, [R1, #IOCControl] ; in case called by Tim + + MOV R0, #0 + STRB R0, [R1, #IOCIRQMSKA] ; kein interrupts + STRB R0, [R1, #IOCFIQMSK] ; disable FIQs + [ IO_Type = "IOMD" + STRB R0, [R1, #IOMD_DMAMSK] ; disable DMA interrupts, too + ] + + [ Keyboard_Type = "PC" :LAND: IO_Type <> "IOMD" + MOV R0, #podule_IRQ_bit ; used for PC keyboard h/w on a podule + | + MOV R0, #KARTRxBit ; used for Archi keyboard or IOMD PC keyboard + ] + STRB R0, [R1, #IOCIRQMSKB] ; allow communication with kbd, when I_bit gets cleared + +; now bits to allow CMOS read/write : need timer + + LDR R0, =20000-1 ; R0 = Timer delay (units of 0.5 microsecond) + ; 20000*0.5E-6 = 0.01 Seconds (100Hz ticker) + ; TMD 21-May-93: "-1" correction applied + + STRB R0, [R1, #Timer0LL] ; Set up the delay + MOV R0, R0, LSR #8 + STRB R0, [R1, #Timer0LH] + STRB R0, [R1, #Timer0GO] ; and start the ticks + + MOV R0, #timer0_bit + STRB R0, [R1, #IOCIRQCLRA] ; Clear pending t0 interrupt j.i.c. + +; now size memory + + BL MemSize ; out: r0 = page size, r1 = memory size, r2 = MEMC CR value, r3-r14 corrupt + + MOV R8, R0 ; R8 = page size in bytes + MOV R13, R1 ; R13 is now the RAM size + MOV R9, R2 ; need this to set soft copy right + + BL TimeCPU ; r7 := CPU speed in kHz/MEMC1a flag + +; first ensure nothing dangerous in MEMC + + [ MEMM_Type <> "ARM600" ; all this stuff is done in MemSize + [ {TRUE} ; new code which allows for MEMC2's small pages + ADRL r2, PageShifts-1 + LDRB r2, [r2, r8, LSR #12] ; get log2(pagesize) + MOV R2, R13, LSR R2 ; number of pages=total memory / pagesize + CMP R2, #128 ; but if fewer than 128 (eg 64 on A305) + MOVCC R2, #128 ; then use 128 (all MEMC1's pages need initialising, + ; even if half of them are not in use) + | + CMP R13, #8*1024*1024 ; if >= 8MBytes, + MOVCS R2, R13, LSR #15 ; then there are R13/32K pages + MOVCC R2, #128 ; else there are 128 pages + ] + SUB R2, R2, #1 ; maximum page number + + LDR R3, =DuffEntry ; a non-existant piece of memory + MOV R11, #AP_Duff ; go away, users +EmptyCamEntries + BL BangCam ; ensure not mapped to anything + SUBS R2, R2, #1 ; dangerous + BPL EmptyCamEntries + +; Put in position all fixed areas of memory +; 32K for cursor etc : CAM entries for 512-32 to 512K in PhysRam + +; SlapIn32K needs R8 = pagesize +; This is now already set up, so no need to compute it from +; MEMC CR (which would be wrong on ARM600 anyway) + + MOV R11, #1 ; user write protected + MOV R3, #CursorChunkAddress + MOV R2, #(512-32)*1024 + BL SlapIn32K + + MOV R3, #SysHeapChunkAddress ; 32K forced in system heap area +; use phys 512+32 to 512+64K if R13<>512K, 512-96 to 512-64K if R13=512K + CMP R13, #512*1024 + MOVEQ R2, #(512-96)*1024 + MOVNE R2, #(512+32)*1024 + + MOV r11, #0 + BL SlapIn32K + + MOV R3, #0 ; 32K system work area + +; use phys 512 to 512+32K if R13<>512K, 512-64 to 512-32K if R13=512K + + CMP R13, #512*1024 + MOVEQ R2, #(512-64)*1024 + MOVNE R2, #512*1024 + + BL SlapIn32K + ] + + [ :DEF:ARM3_Support + MOV r0, #UndefVec + LDR r1, [r0] + LDR r2, UndefRet + MOV r5, #0 + STR r2, [r0] + MRC ARM3, 0, r5, CR_ID, CR0 + STR r1, [r0] + AND r5, r5, #&ff00 + TEQ r5, #&0300 + BNE noarm3 + LDR r0, Cacheable_Default + LDR r1, Updateable_Default + MOV r2, #Disruptive_Default + MCR ARM3, 0, r0, CR_Cacheable, CR0 + MCR ARM3, 0, r1, CR_Updateable, CR0 + MCR ARM3, 0, r2, CR_Disruptive, CR0 + MRC ARM3, 0, r3, CR_Cacheable, CR0 + MRC ARM3, 0, r4, CR_Updateable, CR0 + MRC ARM3, 0, r5, CR_Disruptive, CR0 + TEQ r0, r3 + TEQEQ r1, r4 + TEQEQ r2, r5 + BNE noarm3 + MOV r0, #3 + MCR ARM3, 0, r0, CR_Control, CR0 +noarm3 + ] + +; the fixed areas give us : IRQ stack (in cursor), SVC stack (in sysheap base) +; and bottom block makes most sense done here + +; now keyboard initialisation: initialise baud rate, send dummy, read dummy + + MOV R0, #InitKbdWs + MOV R1, #0 + STRB R1, [R0, #CTRL_Down_Flag] ; clear CTRL down flag, R down flag + STRB R1, [R0, #SHIFT_Down_Flag] + STRB R1, [R0, #KB_There_Flag] + STR R1, [R0, #R_Down_Flag] ; all CMOS reset flags + STR R1, [R0, #KeyDataPtr] + [ MorrisSupport + STR R1, [R0, #Port2Present] + ] + B SetUpKbd ; No stack yet so branch and branch back. +SetUpKbdReturn + + +; set up reset interrupt handler (reads, discards keys, setting flags if CTRL or R) +; NB on ARM600 we need to go into 32-bit mode, so we can safely overwrite vectors + + [ CPU_Type = "ARM600" + mrs AL, r0, CPSR_all ; switch into IRQ32, still IRQs disabled + BIC r0, r0, #&1F + ORR r1, r0, #IRQ32_mode + msr AL, CPSR_all, r1 + + LDR sp_irq, =IRQSTK ; set up sp_irq + + ADRL R2, MOSROMVecs ; pick up from table + LDR R2, [R2, #&18] ; this gets overwritten while active, + MOV R3, #0 + STR R2, [R3, #&18] ; but hopefully by the same value! + + ORR r0, r0, #SVC32_mode ; switch into SVC32 + BIC r0, r0, #I32_bit ; and enable IRQs + msr AL, CPSR_all, r0 + + ; in SVC32 from now until we've finished poking around with vectors + + | + TEQP pc, #IRQ_mode + I_bit ; set up IRQ stack + NOP + LDR sp_irq, =IRQSTK + + ADRL R0, MOSROMVecs ; pick up from table + LDR R0, [R0, #&18] ; this gets overwritten while active, + MOV R1, #0 ; could have been changed by keyboard initialisation + STR R0, [R1, #&18] ; but hopefully by the same value! + + TEQP pc, #SVC_mode ; Enable interrupts, back to supervisor mode + NOP + ] + + + [ :LNOT: AlwaysClearRAM + +; IF por OR FX200 bit set THEN clear memory + MOV R0, #IOC + LDRB R1, [R0, #IOCIRQSTAA] + ANDS R1, R1, #por_bit + BNE %FT20 + + LDR R0, =OsbyteVars + :INDEX: ESCBREAK + LDRB R1, [R0] + CMP R1, #2 ; unlike popular rumour, bit 1 ain't + CMPNE R1, #3 ; a flag + BNE %FT30 +20 + ] + BL ClearPhysRAM +30 + MOV r0, #0 + STR r9, [r0, #MEMC_CR_SoftCopy] ; set soft copy. + STR r7, [r0, #MemorySpeed] ; Remember CPU speed/MEMC1a flag + STR r8, [r0, #Page_Size] ; r8 is still page size from way up there + STR r13, [r0, #RAMLIMIT] ; save sussed memory size in LogRam + + LDR sp, =SVCSTK ; set up a stack + +; do as much other initialisation as possible, to give keyboard stuff time + + [ ProcessorVectors +; Copy default processor vector table and default preveneers. +; Code relies on preveneers being immediately after processor vector table +; but could easily be changed into 2 copy loops. + ASSERT ProcVecPreVeneers = ProcVec_End + ASSERT DefaultPreVeneers = DefaultProcVecs+ProcVec_End-ProcVec_Start + + ADRL R0, DefaultProcVecs + LDR R1, =ProcVec_Start + MOV R2, #ProcVec_End-ProcVec_Start+ProcVecPreVeneersSize +39 + LDR R3, [R0], #4 + STR R3, [R1], #4 + SUBS R2, R2, #4 + BNE %BT39 + ] + +; copy handler addresses + ADRL R1, MOSROMVecs+4 ; don't copy to 0: key stuff is using + ; it as workspace! + MOV R0, #4 + +40 + LDR R2, [R1], #4 ; N.B. IRQ handler better be same as the one in there + STR R2, [R0], #4 + TEQ R0, #EndFiq-MOSROMVecs + BNE %BT40 + + [ CPU_Type = "ARM600" + +; Now we have set up the hardware vectors we can drop back to SVC26 mode + + mrs AL, r0, CPSR_all + BIC r0, r0, #&1F + ORR r0, r0, #SVC26_mode + msr AL, CPSR_all, r0 + ] + + +; Ensure any CMOS operation aborted + + MOV R1,#16 ; Two bytes in case RTC transmitting +35 + BL Start ; Start/clock edge + BL Stop + SUBS R1,R1,#1 + BNE %BT35 + + [ CacheCMOSRAM + BL InitCMOSCache ; initialise cache of CMOS RAM + ] + +; Now copy the initialised data + MOV R0, #IRQ1V + +; first save IOC soft copy so can restore it + + LDRB R2, [R0, #IOCControlSoftCopy-IRQ1V] + Push "R2" + LDRB R2, [R0, #CannotReset-IRQ1V] + Push "R2" + + ADRL r1, StartData +DatCopy + LDR R2, [R1], #4 + STR R2, [R0], #4 + TEQ R0, #(EndData-StartData+IRQ1V) + BNE DatCopy + + [ ResetIndirected + ADR r2, CONT_Break + MOV r0, #0 + STR r2, [r0, #ResetIndirection] + ] + + [ CPU_Type = "ARM600" + MOV r0, #0 ; initialise abort list + STR r0, [r0, #AbortIndirection] + ] + +; Now the SWI despatch + low part of SWI table + ADRL R3, DirtyBranch + LDR R0, =SWIDespatch +SVCTabCopy ; so copy the table + LDR R2, [R1], #4 + STR R2, [R0], #4 + TEQ R1, R3 + BNE SVCTabCopy + +; pad to 1K table here, rather than use ROM space + ADRL R2, NoSuchSWI + LDR R4, =1024+SvcTable ; end of table +PadSVCTable + CMP R0, R4 + STRNE R2, [R0], #4 + BNE PadSVCTable + +; now the dirty branch + LDR R1, [R1] + STR R1, [R0] + +; now the time/date conversions + + LDR R0, =SvcTable + ADRL R1, ConvertStandardDateAndTime + STR R1, [R0, #OS_ConvertStandardDateAndTime*4] + ADD R1, R1, #ConvertDateAndTime - ConvertStandardDateAndTime ; SKS + STR R1, [R0, #OS_ConvertDateAndTime*4] + +; other conversion SWIs, all go through same entry point + + ADRL R1, despatchConvert + MOV R2, #OS_ConvertHex1 +conversionSWIfill + STR R1, [R0, R2, LSL #2] + ADD R2, R2, #1 + CMP R2, #OS_ConvertFileSize+1 + BNE conversionSWIfill + + +; Initialise CAO ptr to none. + + MOV R0, #0 + MOV R1, #32*1024*1024 ; nothing will be here!! + STR R1, [R0, #Curr_Active_Object] + + +KeyWait * 200000 ; 1/5 sec wait (in microseconds) + + [ KeyWait <> 0 +; Check for keyboard there every 1/5 sec. but give up after 2 secs. + MOV r2, #IOC + MOV r3, #10 ; Check for keyboard 10 times (2 secs max). + MOV r4, #InitKbdWs +kbdwait + LDRB r5, [r4, #KB_There_Flag] + LDR r0, =KeyWait*2 ; Wait 1/5 second (give keys down a chance to come in). + BL DoMicroDelay + TEQ r5, #0 ; If keyboard was there 1/5 second ago then + BNE kbdthere ; continue reset + SUBS r3, r3, #1 ; else wait a maximum of 2 seconds. + BNE kbdwait +kbdthere + ] + + +; IF power-on bit set in IOC AND R/T/Del/Copy pressed THEN reset CMOS RAM +; note that memory cleared if POR, so key info has had plenty of time! + MOV R0, #IOC + LDRB R1, [R0, #IOCIRQSTAA] + ANDS R1, R1, #por_bit + BEQ no_cmos_reset + + [ CheckProtectionLink + LDR r0, =IOMD_MonitorType + +; on Issue A's the protection bit is only weakly pulled up, +; so force it high, then read it back + + LDRB r1, [r0] + ORR r1, r1, #IOMD_ProtectionLinkBit + STRB r1, [r0] + + LDRB r1, [r0] + TST r1, #IOMD_ProtectionLinkBit + BEQ no_cmos_reset ; if zero then CMOS is protected + ] + + MOV R0, #InitKbdWs + LDR R7, [R0, #R_Down_Flag] + CMP R7, #0 + BEQ no_cmos_reset ; power on bit checked again there + + ADD sp, sp, #4 ; junk CannotReset flag from stack + +; CMOS reset detectified. +; ************************************************************************** +; Note: if this CMOS reset code ever needs changing again, it's probably +; better to rewrite it. The Compact apparently has a table of default +; CMOS values; R-p.o. just writes the table, DEL-p.o. zeroes all, then +; writes the table. With skipping of the time CMOS, and post-prodding of +; the sync, that would probably be a better algorithm. +; ************************************************************************** + + SetBorder R0, R1, 15, 0, 0 ; flash the border as warning! + + MOVS R3, R7, LSR #16 ; full reset or just system? + MOVNE R3, #-1 ; Del or Copy does all RAM + MOVEQ R3, #UserCMOS ; R or T just system + [ ChecksumCMOS + BL ValChecksum ; unless the CMOS ram's corrupt .. + MOVNE R3, #-1 ; .. then blast it anyway. + MOVNE R0, #0 ; even the econet station number + MOVEQ R0, #1 + | + MOV R0, #1 ; leave the econet station number + ] + MOV R1, #0 ; zero it first +cmrlp BL Write ; CMOS(R0) := R1 + ADD R0, R0, #1 + CMP R0, R3 + MOVEQ R0, #&80 ; skip user cmos + CMP r0, #YearCMOS + ADDEQ r0, r0, #2 + CMP r3, #UserCMOS ; system only? + BNE skipskipforTC + CMP r0, #NewADFSCMOS + CMPNE r0, #CountryCMOS ; skip these if so + ADDEQ r0, r0, #1 +skipskipforTC + CMP R0, #CMOSLimit + BNE cmrlp + [ ChecksumCMOS + BL MakeChecksum ; create a valid checksum + ] +; now put nice values in where necessary +; first full reset defaults + CMP r3, #-1 + BNE not_full_reset + MOV r0, #CountryCMOS + MOV r1, #1 ; country UK + BL Write + MOV r0, #NewADFSCMOS + MOV r1, #&41 ; floppies=1, ST506=0, IDE=1 (changed 01-Sep-93) + BL Write +not_full_reset + +; IF R or Delete pressed THEN set sync 0 ELSE set sync Auto + MOV R0, #InitKbdWs + LDRB R1, [R0, #R_Down_Flag] + CMP R1, #0 + LDREQB R1, [R0, #Del_Down_Flag] + CMPEQ R1, #0 + MOV R0, #VduCMOS + MOVNE R1, #MonitorTypeAuto :OR: Sync_Auto ; if R or Del + MOVEQ R1, #MonitorTypeAuto :OR: Sync_Separate ; if T or Copy + BL Write + + [ MorrisSupport + MOV R8, #IOMD_Base + LDRB R0, [R8, #IOMD_ID0] + CMP R0, #&98 + LDRB R0, [R8, #IOMD_ID1] + CMPEQ r0, #&5B + BNE dont_program_mousetype +; +; Morris based machines use PS2 mice/tracker balls +; + MOV R0, #MouseCMOS + MOV R1, #PointerDevice_PS2Mouse ;type 3 + BL Write + + [ Select16BitSound +; set print and sound CMOS (16bit sound) + B Config16BitSound + ] +dont_program_mousetype + ] + + [ Select16BitSound + LDR r0, =IOMD_MonitorType + +; on Issue A's the protection bit is only weakly pulled up, +; so force it high, then read it back + + LDR r1, [r0] + ORR r1, r1, #IOMD_SoundsystemLinkBit + STR r1, [r0] + + LDR r1, [r0] + TST r1, #IOMD_SoundsystemLinkBit + BEQ Config16BitSound ; if zero, must be Rimmer, so assume 16bit sound hardware present + +; set print and sound CMOS (8bit sound) + MOV R0, #TutuCMOS + MOV R1, #2_0100 ; tbs chars valid, ctrlchars '|x' + BL Write + B ConfigSoundDone + +Config16BitSound +; set print and sound CMOS (16bit sound) + MOV R0, #TutuCMOS + MOV R1, #2_10100100 ; tbs chars valid, ctrlchars '|x' + BL Write + +ConfigSoundDone + ] + + ADR R8, DefaultCMOSTable +50 + LDRB R0, [R8], #1 + CMP R0, #&FF + BEQ hard_reset ; power on bit musta bin set + LDRB R1, [R8], #1 + BL Write + B %BT50 + + LTORG + +DefaultCMOSTable ; list of non-zero options wanted : +; byte pairs of offset, value +; terminated by offset &FF + = KeyDelCMOS, 32 + = FileLangCMOS, 8 + = FontCMOS, 16 ; TMD 15-Dec-93: Changed to 64K from 32K - fixes MED-01774 + = PigCMOS, 10 + = KeyRepCMOS, 8 + = RMASizeCMOS, 0 + = SpriteSizeCMOS, 0 + = MODETVCMOS, &10 ; TV 0,1 + = NetFSIDCMOS, 254 + = NetPSIDCMOS, 235 + = PSITCMOS, (3:SHL:2) :OR: (1:SHL:5) + ; Baud 3 + ; print 1 + + = DBTBCMOS, (1:SHL:4) :OR: (4:SHL:5) + ; Boot (changed from NoBoot 01-Sept-93) + ; Data 4 + + = StartCMOS, (4:SHL:0) :OR: (2:SHL:3) :OR: (1:SHL:6) + ; Drive 4 (changed from Drive 0 01-Sept-93) + ; NOCAPS (changed from CAPS 02-May-91) + ; NODIR + + [ NewClockChip ; only on A1's! + = NewADFSCMOS+1, &FF ; step 3 for each drive + ] + + = NewADFSCMOS+2, 1 ; ADFSBuffers 1 + = SoundCMOS, &F0 ; speaker on, volume 7, channel 1 + + = LanguageCMOS, ConfiguredLang + = YearCMOS, 95 ; changed from 93 to 95 on 12-Jan-95 to fix MED-04318 + = YearCMOS+1, 19 + [ :LNOT: Select16BitSound + = TutuCMOS, 2_0100 ; tbs chars valid, ctrlchars '|x' + ] + = NetFilerCMOS, (0:SHL:0) :OR: (1:SHL:1) :OR: (0:SHL:2) + ; FS list order by name + ; Use $.Arthurlib + ; Large icons + + ; = Mode2CMOS, WimpModeAutoBit :OR: CMOSResetBit ;AKA SystemSpeedCMOS - removed by RManby and SCormie 8/3/95 + = DesktopCMOS, 2_01000000 ; verbose ON + = WimpFlagsCMOS, 2_01101111 ; instant effects, drags off screen + = ProtectionCMOS, 2_01110110 ; allow only peek and user RPC + = MouseStepCMOS, 2 + = FileSwitchCMOS,(1:SHL:0) :OR: (1:SHL:1) :OR: (0:SHL:2) :OR: (0:SHL:3) :OR: (0:SHL:6) + ; truncate names + ; Use DragASprite (changed 01-Sept-93) + ; Interactive file copying + ; Wimp dither colours off + ; last shutdown ordinary + + = DesktopFeaturesCMOS,(1:SHL:0) :OR: (8:SHL:1) :OR: (0:SHL:7) + ; 3D look + ; Homerton.Medium + ; tiled window background + + = SystemSpeedCMOS,(1:SHL:0):OR:(0:SHL:1):OR:(1:SHL:2):OR:(0:SHL:3):OR:(1:SHL:4):OR:(0:SHL:5):OR:(1:SHL:6):OR:(0:SHL:7) + ; AUN ROMBoot Enabled + ; AUN auto-station numbering off + ; Delete-etc reset + ; power saving off + ; WimpMode auto + ; Cache on + ; Broadcast loader disabled + ; broadcast loader colours off + + = FontMax2CMOS, &2C ; 32 point + = FontMax3CMOS, &38 ; 32 point + = AlarmAndTimeCMOS,2_00010000 ; !Alarm autosave on + = FSLockCMOS+5, &EA ; Checksum for no password + = CDROMFSCMOS, &60 ; drives = 0, buffer size = 32K + = &FF + ALIGN + + +no_cmos_reset ; R1 has por_bit set if power on + Push "r1" + MOV r0, #SystemSpeedCMOS + BL Read + BIC r1, r0, #CMOSResetBit ; clear bit indicating CMOS reset + MOV r0, #SystemSpeedCMOS + BL Write + Pull "r1" + + Pull r0 ; always pull CannotReset flag + [ SoftResets + TST r1, #por_bit + BNE hard_reset ; it was a power-on, so it's a hard reset + CMP r0, #0 + [ DebugForcedReset + MOVNE r2, #Reset_CannotResetFlag + ] + BNE hard_reset_forced + +; IF control pressed OR memory implausible (Check SysHpd, CAM map sensible) THEN hard reset + + LDR R0, =SysHeapStart + LDR R8, [R0, #:INDEX: hpdmagic] + LDR R2, =magic_heap_descriptor + CMP R8, R2 ; check sysheap initialised + [ DebugForcedReset + MOVNE r2, #Reset_SysHeapCorrupt + ] + BNE hard_reset_forced + +; also check CAM map sensible + + [ {TRUE} ; new code which allows for MEMC2's small pages + MOV R5, #0 + LDR R4, [R5, #Page_Size] ; R4 = page size + ADRL R3, PageShifts-1 + LDRB R4, [R3, R4, LSR #12] ; R4 = log2(pagesize) + LDR R3, [R5, #RAMLIMIT] ; R3 = total RAM size + MOV R2, R3, LSR R4 ; number of pages=total memory / pagesize + CMP R2, #256 ; but if fewer than 128 (eg 64 on A305) (NB if <256 then <=128) + MOVCC R2, #128 ; then use 128 (all MEMC1's pages need initialising, + ; even if half of them are not in use) + SUB R2, R2, #1 + [ MEMM_Type = "ARM600" + LDR R3, =CamEntriesForVicky + | + LDRLS R3, =CamEntries ; if <= 256 pages, then should be using + ; low-down cam soft copy + LDRHI R3, =CamEntriesForBigMachines ; else should be using hi up one + ] + + LDR R4, [R5, #MaxCamEntry] ; get highest CAM entry + LDR R5, [R5, #CamEntriesPointer] ; and pointer to CAM soft copy + | + MOV R5, #0 + LDR R3, [R5, #RAMLIMIT] ; read amount of RAM + LDR R4, [R5, #MaxCamEntry] ; and highest CAM entry + LDR R5, [R5, #CamEntriesPointer] ; and pointer to CAM soft copy + + CMP R3, #8*1024*1024 ; if >= 8MBytes then there are + MOVCS R2, R3, LSR #15 ; RAM/32k pages + MOVCC R2, #128 ; else there are 128 pages + SUB R2, R2, #1 ; what highest cam index should be + + LDRLS R3, =CamEntries ; if <= 8MBytes, should be using + ; low-down cam soft copy + LDRHI R3, =CamEntriesForBigMachines ; else should be using hi up one + ] + + CMP R5, R3 ; if not the same + [ DebugForcedReset + MOVNE r2, #Reset_WrongCamMapAddress + BNE hard_reset_forced + ] + CMPEQ R4, R2 ; or number of pages not the same + [ DebugForcedReset + MOVNE r2, #Reset_WrongNumberOfPages + ] + BNE hard_reset_forced ; then do a hard reset + +; now check all cam contains sensible values + + MOV R4, #0 + LDR R4, [R4, #Page_Size] + SUB R4, R4, #1 + [ CPU_Type = "ARM600" + ORR R4, R4, #&F0000000 ; can have addresses above 64M + | + ORR R4, R4, #&FC000000 + ] +CamCheck + LDR R3, [R5, R2, LSL #2] + BIC r3, r3, #&F0000000 ; remove PPL + TST R3, R4 + [ DebugForcedReset + MOVNE r2, #Reset_CamMapCorrupt + ] + BNE hard_reset_forced ; wally entry: not pagesize multiple, or >= 32M + SUBS R2, R2, #1 + BPL CamCheck + +; leave CTRL test till last, so the keyboard's had as much time to +; wiggle the wet string as we can give it + MOV R0, #InitKbdWs + LDRB R1, [R0, #CTRL_Down_Flag] + CMP R1, #0 + BNE hard_reset + +soft_reset +; clear out 4K of scratchspace, to use as a reverse CAM soft copy; +; set bytes to indicate page mapped to that address. Can then recalculate +; end of memory. + +; This code doesn't currently work on ARM600 versions - +; 4K of workspace isn't enough to do this with a 4K page size +; We'd probably want to do it differently anyway, using the L2PT +; But since we're removing soft resets it's not worth the effort + + ASSERT MEMM_Type <> "ARM600" + + MOV R5, #ScratchSpace + MOV R1, #4*1024 + MOV R2, #0 +clrscratch + SUBS R1, R1, #4 + STRPL R2, [R5, R1] + BPL clrscratch + + LDR R2, [R2, #Page_Size] + ADRL R8, PageShifts-1 + LDRB R8, [R8, R2, LSR #12] + + MOV r7, #0 + LDR r2, [r7, #RAMLIMIT] + MOV r2, r2, LSR r8 ; last valid page + SUB r2, r2, #1 + + LDR R7, [R7, #CamEntriesPointer] + LDR R12, =DuffEntry + +restoreCAMloop + LDR R3, [R7, R2, LSL #2] + MOV r11, r3, LSR #28 + BIC r3, r3, #&F0000000 + + MOV R0, R3, LSR R8 ; logram page number + LDRB R4, [R5, R0] + CMP r4, #0 ; check for doubly mapped pages + BEQ rclon + + ORR r3, r12, #&30000000 ; force to invalid place if so. + STR r3, [R7, R2, LSL #2] + MOV r3, r12 + MOV r11, #3 ; protected + MOV R0, R3, LSR R8 + LDRB R4, [R5, R0] +rclon + CMP r3, #16*1024*1024 ; in application space? + MOVLT r11, #0 ; noprot if so + STRLT r3, [R7, R2, LSL #2] + ADD R4, R4, #1 + STRB R4, [R5, R0] ; sema for interesting pages + BL BangCam + SUBS R2, R2, #1 + BPL restoreCAMloop + +; now do post-scan to see if we need to do more CAM bashing to get pages back. +; any entries that aren't validateable should be remapped. + + MOV R7, #0 + MOV R12, #ScratchSpace + LDR R2, [R7, #Page_Size] +findapplend + LDRB R3, [R12], #1 + CMP R3, #0 + ADDNE R7, R7, R2 + BNE findapplend + MOV R1, #0 + STR R7, [R1, #AplWorkSize] ; verified value + LDR R3, [R1, #RAMLIMIT] ; calc last valid page: + MOV R3, R3, LSR R8 ; RAMLIMIT >> R8 + MOV R11, #0 ; no PPL + LDR R4, [R11, #CamEntriesPointer] +testforremap + SUBS R3, R3, #1 + BMI finishedremap + LDR R0, [R4, R3, LSL #2] + BIC r0, r0, #&F0000000 ; remove PPL + ADD R1, R0, R2 + SWI XOS_ValidateAddress + BCC testforremap + + Push "R2-R4" + MOV R0, R0, LSR R8 ; curr logram page number + LDRB R4, [R5, R0] + SUB R4, R4, #1 + STRB R4, [R5, R0] ; dec sema + MOV R2, R3 ; entry no + MOV R3, R7 ; addr to set to + BL BangCamUpdate + Pull "R2-R4" +holefilled + ADD R7, R7, R2 + LDRB R0, [R12], #1 ; reinspect our reverse map + CMP R0, #0 + BNE holefilled + MOV R0, #0 + STR R7, [R0, #AplWorkSize] + B testforremap + +finishedremap + MOV R12, #NVECTORS-1 + LDR R11, =VecPtrTab +freenextvec + LDR R2, [R11, R12, LSL #2] +loseveclink + LDR R3, [R2, #TailPtr] + BL FreeSysHeapNode + MOVVC R2, R3 + BVC loseveclink + CMP R3, #0 ; were we at the end of the chain? + [ DebugForcedReset + MOVNE r2, #Reset_VectorChainCorrupt + ] + BNE hard_reset_forced + SUBS R12, R12, #1 + BPL freenextvec +; so that's the code for restore default vectors, basically + BL InitVectors + MOV R0, #0 + LDR R1, [R0, #AplWorkSize] + STR R1, [R0, #MemLimit] + + LDR R3, =TickNodeChain + LDR R2, [R3] + +loseticknodes + CMP R2, #0 + BEQ ticknodesallgone + + LDR R3, [R2] + BL FreeSysHeapNode + [ DebugForcedReset + MOVVS r2, #Reset_TickNodesCorrupt + ] + BVS hard_reset_forced + MOV R2, R3 + B loseticknodes + +ticknodesallgone +; and now it's time to free the IRQ structures + + MOV R12, #(NoInterrupt-1)*12+8 ; last device link offset + LDR R11, =DefaultIRQ1V-DefaultIRQ1Vcode+Devices +freenextdev + LDR R2, [R11, R12] +losedevlink + CMP R2, #0 + BEQ stepdevice + + LDR R3, [R2, #8] + BL FreeSysHeapNode + [ DebugForcedReset + MOVVS r2, #Reset_DeviceVectorCorrupt + ] + BVS hard_reset_forced + MOV R2, R3 + B losedevlink +stepdevice + SUBS R12, R12, #12 + BPL freenextdev + +; now the PIRQ structures and CallBack_Vector + LDR R11, =PIRQ_Chain + MOV r4, #PodDesp_Link +losepirqchain + LDR R2, [R11] + CMP r2, #0 ; for CallBack_Vector + BEQ doobry +losepirqlink + LDR R3, [R2, r4] + BL FreeSysHeapNode + MOVVC R2, R3 + BVC losepirqlink + CMP R3, #0 ; were we at the end of the chain? + [ DebugForcedReset + MOVNE r2, #Reset_PoduleOrCallBackCorrupt + ] + BNE hard_reset_forced + LDR R2, =PIRQ_Chain + CMP R11, R2 + LDR R2, =PFIQasIRQ_Chain + MOVEQ R11, R2 + CMPNE r11, r2 + LDREQ r11, =CallBack_Vector + [ PodDesp_Link <> 0 + MOVEQ r4, #0 + ] + BEQ losepirqchain + + +doobry Pull "R1" ; IOCControl restoration + MOV R0, #0 + STRB R1, [R0, #IOCControlSoftCopy] + MOV R0, #IOC ; and bash the hardware + STRB R1, [R0, #IOCControl] + + MOV R0, #SoftReset + B ResetPart1Done + + | + +; if soft resets are disabled, drop thru into hard reset code + + ] ; end of code to do with soft resets + +hard_reset + [ DebugForcedReset + MOV r2, #0 ; indicate normal hard reset + ] +hard_reset_forced + [ DebugForcedReset + STR r2, [r0, -r0] ; store to logical address zero + ] + + Pull "R2" ; discard old IOC state + +; fill in relevant CamMap entries, so can soft start. + + MOV R8, #0 + LDR R8, [R8, #Page_Size] + ADRL R1, PageShifts-1 + LDRB R1, [R1, R8, LSR #12] + + [ ExpandedCamMap + MOV r2, #0 + [ MEMM_Type = "ARM600" + LDR r0, [r2, #VideoSize] ; offset from start of physical pages to static part + | + LDR r0, =480*1024 + ] + MOV r0, r0, LSR r1 ; r0 := cam entry number + MOV r0, r0, LSL #3 ; r0 := offset into CAM map for start of static part + + MOV R7, #32*1024*8 + MOV R7, R7, LSR R1 ; r7 := cam entry offset for 32K + + | + MOV R0, #(512-32)*1024*4 + MOV R0, R0, LSR R1 ; r0 := cam entry number * 4 + + MOV R7, #32*1024*4 + MOV R7, R7, LSR R1 ; r7 := cam entry offset for 32K + + MOV R2, #0 + ] + LDR R12, [R2, #RAMLIMIT] ; R12 = total RAM size + + ; new code which allows for MEMC2's small pages + MOV R1, R12, LSR R1 ; R1 = number of pages + CMP R1, #256 ; but if fewer than 128 (eg 64 on A305) (NB if <256 then <=128) + MOVCC R1, #128 ; then use 128 (all MEMC1's pages need initialising, + ; even if half of them are not in use) + + SUB R3, R1, #1 + STR R3, [R2, #MaxCamEntry] + + [ MEMM_Type = "ARM600" + LDR R1, =CamEntriesForVicky + | + LDRLS R1, =CamEntries ; if <=256 pages (was if <=8MBytes) then small CAM copy + LDRHI R1, =CamEntriesForBigMachines ; else use big CAM copy + ] + STR R1, [R2, #CamEntriesPointer] + + + [ MEMM_Type = "ARM600" + +; On ARM600 we must zap all the soft CAM map before adding any entries, +; since the old contents are used in BangCamUpdate + + Push "r0" + ADD r2, r1, r3, LSL #3 ; r2 -> last entry to do + LDR r0, =DuffEntry + MOV lr, #AP_Duff ; PPL = no access +WallopDuffOnes + STMDA r2!, {r0, lr} ; store address, PPL + CMP r2, r1 + BCS WallopDuffOnes + Pull "r0" + ] + ADD R0, R0, R1 + + MOV R2, #CursorChunkAddress + LDR r1, =AP_CursorChunk + BL AddCamEntries + + CMP R12, #512*1024 + SUBEQ R0, R0, R7 ; previous entries + ADDNE R0, R0, R7 ; next entries + MOV R2, #0 + MOV r1, #AP_PageZero + BL AddCamEntries + + CMP R12, #512*1024 + SUBEQ R0, R0, R7 ; previous entries + ADDNE R0, R0, R7 ; next entries + MOV R2, #SysHeapChunkAddress + MOV r1, #AP_SysHeap :OR: PageFlags_Unavailable + BL AddCamEntries + + [ MEMM_Type = "ARM600" + ADD R0, R0, R7 ; next entries (ignore 512K machines) + MOV r7, #0 + LDR r7, [r7, #L2PTSize] + MOV r7, r7, LSR #12-3 ; number of pages * 8 + LDR R2, =L2PT + LDR r1, =AP_L2PT :OR: PageFlags_Unavailable + BL AddCamEntries + + ADD r2, r0, #((L1PT-L2PT):SHR:(12-3)) + 4 ; point at PPL for 1st L1 page + LDR r1, =AP_L1PT + STR r1, [r2], #8 ; store 4 CAM entries for 4 x 4K = 16K of L1 + STR r1, [r2], #8 ; mark them as unavailable for removal + STR r1, [r2], #8 + STR r1, [r2], #8 + + ADD R0, R0, R7 ; add on enough pages for L2PT + + MOV r7, #0 + LDR r7, [r7, #SoftCamMapSize] ; number of bytes in soft cam map + ADD r7, r7, #UndStackSize + MOV r7, r7, LSR #12-3 ; number of bytes of cam map for this + LDR R2, =UndStackSoftCamChunk + MOV r1, #AP_UndStackSoftCam + BL AddCamEntries + | + [ MEMM_Type = "MEMC2" +; CCs from CMP still valid + SUBEQ R0, R0, R7 ; previous entries + ADDNE R0, R0, R7 ; next entries + LDR R2, =CursorChunkAddress+64*1024 ; 01F10000 + MOV r1, #AP_CursorChunk + BL AddCamEntries + ] + ] + +; let's boogie with the CMOS for a bit +; read info and move as much memory as we can + + BL InitDynamicAreas + + [ NewStyle_Screen + Push "r0-r12" + MOV r0, #ScreenSizeCMOS + BL Read + + MOV r5, #0 + LDR r10, [r5, #Page_Size] ; needed by MassageScreenSize + MUL r0, r10, r0 ; convert to bytes + LDR r5, [r5, #VideoSize] ; maximum size + BL MassageScreenSize + + MOV r1, #ChangeDyn_Screen ; area number + MOV r2, r0 ; initial size + MOV r3, #ScreenEndAdr ; base address (start of 2nd copy) + LDR r4, =AP_Screen ; area flags + ADRL r6, DynAreaHandler_Screen ; handler + VDWS r7 ; workspace pointer + MOV r8, #0 + STR r8, [r7, #CursorFlags] ; put zero in CursorFlags as an indication that VDU not yet inited + STR r2, [r7, #TotalScreenSize] + ADRL r8, AreaName_Screen ; area name + BL DynArea_Create + Pull "r0-r12" + | + MOV R2, #0 ; CAM entry number to use (irrelevant for new code) + MOV R0, #ScreenSizeCMOS ; CMOS byte to read + MOV R3, #ScreenEndAdr ; where to put it (screen fudged) + LDR R1, =VduDriverWorkSpace+TotalScreenSize + ; variable to save size set + MOV r11, #AP_Screen ; Unprotected + BL ReadCMOSAndConfigure ; Screen must be done first to get video RAM pages + ] + + [ NewStyle_RMA + Push "r0-r12" + MOV r1, #ChangeDyn_RMA ; Area number + MOV r2, #4096 ; Initial size + MOV r3, #RMAAddress ; Base address + MOV r4, #AP_RMA ; Area flags + MOV r5, #RMAMaxSize ; Maximum size + ADRL r6, DynAreaHandler_RMA ; Pointer to handler + MOV r7, r3 ; Workspace ptr points at area itself + ADRL r8, AreaName_RMA ; Title string - node will have to be reallocated + ; after module init, to internationalise it + BL DynArea_Create ; ignore any error, we're stuffed if we get one! + Pull "r0-r12" + | + MOV R0, #1 ; One page. Unprotected + MOV R3, #RMAAddress + ADD R1, R3, #:INDEX: hpdend ; see comment about SysHeap! + MOV r11, #AP_RMA + BL FudgeConfigureRMA + ] + + [ NewStyle_SpriteArea + Push "r0-r12" + MOV r0, #0 ; initialise SpriteSize to zero + STR r0, [r0, #SpriteSize] ; (fixes bug MED-00811) + + MOV r0, #SpriteSizeCMOS ; find out how much spritesize configured + BL GetConfiguredSize ; in: r0 = CMOS address, out: r2 = size + + MOV r1, #ChangeDyn_SpriteArea ; Area number + MOV r3, #-1 ; Base address dynamic + MOV r4, #AP_Sprites ; Area flags + MOV r5, #-1 ; Maximum size + ADRL r6, DynAreaHandler_Sprites ; Pointer to handler + MOV r7, #-1 ; Use base address as workspace ptr + ADRL r8, AreaName_SpriteArea ; Title string - node will have to be reallocated + ; after module init, to internationalise it + BL DynArea_Create ; ignore any error, we're stuffed if we get one! + Pull "r0-r12" + | + MOV R0, #SpriteSizeCMOS + MOV R3, #SpriteSpaceAddress + LDR R1, =SpriteSize ; for Richard. Unprotected + MOV r11, #AP_Sprites + BL ReadCMOSAndConfigure + ] + + [ NewStyle_RAMDisc + Push "r0-r12" + MOV r0, #RAMDiscCMOS ; find out how much RAM disc configured + BL GetConfiguredSize ; in: r0 = CMOS address, out: r2 = size + + MOV r1, #ChangeDyn_RamFS ; Area number + MOV r3, #-1 ; Base address dynamic + MOV r4, #AP_RAMDisc ; Area flags + MOV r5, #16*1024*1024 ; Limit maximum size to 16MB until JSR fixes FileCore + ADRL r6, DynAreaHandler_RAMDisc ; Pointer to handler + MOV r7, #-1 ; Use base address as workspace ptr + ADRL r8, AreaName_RAMDisc ; Title string - node will have to be reallocated + ; after module init, to internationalise it + BL DynArea_Create ; ignore any error, we're stuffed if we get one! + Pull "r0-r12" + | + MOV R0, #RAMDiscCMOS + MOV R3, #RAMDiscAddress + LDR R1, =RAMDiscSize ; for RAMFS + MOV r11, #AP_RAMDisc ; protected + BL ReadCMOSAndConfigure + ] + + [ NewStyle_FontArea + Push "r0-r12" + MOV r0, #FontCMOS ; find out how much font cache configured + BL GetConfiguredSize ; in: r0 = CMOS address, out: r2 = size + + MOV r1, #ChangeDyn_FontArea ; Area number + MOV r3, #-1 ; Base address dynamic + MOV r4, #AP_FontArea ; Area flags + MOV r5, #-1 ; Maximum size + ADRL r6, DynAreaHandler_FontArea ; Pointer to handler + MOV r7, #-1 ; Use base address as workspace ptr + ADRL r8, AreaName_FontArea ; Title string - node will have to be reallocated + ; after module init, to internationalise it + BL DynArea_Create ; ignore any error, we're stuffed if we get one! + Pull "r0-r12" + | + MOV R0, #FontCMOS + MOV R3, #FontCacheAddress + LDR R1, =FontCacheSize ; for Fontmanager + MOV r11, #AP_FontArea + BL ReadCMOSAndConfigure ; still protected + ] + +; get here with R2 = highest CAM entry used (in old model) + + [ MEMM_Type = "ARM600" + LDR R0, =(AplWorkMaxSize-32*1024):SHR:12 ; maximum number of pages in aplspace + MOV R3, #32*1024 ; aplwork start + LDR R1, =AplWorkSize ; aplwork size + MOV r11, #AP_AppSpace + BL FudgeConfigureRMA ; put as much as possible in aplspace + + [ :LNOT: GetPagesFromFreePool ; memory is already in free pool, so don't mess around + MOV r0, #0 + LDR r0, [r0, #RAMLIMIT] + MOV r0, r0, LSR #12 ; only limit on free pool is ram size + MOV R3, #FreePoolAddress + LDR R1, =FreePoolDANode + DANode_Size + MOV r11, #AP_FreePool + BL FudgeConfigureRMA ; and the rest in FreePool + ] + | + MOV R0, #4096 ; try and get maximum amount possible + MOV R3, #32*1024 ; aplwork start + LDR R1, =AplWorkSize ; aplwork size + MOV r11, #AP_AppSpace + BL FudgeConfigureRMA ; stuff rest on AplWork + ] + + MOV R0, #0 + LDR R1, [R0, #AplWorkSize] + ADD R1, R1, #32*1024 + STR R1, [R0, #AplWorkSize] + STR R1, [R0, #MemLimit] + + [ MEMM_Type <> "ARM600" + +; Now add all the NaffEntries to CamEntries +; R2 highest CAM entry used +; NB This is not done on ARM600, as the whole soft CAM map has to be zapped before +; we start, because BangCamUpdate uses the old contents + + LDR R3, [R0, #MaxCamEntry] ; (R0 still zero from above) + CMP R2, R3 + BGT CAMallset + LDR R0, [R0, #CamEntriesPointer] ; (R0 still zero from above) + [ ExpandedCamMap + ADD r3, r0, r3, LSL #3 ; r3 -> last pair of words to do + ADD r0, r0, r2, LSL #3 ; r0 -> first pair of words to do + LDR r1, =DuffEntry ; address + MOV r2, #AP_Duff ; PPL +WallopDuffOnes + STMIA r0!, {r1, r2} ; store address, PPL + CMP r0, r3 + BLS WallopDuffOnes + | + LDR R1, =DuffEntry :OR: (AP_Duff :SHL: 28) +WallopDuffOnes + STR R1, [R0, R2, LSL #2] + ADD R2, R2, #1 + CMP R2, R3 + BLE WallopDuffOnes + ] +CAMallset + ] + + [ :LNOT: NewCDA +; System heap only initialised here on older software models +; On new ones it's already been initialised by hand in InitDynamicAreas, +; so that we can create dynamic areas above here. + + MOV R0, #HeapReason_Init ; initialise system heap + LDR R1, =SysHeapStart + MOV R3, #32*1024 - (SysHeapStart-SysHeapChunkAddress) + STR R3, [R1, #:INDEX: hpdend] ; keep ValidateAddress happy + SWI XOS_Heap ; tuff if it fails + ] + BL InitVectors ; ready for OsByte to read mode + + [ :LNOT: GetPagesFromFreePool + MOV R0, #0 ; initialise module list to empty + STR R0, [R0, #Module_List] + ] + LDR R1, =ModuleSWI_HashTab + MOV R2, #ModuleSHT_Entries-1 +clearmswis + STR R0, [R1, R2, LSL #2] + SUBS R2, R2, #1 + BGE clearmswis + + [ International + MOV R1, #-1 ; We don't have a message file yet ! + STRB R1, [R0, #ErrorSemaphore] ; Don't translate errors. + STR R0, [R0, #KernelMessagesBlock] ; No message file open. + ] + + MOV R0, #IOC + LDRB R1, [R0, #IOCIRQSTAA] + ANDS R1, R1, #por_bit + STRNEB R1, [R0, #IOCIRQCLRA] ; clear POR if set + LDREQ R0, =OsbyteVars + :INDEX: LastBREAK + LDREQB R0, [R0] + TSTEQ R0, #&80 ; tbs set if memory cleared + MOVNE R0, #PowerOnReset + MOVEQ R0, #ControlReset + + +ResetPart1Done ; R0 is reset type + TEQP PC, #SVC_mode + I_bit ; interrupts off since kbd bash done + LDR R1, =OsbyteVars + :INDEX: LastBREAK + STRB R0, [R1] + + MOV R1, #InitKbdWs + LDRB R0, [R1, #KB_There_Flag] + LDRB R1, [R1, #SHIFT_Down_Flag] + Push "R0, R1" ; save until after MOSInit + +; copy IRQ handler: not done with rest of copying +; because soft break needs the info to free any claimed blocks. + + LDR R0, =DefaultIRQ1V + ADRL R1, DefaultIRQ1Vcode + ADRL R2, DefaultIRQ1Vcode_end +CopyDefaultIRQ1V + LDR R3, [R1], #4 + STR R3, [R0], #4 + CMP R1, R2 + BNE CopyDefaultIRQ1V + + LDR R0, =PIRQ_Chain + ADRL R1, Default_PIRQHandler_Node + STR R1, [R0] + STR R1, [R0, #PFIQasIRQ_Chain-PIRQ_Chain] + ASSERT Default_PFIQasIRQHandler_Node = Default_PIRQHandler_Node + + MOV R0, #0 ; put in IRQ handler, word at 0 + STRB r0, [r0, #FIQclaim_interlock] + STRB r0, [r0, #CallBack_Flag] + STR r0, [r0, #CallBack_Vector] + + [ CPU_Type = "ARM600" + +; we're poking locations 0 and &18 here, so we'd best go back to SVC32 + + mrs AL, r2, CPSR_all + BIC r3, r2, #&1F + ORR r3, r3, #SVC32_mode + msr AL, CPSR_all, r3 + ] + + [ DebugForcedReset + LDR R1, [R0] + TEQ R1, #0 ; if normal hard reset + LDREQ R1, BranchThroughZeroInstruction2 ; then get branchthruzero code + | + LDR R1, BranchThroughZeroInstruction2 + ] + STR R1, [R0] ; put branch through 0 code at 0 + + LDR R1, RealIRQHandler + STR R1, [R0, #&18] + + [ CPU_Type = "ARM600" + +; now back to SVC26 + + msr AL, CPSR_all, r2 + ] + MOV R1, #&100 + STR R1, [R0, #RCLimit] + STR R0, [R0, #ReturnCode] + STR R0, [R0, #TickNodeChain] + +;now put in error handler and escape handler + BL DEFHAN + BL DEFHN2 + MOV R0, #ExceptionDumpArea + LDR R1, =DUMPER + SWI XOS_ChangeEnvironment + + VDWS WsPtr ; main MOS initialisation + BL VduInit + BL ExecuteInit + BL KeyInit + BL MouseInit + BL OscliInit ; before initialising modules + + TEQP pc, #SVC_mode ; enable IRQs + NOP + + BL InitialiseMode ; select correct screen mode, in case any + ; module prints anything in initialisation + + MOV R0, #&FD ; read last reset type + MOV R1, #0 + MOV R2, #&FF + SWI XOS_Byte + CMP R1, #SoftReset ; soft reset? + BEQ SkipHardResetPart2 + +; HardResetPart2 + BL InitVariables + BL ModuleInit ; initialise modules + ; scan podules, copy modules. + + MOV R0, #0 ; shrink sysheap as far as will go. + SUB R1, R0, #4*1024*1024 + SWI XOS_ChangeDynamicArea + MOV R0, #ReadCMOS + MOV R1, #SysHeapCMOS + SWI XOS_Byte + AND R2, R2, #2_111111 ; mask to same size as status + MOV R0, #0 + LDR R0, [R0, #Page_Size] + MULTIPLY R3, R0, R2 ; size spare wanted + BL ClaimSysHeapNode + MOV R0, #HeapReason_Free + SWI XOS_Heap + + MOV R0, #ReadCMOS + MOV R1, #FileLangCMOS + SWI XOS_Byte + MOV R1, R2 + MOV R0, #FSControl_SelectFS ; set configured filing system + SWI XOS_FSControl + + MOV r1, #Service_PostInit ; issue post-initialisation service + BL Issue_Service + +; New code added here by TMD 01-Apr-92 +; Go into user mode, issue a dummy SWI, then go back into SVC mode + + TEQP PC, #0 ; enter USR mode (IRQs, FIQs enabled) + NOP ; wait for it to take effect + SWI XOS_WriteI+0 ; I hope it doesn't generate an error + ; otherwise the callback will get deferred! + SWI XOS_EnterOS ; switch back to SVC mode (IRQs, FIQs enabled) + +; end of added code + + [ International ; Open the kernel messages file. + ADR r0, KernelMessagesBlock+4 + ADR r1, MessageFileName + MOV r2, #0 ; Use file directly. + SWI XMessageTrans_OpenFile + MOVVC r0, #-1 + STRVC r0, [r0, #KernelMessagesBlock+1] ; Message file is now open. + ] + +SkipHardResetPart2 ; code executed on all types of reset + [ International + MOV r0, #0 + LDR r1, [r0, #KernelMessagesBlock] ; if we've managed to open message file + TEQ r1, #0 + STRNEB r0, [r0, #ErrorSemaphore] ; then allow errors to be translated + ] + + BL InitialiseMode + SWI XOS_WriteS + = 10, "$SystemName ", 0 ; now RISC OS (no +) again + ALIGN + + MOV R0, #0 + LDR R0, [R0, #RAMLIMIT] + [ {TRUE} ; Give startup message in megabytes + MOV R0, R0, LSR #20 ; /(1024*1024) + LDR R1, =GeneralMOSBuffer + MOV R2, #?GeneralMOSBuffer + SWI XOS_ConvertInteger4 + SWI XOS_Write0 + SWI XOS_WriteS + = "MB", 10,13, 10, 0 ; title complete + ALIGN + | + MOV R0, R0, LSR #10 ; /1024 + LDR R1, =GeneralMOSBuffer + MOV R2, #?GeneralMOSBuffer + SWI XOS_ConvertInteger4 + SWI XOS_Write0 + SWI XOS_WriteS + = "K", 10,13, 10, 0 ; title complete + ALIGN + ] + MOV r0, #0 ; Set DomainId to 0 every reset + STR r0, [r0, #DomainId] ; before calling anyone + +; issue reset service call + + MOV R1, #Service_Reset + SWI XOS_ServiceCall + +; now set up the default FIQ owner + + MOV R1, #Service_ClaimFIQ + SWI XOS_ServiceCall + + MOV R1, #Service_ReleaseFIQ + SWI XOS_ServiceCall + + MOV R0, #FSControl_Shut ; Open files get closed at reset + SWI XOS_FSControl + + BL PostInit + + MOV r0, #&FD ; read last reset type (again!) + MOV r1, #0 + MOV r2, #&FF + SWI XOS_Byte + CMP r1, #SoftReset ; a softie? + SWINE XOS_WriteI+7 ; go beep! Yaay! + + CMP r1, #PowerOnReset + BNE %FT75 + + [ CheckProtectionLink + LDR r1, =IOMD_MonitorType ; check link bit again + LDRB r1, [r1] ; no need to preload bus, since should + TST r1, #IOMD_ProtectionLinkBit ; be still there from earlier + BEQ %FT75 ; zero => protected + ] + + +; if any monitor key pressed, reconfigure, otherwise hang around for a bit +; till keys get a chance to come in again after being reset for the umpteenth +; time by yet another keyboard handler! SKS 07-Jun-88 + + MOV r3, #0 + LDR r3, [r3, #MetroGnome] + ADD r3, r3, #10 ; Hang about for a little while + +KeypadStar_key * -92 + +HorologicalDelayLoop1 + MOV r0, #&79 ; scan keyboard + MOV r1, #&FF ; starting at (&FF + 1) AND &FF +60 + ADD r1, r1, #1 + AND r1, r1, #&FF + SWI XOS_Byte + TEQ r1, #&FF ; if no key down + BEQ %FT70 ; then check if we've run out of time + + ADR r2, MonitorKeypadTable +62 + LDRB r14, [r2], #2 ; search for key in table + TEQ r14, #&FF + BEQ %FT70 + TEQ r1, r14 + BNE %BT62 + LDRB r3, [r2, #-1] ; get corresponding CMOS bits + MOV r0, #ReadCMOS + MOV r1, #VduCMOS + SWI XOS_Byte + BIC r2, r2, #MonitorTypeBits + ORR r2, r2, r3 + MOV r0, #WriteCMOS + SWI XOS_Byte + + TEQ r3, #MonitorTypeAuto ; if we're setting monitortype auto + BNE %FT64 + ADRL r0, ModeCMOSTable +8 ; then configure mode auto + LDR r2, [r0, #-8] ; (load auto value) + BL WriteMultiField + ADRL r0, SyncCMOSTable +8 ; and configure sync auto + LDR r2, [r0, #-8] ; (load auto value) + BL WriteMultiField + +64 + BL InitialiseMode + [ International + SWI XOS_WriteI+10 + BLVC WriteS_Translated + = "MonType:Monitor type reconfigured.",10,13,10,0 + ALIGN + | + SWI XOS_WriteS + = 10,"Monitor type reconfigured.",10,13,10,0 + ALIGN + ] + B %FT75 + +BranchThroughZeroInstruction2 + [ ProcessorVectors + LDR PC, .+ProcVec_Branch0 + | + B .+(RESET1-0) + ] + +MonitorKeypadTable ; internal key number, CMOS bits + = 106, MonitorType0 + = 107, MonitorType1 + = 124, MonitorType2 + = 108, MonitorType3 + = 122, MonitorType4 + = 123, MonitorType5 + = 26, MonitorType6 + = 27, MonitorType7 + = 42, MonitorType8 + = 43, MonitorType9 + = 76, MonitorTypeAuto ; keypad dot + = &FF + ALIGN + [ International +MessageFileName DCB "Resources:$.Resources.Kernel.Messages",0 + ALIGN + ] + +70 + MOV r14, #0 + LDR r14, [r14, #MetroGnome] + CMP r14, r3 + BLO HorologicalDelayLoop1 +75 + + +; Deal with SHIFT pressed/SHIFT-BREAK configured: +; do appropriate FSControl if wanted + + Pull "R0" ; first check kbd there + + CMP R0, #0 + BEQ AutoBootCosNoKbd + + MOV R0, #&FF + MOV R1, #0 + MOV R2, #&FF ; read shifty state + SWI XOS_Byte + AND R0, R1, #8 ; picka da bit + EOR R0, R0, #8 ; invert sense + Pull "R1" + CMP R1, #0 + MOVNE R1, #8 + EORS R1, R1, R0 + BEQ %FT80 + +Hortoculture_Kicking + MOV R0, #FSControl_BootupFS + SWI XOS_FSControl + BVC %FT80 + + Push "r3,r4" + ADD r1, r0, #4 ; Set Boot$Error if it failed (Desktop will report it). + ADR r0, str_booterror + MOV r2, #1024 ; Big enough that terminator will be reached. + MOV r3, #0 + MOV r4, #VarType_String + SWI XOS_SetVarVal + SUBVS r0, r1, #4 ; If setting Boot$Error failed then report original error as before. + BLVS PrintError + SWIVS XOS_NewLine + Pull "r3,r4" +80 +; if either * pressed, drop into * prompt, otherwise hang around for a bit +; till keys get a chance to come in again after being reset for the umpteenth +; time by yet another keyboard handler! SKS 01-Jun-88 + + MOV r3, #0 + LDR r3, [r3, #MetroGnome] + ADD r3, r3, #10 ; Hang about for a little while + +HorologicalDelayLoop2 + MOV r1, #KeypadStar_key :AND: &FF + BL IsKeyPressedAtReset + BEQ DoStartSuper ; EQ -> start up supervisor + + MOV r0, #0 + LDR r0, [r0, #MetroGnome] + CMP r0, r3 + BLO HorologicalDelayLoop2 + + +; Start configured language module if keypad-* wasn't pressed + + MOV R0, #ReadCMOS + MOV R1, #LanguageCMOS + SWI XOS_Byte + + MOV R0, #ModHandReason_GetNames + SUB R1, R2, #1 + MOV R2, #0 ; preferred incarnation + SWI XOS_Module + ADRVSL R3, UtilityMod + LDR R2, [R3, #Module_Title] + CMP R2, #0 + ADDNE R1, R3, R2 +DoStartSuper + ADREQL R1, UtilModTitle ; ALWAYS enter via SWI: sets CAO etc. + MOV R0, #ModHandReason_Enter + ADRL R2, crstring ; no environment + SWI XOS_Module + CMP r0, r0 ; set EQ if failed to enter config.lang + B DoStartSuper ; -> force Super entry + + +str_booterror DCB "Boot$Error",0 + ALIGN + + +AutoBootCosNoKbd + [ International + SWI XOS_WriteI+7 + BLVC WriteS_Translated + = "NoKbd:No keyboard present - autobooting", 10,13,0 + ALIGN + | + SWI XOS_WriteS + = 7, "No keyboard present - autobooting", 10,13,0 + ALIGN + ] + B Hortoculture_Kicking + + +RealIRQHandler + [ ProcessorVectors + LDR PC, .-&18+ProcVec_IRQ + | + B Initial_IRQ_Code+.-&18 + ] + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r1 = INKEY -ve key code to look for + +; Out EQ: key pressed +; NE: key not pressed + +IsKeyPressedAtReset ENTRY "r0-r2" + + MOV r0, #129 + MOV r2, #&FF + SWI XOS_Byte + TEQ r1, #&FF + TEQEQ r2, #&FF + EXIT + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + [ AddTubeBashers +TubeDumpR0 ROUT + Push "R1, R2, lr" + ADR lr, HexTable + TubeChar r0, r1, "MOV r1, #"" """ + MOV R1, #7 +01 MOV R0, R0, ROR #28 + AND R2, R0, #&F + TubeChar R0, R1, "LDRB R1, [lr, R2]" + SUBS R1, R1, #1 + BPL %BT01 + TubeChar r0, r1, "MOV r1, #"" """ + Pull "R1, R2, PC", ,^ + +TubeNewl + TubeChar R0, R1, "MOV R1, #10" + TubeChar R0, R1, "MOV R1, #13" + MOVS pc, lr + +HexTable = "0123456789ABCDEF" + + ] + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + END diff --git a/s/Oscli b/s/Oscli new file mode 100644 index 0000000000000000000000000000000000000000..0159cbfcb74aa1001c75debaa9c57961a8572a6b --- /dev/null +++ b/s/Oscli @@ -0,0 +1,1322 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + TTL => Oscli - main Oscli code and system commands. + + GBLL redirectinkey +redirectinkey SETL True + + MACRO +$l CheckUID $reg, $tmp +$l MOV $tmp, #0 + LDR $tmp, [$tmp, #OscliCBbotUID] + CMP $reg, $tmp + MEND +; exits with HI if buffer OK. + +;****************************************************************************** +; redirection utility routines + +; In: R10 points at filename, V clear +; R1 is type + +; Out: R0, R1, R12 corrupted, redirection done, flags preserved (or V set) + +doredirect ROUT + + Push "R1, R2, lr" +60 LDRB R0, [R10], #1 + CMP R0, #" " + BEQ %BT60 + MOV R2, R1 + LDR R1, =RedirectBuff +61 CMP R0, #" " ; we know it's terminated by space + STRNEB R0, [R1], #1 + LDRNEB R0, [R10], #1 + BNE %BT61 + SUB R10, R10, #1 + MOV R0, #13 + STRB R0, [R1] + LDR R1, =RedirectBuff + MOV R0, #0 + CMP R2, #&40 + LDREQB R1, [R0, #RedirectInHandle] + LDRNEB R1, [R0, #RedirectOutHandle] + STREQB R0, [R0, #RedirectInHandle] + STRNEB R0, [R0, #RedirectOutHandle] + CMP R1, #0 + SWINE XOS_Find ; close any previous File + MOV R12, R1 ; don't really care if handle was invalid + LDR R1, =RedirectBuff + ORR R0, R2, #open_mustopen + open_nodir + SWI XOS_Find ; Open the File + BVS abort_redirect ; bad name etc + CMP R0, #0 ; worked? + BEQ %FT63 + CMP R2, #&40 + MOV R1, #0 + STREQB R0, [R1, #RedirectInHandle] + [ redirectinkey + BEQ %FT00 + | + MOVEQ R0, #RdchV + ADREQL R1, RedirectRdch + ] + STRNEB R0, [R1, #RedirectOutHandle] + MOVNE R0, #WrchV + ADRNEL R1, RedirectWrch + CMP R12, #0 ; Ensure only vectored the once + MOVEQ R2, #0 + SWIEQ XOS_Claim + BVS abort_redirect ; Claim will leave "Sysheap full" msg. +00 + LDR R2, [stack] + CMP R2, #&C0 + GRABS "R1, R2, PC", NE + +; >> file, so move to EOF + + MOV R1, #0 + LDRB R1, [R1, #RedirectOutHandle] + MOV R0, #2 ; read extent + SWI XOS_Args + MOVVC R0, #1 ; write ptr + SWIVC XOS_Args + GRABS "R1, R2, PC", VC + + B abort_redirect + + MakeErrorBlock RedirectFail + +63 ADR R0, ErrorBlock_RedirectFail + [ International + BL TranslateError + ] +abort_redirect ; current error set + Pull "R1, R2, lr" + ORRS PC, lr, #V_bit + + +ParseRDNSpec ROUT +; In : R11 points at string to test. +; Out : EQ/NE for "is it a rdnspec?". V always clear. +; If EQ : R11 points after filename +; R10 points at start of filename +; R1=&40 => redirect input, +; =&80 => redirect output, +; =&C0 => redirect & append output + MOV R1, #&40 +01 LDRB R10, [R11], #1 + CMP R10, #" " + BEQ %BT01 ; skip leading spaces + CMP R10, #"<" + BEQ %FT04 + CMP R10, #">" + MOVNE PC, lr + MOV R1, #&80 + LDRB R10, [R11], #1 + CMP R10, #">" + MOVEQ R1, #&C0 +04 LDREQB R10, [R11], #1 + CMP R10, #" " + MOVNE PC, lr + SUB R10, R11, #1 ; filename start ptr + Push "R0" +02 LDRB R0, [R11], #1 + CMP R0, #" " + BGT %BT02 + Pull "R0" + MOV PC, lr ; it's EQ if had space at end. + + MakeErrorBlock StackFull + +OscliStackFull + ADR R0, ErrorBlock_StackFull + [ International + BL TranslateError + ] + Pull "lr" + ORRS PC, lr, #V_bit + +;****************************************************************************** +; Main OSCLI code + +VecOsCli ROUT + +; first check for rheum on the stack. +; Oscli will have pushed 5 registers when it calls module code : let's +; guarantee 256 bytes (=64 registers) for the module code +; so check half a K left, leaving 236 bytes for any interrupt processing. + + CheckSpaceOnStack 512, OscliStackFull, R10 + + Push "R0-R2" ; lr on stack from caller + +; first skip * and space + +01 LDRB R10, [R0], #1 + CMP R10, #" " + CMPNE R10, #"*" + BEQ %BT01 + CMP R10, #"%" + LDREQB R10, [R0] ; fixed 29-Mar-89; was LDREQ + CMP R10, #13 + CMPNE R10, #10 + CMPNE R10, #0 + CMPNE R10, #"|" + GRABS "R0-R2, PC", EQ ; V clear return + +; now check for redirection. +; Redirection setter ::= "{ " [ >= 1 Redirection spec] "}" +; where +; Redirection spec ::= "> "filename" " | "< "filename" " | ">> "filename" " +; Also check terminator in first 256 chars. + SUB R11, R0, #1 + MOV R1, #0 + ADD R2, R0, #256 +02 LDRB R10, [R11], #1 + CMP R11, R2 + BEQ OscliLineTooLong + CMP R10, #13 + CMPNE R10, #10 + CMPNE R10, #0 + BEQ %FT58 + CMP R10, #"""" + EOREQ R1, R1, R10 + CMP R10, #"{" + CMPEQ R1, #0 + BNE %BT02 + Push "R11" + LDRB R10, [R11], #1 + CMP R10, #" " + BLEQ ParseRDNSpec + Pull "R11", NE + BNE %BT02 +60 BL ParseRDNSpec + BEQ %BT60 + CMP R10, #"}" + Pull "R11" + BNE %BT02 +; R11 points 1 char after { + Push "R5, R6" + BL GetOscliBuffer ; get a buffer + SUB R0, R0, #1 + MOV R2, #0 +50 LDRB R10, [R0], #1 + CMP R0, R11 + STRNEB R10, [R5, R2] + ADDNE R2, R2, #1 + BNE %BT50 + +61 BL ParseRDNSpec + BLEQ doredirect + BVS RedirectionError ; close any redirection set up + BEQ %BT61 + +53 LDRB R10, [R11], #1 + CMP R10, #" " + BEQ %BT53 + SUB R11, R11, #1 + +52 LDRB R10, [R11], #1 + STRB R10, [R5, R2] + ADD R2, R2, #1 + CMP R2, #OscliBuffSize + BEQ %FT51 + CMP R10, #13 + CMPNE R10, #10 + CMPNE R10, #0 + BNE %BT52 + MOV R2, R6 ; buffer UID + ADD R0, R5, #1 ; point after 1st char. + Pull "R5, R6" + B %FT03 + +51 MOV R2, R6 ; longer than 256 + ADR R0, ErrorBlock_OscliLongLine + [ International + BL TranslateError + ] +RedirectionError + BL ReleaseBuff + BL OscliTidy ; shut down the redirection just done. + Pull "R5, R6" +OscliFailure + STR R0, [stack] + Pull "R0-R2, lr" + ORRS PC, lr, #V_bit + +OscliLineTooLong + ADR R0, ErrorBlock_OscliLongLine + [ International + BL TranslateError + ] + B OscliFailure + MakeErrorBlock OscliLongLine + +58 MOV R2, #-1 ; naff buffer UID. +; Redirection dealt with. R0 points after 1st ch command +03 + Push "R2" ; save buffer UID + +; now check for filing system name as prefix + Push "R3" + MOV R3, #0 ; j.i.c. fileswitch is dead!! + SUB R1, R0, #1 + MOV R0, #FSControl_StarMinus + SWI XOS_FSControl + +; here we have: +; V set if -nafffsname encountered +; VC: R2 = -1 if no fs name found +; R3 = 0 if no specials encountered + + BVS letmodprefatit + CMP R3, #0 + BEQ letmodprefatit + Pull "R3" + Push "R2" ; save "temp FS set" indicator + ADR R0, ErrorBlock_NoOscliSpecials + [ International + BL TranslateError + | + SETV + ] + B OscliExit + MakeErrorBlock NoOscliSpecials + +letmodprefatit + Pull "R3" + Push "R2" ; save "temp FS set" indicator + BL CheckForModuleAsPrefix + BVS OscliExit + +; special char checks +pfssss LDRB R10, [R1], #1 + CMP R10, #" " + BEQ pfssss + SUB R0, R1, #1 + CMP R2, #-1 + RSBLT R11, R2, #0 + Push "R2",LT + BLT OnlyOneModuleWanted + + CMP R10, #"/" + BEQ %FT06 + +; see if skip macro expansion + CMP R10, #"%" + LDREQB R10, [R0], #1 + BEQ %FT05 + + CMP R10, #"." ; fudge . + BEQ %FT07 + +; try macro expansion : if find it, expand into a buffer. +; Also scan for parameters while expanding. +; R0 ptr to command, R10 first char. +; If success : Recursively call OSCLI for each line in expansion. + + Push "R0, R3-R6" + [ International + MOV R3,#0 + LDRB R6,[R3,#ErrorSemaphore] ; We are about to get lots of buffer overflow errors, + SUB R6,R6,#1 + STRB R6,[R3,#ErrorSemaphore] + ] + MOV R6, R0 + MOV R3, #:LEN: "Alias$" +31 SUB R3, R3, #:LEN: "Alias$" + MOV R2, #-1 ; negative length means just look for it. + ADR R0, AliasStr + SWI XOS_ReadVarVal + CMP R2, #0 ; V always set anyway + [ International + LDREQB R0,[R2,#ErrorSemaphore] + ADDEQ R0,R0,#1 + STREQB R0,[R2,#ErrorSemaphore] + ] + BEQ %FT10 + + ADD R3, R3, #:LEN: "Alias$" + +; match $R6 with $R3 + + MOV R1, #0 ; offset +32 LDRB R4, [R6, R1] + LDRB R5, [R3, R1] + CMP R4, #&80 ; in table ? + ADRCCL R2, Up_ItAndTerm_Check_Table + LDRCCB R4, [R2, R4] + CMP R4, #" " + CMPLE R5, #" " + BLE %FT33 + UpperCase R5, R2 + CMP R4, R5 + ADDEQ R1, R1, #1 + BEQ %BT32 + CMP R1, #0 + BEQ %BT31 ; failed + CMP R5, #" " + BLE %BT31 + CMP R4, #"." + BNE %BT31 + ADD R1, R1, #1 +33 +; success : copy name, read value + + [ International + MOV R4,#0 + LDRB R0,[R4,#ErrorSemaphore] + ADD R0,R0,#1 + STRB R0,[R4,#ErrorSemaphore] ; We can go back to translating errors. + ] + + SUB R3, R3, #:LEN: "Alias$" +99 LDR R0, =AliasExpansionBuffer + ADD R6, R6, R1 ; save arglist ptr + MOV R4, #0 +34 LDRB R5, [R3], #1 + STRB R5, [R0, R4] + ADD R4, R4, #1 + CMP R5, #0 + BNE %BT34 + MOV R1, R0 ; output buffer same as input! + MOV R2, #256 + MOV R3, #0 + MOV R4, #VarType_Expanded + SWI XOS_ReadVarVal + BVS AliasOscliTooLong + MOV R3, #13 + STRB R3, [R1, R2] + + MOV R3, R1 + MOV R0, R6 ; arglist + MOV R4, R2 ; no of chars got. + BL GetOscliBuffer ; gives buffer ptr in R5, ID in R6 + MOV R1, R5 + MOV R2, #OscliBuffSize + SWI XOS_SubstituteArgs + BVS AliasOscliTooLong + +; Whew! Now ready to recursively call OSCLI with all lines in the buffer. + MOV R0, R1 + ADD R2, R1, R2 +43 SWI XOS_CLI + BVS %FT46 + CheckUID R6, R1 ; check buffer still valid. + BLS FailInAlias +44 LDRB R1, [R0], #1 + CMP R1, #13 + CMPNE R1, #10 + CMPNE R1, #0 + BNE %BT44 + CMP R0, R2 + BLO %BT43 + MOV R2, R6 + BL ReleaseBuff ; release buffer, UID in R2 + Pull "R0, R3-R6" + CLRV + B OscliExit + + MakeErrorBlock OscliTooHard + +FailInAlias + CheckUID R2, R1 + BLGT ReleaseBuff + ADR R0, ErrorBlock_OscliTooHard + [ International + BL TranslateError + ] +46 STR R0, [stack] + Pull "R0, R3-R6" + SETV + B OscliExit + +AliasOscliTooLong + MOV R2, R6 ; buffer UID + BL ReleaseBuff + Pull "R0, R3-R6" + ADRL R0, ErrorBlock_OscliLongLine + [ International + BL TranslateError + | + SETV + ] + B OscliExit + + LTORG + +AliasStr = "Alias$*", 0 +AliasDot = "Alias$" +dotstring = ".", 0 + ALIGN + +10 ; Failed macro expansion. + Pull "R0, R3-R6" + +; try for system command first. +05 LDRB R1, [R0] ; quick check for . tho + CMP R1, #"." + BEQ PercentDot + + ADRL R1, SysCommsModule + MOV R2, #SCHCTab-SysCommsModule + TEQP PC, #C_bit :OR: SVC_mode ; carry set means sys module + BL ModCommsLookUp + BCS OscliExit + +; now try looking round the modules. + MOV R11, #Module_List + Push "R2" +74 LDR R2, [stack] + CMP R2, #0 + BMI OneModule_Failed + LDR R11, [R11, #Module_chain_Link] + CMP R11, #0 + BEQ %FT75 +OnlyOneModuleWanted + LDR R1, [R11, #Module_code_pointer] + LDR R2, [R1, #Module_HC_Table] + CMP R2, #0 + BEQ %BT74 + LDR R12, [R11, #Module_incarnation_list] ; preferred life + ADD R12, R12, #Incarnation_Workspace + TEQP PC, #SVC_mode ; clear C + BL ModCommsLookUp + BCC %BT74 + ADD stack, stack, #4 ; discard R2 + B OscliExit + +75 + ; not in a module : try for current filing system command + STR R0, [stack] ; pull R2, push R0 + MOV R0, #FSControl_ReadModuleBase + SWI XOS_FSControl + Pull "R0" + CMP R1, #0 + BEQ NoFSCommands ; no selected FS! + MOV R12, R2 ; module's workspace ptr + LDR R2, [R1, #Module_HC_Table] + CMP R2, #0 + BEQ SecondaryFSCTab + ORR R2, R2, #&80000000 ; FS command needed flag + TEQP PC, #SVC_mode ; clear C + BL ModCommsLookUp + BCC SecondaryFSCTab + B OscliExit + +SecondaryFSCTab + Push "R0" + MOV R0, #FSControl_ReadSecondaryModuleBase + SWI XOS_FSControl + Pull "R0" + MOVVS R1, #0 + CMP R1, #0 + BEQ NoFSCommands + MOV R12, R2 ; module's workspace ptr + LDR R2, [R1, #Module_HC_Table] + CMP R2, #0 + BEQ NoFSCommands + ORR R2, R2, #&80000000 ; FS command needed flag + TEQP PC, #SVC_mode ; clear C + BL ModCommsLookUp + BCC NoFSCommands + B OscliExit + +NoFSCommands + MOV R1, #Service_UKCommand + BL Issue_Service + CMP R1, #0 + BNE UKCNotClaimed + CMP R0, #0 ; any error? + SETV NE ; V clear if EQ + B OscliExit + +OneModule_Failed + ADD stack, stack, #4 + ADRL R0, ErrorBlock_BadCommand + [ International + BL TranslateError + | + SETV + ] + B OscliExit + +UKCNotClaimed + MOV R1, R0 +DoFSCV_Run + MOV R0, #FSControl_RUN +71 SWI XOS_FSControl +OscliExit + Pull "R2" + Push "R0, PC" + CMP R2, #0 ; -ve means no FS selected. + MOVGE R0, #FSControl_RestoreCurrent + SWIGE XOS_FSControl + Pull "R0, R1" + + Pull "R2" + CMP R2, #-1 + BEQ %FT80 + BL ReleaseBuff + BL RemoveOscliCharJobs ; shut down redirection +80 TST R1, #V_bit + STRNE R0, [stack] ; error pointer + Pull "R0-R2, lr" + BICEQS PC, lr, #V_bit + ORRS PC, lr, #V_bit + +06 ADD R1, R0, #1 ; */ so skip the /, do RUN reason code + B DoFSCV_Run + +07 + Push "R0, R3-R6" + MOV R6, R0 + ADR R0, AliasDot + MOV R3, #0 + MOV R2, #-1 ; negative length means just look for it. + SWI XOS_ReadVarVal + CMP R2, #0 ; V always set anyway + MOVNE R1, #1 ; index to step past . + BNE %BT99 + Pull "R0, R3-R6" +PercentDot ; entry for *%. + ADD R1, R0, #1 + MOV R0, #FSControl_CAT ; *., skip . + B %BT71 + +;*************************************************************************** + +; Routine to look through a module table for a command, and call it. +; Set up R12 yourself if needed. +; R0 points at command to find +; R1 points at module +; R2 offset of command table : top bit set for "want FS command" +; C set means allow messy matching, i.e. it's the system command table + +; Return C set if found and called, V flag from code called +; Might not return if module starts up as current object. + +ModCommsLookUp ROUT + Push "R0, R2-R10, lr" + MOV R4, #0 ; want all flags clear + TEQ R2, #0 ; don't corrupt C! + MOVMI R4, #FS_Command_Flag + BICMI R2, R2, #&80000000 + BL FindItem + Pull "R0, R2-R10, lr", CC + BICCCS PC, lr, #V_bit + C_bit + Push r4 ; save pointer in case needed for syntax mess + +; check number of arguments, error with syntaxmessage if naff. + + ADD R2, R2, R1 ; get R2 back to pointer. + ADD R0, R0, R3 ; point at terminator. +09 LDRB R4, [R0], #1 + CMP R4, #" " ; skip spaces. + BEQ %BT09 + MOV R3, R1 ; hang on to module ptr. + MOV R1, #0 ; no of parms. + MOV R7, #-1 ; flag for buffer got for GSTRANSing + + MOV R6, R0 + SUB R0, R0, #1 + +; Now we have : +; R0 -> commtail, ready for module +; R1 number of parameters +; R2 -> info block for command +; R3 -> module +; R4 current char +; R5 execute offset +; R6 working commtail ptr +; R7 -1 or buffer UID +; R8 becomes gstrans map +; R9 may be a workin gstrans map copy +; R10 may be a working buffer ptr for copying + + LDRB R8, [R2, #5] ; get gstrans_map + MOVS R9, R8 + BEQ nogstransingta + + Push "R2, R5, R6" + BL GetOscliBuffer + MOV R0, R5 ; buffer ptr + MOV R7, R6 ; buffer UID + MOV R10, #0 ; buffer offset for copying + Pull "R2, R5, R6" + +nogstransingta + CMP R4, #13 ; check for more to scan + CMPNE R4, #10 + CMPNE R4, #0 + BEQ %FT12 + + MOVS R9, R9, LSR #1 + BCC stripnextparm + + ; gstrans next ; scan afterwards for naffchars + Push "R0-R2" + + ADD R1, R0, R10 ; buffer pointer + RSB R2, R10, #OscliBuffSize ; room left + ORR R2, R2, #GS_Spc_term + + SUB R0, R6, #1 ; parameter pointer + SWI XOS_GSTrans + BCS buffer_overflowed_oh_bother + BVS bad_string + + CMP R2, #0 + BEQ preversion_detectified ; empty expansions are naff + ADD R10, R10, R2 +nastycharscan + LDRB R2, [R1], #1 + CMP R2, #&7F + CMPNE R2, #" " + BLE preversion_detectified + CMP R1, R10 + BLT nastycharscan + + MOV R6, R0 + Pull "R0-R2" + B next_parameter + +preversion_detectified + ADR R0, ErrorBlock_BadParmString + [ International + BL TranslateError + ] + B pgstcomm +buffer_overflowed_oh_bother + ADRL R0, ErrorBlock_OscliLongLine + [ International + BL TranslateError + ] + B pgstcomm +bad_string + ADR R0, ErrorBlock_BadParmString + [ International + BL TranslateError + ] +pgstcomm + STR R0, [stack] + MOV R2, R7 + BL ReleaseBuff + Pull "R0-R2, r4" + B unpleasantness_in_ModCommsLookUp + + MakeErrorBlock BadParmString + +AddCharForGSTP + CMP R8, #0 + MOVEQ PC, lr + CMP R10, #OscliBuffSize + STRLTB R4, [R0, R10] + ADDLT R10, R10, #1 + MOVLT PC, lr + Push "R0-R2" + B buffer_overflowed_oh_bother + +stripnextparm + Push "R11" + CMP R4, #"""" + MOVEQ R11, #&80000000 + ORREQ R1, R1, R11 + MOVNE R11, #0 +stripnextchar + BL AddCharForGSTP + LDRB R4, [R6], #1 + CMP R4, #"""" + EOREQ R1, R1, R11 + CMP R4, #" " + TSTEQ R1, #&80000000 + BEQ parmfinished + CMP R4, #13 + CMPNE R4, #10 + CMPNE R4, #0 + BNE stripnextchar +parmfinished + BIC R1, R1, #&80000000 + Pull "R11" + +next_parameter + MOV R4, #" " + BL AddCharForGSTP + SUB R6, R6, #1 + +30 LDRB R4, [R6], #1 + CMP R4, #" " + BEQ %BT30 + + ADD R1, R1, #1 + B nogstransingta ; next parameter + + ; parameters counted : check number + +12 BL AddCharForGSTP ; terminate the copy + + BIC R1, R1, #&80000000 + LDR R4, [R2, #4] + MOV R6, R4, LSR #16 ; max no parms + AND R6, R6, #&FF + AND R4, R4, #&FF ; min no parms + CMP R1, R4 + CMPGE R6, R1 + BLT %FT11 + + ; checks finished : call the man. + + Push "R7" ; j.i.c. module writer can't read + + MOV lr, PC ; make link + ADD PC, R3, R5 ; and call + + Pull "R2, r4" + BL ReleaseBuff ; discard buffer got for GSTRANSing + + STRVS R0, [stack] + Pull "R0, R2-R10, lr" + + ORR lr, lr, #C_bit + BICVCS PC, lr, #V_bit + ORRS PC, lr, #V_bit + +; Return a command syntax error. First issue Service_SyntaxError for translation +11 + [ International ; Internationalize syntax error messages + Pull "r4" ; r4-> command string in module + MOV r1, #Service_SyntaxError ; r2->info block for command, r3->module + BL Issue_Service ; Issue SyntaxError service for possible translation + CMP r1, #0 ; Service claimed? + BEQ unpleasantness_in_ModCommsLookUp ; Yes then r0-> error block + + Push "r4" ; Save -> command string + ] + + LDR r4, [r2, #4] + MOV r7, r2 + BL GetOscliBuffer ; get space for error + MOV R2, #ErrorNumber_BadNoParms + STR R2, [R5] + LDR R2, [R7, #8] + CMP R2, #0 + ADREQ R0, %FT13 ; default error message + ADDNE R0, R2, R3 ; point at message + ORREQ r4, r4, #International_Help + TST r4, #International_Help + ADREQL r4, MOSdictionary + BEQ %FT37 + MOV r7, r0 + SUB sp, sp, #16 + LDR r2, [r3, #-4] + LDR r0, [r3, #Module_MsgFile] + TST r0, #12,2 + CMPEQ r0, #1 + CMPCS r2, r0 + MOVLS r0, #0 + BLS %FT33 + ADD r1, r3, r0 + MOV r2, #0 + MOV r0, sp + SWI XMessageTrans_OpenFile + MOVVS r0, #0 +33 MOV r1, r7 + MOV r7, r0 + MOV r2, #0 + SWI XMessageTrans_Lookup + ADDVS r2, r0, #4 + SWI XMessageTrans_Dictionary + ADDVS r2, r0, #4 + MOV r4, r0 + MOV r0, r2 + LDR r2, [sp, #16] + ADD r1, r5, #4 + BL expandsyntaxmessage + MOVS r0, r7 + SWINE XMessageTrans_CloseFile + ADD sp, sp, #16 + Pull r2 + B %FT39 +37 + Pull r2 + ADD r1, r5, #4 + BL expandsyntaxmessage +39 + MOV r0, r5 + +unpleasantness_in_ModCommsLookUp + STR R0, [stack] + Pull "R0, R2-R10, lr" + ORRS PC, lr, #V_bit+C_bit +13 + DCB "NumParm", 0 + + ALIGN + +expandsyntaxmessage + LDRB R3, [R0], #1 + CMP r3, #TokenEscapeChar + BEQ esm_tok + STRB R3, [R1], #1 + CMP R3, #0 + BNE expandsyntaxmessage + SUB r1, r1, #1 + MOV pc, lr + +esm_tok LDRB r3, [r0], #1 + Push "r0, lr" + CMP r3, #0 + MOVEQ r0, r2 + BEQ esm001 + MOV r0, r4 +esmlp SUBS r3, r3, #1 + LDRNEB r14, [r0] ; ECN: Use R14 instead of R4 as using R4 corrupts + ADDNE r0, r0, r14 ; the dictionary pointer thus disallowing recusive tokens + BNE esmlp + ADD r0, r0, #1 +esm001 BL expandsyntaxmessage + Pull "r0, lr" + B expandsyntaxmessage + +;--------------------------------------------------------------------------- +; routine to just find a keyword in a table that has the flags specified. +; R0 points at command to find +; R1 points at module +; R2 offset of command table +; R4 word to EOR with flags : demand 0 result for match +; C set means allow messy matching, i.e. it's the system command table +; Uses R2-R5 + +; Return C set if found : R5 is execute offset, R3 length of string +; R2 is offset of execute offset of field found +; r4 is command pointer + +FindItem ROUT + Push "R4, R6" + ADD R2, R2, R1 + LDRB R4, [R2] + CMP R4, #0 + BEQ FindItem_EOTab +05 MOV R3, #0 ; offset +01 LDRB R4, [R0, R3] + LDRB R5, [R2, r3] + CMP R4, #&80 ; in table ? + ADRCC R6, Up_ItAndTerm_Check_Table + LDRCCB R4, [R6, R4] + CMP R4, #32 + CMPLE R5, #32 + BLE %FT04 ; matched, and we're at the terminator + UpperCase R5, R6 + CMP R4, R5 + ADDEQ R3, R3, #1 + BEQ %BT01 + CMP R4, #"." ; success if abbreviation + BEQ %FT02 + TST lr, #C_bit + BEQ %FT07 ; nomatch + CMP R5, #32 + BGT %FT07 + CMP R4, #"A" + RSBGES R6, R4, #"Z" + BLT %FT04 ; matched, at terminator +07 LDRB R5, [R2], #1 + CMP R5, #32 + BGT %BT07 ; skip to terminator + ADD R2, R2, #3 + BIC R2, R2, #3 ; ALIGN +06 ADD R2, R2, #16 ; !!! DEPENDANT ON TABLE FORMAT!!! + LDRB R5, [R2] + CMP R5, #0 + BNE %BT05 +FindItem_EOTab + Pull "R4, R6" + BICS PC, lr, #C_bit ; back with not found. + +Up_ItAndTerm_Check_Table +; Table to uppercase and test for terminators for passed * commands +; 0 1 2 3 4 5 6 7 8 9 A B C D E F + = 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ; 0 + = 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ; 1 + = 0 , "!", 0 , "#" , 0, 0, 0, "'", "(", ")", "*" , "+", 0 , "-", ".", "/" ; 2 + = "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", 0, ";", 0 , "=", 0 , "?" ; 3 + = "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O" ; 4 + = "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", 0, "]", 0, "_" ; 5 + = "`", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O" ; 6 + = "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "{", 0 , "}", "~", 0 ; 7 + +; WHILE . < Up_ItAndTerm_Check_Table+256 ; top bit stuff done by CMP #&80 +; = . - Up_ItAndTerm_Check_Table +; WEND ; entry for chars > 127 = char + +02 CMP R5, #32 ; only success if $R2 not terminated. + BLE %BT07 + ADD R3, R3, #1 ; skip . +04 MOV r6, r2 + ADD r2, r2, r3 +08 LDRB R5, [R2], #1 + CMP R5, #0 + BNE %BT08 ; demand NULL terminator + ADD R2, R2, #3 + BIC R2, R2, #3 ; ALIGN + LDR R5, [R2, #4] ; get information word + + AND R5, R5, #&C0000000 :AND::NOT:Help_Is_Code_Flag + ; clear param numbers/low flags. + LDR R4, [stack] + EORS R5, R5, R4 + BNE %BT06 ; flags don't match + + LDR R5, [R2] ; get Execute offset + CMP R5, #0 + BEQ %BT06 ; not a command + STR r6, [stack] ; return r4 + Pull "R4, R6" + SUB R2, R2, R1 ; get back to offset. + ORRS PC, lr, #C_bit + +;**************************************************************************** +; variegated routines +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +OscliInit +; circular buffer initialisation : +; botUID := topUID := 0 ; currend := circbuffstart +; Redirection handles := 0 + MOV R0, #0 + STR R0, [R0, #OscliCBbotUID] + STR R0, [R0, #OscliCBtopUID] + LDR R1, =OscliCircBuffStart + STR R1, [R0, #OscliCBcurrend] + STRB R0, [R0, #RedirectInHandle] + STRB R0, [R0, #RedirectOutHandle] + MOV PC, R14 + +; buffer is valid if botUID < UID + + +; GetOscliBuffer used in module handler to get error buffers - saves workspace! + +GetOscliBuffer ROUT + ; return ptr in R5 to next buffer in Oscli's circular job + ; UID in R6 + ; corrupts R2 + +; currend +:= 256 + MOV R2, #0 + LDR R5, [R2, #OscliCBcurrend] + ADD R5, R5, #OscliBuffSize + +; IF currend >= circbufflimit +; THEN currend := circbuffstart + LDR R6, =OscliCircBuffLimit + CMP R5, R6 + LDRHS R5, =OscliCircBuffStart + STR R5, [R2, #OscliCBcurrend] + +; topUID +:= 1 + LDR R6, [R2, #OscliCBtopUID] + ADD R6, R6, #1 + STR R6, [R2, #OscliCBtopUID] +; IF topUID > botUID + noBuffers +; THEN botUID +:= 1 + LDR R5, [R2, #OscliCBbotUID] + SUB R2, R6, R5 + CMP R2, #OscliNoBuffs + MOV R2, #0 + ADDGE R5, R5, #1 + STRGE R5, [R2, #OscliCBbotUID] + +; RETURN currend, topUID + LDR R5, [R2, #OscliCBcurrend] + MOV PC, lr + + +ReleaseBuff ; take UID in R2, check whether can step back topUID + Push "R1-R4" + MOV R1, #0 + LDR R3, [R1, #OscliCBtopUID] + LDR R4, [R1, #OscliCBbotUID] +; IF UID = topUID AND topUID <> botUID + CMP R3, R4 + Pull "R1-R4",EQ + MOVEQS PC, lr + CMP R2, R3 + Pull "R1-R4",NE + MOVNES PC, lr +; THEN $( +; topUID -:= 1 + SUB R3, R3, #1 + STR R3, [R1, #OscliCBtopUID] + +; IF currend = circbuffstart THEN currend := circbufflimit + LDR R3, [R1, #OscliCBcurrend] + LDR R4, =OscliCircBuffStart + CMP R3, R4 + LDREQ R3, =OscliCircBuffLimit +; currend -:= 256 + SUB R3, R3, #OscliBuffSize + STR R3, [R1, #OscliCBcurrend] + Pull "R1-R4" + MOVS PC, lr + + LTORG ; needed now not at top level + +OscliRestoreFS + Push "R0, lr" + MOV R0, #FSControl_RestoreCurrent + SWI XOS_FSControl + Pull "R0, PC" + +OscliTidy ROUT ; shut down redirection, restore permanent FS + Push "lr" + BL RemoveOscliCharJobs + BL OscliRestoreFS + Pull "PC" + +RemoveOscliCharJobs ROUT + Push "R0-R2, lr" + MOV R0, #0 + LDRB R1, [R0, #RedirectInHandle] + CMP R1, #0 + STRNEB R0, [R0, #RedirectInHandle] + SWINE XOS_Find + MOV R0, #0 ; May have got error (discarded) + LDRB R1, [R0, #RedirectOutHandle] + CMP R1, #0 + STRNEB R0, [R0, #RedirectOutHandle] + SWINE XOS_Find + MOV R2, #0 + [ :LNOT: redirectinkey + MOV R0, #RdchV + ADR R1, RedirectRdch + SWI XOS_Release + ] + MOV R0, #WrchV + ADR R1, RedirectWrch + SWI XOS_Release + Pull "R0-R2, PC",,^ + + [ :LNOT: redirectinkey +RedirectRdch ROUT + Push "R1" + MOV R0, #0 + LDRB R1, [R0, #ESC_Status] + TST R1, #1:SHL:6 + BNE %FT01 + LDRB R1, [R0, #RedirectInHandle] + SWI XOS_BGet + BVS RedirectError + Pull "R1, lr", CC + BICCCS PC, lr, #C_bit +01 ADR R1, RedirectRdch + MOV R0, #RdchV + Push "R2" + MOV R2, #0 + SWI XOS_Release + Pull "R2" + MOV R0, #0 + LDRB R1, [R0, #RedirectInHandle] + STRB R0, [R0, #RedirectInHandle] + SWI XOS_Find + Pull "R1, lr" + BICEQS PC, lr, #C_bit ; EQ/NE still Escape state! + ORRNES PC, lr, #C_bit + ] + +RedirectWrch ROUT + Push "R1" + MOV R1, #0 + LDRB R1, [R1, #RedirectOutHandle] + SWI XOS_BPut + Pull "R1, pc", VC, ^ ; VClear in stacked pc/psr + +RedirectError + BL RemoveOscliCharJobs + Pull "R1, lr" + ORRS PC, lr, #V_bit + +; ************************************************************************** +; +; SWI OS_ChangeRedirection - Read/write redirection handles +; +; in: R0 = new input handle (0 => not redirected, -1 => leave alone) +; R1 = new output handle (0 => not redirected, -1 => leave alone) +; +; out: R0 = old input handle (0 => not redirected) +; R1 = old output handle (0 => not redirected) +; + +ChangeRedirection ROUT + MOV R12, #0 + LDRB R10, [R12, #RedirectInHandle] + LDRB R11, [R12, #RedirectOutHandle] + +; do input handle + + CMP R0, #&100 ; if out of range then just read + BCS %FT20 + + STRB R0, [R12, #RedirectInHandle] + + [ :LNOT: redirectinkey + CMP R0, #1 ; CS <=> (R0 non-zero) + TEQ R10, #0 ; NE <=> (R10 non-zero) + BHI %FT20 ; [both non-zero, skip] + + BCS %FT10 ; [just R0 non-zero, so claim] + BEQ %FT20 ; [both zero, skip] + +; R10 non-zero, R0 zero, so release vector + + Push "R0-R2, lr" ; set up registers for claim or release + MOV R0, #RdchV + ADR R1, RedirectRdch + MOV R2, #0 + SWI XOS_Release + STRVS R0, [sp, #0*4] + Pull "R0-R2, lr" + ORRVS lr, lr, #V_bit + ExitSWIHandler VS + B %FT20 + +; R10 zero, R0 non-zero, so claim vector + +10 + Push "R0-R2, lr" + MOV R0, #RdchV + ADR R1, RedirectRdch + MOV R2, #0 + SWI XOS_Claim + STRVS R0, [sp, #0*4] + Pull "R0-R2, lr" + ORRVS lr, lr, #V_bit + ExitSWIHandler VS + ] + +20 + +; do output handle + + CMP R1, #&100 ; if out of range then just read + BCS %FT40 + + STRB R1, [R12, #RedirectOutHandle] + CMP R1, #1 ; CS <=> (R1 non-zero) + TEQ R11, #0 ; NE <=> (R11 non-zero) + BHI %FT40 ; [both non-zero, skip] + + BCS %FT30 ; [just R1 non-zero, so claim] + BEQ %FT40 ; [both zero, skip] + +; R11 non-zero, R1 zero, so release vector + + Push "R0-R2, lr" ; set up registers for claim or release + MOV R0, #WrchV + ADR R1, RedirectWrch + MOV R2, #0 + SWI XOS_Release + STRVS R0, [sp, #0*4] + Pull "R0-R2, lr" + ORRVS lr, lr, #V_bit + ExitSWIHandler VS + B %FT40 + +; R11 zero, R1 non-zero, so claim vector + +30 + Push "R0-R2, lr" + MOV R0, #WrchV + ADR R1, RedirectWrch + MOV R2, #0 + SWI XOS_Claim + STRVS R0, [sp, #0*4] + Pull "R0-R2, lr" + ORRVS lr, lr, #V_bit + ExitSWIHandler VS + +40 + MOV R0, R10 + MOV R1, R11 + ExitSWIHandler + +;************************************************************************** +; Module selection +; Entered with V set if FileSwitch found a - : must get module or give error +; R2 >= 0 if filing system selected: do nothing +; R1 -> command prefix +; Out: R1 updated +; R2 = -1: no module +; R2 = -<larger>: R2 is selected module node +; Selected prefix also preferred + +CheckForModuleAsPrefix ROUT + Push "R0-R6, lr" + ADDVS R1, R1, #1 ; skip - + MOVVS R2, #"-" + BVS %FT02 + CMP R2, #-1 + BNE %FT01 + MOV R2, #":" ; terminators for lookup + +02 ADR R5, %FT10 + STR R1, [stack, #4] +03 LDRB R3, [R1], #1 + UpperCase R3, R4 + LDRB R4, [R5], #1 + CMP R3, R4 + BEQ %BT03 + CMP R4, #0 + LDRNE R1, [stack, #4] + SUBEQ R1, R1, #1 + MOV R6, R1 + LDR R1, =AliasExpansionBuffer +05 LDRB R3, [R6], #1 + CMP R3, #"." ; disallow abbreviations: they're confusing! + CMPNE R3, #" " + BLE %FT01 + CMP R3, R2 + STRNEB R3, [R1], #1 + BNE %BT05 + + MOV R3, #0 + STRB R3, [R1] + + MOV R0, #ModHandReason_LookupName + LDR R1, =AliasExpansionBuffer + SWI XOS_Module + BVS %FT01 + MOV R2, R1 + LDR R1, =AliasExpansionBuffer + MOV R0, #ModHandReason_MakePreferred + SWI XOS_Module + + MOV R0, #Module_List +04 LDR R0, [R0] + SUBS R2, R2, #1 + BPL %BT04 + MOV R1, R6 ; point at rest of command line. + RSB R2, R0, #0 + LDR R0, [stack], #12 ; Pull R0, skip R1,R2 + Pull "R3-R6, lr" + BICS PC, lr, #V_bit + +01 + Pull "R0-R6, PC",, ^ ; return fileswitch error if set +10 + = "MODULE#",0 + ALIGN + + END diff --git a/s/PMF/Buffer b/s/PMF/Buffer new file mode 100644 index 0000000000000000000000000000000000000000..a9e84696a51ed9a222a95357f3397207e6a292f3 --- /dev/null +++ b/s/PMF/Buffer @@ -0,0 +1,283 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.PMF.Buffer + +; ***************************************************************************** +; +; NewInsV - Routine for InsVec +; +; in: R0 = character to be inserted +; R1 = buffer number +; +; out: R0, R1, R3-R12 preserved +; R2 undefined +; C=1 <=> insertion failed +; + +NewInsV ROUT + CMP R1, #NBuffers + MOVCS PC, R14 ; not known about, pass it on + + Push "R3-R5" + MOV R3, R1, LSL #2 ; make index a word index + ADR R2, BuffParms + ADD R2, R2, R3, LSL #1 + LDMIA R2, {R2, R5} ; get address, size + + LDR R4, [R3, #BuffInPtrs] + STRB R0, [R2, R4] ; store byte anyway + ADD R4, R4, #1 ; increment pointer + + TEQ R4, R5 + MOVEQ R4, #0 + + LDR R5, [R3, #BuffOutPtrs] ; does inptr=outptr ? + CMP R4, R5 ; C=1 <=> R4 >= R5 + CMPHI R5, R4 ; C=1 <=> R4 = R5 + STRCC R4, [R3, #BuffInPtrs] ; if not, then safe + + BCC %FT10 ; no event, cos not full + TEQ R1, #(Buff_Mouse :SHL: 2), 2 ; clear carry and test if mouse + CMPNE R1, #Buff_RS423Out ; C=1 => output buffer + BCS %FT10 ; no event, cos not input + + MOV R2, R0 ; put character in 'Y' + MOV R0, #Event_InputFull ; event number + BL OSEVEN ; preserves R0-R3 + MOV R0, R2 ; restore character + SEC ; indicate buffer full +10 + Pull "R3-R5,PC" ; claim call + +; ***************************************************************************** +; +; NewRemV - Routine for RemVec +; +; in: R1 = buffer number (0 => keyboard buffer) +; V=0 => remove character +; V=1 => examine only +; +; out: R0 = R2 = next character for examine option or character removed +; R1, R3-R12 preserved +; C=1 <=> buffer was empty on entry +; + +NewRemV ROUT + BVS Examine + + CMP R1, #NBuffers + MOVCSS PC, R14 ; not known about, pass it on (preserving V) + + Push "R3-R5" + + MOV R3, R1, LSL #2 + LDR R4, [R3, #BuffOutPtrs] + LDR R5, [R3, #BuffInPtrs] + + CMP R4, R5 + CMPHI R5, R4 ; C=1 <=> (R4 = R5) ie empty + BCS RemVExit + + ADR R2, BuffParms + ADD R2, R2, R3, LSL #1 + LDMIA R2, {R2, R5} ; get address, size + + LDRB R2, [R2, R4] ; get next byte to be read out + MOV R0, R2 + ADD R4, R4, #1 ; increment out pointer + + TEQ R4, R5 ; wrap pointer if necessary + MOVEQ R4, #0 + + STR R4, [R3, #BuffOutPtrs] ; bugfix - was STRB + TEQ R1, #Buff_Mouse ; mouse => not output buffer + BEQ RemVExit ; exit (C=0) if not + CMP R1, #Buff_RS423Out ; C=1 => output buffer + BCC RemVExit ; exit (C=0) if not + + LDR R5, [R3, #BuffInPtrs] ; reload in-ptr + TEQ R4, R5 ; are ptrs same now ? + BNE RemVExitCLC ; no, then exit setting C=0 + + Push R0 ; save character + MOV R0, #Event_OutputEmpty ; output buffer empty event + BL OSEVEN ; generate event + Pull R0 ; restore character + +RemVExitCLC + CLC ; make sure carry clear + +RemVExit + Pull "R3-R5,PC" + +Examine + CMP R1, #NBuffers + MOVCSS PC, R14 ; not known about, pass it on (preserving V) + + Push "R3-R5" + + MOV R3, R1, LSL #2 + ADR R2, BuffParms + + LDR R2, [R2, R3, LSL #1] ; R2 -> buffer + + LDR R4, [R3, #BuffOutPtrs] + LDR R5, [R3, #BuffInPtrs] + + CMP R4, R5 + CMPHI R5, R4 ; C=1 <=> (R4 = R5) ie empty + + LDRCCB R2, [R2, R4] ; if ok then examine byte + MOVCC R0, R2 + + Pull "R3-R5,PC" + +; ***************************************************************************** +; +; NewCnpV - Routine for CnpVec +; +; in: R1 = buffer number (0 => keyboard) +; V=0, C=0 => count entries +; V=0, C=1 => count spaces +; V=1 => purge buffer +; +; out: R0 undefined +; (purge) R1-R12 preserved +; (count) R1,R2 = count, R3-R12 preserved +; + +NewCnpV + CMP R1, #NBuffers + MOVCSS PC, R14 ; not known about, pass it on (preserving V) + + Push "R3-R5" + + TEQP R14, #0 ; restore V and C + + MOV R3, R1, LSL #2 + + LDR R4, [R3, #BuffOutPtrs] + + STRVS R4, [R3, #BuffInPtrs] ; if purge, then make in=out + Pull "R3-R5,PC", VS ; and return + + LDR R5, [R3, #BuffInPtrs] + SUB R1, R5, R4 ; in - out (don't stamp on carry) + + ADR R5, BuffParms+4 + LDR R5, [R5, R3, LSL #1] ; get size + + TEQ R1, #0 ; don't stamp on carry + ADDMI R1, R1, R5 ; wrap number of chars if negative + + SUBCS R1, R5, R1 ; C=1 => convert to spaces + SUBCS R1, R1, #1 ; one fewer spaces than BuffSizes + + MOV R2, R1, LSR #8 ; make R2 = hi-byte + AND R1, R1, #&FF ; and R1 = lo-byte + + Pull "R3-R5,PC" + +; ***************************************************************************** + +BuffParms + & KeyBuff + & KeyBuffSize + + & RS423InBuff + & RS423InBuffSize + + & RS423OutBuff + & RS423OutBuffSize + + & PrintBuff + & PrintBuffSize + + & Sound0Buff + & Sound0BuffSize + + & Sound1Buff + & Sound1BuffSize + + & Sound2Buff + & Sound2BuffSize + + & Sound3Buff + & Sound3BuffSize + + & SpeechBuff + & SpeechBuffSize + + & MouseBuff + & MouseBuffSize + +; ***************************************************************************** +; +; DoInsertESC - Insert character into buffer, checking for escape +; +; in: R1 = buffer id +; R2 = character +; + +DoInsertESC + CMP R1, #2 ; if not keyboard or serial input + BCS INSERT ; then don't treat as special + + LDROSB R0, RS423mode ; Z => simulate keyboard + TST R0, R1 ; NZ => RS423 input and RS8Bit + BNE INSERT + + Push R14 + + LDROSB R0, ESCch ; escape character + TEQ R2, R0 ; if escape character + LDROSB R0, ESCaction, EQ + TEQEQ R0, #0 ; and FX229,0 + BNE CKESCY ; not escape or let it thru + +; ESCAPE detected + + LDROSB R0, ESCBREAK ; FX 200 + TST R0, #1 ; bit 0 set ? + BNE %FT10 ; escape ignored + + MOV R0, #Event_Escape + BL OSEVEN ; exits carry set if disabled + BCC %FT10 ; [event enabled, so don't do + ; normal escape action] + Push "R1, R12" + BL DoOsbyte7D ; generate escape condition + Pull "R1, R12" +10 + CLC ; character inserted OK + Pull PC + +CKESCY + MOV R0, #Event_CharInput + BL OSEVEN ; preserves R0-R2 + Pull R14 +INSERT + MOV R0, R2 +INSRT + Push "R10,R12,R14" + MOV R10, #INSV +GoVec + BL GoVec2 + Pull "R10,R12,PC" + +GoVec2 + CallAVector + + END diff --git a/s/PMF/Def b/s/PMF/Def new file mode 100644 index 0000000000000000000000000000000000000000..049ca858c90b06e1c537280f0ecee99080d7b046 --- /dev/null +++ b/s/PMF/Def @@ -0,0 +1,148 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.PMF.Def + MACRO + Protocol +; +; Protocol constants +; +; 4 bit codes for input commands +; +LEDON * &00 +LEDOFF * &10 +REQUEST * &20 +ACK * &30 +SPDDATA * &40 ;Bottom four bits are data to convert +RSTREQ * &80 ;Request for reset +; +; 4 bit input data types +; +; Requests +; +KBID * 0 +SPDRESET * 1 +MDATA * 2 ;New mouse position, even if it hasn't moved +; +; Acks +; +BYTE * 0 +SCAN * 1 +MOUSE * 2 +ALL * 3 +; +; data output +; +; Type d7 d6 d5 d4 d3 d2 d1 d0 number of bytes +; Reset 1 x x x x x x x 1 +; Key up 0 0 1 1 x x x x 2 (row then column) +; Key down 0 0 1 0 x x x x 2 (row then column) +; Mouse change 0 1 x x x x x x 2 (X, Y) +; SPD data 0 0 0 0 x x x x 8 +; KB Ids 0 0 0 1 x x x x 2 (low nibble then high nibble) +; +; The keyboard type +; +IDTYPE * &10 +KBTYPE * 0 ;This is keyboard 0 +; +; Key transitions +; +KEYDOWN * &20 +KEYUP * &30 +; +; Mouse transitions +; +MMOVED * &40 +; +; SPD converted data +; +SPDDONE * 0 +; +; Reset types +; +HRDRESET * &FF +RST1ACK * &FE +RST2ACK * &FD + +; New keyboard protocols + +; Keyboard -> ARM + +K1mdat * &00 ; 0xxx xxxx Mouse data from keyboard +K1kbid * &80 ; 10xx xxxx Keyboard ID from keyboard +K1kdda * &C0 ; 1100 xxxx Key down data +K1kuda * &D0 ; 1101 xxxx Key up data +K1pdat * &E0 ; 1110 xxxx SPD data from keyboard (won't happen) +K1rak2 * &FD ; 1111 1101 Reset acknowledge 2 +K1rak1 * &FE ; 1111 1110 Reset acknowledge 1 +K1hrst * &FF ; 1111 1111 Hard reset + +K1kbidmask * &3F ; 0011 1111 Valid bits in keyboard id + +K1notmousedata * &80 + +; ARM -> Keyboard + +; +; The IOC registers +; + ^ &04, R12 +KARTTx # 0 +KARTRx # 0 + + ^ &20, R12 +IRQStatusB # 4 +IRQReqB # 4 +IRQMaskB # 4 + + ^ &70, R12 +Timer3Low # 4 +Timer3High # 4 +Timer3Go # 4 +Timer3Latch # 4 + +; Register bits + +KARTRxBit * &80 +KARTTxBit * &40 +KARTIRQBits * KARTTxBit :OR: KARTRxBit + +K1leds * &00 ; 0000 0xxx Set LED states +K1rqid * &20 ; 0010 0000 Request keyboard id +K1prst * &21 ; 0010 0001 SPD reset +K1rqmp * &22 ; 0010 0010 Request mouse position +K1nack * &30 ; 0011 0000 Acknowledge (keys- mouse-) +K1sack * &31 ; 0011 0001 Acknowledge (keys+ mouse-) +K1mack * &32 ; 0011 0010 Acknowledge (keys- mouse+) +K1smak * &33 ; 0011 0011 Acknowledge (keys+ mouse+) +K1back * &3F ; 0011 1111 Byte acknowledge (between 2 data bytes) +K1rqpd * &40 ; 0100 xxxx Request SPD data conversion + +; Keyboard vector offsets + + ^ 0 + +KVKeyTran # 4 +KVKeyTranSize # 4 +KVInkeyTran # 4 +KVShiftingList # 4 +KVSpecialList # 4 +KVSpecialCodeTable # 4 +KVInit # 4 +KVPendingAltCode # 4 +KVPendingAltSpecial # 4 ; Used only internally + + MEND + END diff --git a/s/PMF/Internat b/s/PMF/Internat new file mode 100644 index 0000000000000000000000000000000000000000..24eb70526d8e2e993360df98327535bf4949f935 --- /dev/null +++ b/s/PMF/Internat @@ -0,0 +1,250 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > Internat + +The International module +======================== + +Author: Tim Dobson +Name: International +Version: 0.01 +Circulation: Acorn +History: + 0.01: 17-Mar-89 to 03-Apr-89: First draft. + +This document describes the International module version 1.13, as found in +RISC OS 2.00. It also describes the differences between this version and +version 1.05 (the version in Arthur 1.20). + +The International module allows the user to tailor his machine for use in +different countries by setting:- + + a) the mapping of keys to character codes (the *keyboard*), and + + b) the mapping from character codes to characters (the *alphabet*), or + + c) both mappings a) and b) at once (the *country*). + +This module, in conjunction with the MOS, controls the selection of these +mappings, but the interface allows the actual mappings to be implemented in +one or more separate relocatable modules, via the service mechanism. + +Explanation of terms +-------------------- + +Each country has a *country name* and an associated *country number*. + +Each alphabet has an *alphabet name* and an associated *alphabet number*. + +Each country has an associated alphabet, but a given alphabet may be +associated with more than one country. + +Each country also has an associated keyboard, but keyboards do not have their +own names or numbers; keyboards are specified by country name or country +number. + +Country numbers are in the range 0 to 99, alphabet numbers are in the +range 100 to 126. + +Modules can provide new country/alphabet names/numbers by responding to +various sub-reason codes of service call Service_International (&43). + +Operating system interface +-------------------------- + +The operating system maintains the following variables:- + +1) The current alphabet number, ie the alphabet number of the currently +selected alphabet. + +2) The current keyboard number, ie the country number of the currently +selected keyboard. + +3) The current country number, ie the country number of the currently +selected country. NB This may not be relevant if the alphabet and/or keyboard +have been set separately. + +These variables are controlled by a number of OS_Byte calls:- + +OS_Byte &46 - Read/set country +------------------------------ + +in: R1 <> 127 : Select country whose country number is R1. + +out: R1 = old country number, if R1 on entry was valid. + R1 = 0 => R1 on entry did not correspond to a known country (checked + for by issuing the service to convert the country number into an + alphabet number). + + +in: R1 = 127 : Read country number. + +out: R1 = current country number. + + +OS_Byte &47 - Read/set alphabet/keyboard +---------------------------------------- + +in: R1 in range 0..126: Select alphabet from alphabet number or country + number specified by R1. + +out: R1 = old alphabet number, if R1 on entry was valid. + R1 = 0 => R1 on entry did not correspond to a known country or + alphabet. + + +in: R1 = 127: Read alphabet number. + +out: R1 = current alphabet number. + + +in: R1 in range 128..254: Select keyboard from country number specified + by (R1-128). + +out: R1 = old keyboard number, if R1 on entry was valid. + R1 = 0 => R1 on entry did not correspond to a known country. + + +in: R1 = 255: Read keyboard number. + +out: R1 = current keyboard number. + + +OS_Byte &F0 - Read country number +--------------------------------- + +in: R1 = 0 + R2 = &FF + +out: R1 = current country number + +This call is provided for backwards compatibility with international versions +of the Master Compact. + + +Service calls +------------- + +The service call Service_International (R1=&43) is issued at various times by +the operating system and by the International module. The reason for the call +is specified by the contents of R2, as follows:- + +R2 = &00: Convert country name to country number + +in: R3 -> null-terminated country name string (may be abbreviated + with '.') + +out: All registers preserved if country not recognised, otherwise:- + R1 = 0 (call claimed) + R4 = country number + +R2 = &01: Convert alphabet name to alphabet number + +in: R3 -> null-terminated alphabet name string (may be abbreviated + with '.') + +out: All registers preserved if alphabet not recognised, otherwise:- + R1 = 0 (call claimed) + R4 = alphabet number + +R2 = &02: Convert country number to country name + +in: R3 = country number + R4 -> buffer for name + R5 = buffer length + +out: All registers preserved if country number not recognised, otherwise:- + R1 = 0 (call claimed) + Buffer holds country name (no terminator) truncated to buffer length + R5 = number of characters put into buffer + +R2 = &03: Convert alphabet number to alphabet name + +in: R3 = alphabet number + R4 -> buffer for name + R5 = buffer length + +out: All registers preserved if alphabet number not recognised, otherwise:- + R1 = 0 (call claimed) + Buffer holds alphabet name (no terminator) truncated to buffer length + R5 = number of characters put into buffer + + +R2 = &04: Convert country number to alphabet number + +in: R3 = country number + +out: All registers preserved if country number not recognised, otherwise:- + R1 = 0 (call claimed) + R4 = alphabet number + + +R2 = &05: Define a range of characters from a given alphabet + +in: R3 = alphabet number + R4 = ASCII code of first character in range + R5 = ASCII code of last character in range + +out: All registers preserved if alphabet number not recognised, otherwise:- + R1 = 0 (call claimed) + +If the alphabet number is recognised by the module, it should define all +characters in the range R4 to R5 inclusive with the appropriate character +shapes (using VDU 23,code,...). Any characters which do not have defined +shapes in the specified alphabet (eg codes &80-&9F in Latin1) should be left +unchanged. + +R2 = &06: Notification that the keyboard number has changed. + +in: R3 = new keyboard number + R4 = alphabet number associated with the keyboard number (not + necessarily the same as the current alphabet number) + +out: All registers preserved (call should never be claimed). + +This call is issued so that modules providing keyboard handlers. + + +OS_CLI commands provided +------------------------ + + *Alphabet [<country name> | <alphabet name>] + +*Alphabet sets an alphabet from a country or alphabet name. +*Alphabet with no parameter displays the currently selected alphabet. + + + *Country [<country name>] + +*Country sets the appropriate alphabet and keyboard driver for a particular +country. +*Country with no parameter displays the currently selected country. + + + *Keyboard [<country name>] + +*Keyboard sets the keyboard driver for a particular country. +*Keyboard with no parameter displays the currently selected keyboard. + + + *Alphabets + +*Alphabets lists the names of the available alphabets. + + + *Countries + +*Countries lists the names of known countries + diff --git a/s/PMF/KbdDrA1 b/s/PMF/KbdDrA1 new file mode 100644 index 0000000000000000000000000000000000000000..cce231fc850ff93b1d06e599fc15d9093837301a --- /dev/null +++ b/s/PMF/KbdDrA1 @@ -0,0 +1,611 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > Sources.PMF.KbdDrA1 + +; Archimedes keyboard driver. + +; *********************************** +; *** C h a n g e L i s t *** +; *********************************** + +; Date Who Description +; ---- --- ----------- +; 24-Feb-93 SMC Split from file "key". +; Use generic keyboard/mouse interfaces. + + [ PollMouse +K1ack * K1sack + | +K1ack * K1smak + ] + + MACRO +$lab RXonTXoff $reg, $cond +$lab + LDR$cond.B $reg, IRQMaskB + BIC$cond $reg, $reg, #KARTTxBit + ORR$cond $reg, $reg, #KARTRxBit + STR$cond.B $reg, IRQMaskB + MEND + + MACRO +$lab TXonRXoff $reg, $cond +$lab + LDR$cond.B $reg, IRQMaskB + BIC$cond $reg, $reg, #KARTRxBit + ORR$cond $reg, $reg, #KARTTxBit + STR$cond.B $reg, IRQMaskB + MEND + + MACRO +$lab RXon $reg, $cond +$lab + LDR$cond.B $reg, IRQMaskB + ORR$cond $reg, $reg, #KARTRxBit + STR$cond.B $reg, IRQMaskB + MEND + + MACRO +$lab TXon $reg, $cond +$lab + LDR$cond.B $reg, IRQMaskB + ORR$cond $reg, $reg, #KARTTxBit + STR$cond.B $reg, IRQMaskB + MEND + + MACRO +$lab TXoff $reg, $cond +$lab + LDR$cond.B $reg, IRQMaskB + BIC$cond $reg, $reg, #KARTTxBit + STR$cond.B $reg, IRQMaskB + MEND + + GBLS irqregs +irqregs SETS """R4-R10, PC""" + +; ***************************************************************************** +; +; Start of code + +ArthurKeyDriver + +; ***************************************************************************** +; +; Initialise driver. +; +A1KeyInit +; Initialise the baud rate generator + + MOV R12, #IOC + MOV R0, #1 + STRB R0, Timer3Low + MOV R0, #0 + STRB R0, Timer3High + STRB R0, Timer3Go + + STRB R0, KARTTx ; Write dummy byte + + MOV R0, #&800 +10 + SUBS R0, R0, #1 ; copy Jon's loop + BNE %BT10 + + LDRB R0, KARTRx ; Read dummy byte + + [ AssemblePointerV + MOV r0, #PointerV + ADR r1, A1Pointer + Push lr + SWI OS_Claim + Pull lr + ] + + [ AssembleKEYV + MOV r0, #KEYV + ADR r1, A1KeyVec + MOV r2, r12 + Push lr + SWI OS_Claim + Pull pc + | + MOV pc, lr + ] + +; ***************************************************************************** +; +; Reset keyboard hardware. +; +A1Reset + MOV R0, #HRDRESET + STRB R0, ResetState + + ASSERT HRDRESET = &FF + STRB R0, KeyRow ; no key being received + STRB R0, Reply + STRB R0, LastKbId + STRB R0, KbIdHalf + STRB R0, RequestLED + + MOV R0, #K1rqid + STRB R0, RequestKbId + + MOV R0, #0 + STRB R0, JustGotKbId + STRB R0, MouseCount ; start with an X coordinate + STRB R0, SPDRec + STRB R0, RequestSPD + STRB R0, RequestMouse + [ AssemblePointerV + STR r0, MouseXCount + STR r0, MouseYCount + ] + + TXonRXoff R0 ; enable Tx IRQ, disable Rx IRQ + + MOV pc, lr + +; ***************************************************************************** +; +; Handle enable and update LEDs (r1=state (bit 2=scroll, 1=num, 0=ctrl)). +; +; In: r0 = reason code 3 or 4 +; r1 = state (bit 2=scroll lock, 1=num lock, 0=caps lock) if r0=3 +; r12 = IOC +; +A1KeyVec + TEQ r0, #3 ; if not set LED + TEQNE r0, #4 ; and not enable then + MOVNE pc, lr ; pass it on + + Push "r0,r1,r11,lr" + + MOV r11, #KeyWorkSpace + + TEQ r0, #4 ; if enable then + MOVEQ r0, #0 + STREQB r0, JustGotKbId ; clear flag + RXon r0, EQ ; enable RX IRQs + Pull "r0,r1,r11,pc",EQ ; and pass on call + + LDRB r0, KbId + CMP r0, #1 ; if id >= 1 then new (C=1) + BCS %FT10 + + TST r1, #1 + MOVEQ r1, #LEDOFF + MOVNE r1, #LEDON +10 + STRB r1, RequestLED + TXon r0 + + Pull "r0,r1,r11,pc" + + [ AssemblePointerV + +; ***************************************************************************** +; +; A1Pointer - Return mouse movements on PointerV poll. +; +; In: r0 = reason code 0 +; r1 = pointer device type (must be 0 for us) +; Out: r2 = signed 32-bit X movement +; r3 = signed 32-bit Y movement +; +A1Pointer + TEQ r0, #0 ; If not poll + TEQEQ r1, #0 ; or not type 0 then + MOVNE pc, lr ; pass on call. + + LDR r2, MouseXCount + STR r0, MouseXCount + LDR r3, MouseYCount + STR r0, MouseYCount + + Pull pc ; Claim call. + ] + +; ***************************************************************************** +; +; IRQ routine +; +; in: R2 = IOC request B flags +; R0-R3, R11, R12 already saved, R14 irrelevant + + + [ AssemblingArthur +IrqRx ROUT + Push "R4-R10, R14" ; stack regs if new MOS IRQ vector + | +KeyIrq ROUT + TST R2, #KARTTxBit ; transmit empty ? + BNE IrqTx + Push "R4-R10" + MOV R12, #IOC ; already set up in new IRQ scheme + ] + MOV R11, #KeyWorkSpace + +; Keyboard receive interrupt + +; We now have to wait around for a period of 16 microseconds (or so they say) +; because of the hardware design. + +; This is doubly annoying because I have no idea what speed this processor is +; going at, so I don't know how many S-cycles this is, and there aren't enough +; hardware timers around to waste one doing this thankless task. + +; In addition, because I am on the IRQ vector, the other IRQ users have +; probably wasted at least 16 microseconds anyway - at least the code seems +; to work perfectly well without this delay loop. + +; Nevertheless, until we can come up with a better solution, I shall do a +; delay of (about) 16*8 S-cycles. +; + + MOV R0, #16*8/5 ; delay for an unspecified period +IrqRxDelayLoop + SUBS R0, R0, #1 ; this breaks my heart, + BNE IrqRxDelayLoop ; it really does ! + + LDRB R0, KARTRx ; get data byte + LDRB R1, ResetState ; and what we sent last + + CMP R0, #K1rak2 ; is it a reset thingy ? + BCS ProcessReset ; [yes, so check it] + + CMP R1, #K1rak2 ; are we resetting anyway ? + BCS IrqBadRx ; if so then bad reset + + AND R2, R0, #&F0 ; get reason code + + LDRB R1, LastKbId ; get last keyboard ID + TEQ R1, #&FF ; is it valid yet ? + BNE ValidKbId ; [yes, so we know what to expect] + + TEQ R2, #IDTYPE ; is it old keyboard id + BEQ IsOldKeyboard ; [is old keyboard] + + BIC R2, R2, #K1kbidmask ; check for new keyboard id + TEQ R2, #K1kbid + BNE IrqBadRx ; not a keyboard id, so reset + + AND R1, R0, #K1kbidmask ; get relevant bits + [ AssembleA1KeyHandler + ADRL R0, NewKeyStruct + ] + B AcknowledgeId + +IsOldKeyboard + AND R0, R0, #&0F ; get ID part + LDRB R1, KbIdHalf + TST R1, #&80 + STRNEB R0, KbIdHalf ; got half of keyboard id + MOVNE R0, #K1nack + BNE IrqRxAck + + ORR R1, R1, R0, LSL #4 ; get full keyboard id + MOV R0, #&FF + STRB R0, KbIdHalf + [ AssembleA1KeyHandler + ADRL R0, OldKeyStruct + ] + +AcknowledgeId + [ AssembleA1KeyHandler + LDRB R8, LastKbId ; get last keyboard id + TEQ R8, R1 ; is it same + STRNE R0, KeyVec ; if different, set up our handler + ] + MOV R0, #&FF + STRB R0, JustGotKbId ; tell TX handler to disable interrupts until KEYV enable call + + [ AssembleKEYV + MOV r0, #0 + MOV r10, #KEYV + BL CallVector + | + BL GotKbId + ] + + B IrqRxAckScan ; send ack + +; R1 = keyboard ID - now dispatch code + +ValidKbId + TEQ R1, #0 + BNE NewKeyboardDispatch + +OldKeyboardDispatch + TST R0, #MMOVED ; is it mouse data ? + BNE ProcessOldMouseData + TEQ R2, #KEYDOWN ; is it key down ? + BEQ ProcessOldKeyDown + TEQ R2, #KEYUP ; is it key up ? + BEQ ProcessOldKeyUp + TEQ R2, #SPDDONE ; is it SPD data ? + BEQ ProcessOldSPDData + B IrqBadRx ; spurious + +NewKeyboardDispatch + TST R2, #K1notmousedata ; is it mouse data ? + BEQ ProcessNewMouseData + TEQ R2, #K1kdda ; is it key down ? + BEQ ProcessNewKeyDown + TEQ R2, #K1kuda ; is it key up ? + BEQ ProcessNewKeyUp + TEQ R2, #K1pdat ; is it SPD data ? + BEQ ProcessNewSPDData + B IrqBadRx ; spurious + + +; ***************************************************************************** +; +; ProcessReset - Process reset code from keyboard +; +; in: R0 = code from keyboard +; R1 = ResetState + +ProcessReset ROUT + +; Check sequencing + + TEQ R1, R0 ; is reply what was expected + BNE IrqBadRx ; no, so reset + +; Now continue the sequence + + TEQ R1, #K1rak2 ; end of sequence ? + MOVEQ R1, #K1nack ; then send a nack + SUBNE R1, R1, #1 ; else next thing to go + STRB R1, ResetState ; store back + + TXonRXoff R0 + + Pull $irqregs + +IrqBadRx + +; Restart the reset sequence + + BL A1Reset + Pull $irqregs + +; ***************************************************************************** + +ProcessOldSPDData +ProcessNewSPDData + LDRB R1, SPDRec + SUBS R1, R1, #1 + STRCSB R1, SPDRec ; dec number to go (if not 0) + + LDRCS R1, SPDoutput + MOVCS R1, R1, LSR #4 + ORRCS R1, R1, R0, LSL #28 ; put in new data + STRCS R1, SPDoutput + + B IrqRxAckScan + +; ***************************************************************************** + +ProcessOldMouseData ; R0 = 01xx xxxx + TST R0, #&20 ; get sign bit of data (bit 5) + BICEQ R0, R0, #&40 ; move to bit 6 (where it is on new) +ProcessNewMouseData + LDRB R1, MouseCount + ADR R2, MouseDelta + STRB R0, [R2, R1] ; no need to clear top bit + + EORS R1, R1, #1 ; move to other coordinate + STRB R1, MouseCount + + MOVNE R0, #K1back + BNE IrqRxAck + + LDRB R3, [R2, #1] ; get delta Y + MOV R3, R3, LSL #25 ; sign extend it + MOV R3, R3, ASR #25 + + LDRB R2, [R2] ; get delta X + MOV R2, R2, LSL #25 ; sign extend it + MOV R2, R2, ASR #25 + + [ AssemblePointerV + LDR r0, MouseXCount + ADD r0, r0, r2 + STR r0, MouseXCount + LDR r0, MouseYCount + ADD r0, r0, r3 + STR r0, MouseYCount + | + BL ProcessMouseXY + ] + + B IrqRxAckScan + +; ***************************************************************************** + +; in: R1 = keyboard id + +ProcessOldKeyDown +ProcessNewKeyDown ROUT + LDRB R2, KeyRow + TEQ R2, #&FF ; have we had a row already ? + STREQB R0, KeyRow ; no so store row + MOVEQ R0, #K1back + BEQ IrqRxAck ; and acknowledge Rx + + EOR R3, R0, R2 ; test if save movement type + TST R3, #&F0 + BNE IrqBadRx ; not same, so reset + + AND R0, R0, #&0F ; get new data + AND R2, R2, #&0F ; and row data + + TEQ R1, #0 + ORREQ R2, R2, R0, LSL #4 ; old keyboard number + ORRNE R2, R0, R2, LSL #4 ; new key number + + MOV R0, #&FF + STRB R0, KeyRow ; reset 'had row' flag + + MOV r0, #2 ; indicate key down + MOV r1, r2 + [ AssembleKEYV + MOV r10, #KEYV + BL CallVector + MOV r12, #IOC + | + BL GotKey + ] + +IrqRxAckScan + +; Re-enable Tx interrupts and queue an acknowledge + + MOV R0, #K1ack ; either sack or smak as appropriate +IrqRxAck + STRB R0, Reply + TXonRXoff R0 + Pull $irqregs ; claimed irq, so grab link and PC + +; ***************************************************************************** + +; in: R1 = keyboard id + +ProcessOldKeyUp +ProcessNewKeyUp ROUT + LDRB R2, KeyRow + TEQ R2, #&FF ; have we had a row already ? + STREQB R0, KeyRow ; no so store row + MOVEQ R0, #K1back + BEQ IrqRxAck ; and acknowledge Rx + + EOR R3, R0, R2 ; test if save movement type + TST R3, #&F0 + BNE IrqBadRx ; not same, so reset + + AND R0, R0, #&0F ; get new data + AND R2, R2, #&0F ; and row data + + TEQ R1, #0 + ORREQ R2, R2, R0, LSL #4 ; old key number + ORRNE R2, R0, R2, LSL #4 ; new key number + + MOV R0, #&FF + STRB R0, KeyRow ; reset 'had row' flag + + MOV r0, #1 ; indicate key up + MOV r1, r2 + [ AssembleKEYV + MOV r10, #KEYV + BL CallVector + MOV r12, #IOC + | + BL GotKey + ] + + B IrqRxAckScan + +; ***************************************************************************** + +IrqTx ROUT + [ AssemblingArthur + Push "R4-R10, R14" ; stack regs if new MOS IRQ vector + | + Push "R4-R10" + MOV R12, #IOC ; already set up in new IRQ scheme + ] + MOV R11, #KeyWorkSpace + +; First see if we're in a reset sequence + + LDRB R0, ResetState ; are we in a reset ? + TEQ R0, #0 + BEQ %FT05 ; not in a reset + + CMP R0, #K1rak2 ; are we sending the reset nack ? + BCS %FT25 ; no, just send reset code + MOV R1, #0 ; yes, zero the reset state + STRB R1, ResetState + STRB R0, KARTTx + Pull $irqregs ; don't disable TX + +; Now see if any outstanding requests + +05 + LDRB R0, RequestSPD ; is there an SPD request ? + TEQ R0, #0 + BEQ %FT10 ; [no SPD request] + + MOV R1, #K1prst ; code to send keyboard + MOV R2, #0 ; no further SPD request + STRB R2, RequestSPD + MOV R2, #8 + STRB R2, SPDRec ; nibbles still to be sent/received + STRB R1, KARTTx ; send the byte + Pull $irqregs ; exit without disabling Tx + +10 + LDRB R0, RequestKbId ; is there a pending keyboard request ? + TEQ R0, #0 + MOVNE R1, #0 + STRNEB R1, RequestKbId ; no further request + STRNEB R0, KARTTx ; send the byte + Pull $irqregs, NE ; exit without disabling Tx + + LDRB R0, RequestMouse ; is there a pending mouse request ? + TEQ R0, #0 + MOVNE R1, #0 + STRNEB R1, RequestMouse ; no further request + STRNEB R0, KARTTx + Pull $irqregs, NE ; exit without disabling Tx + + LDRB R0, RequestLED ; is there a pending LED request ? + TEQ R0, #&FF + MOVNE R1, #&FF + STRNEB R1, RequestLED + STRNEB R0, KARTTx + Pull $irqregs, NE ; exit without disabling Tx + + LDRB R0, SPDRec ; are we converting some SPD data + TEQ R0, #0 + BEQ %FT20 ; branch if not + + LDR R1, SPDinput + AND R2, R1, #&F ; get nybble to be sent + ORR R2, R2, #K1rqpd + MOV R1, R1, LSR #4 ; shift out the nybble sent + STR R1, SPDinput + STRB R2, KARTTx + B %FT30 ; disable Tx, so we don't send another + ; nibble before we get the conversion +20 + LDRB R0, Reply + TEQ R0, #&FF + BEQ %FT30 ; no reply to send +25 + STRB R0, KARTTx ; send the reply + MOV R0, #&FF + STRB R0, Reply ; nothing else to send + + LDRB R0, JustGotKbId + TEQ R0, #0 ; if just got keyboard id then + TXoff R0, NE ; disable all interrupts + Pull $irqregs, NE ; and wait for KEYV enable call +30 + RXonTXoff R0 + Pull $irqregs + + END diff --git a/s/PMF/RS423 b/s/PMF/RS423 new file mode 100644 index 0000000000000000000000000000000000000000..81fb7f238cf936bb79e82fd625f69267c5f1a77b --- /dev/null +++ b/s/PMF/RS423 @@ -0,0 +1,714 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.PMF.rs423 + +; ************************************************************ +; *** C h a n g e L i s t (better late than never!) *** +; ************************************************************ + +; Date Description +; ---- ----------- +; 15-Feb-88 Changed ModifyControl6850 to fix GTE/CMD control register +; sensitivity problem +; 08-Apr-88 Transmit code doesn't need to reload DCDDSRCopy, it's got the +; register in R2 +; 12-Apr-88 Removed DCDDSRCopy - bits are now in SerialFlags +; Started code to do SerialFlags bits and SWI SerialOp +; 18-Apr-88 Started XON/XOFF stuff +; 13-May-88 Added new SerialOps to read/set baud rates + +; ***************************************************************************** +; +; RS423IRQ - Entry point for 6551 interrupt +; + +RS423IRQ ROUT + [ AssemblingArthur + Push R14 ; stack R14 if new MOS IRQ vector + | + BYTEWS WsPtr ; already set up in new IRQ scheme + ] + LDR R11, =ACIA + LDRB R2, ACIAStatus ; clear interrupt and read status + +; if we want to support 6850 IRQ mask variable, then some code needed here +; to mess around with the bits + + TST R2, #ACIATDRE ; if TDRE bit set then push status + ADRNE R0, %FT20 ; and address of TX processing routine + Push "R0,R2", NE + + TST R2, #ACIARDRF ; if RDRF bit set then push status + ADRNE R0, %FT10 ; and address of RX processing routine + Push "R0,R2", NE + + LDR R1, SerialFlags ; get old DCD,DSR bits + EOR R0, R1, R2, LSL #DCDDSRShift ; difference between old/new + ANDS R0, R0, #(1:SHL:SF_DCDHigh):OR:(1:SHL:SF_DSRHigh) + Pull PC, EQ ; [same, so return] + + EOR R1, R1, R0 ; R1 := new + STR R1, SerialFlags ; store new version + TST R1, #(1:SHL:SF_DCDIgnore) ; if ignoring DCD + BNE %FT04 ; then don't generate event + TST R1, #(1:SHL:SF_DCDHigh) ; if DCD is now non-zero + BNE RS423Error ; then generate event +04 + TST R1, #(1:SHL:SF_DSRIgnore) ; if ignoring DSR + TSTEQ R1, #(1:SHL:SF_DSRHigh) ; or it's still high + Pull PC, NE ; then no action + + TST R0, #(1:SHL:SF_DSRHigh) ; else if DSR has changed + BLNE RSBUSY ; then it's changed to zero, + ; so reenable TX IRQ if poss + Pull PC ; then finish IRQ + +; Process receive interrupt + +10 + Pull R2 ; pull stacked status + LDRB R3, RS423conflag ; RXirq enabled ? + TST R3, #RXEN6850 + Pull PC, EQ ; no, then exit + + LDRB R0, ACIARxData ; read data (and clear RDRF) + LDR R1, SerialFlags + MOV R3, #(ACIAOverRun :OR: ACIAFramingError :OR: ACIAParityError) + TST R1, #(1:SHL:SF_DCDIgnore) ; if not ignoring DCD + ORREQ R3, R3, #ACIADCD ; then it causes event + TST R2, R3 + BNE RS423Error + +; no error on receive + + TST R1, #(1:SHL:SF_XONXOFFOn) ; if not doing xon/xoff + BEQ %FT15 ; then skip + TEQ R0, #XOFFChar ; else if XOFF char + ORREQ R1, R1, #(1:SHL:SF_HeXOFFedMe) ; then set bit + STREQ R1, SerialFlags ; store back + Pull PC, EQ ; and exit + + TEQ R0, #XONChar ; else if XON char + BICEQ R1, R1, #(1:SHL:SF_HeXOFFedMe) ; then clear bit + STREQ R1, SerialFlags ; store back + BEQ EnableTXI ; and reenable TXI + +15 + LDRB R2, RS423InputSupr ; RS423 input suppressed ? + TEQ R2, #0 ; NZ => suppressed + Pull PC, NE ; return if suppressed + + MOV R1, #Buff_RS423In ; RS423 input buffer id + MOV R2, R0 ; R2 := character + BL DoInsertESC ; insert into buffer + ; possibly checking for ESC + BL CountRS ; count spaces left + + Pull PC, CS ; enough left, so exit + B RLO ; this pulls PC + +; Process transmit interrupt + +20 + Pull R2 ; restore stacked status + LDR R1, SerialFlags + TST R1, #(1:SHL:SF_DSRIgnore) ; if ignoring DSR + BNE %FT25 ; then skip + TST R2, #ACIADSR ; else if DSR high + BNE TXDINT ; then don't send char +25 + LDRB R0, XONXOFFChar ; is there an XON or XOFF + TEQ R0, #0 ; to send (R0 = 0 if not) + MOVNE R1, #0 ; If so, then zero character + STRNEB R1, XONXOFFChar + BNE %FT40 ; and send this char + + TST R1, #(1:SHL:SF_HeXOFFedMe) ; if we are XOFFed + BNE TXDINT ; then shut up +28 + CLRV + MOV R1, #Buff_RS423Out ; RS423 output buffer id + BL REMOVE + BCC %FT30 ; character to send + + LDRB R0, PrinterDrivType + TEQ R0, #2 ; RS423 printer ? + BNE TXDINT ; no, then shut down RS423 + + CLRV + MOV R1, #Buff_Print ; printer buffer id + BL REMOVE + + MOVCS R1, #0 ; if no char, mark + STRCS R1, PrinterActive ; printer driver dormant + BCS TXDINT ; and shut down RS423 +30 + LDR R1, SerialFlags + TST R1, #(1:SHL:SF_XONXOFFOn) ; if xon/xoff not on + BEQ %FT40 ; then skip + TEQ R0, #XOFFChar ; else if XOFF char + ORREQ R1, R1, #(1:SHL:SF_UserXOFFedHim) ; then set user bit + TEQ R0, #XONChar ; else if XON char + BICEQ R1, R1, #(1:SHL:SF_UserXOFFedHim) ; then clear user bit + STR R1, SerialFlags ; store back always + BNE %FT40 ; and skip if not XON char + +; user sending an XON char, so only let it thru if we're not trying to XOFF him + + TST R1, #(1:SHL:SF_IXOFFedHim) ; if we're trying to XOFF him + BNE %BT28 ; then don't send XON, go and + ; look for another character +40 + STRB R0, ACIATxData ; write data + Pull PC + + +TXDINT ; disable TX interrupt + MOV R0, #&80 ; indicate RS423 + STRB R0, RS423use ; not in use + + LDR R0, SerialFlags + TST R0, #(1:SHL:SF_XONXOFFOn) ; if XON/XOFF + BNE DisableTXI ; then just disable TXI + + LDRB R0, RS423conflag + TST R0, #RXEN6850 + BEQ RLO ; RXI disabled, so shut him up + + BL CountRS + BCS DisableTXI ; no overflow, just disable TXI +RLO + LDR R1, SerialFlags + TST R1, #(1:SHL:SF_XONXOFFOn) ; if XON/XOFF + ORRNE R1, R1, #(1:SHL:SF_IXOFFedHim) + STRNE R1, SerialFlags + MOVNE R1, #XOFFChar + BNE SendXONXOFF + + MOV R1, #RLOTXD6850 ; tell him to shut up + B RSED + +SendXONXOFF + STRB R1, XONXOFFChar +EnableTXI + MOV R1, #RHITXE6850 + B RSED + +DisableTXI + MOV R1, #RHITXD6850 ; just disable transmit irq +RSED + MOV R2, #&9F ; alter bits 5,6 of control + Pull R14 + +; and drop thru to ... + +; ***************************************************************************** +; +; ModifyControl6850 - Simulate update of 6850 control register +; +; Changed 15-Feb-88 to only modify control register if different +; (GTE/CMD chips corrupt received characters if control register is +; written to (unnecessarily) just after a character has been received) +; Change uses R4 as a temporary, which is therefore pushed + pulled +; in addition to R1 and R2, in the middle of the routine. +; +; in: WsPtr -> OsbyteVars +; R2 = AND mask +; R1 = EOR mask +; +; out: R1 = old value of register (taken from soft copy) +; R0, R2, R3 preserved +; + +ModifyControl6850 ROUT + Push "R0, R3, R4, R11, R14" + + PHPSEI ; doesn't really "push" it + LDR R11, =ACIA + + LDRB R3, RS423conflag ; load soft copy + AND R0, R2, R3 ; AND with mask + EOR R0, R0, R1 ; EOR with mask + STRB R0, RS423conflag ; store back to soft copy + MOV R4, R1 ; save EOR mask in R4 + MOV R1, R3 ; old copy into R1 + +; now R0 = new register, R1 and R2 must be preserved + + AND R3, R0, #DIVBITS6850 + TEQ R3, #DIVRESET6850 ; reset ACIA ? + STREQB R0, ACIAReset ; any old data will do + BEQ %FT20 ; and finish there + + Push "R1, R2" + MVN R2, R2 ; NOT (AND mask) + ORR R2, R2, R4 ; (EOR mask) OR NOT (AND mask) + TST R2, #WSB6850 ; if zero then not modifying + LDREQB R1, ACIACommand ; format bits, so fake new bits + ANDEQ R1, R1, #(ACIAPME :OR: ACIAPMC0 :OR: ACIAPMC1) ; in com. reg + BEQ %FT10 ; and leave control reg alone + + AND R3, R0, #WSB6850 ; get word select bits + + ADR R1, ControlDPS ; point to table + LDRB R1, [R1, R3, LSR #WSBSHIFT] ; get bits for control reg + + LDRB R2, ACIAControl ; get current register + BIC R4, R2, #ACIAWSB ; zero those bits in current + ORR R4, R4, R1 ; or in new bits + TEQ R4, R2 ; if different + STRNEB R4, ACIAControl ; then store back + + ADR R1, CommandDPS + LDRB R1, [R1, R3, LSR #WSBSHIFT] ; get bits for command reg + ; ABC00000 +10 + AND R0, R0, #RXEN6850 :OR: RTBITS6850 ; isolate RXI,RTS/TXI + ORR R1, R1, R0, LSR #3 ; ABCgeF00 + TST R0, #RXEN6850 + EORNE R1, R1, #(&10 :OR: ACIARIRD) ; ABC0eFg0 + TST R1, #&04 + EOREQ R1, R1, #&08 ; ABC0EFg0 + EOR R1, R1, #ACIARIRD ; ABC0EFG0 + LDRB R3, ACIACommand + AND R3, R3, #(ACIAREM :OR: ACIADTR :OR: ACIATIC0 :OR: ACIATIC1) + + LDR R4, SerialFlags + TST R4, #(1:SHL:SF_SendingBreak) ; if sending break + BICNE R1, R1, #(ACIATIC0 :OR: ACIATIC1) ; then use hardware bits + BICEQ R3, R3, #(ACIATIC0 :OR: ACIATIC1) ; else use software bits + + ORR R1, R1, R3 + STRB R1, ACIACommand + Pull "R1, R2" +20 + PLP + Pull "R0, R3, R4, R11, PC" + +; ***************************************************************************** +; +; Comes here either a) when DCD or DSR have changed to non-zero, +; or b) when a receive interrupt happens and error bits are set +; +; Converts 6551 status register in R2 into +; 6850 status register shifted right one bit in R1 (DSR in bit 2) +; then calls event (with char in R2 for case b) above) +; + +RS423Error ROUT + +; R2 = x | DSR | DCD | x | x | OV | FE | PE + + MOVS R1, R2, LSR #1 ; bit 1=OV, bit 0=FE, C=PE + MOV R1, R1, LSL #3 ; bit 4=OV, bit 3=FE + AND R1, R1, #(1:SHL:4) :OR: (1:SHL:3) ; remove other bits + ORRCS R1, R1, #(1:SHL:5) ; bit 5=PE, bit 4=OV, bit 3=FE + AND R2, R2, #(1:SHL:6) :OR: (1:SHL:5) ; R2 bit 6=DSR, bit 5=DCD + ORR R1, R1, R2, LSR #4 ; 0|0|PE|OV|FE|DSR|DCD|0 + + MOV R2, R0 ; char in R2 (if receive) + MOV R0, #Event_RS423Error + BL OSEVEN + + Pull PC + + +; ***************************************************************************** + +; Tables for converting Data/Parity/Stop bits in 6850 +; to control and command registers in 6551 + +ControlDPS + = ControlBits7e2, ControlBits7o2, ControlBits7e1, ControlBits7o1 + = ControlBits8n2, ControlBits8n1, ControlBits8e1, ControlBits8o1 + +CommandDPS + = CommandBits7e2, CommandBits7o2, CommandBits7e1, CommandBits7o1 + = CommandBits8n2, CommandBits8n1, CommandBits8e1, CommandBits8o1 + + ALIGN + +; ***************************************************************************** +; +; CountRS - See if there are "enough" spaces left in RS423 buffer +; +; in: WsPtr -> OsbyteVars +; +; out: C=0 => spaces < limit +; C=1 => spaces >= limit +; + +CountRS ROUT + Push R14 + MOV R1, #Buff_RS423In ; RS423 input buffer id + CMP R1, #0 ; V=0, C=1 so count spaces + BL CnpEntry + ORR R1, R1, R2, LSL #8 ; get combined result + LDRB R2, RS423HandShake ; limiting number of spaces + CMP R1, R2 ; C=1 => (spaces >= limit) + Pull PC + +; ***************************************************************************** +; +; SerialOp - Handler for SWI OS_SerialOp +; + +SerialOp ROUT + TEQP PC, #SVC_mode :OR: I_bit ; disable IRQs + LDR R11, =ACIA + BYTEWS R12 + CMP R0, #(SerialOpTableEnd-SerialOpTable) :SHR: 2 + BCS BadSerialOp + LDR R10, [PC, R0, LSL #2] ; SerialOpTable must follow + ADD PC, PC, R10 ; immediately + +SerialOpTable + & ReadWriteFlags-SerialOpTable-4 + & ReadWriteDataFormat-SerialOpTable-4 + & SendBreak-SerialOpTable-4 + & SendByte-SerialOpTable-4 + & GetByte-SerialOpTable-4 + & SetRXBaudRate-SerialOpTable-4 + & SetTXBaudRate-SerialOpTable-4 +SerialOpTableEnd + +BadSerialOp + ADR R0, ErrorBlock_UnknownSerialOp + ORR R14, R14, #V_bit + ExitSWIHandler + + MakeErrorBlock UnknownSerialOp + +; ***************************************************************************** +; +; ReadWriteFlags - Read/write serial flags +; +; in: R1 = EOR mask +; R2 = AND mask +; R11 -> ACIA +; R12 -> BYTEWS +; +; out: R1 = old flags +; R2 = new flags +; +; Flags are defined in $.Hdr.RS423 +; Still to do - if setting DSRIgnore then possibly wake up TX +; + +ReadWriteFlags ROUT + Push "R9, R14" + MVN R10, #SF_ModifyBits ; R10 = bits that aren't modifyable + BIC R1, R1, R10 ; EOR mask must have those bits clear + ORR R2, R2, R10 ; AND mask must have those bits set + + LDR R10, SerialFlags + + MOV R14, #IOC ; now read ring indicator bit + LDRB R14, [R14, #IOCIRQSTAA] + TST R14, #ring_bit + BICEQ R10, R10, #1:SHL:SF_Ringing ; clear or set bit accordingly + ORRNE R10, R10, #1:SHL:SF_Ringing + + LDRB R14, ACIACommand ; now read DTR bit + TST R14, #ACIADTR ; NZ => on + BICNE R10, R10, #1:SHL:SF_DTROff + ORREQ R10, R10, #1:SHL:SF_DTROff + +; R10 is now the complete 'old' SerialFlags + + AND R9, R10, R2 + EOR R2, R9, R1 + MOV R1, R10 + +; now reflect 'new' SerialFlags DTR setting in hardware + + TST R2, #1:SHL:SF_DTROff + BICNE R14, R14, #ACIADTR ; R14 is new command register setting + ORREQ R14, R14, #ACIADTR + STRB R14, ACIACommand ; (R11 still points to ACIA) + +; if DSRIgnore has just been turned on and DSR is high then reenable TX + + EOR R10, R1, R2 ; form mask of bits which have changed + AND R10, R10, R2 ; from 0 to 1 + + TST R10, #1:SHL:SF_XONXOFFOn ; if we just enabled xon/xoff + BICNE R2, R2, #(1:SHL:SF_HeXOFFedMe):OR:(1:SHL:SF_IXOFFedHim):OR:(1:SHL:SF_UserXOFFedHim) ; then clear all these bits + STR R2, SerialFlags + + TST R10, #1:SHL:SF_DSRIgnore ; if DSR ignore has changed to high + TSTNE R2, #1:SHL:SF_DSRHigh ; and actual state is high + BLNE DoRSBUSY ; then reenable transmit + + Pull "R9, R14" + ExitSWIHandler + +DoRSBUSY ROUT + Push "R0-R2,R14" + BL RSBUSY + Pull "R0-R2,PC" + +; ***************************************************************************** +; +; ReadWriteDataFormat - Read/write data format (word length, stop bits +; and parity) +; +; in: R1 = -1 => just read format +; R1 <> -1 => set format to R1 +; +; Bits 0,1 : 0 => 8 bit word +; 1 => 7 bit word +; 2 => 6 bit word +; 3 => 5 bit word +; +; Bit 2 : 0 => 1 stop bit +; 1 => 2 stop bits +; OR 1.5 stop bits if 5 bit word without parity +; OR 1 stop bit if 8 bit word with parity +; +; Bit 3 : 0 => parity disabled (no parity bit) +; 1 => parity enabled +; +; Bits 4,5 : 0 => odd parity +; 1 => even parity +; 2 => parity bit always 1 on TX (ignored on RX) +; 3 => parity bit always 0 on TX (------""-----) +; +; Thus bits 0..2 go to bits 5..7 of the control register, and +; bits 3..5 go to bits 5..7 of the command register. +; +; R11 -> ACIA +; R12 -> BYTEWS +; +; out: R1 = old format in bits 0..5 as above +; + +ReadWriteDataFormat ROUT + Push "R9, R14" + + LDRB R10, ACIAControl + MOV R9, R10, LSR #5 ; R9 = control format bits in 0..2 + EOR R10, R10, R9, LSL #5 ; R10 = control non-format bits + + LDRB R14, ACIACommand + AND R12, R14, #(ACIAPME :OR: ACIAPMC0 :OR: ACIAPMC1) + EOR R14, R14, R12 ; R14 = command non-format bits + + ORR R9, R9, R12, LSR #5-3 ; R9 = complete old state + + CMP R1, #-1 ; just reading ? + BEQ %FT10 + +; now update real registers + + ORR R10, R10, R1, LSL #5 ; new control register + STRB R10, ACIAControl ; (bits above 7 don't matter) + + MOV R10, R1, LSR #3 + ORR R14, R14, R10, LSL #5 ; new command register + STRB R14, ACIACommand ; (bits above 7 don't matter) + +; now work out if new format corresponds to a BBC format, and if so, update +; 6850 control register copy + + AND R1, R1, #&3F ; only use bits 0..5 + ADR R14, ReverseFormatTable + LDRB R14, [R14, R1] + TEQ R14, #&FF ; if &FF then not BBC format + BEQ %FT10 ; so don't modify 6850 soft copy + + BYTEWS R12 + LDRB R10, RS423conflag + BIC R10, R10, #WSB6850 ; clear existing word bits out + ORR R10, R10, R14 ; OR in new bits + STRB R10, RS423conflag ; and store back +10 + MOV R1, R9 ; R1 = old state + Pull "R9, R14" + ExitSWIHandler + +ReverseFormatTable + = &14, &FF, &FF, &FF, &10, &FF, &FF, &FF + = &1C, &0C, &FF, &FF, &1C, &04, &FF, &FF + = &14, &FF, &FF, &FF, &10, &FF, &FF, &FF + = &18, &08, &FF, &FF, &18, &00, &FF, &FF + = &14, &FF, &FF, &FF, &10, &FF, &FF, &FF + = &FF, &FF, &FF, &FF, &FF, &FF, &FF, &FF + = &14, &FF, &FF, &FF, &10, &FF, &FF, &FF + = &FF, &FF, &FF, &FF, &FF, &FF, &FF, &FF + ALIGN + +; ***************************************************************************** +; +; SendBreak - Send a break for R1 centiseconds +; +; in: R1 = length of break in centiseconds +; R11 -> ACIA +; R12 -> BYTEWS +; +; out: R1 preserved +; + +SendBreak ROUT + Push "R9, R14" + LDR R10, SerialFlags ; protect command register during break + ORR R10, R10, #(1:SHL:SF_SendingBreak) + STR R10, SerialFlags + + LDRB R10, ACIACommand +; BIC R10, R10, #(ACIATIC0 :OR: ACIATIC1) + ASSERT RonBreak = (ACIATIC0 :OR: ACIATIC1) + ORR R10, R10, #RonBreak + STRB R10, ACIACommand + + TEQP PC, #SVC_mode ; enable IRQs + + [ AssemblingArthur :LOR: Module + MOV R14, #MetroGnome ; use monotonic variable now + | + ADR R14, RealTime ; doesn't exist in my world + ] + LDR R10, [R14] + ADD R10, R10, R1 ; R10 = target time +10 + LDR R9, [R14] + CMP R9, R10 + BMI %BT10 ; not BLT (these are clock numbers) + + TEQP PC, #SVC_mode :OR: I_bit ; disable IRQs again + + LDR R10, SerialFlags ; deprotect command register + BIC R10, R10, #(1:SHL:SF_SendingBreak) + STR R10, SerialFlags + + Push "R1, R2" ; now update 6551 command register + MOV R1, #0 ; from the 6850 control soft copy + MOV R2, #&FF ; (to put back the RTS setting) + BL ModifyControl6850 + Pull "R1, R2, R9, R14" + + ExitSWIHandler + +; ***************************************************************************** +; +; SendByte - Attempt to put a byte into transmit buffer, and wake up +; transmit process +; +; in: R1 = character +; R11 -> ACIA +; R12 -> BYTEWS +; +; out: R1 preserved +; C=0 => character inserted +; C=1 => buffer was full +; + +SendByte ROUT + Push "R0-R2, R14" + MOV R0, R1 ; put character in R0 + MOV R1, #Buff_RS423Out + BL INSRT + Pull "R0-R2, R14", CS ; if failed then nowt else to do + ORRCS R14, R14, #C_bit + ExitSWIHandler CS + +; character successfully inserted, so try to wake up transmit process +; (R12 still -> ByteWS) + + BL RSBUSY + Pull "R0-R2, R14" + BIC R14, R14, #C_bit + ExitSWIHandler + +; ***************************************************************************** +; +; GetByte - Attempt to remove a byte from receive buffer, and reenable +; RTS if now enough space in buffer +; +; in: R11 -> ACIA +; R12 -> BYTEWS +; +; out: C=0 => R1 = character read +; C=1 => R1 preserved, buffer was empty +; + +GetByte ROUT + Push "R0-R2, R14" + MOV R1, #Buff_RS423In + CLRV + BL REMOVE ; out: R2 = char, if C=0 + STRCC R2, [R13, #1*4] ; store char in stacked R1 + LDR R14, [R13, #3*4] ; reload stacked R14 + BICCC R14, R14, #C_bit ; set/clear carry appropriately + ORRCS R14, R14, #C_bit + STR R14, [R13, #3*4] ; store back + +; (R12 -> BYTEWS still) + + BLCC RSETX ; if removed char, then reenable RTS + ; if enough spaces + Pull "R0-R2, R14" + ExitSWIHandler + + LTORG + +; ***************************************************************************** +; +; SetRXBaudRate - Set/read receive baud rate +; +; in: R1 = -1 => read RX baud rate +; R1 = 0..15 => set RX baud rate to this + +SetRXBaudRate ROUT + Push "R0,R2,R3, R14" + LDRB R11, SerULAreg + AND R11, R11, #&78 ; get RX bits + MOV R11, R11, LSR #3 + ADR R10, ReverseSerProcTable + LDRB R11, [R10, R11] + CMP R1, #-1 + BLNE DoOsbyte07 ; if setting then call setting routine + MOV R1, R11 + Pull "R0,R2,R3, R14" + ExitSWIHandler + +; ***************************************************************************** +; +; SetTXBaudRate - Set/read transmit baud rate +; +; in: R1 = -1 => read TX baud rate +; R1 = 0..15 => set TX baud rate to this + +SetTXBaudRate ROUT + Push "R0,R2,R3, R14" + LDRB R11, SerULAreg + AND R11, R11, #&87 ; get TX bits + TST R11, #&80 + EORNE R11, R11, #&88 ; put bit 7 into bit 3 + ADR R10, ReverseSerProcTable + LDRB R11, [R10, R11] + CMP R1, #-1 + BLNE DoOsbyte08 ; if setting then call setting routine + MOV R1, R11 + Pull "R0,R2,R3, R14" + ExitSWIHandler + + +ReverseSerProcTable + = 8, 4, 6, 2, 7, 3, 5, 1 + = 15, 11, 13, 9, 14, 10, 12, 16 + + + END diff --git a/s/PMF/convdate b/s/PMF/convdate new file mode 100644 index 0000000000000000000000000000000000000000..8566c866e739ab735cad4430e6438c563e0bf2d4 --- /dev/null +++ b/s/PMF/convdate @@ -0,0 +1,553 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.PMF.ConvDate + + MACRO + CDATT $mnemonic, $stackoffset, $digits + ASSERT (:LEN: "$mnemonic") = 2 + ASSERT ((CDAT$mnemonic-(CDATBranch+8)) :AND: &FFFFFC03) = 0 + ASSERT ($stackoffset >=0) :LAND: ($stackoffset < 64) + LCLA digits + [ "$digits"="" +digits SETA 2 + | +digits SETA $digits + ] + ASSERT (digits >= 1) :LAND: (digits <= 3) + + DCB digits :OR: ($stackoffset :SHL: 2) + DCB (CDAT$mnemonic-(CDATBranch+8)) :SHR: 2 + = "$mnemonic" + MEND + +; ***************************************************************************** +; +; ConvertStandardDateAndTime - Convert from 5-byte cs representation to +; format specified in <SYS$DateFormat> +; +; in: R0 -> time block +; [R0, #0..4] = 5-byte centisecond representation +; R1 -> buffer to accept conversion +; R2 = size of buffer +; +; out: V=0 => successful conversion +; R0 = input value of R1 +; R1 = updated pointer to buffer +; R2 = updated size of buffer +; +; V=1 => failed conversion +; R0 -> error block +; R1 = input value of R1 +; R2 = input value of R2 +; + + +ConvertStandardDateAndTime ROUT + BIC R10, R13, #&00FF + BIC R10, R10, #&7F00 ; R10 -> assumed start of stack + SUB R10, R13, R10 ; R10 := free space on stack + CMP R10, #&200 ; to be on the safe side + BCS %FT10 + +; not enough stack for operation + + ADR R0, ErrorBlock_CDATStackOverflow + [ International + Push "lr" + BL TranslateError + Pull "lr" + ] + SWI XOS_GenerateError + ORR R14, R14, #V_bit + ExitSWIHandler + + MakeErrorBlock CDATStackOverflow + +10 + SUB R13, R13, #&100 ; room for reading <SYS$DateFormat> + Push "R0-R4, R14" + ADR R0, DateFormatVarName ; R0 -> "SYS$DateFormat" + ADD R1, R13, #6*4 ; R1 -> buffer for string + MOV R2, #255 ; R2 = maximum length of string + MOV R3, #0 ; not wild carding + MOV R4, #VarType_Expanded ; convert to string + SWI XOS_ReadVarVal + BVS %FT30 + MOV R0, #0 + STRB R0, [R1, R2] ; terminate string with zero + MOV R3, R1 ; R3 -> format string + Pull "R0-R2" + SWI XOS_ConvertDateAndTime + Pull "R3,R4, R14" +20 + ADD R13, R13, #&100 + ORRVS R14, R14, #V_bit + ExitSWIHandler + +; format specifier not found + +30 + ADD R13, R13, #4 ; throw away stacked R0 + Pull "R1-R4, R14" + B %BT20 + +DateFormatVarName + = "SYS$DateFormat",0 + ALIGN + +; ***************************************************************************** +; +; ConvertDateAndTime - Convert from 5-byte cs representation to +; format specified by user +; +; in: R0 -> time block +; [R0, #0..4] = 5-byte centisecond representation +; R1 -> buffer to accept conversion +; R2 = size of buffer +; R3 -> format string +; +; out: V=0 => successful conversion +; R0 = input value of R1 +; R1 = updated pointer to buffer +; R2 = updated size of buffer +; +; V=1 => failed conversion +; R0 -> error block +; R1 = input value of R1 +; R2 = input value of R2 +; + +ConvertDateAndTime ROUT + + [ {TRUE} ; International vesion just calls territory manager. + Push "R4,R14" + + + MOV R4,R3 ; Territory SWI wants things one register up. + MOV R3,R2 + MOV R2,R1 + MOV R1,R0 + MOV R0,#-1 ; Use configured territory. + SWI XTerritory_ConvertDateAndTime + Pull "R4,R14" + ORRVS R14, R14, #V_bit ; set V in R14 for exit + ExitSWIHandler + + | + Push "R1-R11, R14" + + LDRB R4, [R0, #0] ; read the 5 byte value to convert + LDRB R5, [R0, #1] + ORR R4, R4, R5, LSL #8 + LDRB R5, [R0, #2] + ORR R4, R4, R5, LSL #16 + LDRB R5, [R0, #3] + ORR R4, R4, R5, LSL #24 ; R4 contains bottom 4 bytes + LDRB R5, [R0, #4] ; R5 contains 5th byte + + MOV R6, R4, LSR #8 + ORR R6, R6, R5, LSL #24 ; R6 := centiseconds DIV 256 + LDR R7, =ticksperday/256 ; (ticksperday is a multiple of 256) + DivRem R8, R6, R7, R9 ; R8 = number of days since 1900 + AND R4, R4, #&FF ; R4 := centiseconds MOD 256 + ORR R6, R4, R6, LSL #8 ; R6 := centiseconds today + +; first work out bits from R6 + + LDR R7, =ticksperhour + DivRem R4, R6, R7, R9 ; R4 := hours + LDR R7, =ticksperminute + DivRem R5, R6, R7, R9 ; R5 := minutes + LDR R7, =tickspersecond + DivRem R10, R6, R7, R9 ; R10 := seconds + ; R6 := centiseconds + Push "R4,R5,R6,R10" + +; now work out bits from R8 + + ADD R11, R8, #1 ; R11 := fudged copy of days since 1900 + MOV R5, #7 + DivRem R6, R11, R5, R7 ; R11 := days MOD 7 (ie day of week) + ADD R11, R11, #1 ; make in range 1..7 + + MOV R5, #00 ; units of years = 00 + MOV R4, #19 ; hundreds of years = 19 +10 + MOV R6, #0 ; 0 if not a leap year + TST R5, #3 ; if not divis by 4 then not leap year + BNE %FT30 + TEQ R5, #0 ; elif not divis by 100 then leap + BNE %FT20 + TST R4, #3 ; elif not divis by 400 then not leap + BNE %FT30 +20 + MOV R6, #1 ; 1 if leap year +30 + LDR R7, =365 ; normally take off 365 days per year + ADD R7, R7, R6 ; extra day if leap year + + SUBS R8, R8, R7 ; try taking off 365 or 366 days + BCC %FT40 ; [failed the subtract] + ADD R5, R5, #1 ; increment year if successful + CMP R5, #100 + MOVEQ R5, #0 + ADDEQ R4, R4, #1 + B %BT10 + +40 + ADD R8, R8, R7 ; add back on if we couldn't do it + ; R8 is day of year (0..365) + Push "R4,R5" ; push yearhi, yearlo + + ADD R7, R8, #1 ; R7 = day number in range 1-366 + Push "R7, R11" ; push d-o-y, d-o-w + +; now compute week number + + SUBS R7, R11, #2 ; dow (Sun=-1, Mon=0,... ,Sat=5) + ADDCC R7, R7, #7 ; dow (Mon=0,... ,Sun=6) + SUB R7, R8, R7 ; day-of-year no. of start of week + + ADD R7, R7, #6 ; work out week number as if + ; 1st part week is week 0 + MOV R10, #7 + DivRem R11, R7, R10, R9 ; R11 = week number (0..53) + ; R7 (remainder) indicates dayofweek + ; of start of year (Mon=6,Tue=5..Sun=0) + CMP R7, #3 ; if year starts on Mon..Thu + ADDCS R11, R11, #1 ; then 1st part week is week 1 + + TEQ R7, #4 ; if a Wednesday + TEQEQ R6, #1 ; in a leap year + TEQNE R7, #3 ; or a Thursday in any year + MOVEQ R9, #53 ; then allow 53 weeks in year + MOVNE R9, #52 ; else only 52 weeks + CMP R11, R9 ; if more than this + MOVHI R11, #1 ; then week 1 of next year + + TEQ R11, #0 ; if not week 0 + BNE %FT45 ; then finished + + CMP R7, #1 ; HI => Fri, EQ => Sat, CC => Sun + ADC R11, R11, #52 ; Fri => 53, Sun => 52, Sat => dunno + BNE %FT45 + +; 1st day of year is Saturday +; if previous year was leap, then is week 53, else is week 52 + + SUBS R5, R5, #1 ; decrement year + MOVCC R5, #99 + SUBCC R4, R4, #1 + + TST R5, #3 ; if not divis by 4 then not leap year + BNE %FT42 + TEQ R5, #0 ; elif not divis by 100 then leap + BNE %FT45 + TST R4, #3 ; elif not divis by 400 then not leap +42 + MOVNE R11, #52 ; not leap, so must be week 52 +45 + Push "R11" ; push weekno + + ADRL R7, MonthLengths+1 ; R7 -> Jan(31) (Feb is stored as 29) + EOR R6, R6, #1 ; R6 = 1 <=> not a leap year + MOV R9, #1 ; month number (1 = Jan) +50 + LDRB R10, [R7], #1 ; get next month + CMP R9, #2 ; if we're trying for Feb + SUBEQ R10, R10, R6 ; and not leap then subtract a day + SUBS R8, R8, R10 ; subtract off month value + ADDCS R9, R9, #1 ; if successful month +:= 1 + BCS %BT50 + + ADD R8, R8, R10 ; add the month back on if we failed + ADD R8, R8, #1 ; day of month in range 1..31 + + Push "R8,R9" ; push d-o-m, month +CDATMainLoop + SUBS R2, R2, #1 ; decrement buffer size + BCC CDATBufferError ; error: buffer too small + LDRB R0, [R3], #1 ; get byte from format string + TEQ R0, #"%" ; is it a escape sequence ? + BEQ %FT65 ; yes, then do specially + STRB R0, [R1], #1 ; no, then store in output buffer + TEQ R0, #0 ; end of format string ? + BNE CDATMainLoop ; no, then loop + +; end of format string, so finish + + SUB R1, R1, #1 ; make R1 point to 0 byte + + ADD R13, R13, #11*4 ; junk dom,month,woy,doy + ; junk dow,yearhi,yearlo,hours + ; junk mins,secs,centisecs + + Pull "R0,R3" ; R0 := input R1; junk input R2 + Pull "R3-R11, R14" ; restore other registers + ExitSWIHandler ; and exit + +; come here if run out of buffer space for string + +CDATBufferError + ADR R0, ErrorBlock_CDATBufferOverflow ; point R0 to error block +CDATError + ADD R13, R13, #11*4 ; junk dom,month,woy,doy + ; junk dow,yearhi,yearlo,hours + ; junk mins,secs,centisecs + Pull "R1-R11,R14" ; restore all registers apart from R0 + ORR R14, R14, #V_bit ; set V in R14 for exit + ExitSWIHandler + + MakeErrorBlock CDATBufferOverflow + + MakeErrorBlock CDATBadField + +; process "%" escape sequences + +65 + LDRB R0, [R3], #1 ; get next character + TEQ R0, #"0" ; if char = "0" + MOVEQ R0, #0 ; convert to <0> + TEQNE R0, #"%" ; or if char = "%", store "%" + STREQB R0, [R1], #1 ; store <0> or "%" + BEQ CDATMainLoop ; and loop + + UpperCase R0, R5 ; convert character to upper case + EORS R7, R0, #"Z" ; zero if we have "Z" specifier + BNE %FT67 ; not "Z" + + LDRB R0, [R3], #1 ; is "Z", so get another char + UpperCase R0, R5 ; convert character to upper case +67 + TEQ R0, #0 ; are they a wally! + BEQ CDATFieldError ; yes, then bomb out (avoid data abort) + + LDRB R4, [R3], #1 ; get next char + UpperCase R4, R5 ; and convert that to upper case + + ORR R0, R0, R4, LSL #8 ; 2 chars in bottom two bytes + + ADR R4, CDATEscTab ; point to table + ADR R5, CDATEscTabEnd ; end of table +70 + TEQ R4, R5 ; are we at end of table +CDATFieldError + ADREQ R0, ErrorBlock_CDATBadField + BEQ CDATError ; yes, then invalid escape sequence + LDR R6, [R4], #4 ; chars in top two bytes + EOR R6, R6, R0, LSL #16 ; if match, then must be < 1:SHL:16 + CMP R6, #(1 :SHL: 16) + BCS %BT70 ; no match, so loop + +; found mnemonic match + + AND R0, R6, #&03 ; R0 = number of digits to print + AND R4, R6, #&FC ; R4 = stack offset + LDR R4, [R13, R4] ; R4 = data item + MOV R6, R6, LSR #8 ; R6 = code offset in words +CDATBranch + ADD PC, PC, R6, LSL #2 ; go to routine + +CDATEscTab + CDATT DY, 0 + CDATT ST, 0 + CDATT MN, 1 + CDATT MO, 1 + CDATT M3, 1 + CDATT WK, 2 + CDATT DN, 3, 3 + CDATT WN, 4, 1 + CDATT W3, 4, 1 + CDATT WE, 4, 1 + CDATT CE, 5 + CDATT YR, 6 + CDATT 24, 7 + CDATT 12, 7 + CDATT AM, 7 + CDATT PM, 7 + CDATT MI, 8 + CDATT CS, 9 + CDATT SE, 10 +CDATEscTabEnd + +; routine to print R0 digits of the number held in R4, +; R7=0 <=> suppress leading zeroes + +CDATDY +CDATMN +CDATWK +CDATDN +CDATWN +CDATCE +CDATYR +CDAT24 +CDATMI +CDATCS +CDATSE +CDATDecR4 ROUT + ADD R2, R2, #1 ; undo initial subtract + ADR R6, PowersOfTen +10 + MOV R5, #0 + TEQ R0, #1 ; if on last digit + MOVEQ R7, #1 ; definitely don't suppress +20 + LDRB R8, [R6, R0] ; get power of ten to subtract + SUBS R4, R4, R8 ; subtract value + ADDCS R5, R5, #1 + BCS %BT20 + ADD R4, R4, R8 ; undo failed subract + + ORRS R7, R7, R5 ; Z => suppress it + BEQ %FT30 ; [suppressing] + + ORR R5, R5, #"0" ; convert to ASCII digit + SUBS R2, R2, #1 ; one less space in buffer + BCC CDATBufferError + STRB R5, [R1], #1 ; store character +30 + SUBS R0, R0, #1 ; next digit + BNE %BT10 ; [another digit to do] + B CDATMainLoop + +PowersOfTen + = 0, 1, 10, 100 + ALIGN + +; Hours in 12 hour format + +CDAT12 + CMP R4, #12 ; if in range 12..23 + SUBCS R4, R4, #12 ; then make in range 00..11 + TEQ R4, #0 ; if 00 + MOVEQ R4, #12 ; then make 12 + B CDATDecR4 + +; AM or PM indication + +CDATAM +CDATPM + CMP R4, #12 ; if earlier than 12 o'clock + ADRCC R4, CDATamstr ; then am + ADRCS R4, CDATpmstr ; else pm +CDATdostr + LDRB R0, [R4], #1 ; get byte from string + TEQ R0, #0 ; if zero, then end of string + BEQ CDATMainLoop ; so loop +CDATdostrloop + STRB R0, [R1], #1 ; we know there's room for one char +CDATdostr2 + LDRB R0, [R4], #1 ; get byte from string + TEQ R0, #0 ; if zero, then end of string + BEQ CDATMainLoop ; so loop + SUBS R2, R2, #1 ; dec R2 for next char + BCS CDATdostrloop ; OK to do another char + B CDATBufferError ; ran out of buffer space + +CDATST + TEQ R4, #1 + TEQNE R4, #21 + TEQNE R4, #31 + ADREQ R4, CDATststr + BEQ CDATdostr + TEQ R4, #2 + TEQNE R4, #22 + ADREQ R4, CDATndstr + BEQ CDATdostr + TEQ R4, #3 + TEQNE R4, #23 + ADREQ R4, CDATrdstr + ADRNE R4, CDATthstr + B CDATdostr + +CDATW3 + ADRL R0, DayNameTable-4 ; Sun is 1 + B CDATdo3 +CDATM3 + ADRL R0, MonthNameTable-4 ; Jan is month 1 +CDATdo3 + ADD R4, R0, R4, LSL #2 ; point to short month name + LDRB R0, [R4], #1 ; get 1st char of month + BIC R0, R0, #&20 ; upper case + STRB R0, [R1], #1 ; and store + B CDATdostr2 ; then do rest + +CDATWE + ADD R4, R4, #12 ; skip months +CDATMO + ADR R0, LongMonthTable-1 ; Jan is month 1 + LDRB R4, [R0, R4] ; get offset to month string + ADD R4, R0, R4 ; point to start of string + B CDATdostr + +CDATamstr + = "am", 0 +CDATpmstr + = "pm", 0 +CDATststr + = "st", 0 +CDATndstr + = "nd", 0 +CDATrdstr + = "rd", 0 +CDATthstr + = "th", 0 + +LongMonthTable + = LongJan-(LongMonthTable-1) + = LongFeb-(LongMonthTable-1) + = LongMar-(LongMonthTable-1) + = LongApr-(LongMonthTable-1) + = LongMay-(LongMonthTable-1) + = LongJun-(LongMonthTable-1) + = LongJul-(LongMonthTable-1) + = LongAug-(LongMonthTable-1) + = LongSep-(LongMonthTable-1) + = LongOct-(LongMonthTable-1) + = LongNov-(LongMonthTable-1) + = LongDec-(LongMonthTable-1) + = LongSun-(LongMonthTable-1) + = LongMon-(LongMonthTable-1) + = LongTue-(LongMonthTable-1) + = LongWed-(LongMonthTable-1) + = LongThu-(LongMonthTable-1) + = LongFri-(LongMonthTable-1) + = LongSat-(LongMonthTable-1) + +LongJan = "January", 0 +LongFeb = "February", 0 +LongMar = "March", 0 +LongApr = "April", 0 +LongMay = "May", 0 +LongJun = "June", 0 +LongJul = "July", 0 +LongAug = "August", 0 +LongSep = "September", 0 +LongOct = "October", 0 +LongNov = "November", 0 +LongDec = "December", 0 +LongSun = "Sunday", 0 +LongMon = "Monday", 0 +LongTue = "Tuesday", 0 +LongWed = "Wednesday", 0 +LongThu = "Thursday", 0 +LongFri = "Friday", 0 +LongSat = "Saturday", 0 + + ALIGN + ] + LTORG + + END diff --git a/s/PMF/i2cutils b/s/PMF/i2cutils new file mode 100644 index 0000000000000000000000000000000000000000..140481975a9fd3a65eb3538892a932cedb8251f3 --- /dev/null +++ b/s/PMF/i2cutils @@ -0,0 +1,857 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.PMF.i2cutils + +; Authors JBiggs (m2), PFellows, TDobson, AGodwin + +PhysChecksum * (((CheckSumCMOS + &30) :MOD: &F0) + &10) + +; ***************************************************************************** +; +; HexToBCD - Convert byte in hex to BCD +; +; in: R0 = byte in hex +; +; out: R0 = byte in BCD (ie R0 := (R0 DIV 10)*16 + R0 MOD 10) +; All other registers preserved +; + +HexToBCD ROUT + Push "R1,R2, R14" + MOV R1, #10 + DivRem R2, R0, R1, R14 ; R2=R0 DIV 10; R0=R0 MOD 10 + ADD R0, R0, R2, LSL #4 + Pull "R1,R2, PC" + +; ***************************************************************************** +; +; BCDToHex - Convert byte in BCD to hex +; +; in: R0 = byte in BCD (ie x*16 + y) +; +; out: R0 = byte in hex (ie x*10 + y) +; All other registers preserved +; + +BCDToHex ROUT + Push "R14" + MOV R14, R0, LSR #4 ; R14 := x + ADD R14, R14, R14, LSL #1 ; R14 := x*3 + SUB R0, R0, R14, LSL #1 ; R0 := R0 - x*6 = x*10 + Pull "PC" + +; ***************************************************************************** +; +; SetC1C0 - Set clock and data lines to values in R1 and R0 respectively +; +; out: All registers preserved, including PSR +; + +SetC1C0 ROUT + Push "R0-R2,R14" + ADD R0, R0, R1, LSL #1 ; R0 := C0 + C1*2 + + [ AssemblingArthur :LOR: Module + MOV R2, #0 ; prepare to index soft copy + LDRB R1, [R2, #IOCControlSoftCopy] ; read soft copy + BIC R1, R1, #&03 ; clear clock and data + ORR R0, R1, R0 ; put in new clock and data + ORR R0, R0, #&C0 ; make sure two test bits are + ; always set to 1 ! + STRB R0, [R2, #IOCControlSoftCopy] ; store back to soft copy + | + ORR R0, R0, #&FC ; set other bits to 1 + ] + + MOV R2, #IOC + STRB R0, [R2, #IOCControl] + + MOV R0, #10 ; delay for >= 10/2 microsecs + BL DoMicroDelay + + Pull "R0-R2,PC",,^ + +; ***************************************************************************** +; +; DoMicroDelay - Delay for >= R0/2 microseconds +; +; in: R0 = time delay in 1/2 microsecond units +; R2 -> IOC +; On ARM600, we may or may not be in a 32-bit mode +; +; out: R0,R1 corrupted +; + +DoMicroDelay ROUT + Push R14 + + STRB R0, [R2, #Timer0LR] ; copy counter into output latch + LDRB R1, [R2, #Timer0CL] ; R1 := low output latch +10 + STRB R0, [R2, #Timer0LR] ; copy counter into output latch + LDRB R14, [R2, #Timer0CL] ; R14 := low output latch + TEQ R14, R1 ; unchanged ? + BEQ %BT10 ; then loop + MOV R1, R14 ; copy anyway + SUBS R0, R0, #1 ; decrement count + BNE %BT10 ; loop if not finished + + Pull PC + + LTORG + +; ***************************************************************************** +; +; ClockData - Clock a bit of data down the IIC bus +; +; in: R0 = data bit +; +; out: All registers preserved, including PSR +; + +ClockData ROUT + Push "R1, R14" + + MOV R1, #0 ; Clock lo + BL SetC1C0 + + [ {TRUE} +; Disable interrupts to ensure clock hi with data hi is only transient +; This allows BMU to detect idle condition by polling + + MOV R1,PC + ORR R1,R1,#I_bit + TEQP PC,R1 + ] + MOV R1, #1 ; Clock hi + BL SetC1C0 + +; Delay here must be >= 4.0 microsecs + + MOV R1, #0 ; Clock lo + BL SetC1C0 + + Pull "R1, PC",,^ + +ClockData0 ROUT ; Clock a zero bit + Push "R0, R14" + MOV R0, #0 + BL ClockData + Pull "R0, PC",,^ + +; ***************************************************************************** +; +; Start - Send the Start signal +; +; out: All registers preserved, including PSR +; + +Start ROUT + Push "R0-R2,R14" + + MOV R0, #1 ; clock HI, data HI + MOV R1, #1 + BL SetC1C0 + +; Delay here must be >= 4.0 microsecs + + MOV R0, #0 ; clock HI, data LO + MOV R1, #1 + BL SetC1C0 + + [ {TRUE} +; Hold start condition for BMU + + MOV R2, #IOC + MOV R0,#10 + BL DoMicroDelay + ] + +; Delay here must be >= 4.7 microsecs + + MOV R0, #0 ; clock LO, data LO + MOV R1, #0 + BL SetC1C0 + + Pull "R0-R2,PC",,^ + +; ***************************************************************************** +; +; Acknowledge - Check acknowledge after transmitting a byte +; +; out: All registers preserved +; V=0 => acknowledge received +; V=1 => no acknowledge received +; + +Acknowledge ROUT + Push "R0-R2,R14" + + MOV R0, #1 ; clock LO, data HI + MOV R1, #0 + BL SetC1C0 + + [ {TRUE} +; Disable interrupts to ensure clock hi with data hi is only transient +; This allows BMU to detect idle condition by polling + + MOV R1,PC + Push "R1" + ORR R1,R1,#I_bit + TEQP PC,R1 + ] + MOV R0, #1 ; clock HI, data HI + MOV R1, #1 + BL SetC1C0 + +; Delay here must be >= 4.0 microsecs + + MOV R2, #IOC + LDRB R2, [R2, #IOCControl] ; get the data from IOC + + MOV R0, #0 + MOV R1, #0 ; clock lo + BL SetC1C0 + + [ {TRUE} + Pull "R1" + TEQP PC,R1 + ] + + TST R2, #1 ; should be LO for correct acknowledge + MOV R2, PC + BICEQ R2, R2, #V_bit ; clear V if correct acknowledge + ORRNE R2, R2, #V_bit ; set V if no acknowledge + TEQP R2, #0 + + Pull "R0-R2,PC" + +; ***************************************************************************** +; +; Stop - Send the Stop signal +; +; out: All registers preserved, including PSR +; + +Stop ROUT + Push "R0,R1,R14" + + MOV R0, #0 ; clock HI, data LO + MOV R1, #1 + BL SetC1C0 + +; Delay here must be >= 4.0 microsecs + + MOV R0, #1 ; clock HI, data HI + MOV R1, #1 + BL SetC1C0 + + Pull "R0,R1,PC",,^ + +; ***************************************************************************** +; +; TXByte - Transmit a byte +; +; in: R0 = byte to be transmitted +; +; out: All registers preserved, including PSR +; + +TXByte ROUT + Push "R0-R2,R14" + MOV R2, R0 ; byte goes into R2 + MOV R1, #&80 ; 2^7 the bit mask +10 + ANDS R0, R2, R1 ; zero if bit is zero + MOVNE R0, #1 + BL ClockData ; send the bit + MOVS R1, R1, LSR #1 + BNE %BT10 + Pull "R0-R2,PC",,^ + +; ***************************************************************************** +; +; RXByte - Receive a byte +; +; out: R0 = byte received +; All other registers preserved, including PSR +; + +RXByte ROUT + Push "R1-R4, R14" + MOV R3, #0 ; byte:=0 + MOV R2, #IOC + MOV R4, #7 + + MOV R0, #1 ; clock LO, data HI + MOV R1, #0 + BL SetC1C0 +10 + [ {TRUE} +; Disable interrupts to ensure clock hi with data hi is only transient +; This allows BMU to detect idle condition by polling + + MOV R1,PC + Push "R1" + ORR R1,R1,#I_bit + TEQP PC,R1 + ] + MOV R0, #1 ; pulse clock HI + MOV R1, #1 + BL SetC1C0 + + LDRB R1, [R2, #IOCControl] ; get the data from IOC + AND R1, R1, #1 + ADD R3, R1, R3, LSL #1 ; byte:=byte*2+(IOC?0)AND1 + + MOV R0, #1 ; return clock LO + MOV R1, #0 + BL SetC1C0 + + [ {TRUE} + Pull "R1" + TEQP PC,R1 + ] + SUBS R4, R4, #1 + BCS %BT10 + + MOV R0, R3 ; return the result in R0 + Pull "R1-R4, PC",,^ + +; ***************************************************************************** +; +; Write - Write a byte of CMOS RAM specified by logical address +; +; in: R0 = address in CMOS RAM +; R1 = data +; +; out: All registers preserved +; + +Write ROUT + Push "R0-R4, R14" + BL MangleCMOSAddress + Pull "R0-R4, PC", CS ; if invalid, then exit + + MOV R2, R0 + MOV R3, R1 + [ ChecksumCMOS + BL ReadStraight ; calculate new checksum : + MOV R4, R0 + MOV R0, #PhysChecksum + BL ReadStraight + SUB R0, R0, R4 ; = oldsum - oldcontents + ADD R4, R0, R3 ; + newcontents + + AND R4, R4, #&FF + CMPS R2, #PhysChecksum ; don't write new checksum ... + ORREQ R4, R4, #&100 ; if checksum is being written + ] +10 + [ CacheCMOSRAM + ADR R0, CMOSRAMCache-16 ; update cache, but always write to + STRB R3, [R0, R2] ; real hardware as well + ] + BL Start + + MOV R0, #&A0 + BL TXAck + + MOV R0, R2 ; address + BL TXAck + + MOV R0, R3 ; data + BL TXAck + + BL Stop + [ ChecksumCMOS + TST R4, #&100 ; loop again to write new checksum + MOV R3, R4 + MOV R2, #PhysChecksum + ORR R4, R4, #&100 ; but ensure it only happens once + BEQ %BT10 + ] + Pull "R0-R4, PC" + +; ***************************************************************************** +; +; Read - Read a byte of CMOS RAM specified by logical address +; ReadStraight - Read a byte of CMOS RAM specified by physical address +; +; in: R0 = address in CMOS RAM +; +; out: R0 = data (illegal address return 0) +; All other registers preserved +; + +ReadStraight ROUT + Push "R1,R2,R14" + B %FT10 + +Read + Push "R1,R2,R14" + BL MangleCMOSAddress + MOVCS R0, #0 ; pretend illegal addresses contain 0 + Pull "R1,R2,PC", CS +10 + [ CacheCMOSRAM + TEQ R0, #&40 ; is it Econet station number + BEQ %FT15 ; if so then don't use cache + [ {FALSE} ; CMOS read debugging + MOV R1, #0 + LDR R1, [R1] ; if !0 < &100 then it's a handle to bput to + CMP R1, #&100 + SWICC XOS_BPut + ] + CMP R0, #&10 ; only cache values &10..&3F,&41..&FF + ADRCS R2, CMOSRAMCache-&10 ; if in range + LDRCSB R0, [R2, R0] ; read from cache + Pull "R1,R2,PC", CS ; and exit +15 + +; else drop thru into real CMOS reading code + ] + + MOV R2,R0 ; save the address + + BL Start + + MOV R0, #&A0 + BL TXAck + + MOV R0, R2 ; address + BL TXAck + + BL Start + + MOV R0, #&A1 + BL TXAck + + BL RXByte ; returned in R0 + MOV R2, R0 ; copy to R2 for now + + MOV R0, #1 + BL ClockData + + BL Stop + + MOV R0, R2 ; return the result + + Pull "R1,R2,PC" + +; ***************************************************************************** +; +; MangleCMOSAddress - Convert from logical to physical CMOS address +; +; in: R0 = logical address (&00..&FF) +; +; out: C=0 => valid logical address (ie &00..&EF) +; R0 = physical address (&40..&FF,&10..&3F) +; +; C=1 => invalid logical address (ie &F0..&FF) +; R0 preserved +; + +MangleCMOSAddress ROUT + CMP R0, #&F0 + ORRCSS PC, R14, #C_bit ; indicate invalid + ADD R0, R0, #&40 ; now in range &40..&13F + CMP R0, #&100 + SUBCS R0, R0, #(&100-&10) ; now in range &40..&FF, &10..&3F + BICS PC, R14, #C_bit ; indicate valid + +; ***************************************************************************** + +HTBTA ROUT + Push R14 + BL HexToBCD + BL TXAck + Pull PC + +TXAck ROUT + Push R14 + BL TXByte + BL Acknowledge + Pull PC + +CD0RBTH ROUT + Push R14 + BL ClockData0 + BL RXByte + BL BCDToHex + Pull PC + +; ***************************************************************************** +; +; ValChecksum - test to see if the CMOS checksum is OK +; This routine performs MangleCMOSAddress inherently, and +; assumes the checksum is the last logical location. +; +; in: none +; +; out: R0 = calculated checksum +; Z set if checksum is valid +; All other registers preserved +; + + [ ChecksumCMOS + +ValChecksum ROUT + Push "R1,R2,R3,R14" + + MOV R2, #&40 + MOV R3, #CMOSxseed +; +; Write a memory word address to the 8583 +10 + BL Start + + MOV R0, #&A0 ; 8583 write address + BL TXAck + + MOV R0, R2 ; memory word address + BL TXAck + + BL Start + + MOV R0, #&A1 ; 8583 read address + BL TXAck +; +; Read data from the 8583 from locations &40 through &FF, then +; loop back to &10 (we have to write the address again) and read +; on until &3E .. thus missing out the checksum location. +; +20 + BL RXByte ; returned in R0 + ADD R3, R3, R0 ; accumulate into R3 + + ADD R2, R2, #1 ; increment R2 to phys. address + TST R2, #&100 ; limit, or until checksum. + BNE %30 + CMPS R2, #PhysChecksum + BEQ %30 + + MOV R0, #0 ; not done .. ACK that byte + BL ClockData + B %BT20 ; .. and continue reading +30 + MOV R0, #1 ; finish off reading block + BL ClockData + BL Stop + TST R2, #&100 ; either go back for bytes 10 - 3f + MOVNE R2, #&10 ; or finish up completely. + BNE %BT10 + +; +; R3 contains the actual checksum. Compare it with the recorded checksum +; + MOV R0, #PhysChecksum + BL ReadStraight + AND R2, R0, #&FF ; value from checksum location + AND R0, R3, #&FF ; calculated value into R0 + CMPS R0, R2 + + Pull "R1,R2,R3,PC" + ] + +; ***************************************************************************** +; +; MakeChecksum - calculate and write a correct checksum +; +; in: none +; +; out: R0 = calculated checksum +; All other registers preserved +; + + [ ChecksumCMOS + +MakeChecksum ROUT + Push R14 + BL ValChecksum + MOV R1, R0 + MOV R0, #CheckSumCMOS + BL Write + Pull PC + ] + +; ***************************************************************************** +; +; SetTime - Write the CMOS clock time +; +; in: R0 = hours +; R1 = minutes +; R2 = day of month +; R3 = month +; R5 = year (lo) +; R6 = year (hi) +; R7 = seconds +; R8 = centiseconds +; +; Any of the above, if -1, will not be written to +; + +SetTime ROUT + Push "R4, R14" ; save registers + + [ :LNOT: NewClockChip + CMP R1, #-1 ; test if setting mins + BEQ %FT10 ; [no, then skip] + + Push R0 + MOV R7, #0 ; zero seconds and centiseconds + MOV R8, #0 + STRB R8, CentiTime + STRB R7, SecondsTime + STRB R7, SecondsDirty ; seconds are in sync now + + BL Start + MOV R0, #&D0 + BL TXAck + MOV R0, #&20 ; zero the seconds on the chip + BL TXAck + BL Stop + Pull R0 +10 + CMP R3, #-1 ; test if setting months + BEQ %FT20 ; [no, then skip] + + Push "R0,R1" + MOV R1, R3 + MOV R0, #MonthCMOS + BL Write ; remember last updated months + + CMP R3, #2 ; if Jan + CMPEQ R2, #28 ; or Feb 1..28 + MOVLS R1, #0 ; not had 29th of Feb + MOVHI R1, #1 ; have had 29th of Feb + MOV R0, #LeapCMOS + BL Write ; set 29thFeb flag + Pull "R0,R1" +20 + ] + +; write year to CMOS RAM + + Push "R0,R1" + MOVS R1, R5 + MOVPL R0, #YearCMOS + BLPL Write + MOVS R1, R6 + MOVPL R0, #YearCMOS+1 + BLPL Write + Pull "R0,R1" + + MOV R4, R0 ; save hours in R4 + CMP R4, #-1 ; are we writing time ? + BEQ %FT30 ; [no, then skip] + + [ NewClockChip + BL Start + MOV R0, #&A0 + BL TXAck + MOV R0, #1 ; start at address 1 + BL TXAck + MOV R0, R8 ; centiseconds + BL HTBTA + MOV R0, R7 ; seconds + BL HTBTA + MOV R0, R1 ; minutes + BL HTBTA + MOV R0, R4 ; hours + BL HTBTA + BL Stop + | + BL Start + MOV R0, #&D0 + BL TXAck + MOV R0, #0 ; start at address 0 + BL TXAck + MOV R0, R4 ; hours + BL HTBTA + MOV R0, R1 ; minutes + BL HTBTA + BL Stop + ] +30 + CMP R2, #-1 ; are we writing date ? + BEQ %FT40 ; [no, then skip] + + [ NewClockChip + BL Start + MOV R0, #&A0 + BL TXAck + MOV R0, #5 ; start at address 5 + BL TXAck + MOV R0, R2 ; day of month + BL HexToBCD + ORR R0, R0, R5, LSL #6 ; year in bits 6,7; day in bits 0..5 + BL TXAck + MOV R0, R3 ; months + BL HTBTA + BL Stop + | + BL Start + MOV R0, #&D0 + BL TXAck + MOV R0, #2 ; start at address 2 + BL TXAck + MOV R0, R2 ; days + BL HTBTA + MOV R0, R3 ; months + BL HTBTA + BL Stop + ] +40 + MOV R0, R4 ; put hours back in R0 + BL RTCToRealTime + + Pull "R4, PC" + +; ***************************************************************************** +; +; ReadTime - Read the CMOS clock time +; +; in: - +; +; out: R0 = hours +; R1 = minutes +; R2 = days +; R3 = months +; R5 = year (lo) +; R6 = year (hi) +; R7 = seconds +; R8 = centiseconds +; + +ReadTime ROUT + Push "R4, R14" + + [ NewClockChip + BL Start + MOV R0, #&A0 + BL TXAck + MOV R0, #&01 ; start at address 1 + BL TXAck + BL Start + MOV R0, #&A1 + BL TXAck + BL RXByte + BL BCDToHex + MOV R8, R0 ; centiseconds + BL CD0RBTH + MOV R7, R0 ; seconds + BL CD0RBTH + MOV R1, R0 ; minutes + BL CD0RBTH + MOV R4, R0 ; hours + BL ClockData0 + BL RXByte + AND R0, R0, #&3F ; day of month (clear year bits) + BL BCDToHex + MOV R2, R0 + BL ClockData0 + BL RXByte + AND R0, R0, #&1F ; month (clear day of week bits) + BL BCDToHex + MOV R3, R0 + MOV R0, #1 + BL ClockData + BL Stop + | + BL Start + MOV R0, #&D0 + BL TXAck + MOV R0, #&00 ; start at address 0 + BL TXAck + BL Start + MOV R0, #&D1 + BL TXAck + BL RXByte + BL BCDToHex + MOV R4, R0 ; hours + BL CD0RBTH + MOV R1, R0 ; minutes + BL CD0RBTH + MOV R2, R0 ; days + BL CD0RBTH + MOV R3, R0 ; months + MOV R0, #1 + BL ClockData + BL Stop + LDRB R7, SecondsTime + LDRB R8, CentiTime + ] + + MOV R0, #YearCMOS + BL Read + MOV R5, R0 ; year (lo) + + MOV R0, #YearCMOS+1 + BL Read + MOV R6, R0 ; year (hi) + + MOV R0, R4 ; put hours in R0 + +; Ensure day/month are non-zero, fixes RTCToRealTime + [ {TRUE} ; LRust, fix RP-0370 + TEQ R2, #0 ; Valid day? + MOVEQ R2, #1 ; No then force 1st + TEQ R3, #0 ; Invalid month? + MOVEQ R3, #1 ; Yes then force Jan + ] + Pull "R4, PC" + +; ***************************************************************************** +; +; InitCMOSCache - Initialise cache of CMOS RAM + + [ CacheCMOSRAM + +InitCMOSCache ENTRY "r0-r3" + MOV R2, #16 + ADR R3, CMOSRAMCache-16 + + BL Start + + MOV R0, #&A0 ; 8583 write address + BL TXAck + + MOV R0, R2 ; memory word address + BL TXAck + + BL Start + + MOV R0, #&A1 ; 8583 read address + BL TXAck + +10 + BL RXByte ; returned in R0 + STRB R0, [R3, R2] + ADD R2, R2, #1 ; increment R2 to phys. address + CMP R2, #&100 + BEQ %FT20 + + MOV R0, #0 ; not done .. ACK that byte + BL ClockData + B %BT10 ; .. and continue reading +20 + MOV R0, #1 ; finish off reading block + BL ClockData + BL Stop + EXIT + + ] + END diff --git a/s/PMF/key b/s/PMF/key new file mode 100644 index 0000000000000000000000000000000000000000..6a467b862b12feba356ad3dff96068d7565971b9 --- /dev/null +++ b/s/PMF/key @@ -0,0 +1,1428 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.PMF.Key + +; ARTHUR keyboard code + +; Authors Tim Dobson, Jon Thackray +; Started 13-Oct-86 + +; ************************************************************ +; *** C h a n g e L i s t (better late than never!) *** +; ************************************************************ + +; Date Who Description +; ---- --- ----------- +; 17-Feb-88 Added Sam's code to call the callback vector in RDCH/INKEY +; idle loop +; 02-Mar-88 Initialise KeyVec to NewKeyStruct before the keyboard has told +; us its ID, so Sam can call INKEY(-ve) with no keyboard +; 13-Apr-88 Fixed RDCH from RS423 if treating as keyboard, getting NUL+char +; (didn't try to reenable RTS on 2nd char) +; 11-Jun-88 Put input redirection where it was needed really. SKS +; 12-Aug-88 Read mouse position from buffer forces inside bounding box +; 02-Sep-88 Buffered mouse coords stored in absolute terms, not relative to +; origin at time of click. Made relative after reading out and +; clipping to bounding box. Mouse event coords are still relative +; to origin at time of click. +; 06-Feb-91 LastLED added to stop unnecessary LED transmissions +; +; 24-Feb-93 SMC Split off Archimedes keyboard driver into file KbdDrA1. +; Split off mouse stuff into file mouse. +; Added new interfaces for generic keyboard driver. +; 23-Aug-93 SMC GotKbId now sets KbId but remembers the last in LastKbId. +; 24-Aug-93 SMC Key handler can now get keyboard stuff going. +; 18-Nov-93 SMC Fixed bug in key handler stuff (no handler => KeyVec=-1). +; 25-Nov-93 SMC Key handler and keyboard driver now trigger each other correctly. +; 25-Apr-94 RCM ReadCh modified for Stork's power saving scheme. +; + + GBLL MouseBufferFix +MouseBufferFix SETL {TRUE} + + + [ :LNOT: AssemblingArthur + GBLL redirectinkey +redirectinkey SETL {FALSE} + ] + +; ***************************************************************************** +; +; Entry point for keyboard code - Initialisation +; + +KeyInit ROUT + MOV R11, #KeyWorkSpace + Push R14 + + [ AssemblingArthur + TEQP PC,#I_bit :OR: SVC_mode + | + SWI OS_IntOff + SWI OS_EnterOS + ] + + [ Keyboard_Type = "A1A500" + BL A1KeyInit + ] + + [ :LNOT: AssemblingArthur + MOV R0, #RdchV + ADRL R1, NewRdch + SWI OS_Claim + ] + + [ AssembleA1KeyHandler + ADRL R0, NewKeyStruct ; point to new structure for now + STR R0, KeyVec + | + MOV R0, #-1 ; no default key handler + STR R0, KeyVec + ] + + MOV R0, #&FF ; indicate no previous keyboard id + STRB R0, LastKbId + STRB R0, KbId + + BL ClearKbd + + [ Keyboard_Type = "A1A500" + BL A1Reset + ] + + [ :LNOT: AssemblingArthur + TEQP PC, #I_bit + MOVNV R0, R0 + ] + + Pull PC ; go back to user + +; ***************************************************************************** +; +; KeyPostInit - Called after modules have initialised +; + +KeyPostInit ROUT + Push R14 + MOV R11, #KeyWorkSpace + PHPSEI ; disable interrupts round this bit + Push R14 ; save I_bit indication + LDRB R1, LastKbId + TEQ R1, #&FF ; if no keyboard initialised yet then + LDREQB R1, KbId ; try now + BLEQ GotKbId + Pull R14 ; restore I_bit indication + PLP ; set I_bit from this + + LDROSB R1, LastBREAK ; is it a soft reset ? + TEQ R1, #0 + Pull PC, EQ ; if so, then exit + + MOV R0, #OsbyteSetCountry + LDROSB R1, Country + SWI XOS_Byte + Pull PC + +; ***************************************************************************** + +ClearKbd ROUT + Push R14 + + MOV R0, #&FF + STRB R0, CurrKey ; no current key + STRB R0, OldKey + STRB R0, LastLED + +; Set up keyboard table + + MOV R0, #0 ; All keys up + STR R0, KeysDown ; zero 160 bits = 5 words + STR R0, KeysDown +4 + STR R0, KeysDown +8 + STR R0, KeysDown +12 + STR R0, KeysDown +16 + + Pull PC + +; ***************************************************************************** +; +; UpdateLEDs - Update the LED(s) from the keyboard status byte +; +; in: R11 -> keyboard workspace +; R12 -> IOC +; +; out: R0, R1 corrupted +; + +UpdateLEDs ROUT + LDRB r0, KbId ; get keyboard id + TEQ r0, #&FF ; if not found yet + MOVEQ pc, lr ; then exit + + LDROSB r0, KeyBdStatus ; Build current LED state byte. + TST r0, #KBStat_NoCapsLock + MOVEQ r1, #1 + MOVNE r1, #0 + TST r0, #KBStat_NoNumLock + ORREQ r1, r1, #2 + TST r0, #KBStat_ScrollLock + ORRNE r1, r1, #4 + + LDRB r0, LastLED ; Only update if different. + TEQ r0, r1 + MOVEQ pc,lr + + STRB r1, LastLED + + MOV r0, #3 + [ AssembleKEYV + Push "r10-r12,lr" + MOV r11, pc ; Save current PSR. + TEQP pc, #SVC_mode + I_bit ; Call KEYV in SVC mode, no IRQs. + MOV r10, #KEYV + Push "lr" ; Save SVC lr. + BL CallVector + Pull "lr" ; Restore SVC lr. + TEQP r11, #0 ; Go back to old mode. + NOP + Pull "r10-r12,pc" + | + [ Keyboard_Type = "A1A500" + B A1KeyVec + | + MOV pc, lr + ] + ] + +; ***************************************************************************** +; +; Handle new keyboard id. +; In: r1 = keyboard id +; r11 = KeyWorkSpace +; Out: preserve flags +; +GotKbId + Push lr + + STRB r1, KbId ; Store the new keyboard id. + + LDR r0, KeyVec + Push r0 ; Save old key handler so we know if it's changed. + + LDRB r8, LastKbId + TEQ r8, r1 ; If we have a different keyboard id then + BLNE IssueKeyboardService ; issue service. + + LDR lr, KeyVec ; Get possibly new key handler. + Pull r0 ; And old handler. + TEQ r0, lr ; If key handler has not changed then + BLEQ KeyboardEnable ; handler has not initialised with OS_InstallKeyHandler so we try. + + Pull pc,,^ + +; ***************************************************************************** +; Initialise keyboard handler and enable keyboard driver. +; +; In: r1 = keyboard id +; +KeyboardEnable + Push lr + + BL ClearKbd + + LDR r0, KeyVec + CMP r0, #-1 ; If no key handler + LDRNEB r1, KbId ; or no keyboard yet then + TEQNE r1, #&FF + Pull pc, EQ ; can't initialise. + + STRB r1, LastKbId ; Remember last keyboard id that initialised. + + LDR r8, [r0, #KVInit] ; Initialise key handler. + ADD r8, r8, r0 + BL CallUserKeyCode + + MOV r0, #4 ; Initialise keyboard driver. + [ AssembleKEYV + MOV r10, #KEYV + BL CallVector + | + [ Keyboard_Type = "A1A500" + BL A1KeyVec + ] + ] + Pull pc + + [ AssembleKEYV +; ***************************************************************************** +; +; Default KEYV handler (deal with keyboard id, keys up/down). +; +; In: r0 = reason code 0 +; r1 = keyboard id +; or +; r0 = reason code 1 or 2 +; r1 = key code +; +KeyVector ROUT + CMP r0, #3 ; If not id/key up/key down then + Pull pc, CS ; just claim call. + + Push "r0-r12" + + MOV r11, #KeyWorkSpace + + TEQ r0, #0 ; If keyboard id then + BLEQ GotKbId ; handle it + Pull "r0-r12,pc",EQ ; and claim call. + | +GotKey ROUT + Push lr + ] + + MOV r2, r1 + SUB r1, r0, #1 + + CMP R2, #&A0 + BCS %FT05 + ADR R0, KeysDown + MOV lr, R2, LSR #5 + LDR lr, [R0, lr, LSL #2]! ; load appropriate word + MOV R3, #&80000000 ; index 0 is in top bit + TEQ r1, #0 + BNE %FT03 + + TST lr, R3, ROR R2 ; if going up and key already up (keyboard reinitialised) then + BEQ %FT50 ; nothing to do + B %FT04 ; else clear flag, generate event etc. +03 + TST lr, R3, ROR R2 ; if going down and key already down (weird) then + BNE %FT50 ; nothing to do else... +04 + EOR lr, lr, R3, ROR R2 ; switch state of flag + STR lr, [R0] ; store back +05 + BL KeyboardEvent ; generate key up/down event + + BL CheckForShiftingKey + BCC %FT10 ; [not shifting key] + + BL CallSpecialReturnNChars + B %FT50 + +10 + TEQ r1, #0 ; if key up then + BEQ %FT30 ; go and deal with it + + LDRB R0, CurrKey + TEQ R0, #&FF ; have we got a current key ? + BEQ %FT20 + + LDRB R1, OldKey + TEQ R1, #&FF ; have we got an old key ? + BNE %FT50 ; ignore new - we've got 2 down already + + STRB R0, OldKey ; make current key old +20 + STRB R2, CurrKey ; update current + MOV R0, #2 + STRB R0, Debouncing + STRB R0, AutoRepeatCount ; generate char after 2 100Hz ticks + + B %FT50 + +30 + LDRB R0, OldKey + TEQ R0, R2 ; is it old key going up ? + BNE %FT40 + +; Old key going up + + LDRB R0, CurrKey ; current key is one to ignore in scan + BL ScanKeys + + STRPLB R0, OldKey ; found key, so current -> old + BPL %BT20 ; and R2 -> current + + MOV R0, #&FF ; else mark old key invalid + STRB R0, OldKey + B %FT50 ; and return + +40 + LDRB R1, CurrKey + TEQ R1, R2 ; is it current key going up ? + BNE %FT50 ; not interested if not + + BL ScanKeys ; R0 was OldKey + BPL %BT20 ; was a key so make that current + + STRB R2, CurrKey ; mark current key up (R2 = -1) + +50 + [ AssembleKEYV + Pull "r0-r12,pc" + | + Pull pc + ] + +; ***************************************************************************** +; +; KeyboardEvent - Generate key up/down event +; +; in: R1 = 0 for up, 1 for down +; R2 = key index +; + +KeyboardEvent ROUT + LDRB R3, KbId ; tell event user the keyboard id + MOV R0, #Event_Keyboard + B OSEVEN + +; ***************************************************************************** +; +; Scan keyboard for keys down, ignoring key number R0 and shifting keys +; +; in: R0 = key number to ignore +; +; out: N=0 => R2 = key number found +; N=1 => no key found; R2 = -1 +; R0 preserved +; + +ScanKeys ROUT + Push "R0, R14" + ADR R1, KeysDown + MOV R2, #4 +10 + LDR R3, [R1, R2, LSL #2] ; get the word + TEQ R3, #0 ; if any keys in this down, skip + BNE %FT20 +15 + SUBS R2, R2, #1 ; N=1 last time round + BPL %BT10 + Pull "R0, PC" + +20 + MOV R2, R2, LSL #5 ; multiply by 32 + ADD R2, R2, #32 ; and add 32 +30 + TEQ R3, #0 ; no more bits ? + MOVEQ R2, R2, LSR #5 ; then reset R2 to word offset + BEQ %BT15 ; and continue word loop + SUB R2, R2, #1 ; decrement key number + MOVS R3, R3, LSR #1 ; shift out bit + BCC %BT30 + + CMP R2, R0 ; is it old key (C=1 if it is) + BLNE CheckForShiftingKeyR0R3 ; check that it's not shifting key + BCS %BT30 ; C=1 => invalid, so loop + + TEQ R2, #0 ; N := 0 + Pull "R0, PC" + +; ***************************************************************************** +; +; CheckForShiftingKey - either going down or going up +; +; in: R2 = key number +; +; out: C=1 <=> is shifting key, so don't set current key etc +; R0 -> key structure +; R4 = shifting key index, or 0 if not shifting key +; R3,R5 undefined +; R1,R2,R6-R12 preserved +; + +CheckForShiftingKeyR0R3 ROUT ; version that saves R0, for ScanKeys + Push "R0,R3,R14" + BL CheckForShiftingKey + Pull "R0,R3,PC" + +CheckForShiftingKey ROUT + LDR R0, KeyVec + [ :LNOT: AssembleA1KeyHandler + CMP R0, #-1 + MOVEQ PC, R14 + ] + LDR R3, [R0, #KVKeyTranSize] ; maximum internal key number +1 + CMP R2, R3 ; is it outside table ? + LDRCC R3, [R0, #KVKeyTran] ; no, R3 := offset to keytran + ADDCC R3, R3, R0 ; R3 -> keytran + LDRCC R3, [R3, R2, LSL #2] ; R3 = table word for this key + CMNCC R3, #1 ; C=1 <=> outside table or is special + MOVCC PC, R14 ; can't be shifting key + + LDR R3, [R0, #KVShiftingList] ; R3 = offset to shifting key list + LDRB R4, [R3, R0]! ; R4 = length of shifting key list + TEQ R4, #0 +10 + LDRNEB R5, [R3, R4] + TEQNE R5, R2 + SUBNES R4, R4, #1 + BNE %BT10 + + CMP R4, #1 ; C=1 <=> shifting key + MOV PC, R14 ; not one of the shifting keys + +; ***************************************************************************** +; +; CallSpecialCode - Call code for a special key +; +; in: R0 -> Key structure +; R1 = 0 for up, 1 for down (shifting keys); 2 for first, 3 for repeat +; R2 = key number +; + +CallSpecialCode ROUT + ADR R6, NullCharList + LDR R3, [R0, #KVSpecialList] ; R3 = offset to special list + LDRB R4, [R3, R0]! ; R4 = length of special list + TEQ R4, #0 + MOVEQ PC, R14 ; no special keys, so can't be one +10 + LDRB R5, [R3, R4] + TEQ R5, R2 + BEQ %FT20 + SUBS R4, R4, #1 + BNE %BT10 + MOV PC, R14 + +20 + LDR R3, [R0, #KVSpecialCodeTable] ; R3 = offset to special table + ADD R3, R3, R0 ; R3 -> special code table + SUB R5, R3, #4 ; 0th entry is for 1st special + + LDR R8, [R5, R4, LSL #2] ; R8 = offset to code for this special + ADD R8, R8, R3 ; R8 = address of code for this special + ADR R3, ReturnVector + +; and drop thru to ... + +CallUserKeyCode ROUT + Push R14 + LDROSB R5, KeyBdStatus + LDRB R7, PendingAltType + BL %FT10 + STRB R7, PendingAltType + STROSB R5, KeyBdStatus, R12 + Pull R14 + MOV R12, #IOC + B UpdateLEDs + +10 + ADRL R12, UserKeyWorkSpace + MOV PC, R8 + +NullCharList + = 0 + ALIGN + +ReturnVector + B MouseButtonChange + B DoBreakKey + +; ***************************************************************************** +; +; Centisecond tick routine +; +; out: R12 corrupted + +CentiSecondTick ROUT + Push "R11, R14" + MOV R11, #KeyWorkSpace + MOV R12, #IOC + + [ PollMouse + MOV R0, #K1rqmp + STRB R0, RequestMouse + TXon R0 + ] + + LDR R0, InkeyCounter + SUBS R0, R0, #1 ; decrement + STRCS R0, InkeyCounter ; store back unless was frozen at 0 + + LDRB R2, CurrKey + TEQ R2, #&FF + Pull "R11,PC", EQ ; no current key, so no auto-repeat + + BL UpdateLEDs ; update LEDs from keyboard status + + LDRB R0, AutoRepeatCount + SUBS R0, R0, #1 ; decrement count (if frozen then C:=0) + STRHIB R0, AutoRepeatCount ; store back if now non-zero and not frozen + Pull "R11,PC", NE ; return if non-zero or was frozen + + LDRB R1, Debouncing ; get debounce flag + TEQ R1, #0 + + STRNEB R0, Debouncing ; if not zero, zero it + LDROSB R0, KeyRepDelay, NE ; and load delay + MOVNE R1, #2 ; indicate first time + + LDROSB R0, KeyRepRate, EQ ; if zero, then load repeat + MOVEQ R1, #3 ; indicate subsequent time + + STRB R0, AutoRepeatCount ; in any case, store back + + Push "R4-R10" ; save registers + BL GenerateChar ; R2 = key number + Pull "R4-R11,PC" + +; ***************************************************************************** +; +; DoBreakKey - Called by key handler when break key up or down +; +; in: R0 -> key structure +; R1 = 0 for up, 1 for down (shouldn't be 2 or 3) +; R2 = ARM internal key number +; R3 = address of ReturnVector +; R4 = special number 1..n +; R5 = keyboard status +; +; out: R6 -> list of chars to return +; + +DoBreakKey ROUT + TST R5, #KBStat_ShiftEngaged ; shift down ? + MOVEQ R3, #31 + MOVNE R3, #29 + + TST R5, #KBStat_CtrlEngaged ; ctrl down ? + BICNE R3, R3, #4 + + LDROSB R2, BREAKvector + MOVS R2, R2, LSL R3 ; put relevant bits in C,N + + MOVCS PC, R14 ; 2 or 3 => ignore + BPL %FT10 ; 0 => do a reset + + TEQ R1, #1 ; is it key down ? + ADREQ R6, EscList ; yes, return ESCAPE + MOV PC, R14 ; else just return + +10 + [ AssemblingArthur + TEQ R1, #0 ; is it key up ? + MOVNE PC, R14 ; no, then return + +; This entry point is used by new SWI OS_Reset (TMD 06-Jan-94) + +PerformReset + +; offer the pre-reset service + + TEQP PC, #ARM_CC_Mask ; set FI bits, SVC mode + +; Ensure any CMOS operation aborted + + MOV R1,#16 ; Two bytes in case RTC transmitting +20 BL Start ; Start/clock edge + BL Stop + SUBS R1,R1,#1 + BNE %BT20 + + MOV R1, #Service_PreReset + IssueService + + TEQP PC, #ARM_CC_Mask ; set FI bits, SVC mode + ; just in case! + B CONT_Break + | + MOV PC, R14 ; do nowt + ] + +EscList + = 1, &1B + ALIGN + +; ***************************************************************************** +; +; Generate a character in keyboard buffer, if necessary +; +; in: R1 = 2 if first press; 3 if repetition +; R2 = key number +; R12 -> IOC +; + +GenerateChar ROUT + Push R14 + LDR R0, KeyVec + [ :LNOT: AssembleA1KeyHandler + CMP R0, #-1 + Pull PC,EQ + ] + LDR R3, [R0, #KVKeyTranSize] ; get size + CMP R2, R3 ; if outside table + BCS %FT04 ; then assume special + + LDR R3, [R0, #KVKeyTran] ; R3 = offset to KeyTran + ADD R3, R3, R0 ; R3 -> KeyTran + +; now modify for CTRL and SHIFT + + LDROSB R5, KeyBdStatus + + TST R5, #KBStat_CtrlEngaged + ADDNE R3, R3, #2 + + TST R5, #KBStat_ShiftEngaged + ADDNE R3, R3, #1 + + LDRB R3, [R3, R2, LSL #2] ; get real code + +; apply CAPS lock modifying + + BIC R6, R3, #&20 ; get upper-case code + CMP R6, #"A" + RSBCSS R6, R6, #"Z" ; is it alphabetic ? + BCC %FT20 + + TST R5, #KBStat_ShiftEnable ; if SHCAPS + EORNE R3, R3, #&20 ; then swap case + + TSTEQ R5, #KBStat_NoCapsLock ; else if CAPS + BICEQ R3, R3, #&20 ; force upper case +20 + TEQ R3, #&FF ; is it a special ? + BEQ %FT04 ; [yes, so skip] + + LDROSB R6, ESCch ; if ESCAPE character + TEQ R3, R6 + LDROSB R6, ESCaction, EQ ; and normal ESCAPE action + TEQEQ R6, #0 + LDROSB R6, ESCBREAK, EQ ; and ESCAPE not disabled + TSTEQ R6, #1 + BICEQ R5, R5, #KBStat_PendingAlt ; then cancel pending alt + STROSB R5, KeyBdStatus, R6, EQ ; and store back + + TST R5, #KBStat_PendingAlt ; is there a pending Alt ? + BNE ProcessPendingAlt + + TEQ R3, #0 ; is it NUL ? + BNE %FT10 ; no, so skip + + ADR R6, NULNULList ; then insert NUL NUL + B ReturnNChars + +CallSpecialReturnNChars + Push R14 +04 + BL CallSpecialCode + +ReturnNChars + LDRB R3, [R6], #1 ; R1 = count of characters + +; TMD 25-Sep-89: Fix bug which resulted in Break key (acting as Escape) not +; working if buffer was full - only count spaces if more than 1 character going +; into buffer + + [ {TRUE} + CMP R3, #1 + Pull PC, CC ; no chars, so exit now + BEQ %FT05 ; only 1 char, don't count + | + TEQ R3, #0 ; no chars? + Pull PC, EQ ; then exit now + ] + + MOV R1, #Buff_Key + CMP PC, #0 ; C=1, V=0 so count spaces + BL CnpEntry + ORR R1, R1, R2, LSL #8 ; R1 = number of spaces + CMP R3, R1 ; are there enough ? + Pull PC, HI ; no, then forget them + +05 + LDRB R2, [R6], #1 ; send chars + BL InsertKeyZCOE ; one at a time + SUBS R3, R3, #1 + BNE %BT05 + Pull PC + +10 + Pull R14 ; restore stacked R14 + MOV R2, R3 + +; and drop thru to ... + +; ***************************************************************************** +; +; InsertKeyZCOE - Insert key zeroing count on escape +; +; in: R2 = character +; + +InsertKeyZCOE + LDROSB R0, KeyBdDisable ; disable insertion of codes ? + TEQ R0, #0 + MOVNE PC, R14 ; [disabled] + LDROSB R0, ESCch ; escape character + TEQ R0, R2 ; if is esc char + LDROSB R0, ESCaction, EQ + TEQEQ R0, #0 ; and FX229,0 + + STREQB R0, AutoRepeatCount ; then zero repeat counter + +; and drop thru to ... + +; ***************************************************************************** +; +; RDCHS - Insert character into keyboard buffer +; +; in: R2 = character +; + +RDCHS ROUT + MOV R1, #Buff_Key ; keyboard buffer id + +; Insert character R2 into buffer R1, checking for escape character + + B DoInsertESC + +; ***************************************************************************** + +NULNULList ; list for returning NUL NUL + = 2, 0, 0 + ALIGN + +; ***************************************************************************** + +ProcessPendingAlt + ADR R6, NullCharList + LDR R8, [R0, #KVPendingAltCode] + ADD R8, R8, R0 + BL CallUserKeyCode + B ReturnNChars + +; ***************************************************************************** +; +; Read character entry point +; +; in: - +; out: R0 = character +; C=1 => ESCAPE +; R1-R13 preserved +; + +NewRdch + Push "R1-R4,R11" + MOV R11, #KeyWorkSpace + MOV R4, #1 ; indicate RDCH not INKEY + BL RdchInkey + Pull "R1-R4,R11,PC" + +; ***************************************************************************** +; +; RDCH/INKEY +; +; in: R4 = 0 => INKEY +; R4 <> 0 => RDCH ; *** TMD This changed 25-Apr-91 *** +; +; out: V=1 => error (and possibly R0 -> error block if you're lucky!) +; + +RdchInkey ENTRY + +; Enable interrupts so that keyboard can work properly + + TEQP pc, #SVC_mode + + [ redirectinkey + MOV r1, #0 + LDRB r1, [r1, #RedirectInHandle] + TEQ r1, #0 + BEQ %FT10 + +; Tutu doesn't believe that an escape condition should break redirection +; - similar to exec if you turn off escape ack side-effects + + SWI XOS_BGet ; get byte from redirection handle + BVS RedirectBadExit + BCC ReturnChar ; (C=0) + +; EOF, so close redirect file and read from exec file or keyboard + +; stop redirecting, BEFORE closing file, in case the CLOSE gets an error + + MOV r0, #0 + STRB r0, [r0, #RedirectInHandle] ; Convenient, huh ? + SWI XOS_Find ; close file (R0=0, R1=handle) + EXIT VS + +10 + ] + +; First check for EXEC file + + LDROSB R1, ExecFileH ; read EXEC handle + TEQ R1, #0 + BEQ %FT20 ; no exec file + + SWI XOS_BGet ; get byte from exec handle + BVS ExecBadExit + BCC ReturnChar ; (C=0) + +; EOF, so close exec file and read from keyboard + +; stop EXECing, BEFORE closing file, in case the CLOSE gets an error + + STROSB R0, ExecFileH, R0 ; (STROSB sets temp reg to 0) + SWI XOS_Find ; close file (R0=0, R1=handle) + EXIT VS +20 + Push "R5,R6" + MOV R5, #0 + [ StorkPowerSave + LDRB R5, [R5, #PortableFlags] ; 0 if not a portable, else Portable_Features result + | + LDRB R5, [R5, #PortableFlag] ; 0 if want to try issuing SWI, 1 if know it's hopeless + ] + +RdchLoop + MOV R0, #0 + LDRB R0, [R0, #ESC_Status] + MOVS R0, R0, LSL #(32-6) ; shift relevant bit into carry + MOVCS R0, #27 ; escape detected + BCS ReturnChar2 + + LDROSB R1, InputStream ; 0 => keyboard, 1 => RS423 + BL RDCHG + BCC ReturnChar2 + +; Sam's hack to call the callback vector if appropriate + + [ AssemblingArthur + MOV R0, #0 + LDRB R14, [R0, #CallBack_Flag] + TST R14, #CBack_VectorReq + BLNE process_callback_chain + ] + +; here endeth the hack + + TEQ R4, #0 ; EQ => inkey, NE => rdch + LDREQ R0, InkeyCounter ; if inkey + TEQEQ R0, #0 ; and count expired + BEQ InkeyTimeout + + [ StorkPowerSave + TST R5, #PortableFeature_Idle + SWINE Portable_Idle + TST R5, #PowerSave + BNE RdchLoop ; if we've gone slow already, then loop + TST R5, #PortableFeature_Speed + BEQ RdchLoop ; if speed change doesn't work, then loop + MOV R0, #1 ; go slow + MOV R1, #0 + SWI XPortable_Speed ; out: R0 = old speed, R1 = new speed + ORRVC R5, R5, #PowerSave ; if OK, indicate power save mode + MOVVC R6, R0 ; and remember old speed + MOVVS R5, #0 ; if got error, then indicate we don't want to try again + STRVSB R5, [R5, #PortableFlags] ; and store this back for future RDCHs + | + CMP R5, #1 ; if we've gone slow already (2), or there's no portable module (1), then loop + BCS RdchLoop + MOV R0, #1 ; go slow + MOV R1, #0 ; ignore old speed + SWI XPortable_Speed ; out: R0 = old speed, R1 = new speed + MOVVC R5, #2 ; if OK, indicate we've successfully gone slow + MOVVC R6, R0 ; and remember old speed + MOVVS R5, #1 ; if got error, then indicate we don't want to try again + STRVSB R5, [R5, #PortableFlag-1] ; and store this back for future RDCHs + ] + B RdchLoop + +InkeyTimeout + MOV R0, #&FF ; indicate timeout + SEC ; and set carry +ReturnChar2 + TEQ R5, #2 ; NB preserves carry + BLEQ RestoreSpeed + Pull "R5,R6" +ReturnChar + CLRPSR V_bit, R14 + EXIT + +RestoreSpeed ENTRY "R0" + MOV R0, R6 ; restore old speed + MOV R1, #0 ; AND mask of 0 + SWI XPortable_Speed + EXITS ; restore R0 and carry + +ExecBadExit ; got an error from BGET + Push R0 ; save error pointer + STROSB R0, ExecFileH, R0 ; (STROSB sets temp reg to 0) + SWI XOS_Find ; close file (R0=0, R1=handle) + Pull "R1, R14" ; pull registers + MOVVC R0, R1 ; if closed OK, then restore old error + ORRS PC, R14, #V_bit ; still indicate error + + [ redirectinkey +RedirectBadExit ; got an error from BGET + BL RemoveOscliCharJobs ; preserves r0 + Pull "R14" ; pull register + ORRS PC, R14, #V_bit ; still indicate error + ] + +; ***************************************************************************** +; +; RDCHG - Fetch character from input buffer +; Expand soft keys as necessary +; Pass cursor control keys to VDU driver +; Return carry set if character not available +; +; in: R1 = input buffer id (0 => keyboard, 1 => RS423) + +RDCHG ROUT + Push R14 + +; insert check here for ECONET interception of RDCH + +RDCHNM + LDROSB R0, SoftKeyLen ; are we expanding a soft key + TEQ R0, #0 + BEQ RDCHG1 ; not expanding + + LDROSB R2, RS423mode + TST R1, R2 ; if RS423 and 8 bit data + BNE RDCHG1 ; ignore soft keys + + LDR R2, SoftKeyPtr + LDRB R2, [R2, -R0] ; get character out of buffer + + SUB R0, R0, #1 ; decrement character count + STROSB R0, SoftKeyLen, R3 ; store back + + MOV R0, R2 ; put character in R0 + CLC ; and exit with carry clear + Pull PC + +RDCHG1 + BL KeyREMOVECheckRS423 ; remove character, if none, exit CS + + LDROSB R2, RS423mode ; 0 => treat RS423 as keyboard + TST R1, R2 ; NZ => let RS423 deliver 8-bit codes + BNE RDCHGCLC + + TEQ R0, #0 ; is it NUL ? + BNE %FT10 + + BL KeyREMOVECheckRS423 ; get another char, if none then + ; spurious, so ignore + + TEQ R0, #0 ; is it NUL NUL ? + BNE RDCHGCLC ; no, then return this character + + LDRB R2, [R0, #OsbyteVars + :INDEX: IPbufferCh]! + ; R0 was 0, so now -> 1st of 8 keybases + ADD R3, R0, #8 +05 + TEQ R2, #2 ; is this key base = 2 ? + MOVEQ R0, #0 ; if so then return NUL NUL + BEQ ReturnNULR0 + LDRB R2, [R0, #1]! ; load next key base + TEQ R0, R3 ; if not tried all of them + BNE %BT05 ; then loop + MOV R0, #0 ; no special key bases, + ; so just return NUL +10 + TST R0, #&80 + BEQ RDCHGCLC + +; now check for cursor key movement + + AND R3, R0, #&0F ; save bottom nybble + CMP R3, #&0B ; is it a cursor key ? + BCC NotCursorKey + + TST R0, #&40 ; don't let Cx-Fx be cursor keys + BNE NotCursorKey + + LDROSB R2, CurEdit ; FX 4 state + CMP R2, #1 + ADDLS R0, R3, #&87-&0B ; 0 or 1 => force in range &87-&8B + BCC ItsCursorEdit ; 0 => cursor edit + BEQ RDCHGCLC ; 1 => return these codes + +NotCursorKey + MOV R0, R0, LSR #4 + EOR R0, R0, #&0C ; 4..7, 0..3 + LDRB R2, [R0, #OsbyteVars+IPbufferCh-OSBYTEFirstVar] + ; get key variable + CMP R2, #1 ; is it 0 (ignore) or 1 (softkey) + BCC RDCHG1 ; get another char if 0 + + BEQ ExpandSoftKey ; expand soft key if 1 + + TEQ R2, #2 ; is it special Compact option ? + EOREQ R0, R0, #&0C ; undo that mangling ! + ORREQ R0, R3, R0, LSL #4 ; if so, then return NUL <code> + BEQ ReturnNULR0 + + ADD R0, R2, R3 ; add offset to base + AND R0, R0, #&FF ; make it wrap + +RDCHGCLC + CLC + Pull PC + + +ItsCursorEdit + LDROSB R2, WrchDest + TST R2, #2 ; if wrch not to VDU + BNE RDCHG1 ; then ignore character + + Push "R1,R4-R12" + [ AssemblingArthur + VDWS WsPtr + BL DoCursorEdit + | + BL DCE10 + ] + Pull "R1,R4-R12" + + BCS RDCHG1 ; no character yet, so loop + Pull PC ; NB carry clear - no ESCAPE ! + + [ :LNOT: AssemblingArthur +DCE10 + MOV R1, #VduDriver + ADD PC, R1, #CursorEdit + ] + +; ***************************************************************************** +; +; ReturnNULR0 - Return NUL followed by R0 from RDCH +; + +ReturnNULR0 ROUT + ADR R2, SoftKeyExpand ; store code in SoftKeyExpand +0 + STRB R0, [R2], #1 ; and set ptr to SoftKeyExpand +1 + STR R2, SoftKeyPtr + MOV R2, #1 ; set key length to 1 + STROSB R2, SoftKeyLen, R0 ; (sets R0 to 0!) + B RDCHGCLC ; return NUL as first character + +; ***************************************************************************** + +KeyREMOVECheckRS423 ROUT + Push R14 + BL KeyREMOVE + Pull "R14, PC", CS ; pull stacked R14 if CS + +; new code inserted here 14/8/87 to try to reenable RTS for RS423 input + + [ DriversInKernel + TEQ R1, #1 ; RS423 input ? + Pull PC, NE ; no, then exit + Push "R0,R1,R12" ; preserve char + buffer id + R12 + BYTEWS R12 + BL RSETX ; reenable RTS if now enough spaces + Pull "R0,R1,R12, PC" ; restore char, buffer id and exit + | + Pull PC + ] + +; ***************************************************************************** + +KeyREMOVE + Push "R10,R12,R14" + CLRV ; do remove not examine + MOV R10, #REMV + B GoVec + + +; expand a soft key as a variable (R3 = key number) + +ExpandSoftKey ROUT + Push "R1,R4" + BL SetupKeyName + ADR R1, SoftKeyExpand + MOV R2, #255 ; max length of string + MOV R3, #0 ; no name pointer + MOV R4, #VarType_Expanded + SWI XOS_ReadVarVal + + Pull "R1,R4", VS + BVS RDCHG1 ; no string or bad + + STROSB R2, SoftKeyLen, R0 ; store length (may be zero) + ADD R1, R1, R2 ; R1 -> last char+1 + STR R1, SoftKeyPtr + Pull "R1,R4" + B RDCHNM ; try to expand it + +KeyName + = keyprefix,0 + ALIGN + +; ***************************************************************************** +; +; SetupKeyName - Set up the name <keyprefix><n><0> in SoftKeyName +; +; in: R11 -> KeyWS +; R3 = key number +; +; out: R0 -> SoftKeyName, which contains <keyprefix><n><0> +; R2-R4 corrupted +; + +SetupKeyName ROUT + ADR R2, KeyName + ADR R0, SoftKeyName +10 + LDRB R4, [R2], #1 ; copy keyprefix in + TEQ R4, #0 + STRNEB R4, [R0], #1 + BNE %BT10 ; now put digits at R0 + + ORR R3, R3, #"0" + CMP R3, #"9"+1 + + MOVCS R2, #"1" ; if >=10 then put in "1" + STRCSB R2, [R0], #1 + SUBCS R3, R3, #10 ; and subtract 10 + + STRB R3, [R0], #1 + STRB R4, [R0] ; (R4=0) terminate + + ADR R0, SoftKeyName + MOV PC, R14 + +; ***************************************************************************** +; +; DoInkeyOp - Perform INKEY + +DoInkeyOp + TST R2, #&80 ; INKEY(+ve) ? + BNE NewInkeyNeg + +NewInkeyPos + Push R4 + MOV R11, #KeyWorkSpace + AND R1, R1, #&FF ; no funny business + AND R2, R2, #&FF ; ditto + ORR R1, R1, R2, LSL #8 ; get combined count + STR R1, InkeyCounter + + MOV R4, #0 ; indicate inkey not rdch + BL RdchInkey + + MOV R1, R0 ; make X the character + MOVCC R2, #0 ; Y := 0 if normal exit + MOVCS R2, R0 ; Y := &1B or &FF for ESC or timeout + + Pull "R4,PC" ; return preserving V and R0 + +NewInkeyNeg + EOR R1, R1, #&7F ; invert bits for scan call + BL BBCScanKeys + Pull PC + +; ***************************************************************************** +; +; BBCScanKeys - Test individual key or scan for key depression +; +; in: R1 = 0..&7F => scan keyboard from BBC internal key R1 +; out: C=0 => R1 = BBC internal key found +; C=1 => R1 = &FF (no key found) +; +; in: R1 = &80..&FF => test if BBC internal key (R1 EOR &80) is down +; out: C=0, R1=R2=&00 => key is up +; C=1, R1=R2=&FF => key is down +; + +BBCScanKeys ROUT + Push R11 + MOV R11, #KeyWorkSpace + AND R1, R1, #&FF ; trap wallies + + LDR R2, KeyVec + + TST R1, #&80 ; >=&80 => test single key + ; < &80 => scan for key + BEQ DoBBCScan ; [is scanning not testing] + + [ :LNOT: AssembleA1KeyHandler + ADD R0, R2, #1 + CMP R0, #1 ; if no key handler then + MOVCC R1, #0 ; return key up (C=0) + BCC ExitBBCScan + ] + + LDR R0, [R2, #KVInkeyTran] + ADD R0, R2, R0 ; R0 -> InkeyTran or InkeyTran2 + + ADD R0, R0, #4 * &FF ; R0 -> InkeyTran+4*&FF + LDR R0, [R0, -R1, LSL #2] ; get word of indexes into KeysDown + MOV R2, #&FF000000 +02 + CMP R0, #-1 ; is it all FF's + MOVEQ R1, #0 ; if so then none of keys down + BEQ %FT04 + + AND R1, R0, #&FF ; just get bottom byte + ADR R3, KeysDown ; look up in KeysDown + MOV R1, R1, LSR #5 + LDR R3, [R3, R1, LSL #2] ; get word of 32 bits + AND R1, R0, #31 + MOV R3, R3, LSL R1 ; put relevant bit into top bit + MOVS R1, R3, LSR #31 ; R1 = 0 if up, 1 if down + ORREQ R0, R2, R0, LSR #8 ; shift down, putting FF in top byte + BEQ %BT02 +04 + CMP R1, #1 ; C=1 <=> at least one of keys down + MOVCC R1, #0 + MOVCS R1, #&FF + MOV R2, R1 +ExitBBCScan + Pull R11 + MOV PC, R14 + +DoBBCScan + [ :LNOT: AssembleA1KeyHandler + CMP R2, #-1 ; if no key handler then + MOVEQ r1, #&FF ; return all keys up (C=1) + BEQ ExitBBCScan + ] + LDR R0, [R2, #KVInkeyTran] + ADD R0, R2, R0 ; R0 -> InkeyTran or InkeyTran2 + + Push "R4, R5" + ADD R0, R0, #4 * &7F ; R0 -> InkeyTran+4*&7F + MOV R4, #&FF000000 +10 + LDR R3, [R0, -R1, LSL #2] ; get word of indexes into KeysDown +15 + CMP R3, #-1 ; all FFs ? + BEQ %FT18 ; then not one of these keys + + AND R5, R3, #&FF + ADR R2, KeysDown + MOV R5, R5, LSR #5 + LDR R2, [R2, R5, LSL #2] ; get word of bits + AND R5, R3, #31 + MOV R2, R2, LSL R5 ; put relevant bit into top bit + MOVS R5, R2, LSR #31 ; R5 = 0 for up, 1 for down + BNE %FT20 ; [down, so stop] + ORR R3, R4, R3, LSR #8 ; up -> shift down putting FF in top + B %BT15 +18 + ADD R1, R1, #1 ; go to next key + TEQ R1, #&80 ; if not run out of keys + BNE %BT10 ; then loop + MOV R1, #&FF ; indicate no key +20 + CMP R1, #&FF ; C=0 <=> found key + Pull "R4,R5,R11" + MOV PC, R14 + +; ***************************************************************************** +; +; Write keys down information +; +; in: R1 = Current key (in BBC internal key format) +; R2 = Old key (------------""------------) +; +; out: R1, R2 preserved +; + +WriteKeysDown ROUT + Push R14 + MOV R11, #KeyWorkSpace + MOV R0, R1 + BL ConvertInternalKey + STRB R0, CurrKey + MOV R0, R2 + BL ConvertInternalKey + STRB R0, OldKey + Pull PC + +ConvertInternalKey + TST R0, #&80 ; if not in range &80..&FF + MOVEQ R0, #&FF ; return value &FF (key not valid) + MOVEQ PC, R14 + + EOR R0, R0, #&7F ; else convert to inkey value + Push R4 + LDR R3, KeyVec + [ :LNOT: AssembleA1KeyHandler + CMP R3, #-1 ; if no key handler then + MOVEQ R0, #&FF ; return no key + MOVEQ PC, R14 + ] + LDR R4, [R3, #KVInkeyTran] + ADD R3, R3, R4 ; R3 -> InkeyTran or InkeyTran2 + Pull R4 + + SUB R3, R3, #&80*4 ; R3 -> InkeyTran-4*&80 + + LDRB R0, [R3, R0, LSL #2] ; convert to ARM internal key + ; (just get 1st key for this key) + MOV PC, R14 + + +; ***************************************************************************** +; +; InstallKeyHandler - Install user key handler +; +; in: R0 = new key handler +; 0 => just read old key handler +; 1 => just read keyboard id +; +; out: R0 = old key handler, or +; R0 = keyboard id if R0 was 1 on entry (&FF => no keyboard id yet) +; + +InstallKeyHandler ROUT + MOV R11, PC + TST R11, #I_bit + TEQEQP R11, #I_bit ; disable IRQs + + MOV R11, #KeyWorkSpace + TEQ R0, #1 ; asking for keyboard id ? + LDREQB R0, KbId ; then load it + ExitSWIHandler EQ ; and exit + + LDR R10, KeyVec ; R10 -> old key handler + TEQ R0, #0 ; if not just reading it + STRNE R0, KeyVec ; then store new one + MOV R0, R10 ; R0 -> old key handler + ExitSWIHandler EQ ; exit if just reading + + Push "R0-R12,LR" + BL KeyboardEnable + Pull "R0-R12,LR" + ExitSWIHandler + +; ***************************************************************************** +; +; IssueKeyboardService - Issue keyboard handler service +; +; in: R11 -> KeyWorkSpace +; +; out: R0,PSR preserved +; + +IssueKeyboardService + Push "R0,R14" + MOV R1, #Service_KeyHandler + LDRB R2, KbId + IssueService + Pull "R0,PC",,^ + + + END diff --git a/s/PMF/key2 b/s/PMF/key2 new file mode 100644 index 0000000000000000000000000000000000000000..6a9420154c28aa549377498892ba0f15abf2092e --- /dev/null +++ b/s/PMF/key2 @@ -0,0 +1,943 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.PMF.Key2 + +; ARTHUR keyboard code (Keyboard table handler) + +; Author Tim Dobson +; Started 15-Apr-87 + +; ************************************************************ +; *** C h a n g e L i s t (better late than never!) *** +; ************************************************************ + +; Date Description +; ---- ----------- +; 19-Feb-88 Modified InkeyTran2 so that INKEY(-95) returns state of new key +; next to left shift key on international keyboards +; 11-Aug-88 Modified A500 keyboard as follows:- +; LOOKS = ALT; MENU = F0; F10 = F10; keypad # = F11; +; keypad % = F12; keypad / = F13 + + MACRO + IKT $A, $B, $C, $D, $E, $F, $G, $H + IKT2 $A + IKT2 $B + IKT2 $C + IKT2 $D + IKT2 $E + IKT2 $F + IKT2 $G + IKT2 $H + MEND + + MACRO + IKT2 $TE + LCLA T +T SETA $TE + [ (T :AND: &FF00) = 0 +T SETA T :OR: &FF00 + ] + [ (T :AND: &FF0000) = 0 +T SETA T :OR: &FF0000 + ] + [ (T :AND: &FF000000) = 0 +T SETA T :OR: &FF000000 + ] + & T + MEND + + +; Special keys + +K0ShiftKey * &0A +K0LooksKey * &0B +K0ControlKey * &0C +K0RightMouse * &0D +K0CentreMouse * &0E +K0LeftMouse * &0F +K0TabKey * &30 +K0CapsKey * &40 +K0BreakKey * &05 ; key marked ESCAPE is BREAK +K0NumPadHash * &04 +K0NumPadPercent * &17 +K0NumPadSlash * &07 +K0NumPadStar * &06 +K0NumPad7 * &14 +K0NumPad8 * &77 +K0NumPad9 * &27 +K0NumPadMinus * &16 +K0NumPad4 * &24 +K0NumPad5 * &97 +K0NumPad6 * &67 +K0NumPadPlus * &87 +K0NumPad1 * &64 +K0NumPad2 * &37 +K0NumPad3 * &57 +K0NumPadEnter * &47 +K0NumPad0 * &94 +K0NumPadDot * &44 + +K1ShiftLeft * &4C +K1ShiftRight * &58 +K1CtrlLeft * &3B +K1CtrlRight * &61 +K1AltLeft * &5E +K1AltRight * &60 +K1RightMouse * &72 +K1CentreMouse * &71 +K1LeftMouse * &70 +K1TabKey * &26 +K1CapsKey * &5D +K1NumKey * &22 +K1ScrollKey * &0E +K1BreakKey * &0F +K1BackTickKey * &10 +K1PoundKey * &1D +K1NumPadSlash * &23 +K1NumPadStar * &24 +K1NumPadHash * &25 +K1NumPad7 * &37 +K1NumPad8 * &38 +K1NumPad9 * &39 +K1NumPadMinus * &3A +K1NumPad4 * &48 +K1NumPad5 * &49 +K1NumPad6 * &4A +K1NumPadPlus * &4B +K1NumPad1 * &5A +K1NumPad2 * &5B +K1NumPad3 * &5C +K1NumPadEnter * &67 +K1NumPad0 * &65 +K1NumPadDot * &66 + +; UserKeyWorkSpace allocation + + ^ 0, R12 +ShiftCount # 1 +CtrlCount # 1 +MyMouseButtons # 1 +KeyReturn # 2 ; length byte (1), value byte +KeyNULReturn # 3 ; length byte (2), NUL, value byte + + ASSERT (:INDEX: @) <= UserKeyWorkSpaceSize + +; ***************************************************************************** + +OldKeyStruct + & KeyTran-OldKeyStruct + & (KeyTranEnd-KeyTran) :SHR: 2 + & InkeyTran-OldKeyStruct + & ShiftingKeyList-OldKeyStruct + & SpecialList-OldKeyStruct + & SpecialCodeTable-OldKeyStruct + & KeyStructInit-OldKeyStruct + & PendingAltCode-OldKeyStruct + +ShiftingKeyList + = ShiftingKeyListEnd-ShiftingKeyList-1 + = K0ShiftKey, K0ControlKey, K0LooksKey + = K0RightMouse, K0CentreMouse, K0LeftMouse + = K0BreakKey +ShiftingKeyListEnd + ALIGN + +SpecialList + [ Keyboard_Type = "A1A500" + = SpecialListEnd-SpecialList-1 + = K0ShiftKey, K0ControlKey, K0LooksKey + = K0RightMouse, K0CentreMouse, K0LeftMouse + = K0CapsKey, K0TabKey, K0BreakKey +SpecialListPad + = K0NumPadHash, K0NumPadPercent, K0NumPadSlash, K0NumPadStar + = K0NumPad7, K0NumPad8, K0NumPad9, K0NumPadMinus + = K0NumPad4, K0NumPad5, K0NumPad6, K0NumPadPlus + = K0NumPad1, K0NumPad2, K0NumPad3, K0NumPadEnter + = K0NumPad0, K0NumPadDot + ] +SpecialListEnd + ALIGN + +SpecialCodeTable + [ Keyboard_Type = "A1A500" + & ProcessKShift-SpecialCodeTable + & ProcessKCtrl-SpecialCodeTable + & ProcessKAlt-SpecialCodeTable + & ProcessKRight-SpecialCodeTable + & ProcessKCentre-SpecialCodeTable + & ProcessKLeft-SpecialCodeTable + & ProcessKCaps-SpecialCodeTable + & ProcessKTab-SpecialCodeTable + & ProcessKBreak-SpecialCodeTable + & ProcessK0Pad-SpecialCodeTable + & ProcessK0Pad-SpecialCodeTable + & ProcessK0Pad-SpecialCodeTable + & ProcessK0Pad-SpecialCodeTable + & ProcessK0Pad-SpecialCodeTable + & ProcessK0Pad-SpecialCodeTable + & ProcessK0Pad-SpecialCodeTable + & ProcessK0Pad-SpecialCodeTable + & ProcessK0Pad-SpecialCodeTable + & ProcessK0Pad-SpecialCodeTable + & ProcessK0Pad-SpecialCodeTable + & ProcessK0Pad-SpecialCodeTable + & ProcessK0Pad-SpecialCodeTable + & ProcessK0Pad-SpecialCodeTable + & ProcessK0Pad-SpecialCodeTable + & ProcessK0Pad-SpecialCodeTable + & ProcessK0Pad-SpecialCodeTable + & ProcessK0Pad-SpecialCodeTable + ] + +; ***************************************************************************** + +NewKeyStruct + & KeyTran2-NewKeyStruct + & (KeyTran2End-KeyTran2) :SHR: 2 + & InkeyTran2-NewKeyStruct + & NewShiftingKeyList-NewKeyStruct + & NewSpecialList-NewKeyStruct + & NewSpecialCodeTable-NewKeyStruct + & KeyStructInit-NewKeyStruct + & PendingAltCode-NewKeyStruct + +NewShiftingKeyList + = NewShiftingKeyListEnd-NewShiftingKeyList-1 + = K1ShiftLeft, K1ShiftRight, K1CtrlLeft, K1CtrlRight + = K1RightMouse, K1CentreMouse, K1LeftMouse, K1BreakKey +NewShiftingKeyListEnd + ALIGN + +NewSpecialList + [ Keyboard_Type = "A1A500" + = NewSpecialListEnd-NewSpecialList-1 + = K1ShiftLeft, K1ShiftRight, K1CtrlLeft, K1CtrlRight + = K1AltLeft, K1AltRight + = K1RightMouse, K1CentreMouse, K1LeftMouse + = K1CapsKey, K1TabKey + = K1NumKey, K1ScrollKey + = K1BreakKey, K1BackTickKey, K1PoundKey +NewSpecialListPad + = K1NumPadSlash, K1NumPadStar, K1NumPadHash + = K1NumPad7, K1NumPad8, K1NumPad9, K1NumPadMinus + = K1NumPad4, K1NumPad5, K1NumPad6, K1NumPadPlus + = K1NumPad1, K1NumPad2, K1NumPad3, K1NumPadEnter + = K1NumPad0, K1NumPadDot + ] +NewSpecialListEnd + ALIGN + +NewSpecialCodeTable + [ Keyboard_Type = "A1A500" + & ProcessKShift-NewSpecialCodeTable + & ProcessKShift-NewSpecialCodeTable + & ProcessKCtrl-NewSpecialCodeTable + & ProcessKCtrl-NewSpecialCodeTable + & ProcessKAlt-NewSpecialCodeTable + & ProcessKAlt-NewSpecialCodeTable + & ProcessKRight-NewSpecialCodeTable + & ProcessKCentre-NewSpecialCodeTable + & ProcessKLeft-NewSpecialCodeTable + & ProcessKCaps-NewSpecialCodeTable + & ProcessKTab-NewSpecialCodeTable + & ProcessKNum-NewSpecialCodeTable + & ProcessKScroll-NewSpecialCodeTable + & ProcessKBreak-NewSpecialCodeTable + & ProcessKBackTick-NewSpecialCodeTable + & ProcessKPound-NewSpecialCodeTable + & ProcessK1Pad-NewSpecialCodeTable + & ProcessK1Pad-NewSpecialCodeTable + & ProcessK1Pad-NewSpecialCodeTable + & ProcessK1Pad-NewSpecialCodeTable + & ProcessK1Pad-NewSpecialCodeTable + & ProcessK1Pad-NewSpecialCodeTable + & ProcessK1Pad-NewSpecialCodeTable + & ProcessK1Pad-NewSpecialCodeTable + & ProcessK1Pad-NewSpecialCodeTable + & ProcessK1Pad-NewSpecialCodeTable + & ProcessK1Pad-NewSpecialCodeTable + & ProcessK1Pad-NewSpecialCodeTable + & ProcessK1Pad-NewSpecialCodeTable + & ProcessK1Pad-NewSpecialCodeTable + & ProcessK1Pad-NewSpecialCodeTable + & ProcessK1Pad-NewSpecialCodeTable + & ProcessK1Pad-NewSpecialCodeTable + ] + +; Now the code to handle it + +; Initialise keyboard table handler +; +; in: R12 -> my workspace +; R5 = KeyBdStatus +; R7 = PendingAltType +; +; out: R5 = new KeyBdStatus +; R7 = new PendingAltType + +KeyStructInit ROUT + MOV R0, #0 ; no shift or ctrl keys down + STRB R0, ShiftCount + STRB R0, CtrlCount + STRB R0, MyMouseButtons + STRB R0, KeyNULReturn+1 ; NUL for NUL char return + MOV R0, #1 ; string length for single key return + STRB R0, KeyReturn+0 + MOV R0, #2 ; length for NUL char return + STRB R0, KeyNULReturn+0 + + BIC R5, R5, #(KBStat_ShiftEngaged :OR: KBStat_CtrlEngaged :OR: KBStat_PendingAlt) + MOV PC, R14 + +ProcessKShift ROUT + ADR R0, ShiftCount + MOV R2, #KBStat_ShiftEngaged +ProcessShiftOrCtrl + TEQ R1, #0 ; R1=1 => down, R1=0 => up + LDRB R3, [R0] + ADDNE R3, R3, #1 ; if down then increment + SUBEQ R3, R3, #1 ; if up then decrement + STRB R3, [R0] + TEQ R3, #0 + ORRNE R5, R5, R2 ; one or more shift/ctrl keys down + BICEQ R5, R5, R2 ; zero shift/ctrl keys down + MOV PC, R14 + +ProcessKCtrl ROUT + ADR R0, CtrlCount + MOV R2, #KBStat_CtrlEngaged + B ProcessShiftOrCtrl + +ProcessKRight ROUT + MOV R2, #1 +ProcessMouseButton + TEQ R1, #0 + LDRB R0, MyMouseButtons + ORRNE R0, R0, R2 ; button going down + BICEQ R0, R0, R2 ; button going up + STRB R0, MyMouseButtons + MOV PC, R3 ; call his routine and exit + +ProcessKCentre ROUT + MOV R2, #2 + B ProcessMouseButton + +ProcessKAlt ROUT + TST R5, #KBStat_ShiftEngaged + MOVEQ R7, #1 ; Alt + MOVNE R7, #2 ; Shift-Alt + TST R5, #KBStat_CtrlEngaged + ADDNE R7, R7, #2 ; Ctrl-Alt, Ctrl-Shift-Alt + ORR R5, R5, #KBStat_PendingAlt ; indicate a pending alt + MOV PC, R14 + +ProcessKLeft ROUT + MOV R2, #4 + B ProcessMouseButton + +ProcessKCaps ROUT + TEQ R1, #2 ; is it first press ? + MOVNE PC, R14 ; don't auto-repeat + + TST R5, #KBStat_ShiftEngaged ; if shift down + BICNE R5, R5, #KBStat_NoCapsLock ; then force CAPS on + ORRNE R5, R5, #KBStat_ShiftEnable ; and SHIFT CAPS state + EOREQ R5, R5, #KBStat_NoCapsLock ; else toggle caps lock state + BICEQ R5, R5, #KBStat_ShiftEnable ; and cancel shift enable + + MOV PC, R14 + +ProcessKTab ROUT + LDROSB R0, TABch ; TAB key code + TST R0, #&80 ; top bit set ? + BEQ ReturnOneChar ; no, don't shift or ctrl it + TST R5, #KBStat_ShiftEngaged + EORNE R0, R0, #&10 ; modify for shift + TST R5, #KBStat_CtrlEngaged + EORNE R0, R0, #&20 ; modify for ctrl +ReturnOneChar + ADR R6, KeyReturn ; pass pointer back to MOS + STRB R0, [R6, #1] ; having poked byte in + MOV PC, R14 + +ProcessKNum ROUT + TEQ R1, #2 ; is it first press ? + EOREQ R5, R5, #KBStat_NoNumLock ; yes, then toggle num lock + MOV PC, R14 ; (don't auto-repeat) + +ProcessKScroll ROUT + TEQ R1, #2 ; is it first press ? + EOREQ R5, R5, #KBStat_ScrollLock ; yes, then toggle scroll lock + MOV PC, R14 ; (don't auto-repeat) + +ProcessKBreak ROUT + ADD PC, R3, #4 ; offset for break routine + + [ Keyboard_Type = "A1A500" +ProcessKBackTick ROUT + Push R14 + BL TestForBfont + Pull R14 + MOVEQ R0, #&BB ; Bfont back tick + MOVNE R0, #&60 ; anything else back tick + B ReturnNULChar + +ProcessKPound ROUT + Push R14 + BL TestForBfont + Pull R14 + BNE %FT10 + TST R5, #KBStat_ShiftEngaged + MOVEQ R0, #&60 ; Bfont pound + MOVNE R0, #&9E ; Bfont currency + B ReturnNULChar +10 + TST R5, #KBStat_ShiftEngaged + MOVEQ R0, #&A3 ; anything else 'pound' + MOVNE R0, #&A4 ; anything else currency + B ReturnNULChar + ] + + [ Keyboard_Type = "A1A500" +ProcessK0Pad ROUT + ADR R0, PadK0NumTran-(SpecialListPad-SpecialList) ; on + ADR R2, PadK0CurTran-(SpecialListPad-SpecialList) ; off + B ProcessPad + ] + [ Keyboard_Type = "A1A500" +ProcessK1Pad ROUT + ADR R0, PadK1NumTran-(NewSpecialListPad-NewSpecialList) ; on + ADR R2, PadK1CurTran-(NewSpecialListPad-NewSpecialList) ; off + ] +ProcessPad + TST R5, #KBStat_NoNumLock ; test num lock + MOVNE R0, R2 ; numlock off -> use R2 + LDRB R0, [R0, R4] ; get table entry + TEQ R0, #&FF ; dummy key ? + MOVEQ PC, R14 ; then exit + + LDROSB R2, KeyBase ; add on numeric key base + SUB R0, R0, #"0" + ADD R0, R0, R2 + + LDROSB R2, KeyOpt ; zero => ctrl/shift modifies + TEQ R2, #0 + BNE %FT10 ; [don't modify] + + TST R0, #&80 ; top bit set ? + BEQ %FT10 ; no, then don't modify + + TST R5, #KBStat_ShiftEngaged + EORNE R0, R0, #&10 ; modify for shift + TST R5, #KBStat_CtrlEngaged + EORNE R0, R0, #&20 ; modify for ctrl +10 + B ReturnOneChar + + + [ Keyboard_Type = "A1A500" +PadK0NumTran + = "#%/*789-456+123",13,"0." +PadK0CurTran + = "#%/*",&1E,&8F,&9F,"-",&8C,&FF,&8D,"+",&8B,&8E,&9E,13,&CD,&7F + ] + [ Keyboard_Type = "A1A500" +PadK1NumTran + = "/*#789-456+123",13,"0." +PadK1CurTran + = "/*#",&1E,&8F,&9F,"-",&8C,&FF,&8D,"+",&8B,&8E,&9E,13,&CD,&7F + ] + ALIGN + + [ Keyboard_Type = "A1A500" +; ***************************************************************************** +; +; TestForBfont - Check if keyboard corresponds to a Bfont font +; +; in: IRQ mode +; +; out: Z => Bfont, NZ => anything else +; + +TestForBfont ROUT + + [ {TRUE} + Push R14 + LDROSB R14, KeyAlphabet + TEQ R14, #100 ; EQ => Bfont + Pull PC + | + + [ BleedinDaveBell +FTDefault * %FT20 + | +FTDefault * %FT10 + ] + + Push "R0-R4,R14" + + TEQP R14, #(SVC_mode :EOR: IRQ_mode) ; change to SVC mode + MOVNV R0, R0 ; wait for it to happen + + Push R14 ; save R14_svc + + MOV R0, #OsbyteSetAlphKey + MOV R1, #&FF ; indicate read keyboard no. + SWI XOS_Byte + BVS FTDefault ; error - indicate default + + MOV R3, R1 ; R3 = keyboard country no. + MOV R1, #Service_International + MOV R2, #Inter_CNoToANo ; convert to alphabet number + SWI XOS_ServiceCall + BVS FTDefault + + TEQ R1, #0 ; was it claimed ? + BNE FTDefault ; no, then indicate default + + TEQ R4, #100 ; is it alphabet bfont ? + BEQ %FT10 +20 + Pull R14 ; restore R14_svc + MOV R0, PC + TEQP R0, #(SVC_mode :EOR: IRQ_mode) ; go back to IRQ mode + MOVNV R0, R0 + Pull "R0-R4,R14" + BICS PC, R14, #Z_bit ; indicate not bfont + +10 + Pull R14 ; restore R14_svc + MOV R0, PC + TEQP R0, #(SVC_mode :EOR: IRQ_mode) ; go back to IRQ mode + MOVNV R0, R0 + Pull "R0-R4,R14" + ORRS PC, R14, #Z_bit ; indicate is bfont + ] + ] + +; ***************************************************************************** +; +; PendingAltCode - Process ALT+char +; +; in: R0 -> key structure +; R2 = internal key number for char +; R3 = character +; R5 = keyboard status +; R7 = pending alt type +; +; out: R6 -> returned key list +; + +PendingAltCode ROUT + BIC R5, R5, #KBStat_PendingAlt ; cancel pending alt + TEQ R7, #4 ; is it CTRL-SHIFT-ALT char ? + MOVNE R0, R3 + BNE ReturnOneChar + ORR R0, R3, #&80 ; set top bit +ReturnNULChar + ADR R6, KeyNULReturn + STRB R0, [R6, #2] + MOV PC, R14 + +; ***************************************************************************** + +KeyTran ROUT + [ Keyboard_Type = "A1A500" +; Column 0 + +00 + = &82, &92, &A2, &B2 ; f2 + = &83, &93, &A3, &B3 ; f3 + = &84, &94, &A4, &B4 ; f4 + = &86, &96, &A6, &B6 ; f6 + = &CB, &DB, &EB, &FB ; pad #, now f11 + & -1 ; ESCAPE + & -1 ; pad * + = &CD, &DD, &ED, &FD ; pad /, now f13 + = &88, &98, &A8, &B8 ; f8 + = &CA, &DA, &EA, &FA ; f10 - now really f10! + + & -1,-1,-1,-1,-1,-1 ; SHIFT,LOOKS,CMD,RIGHT,CENTRE,LEFT + +; Column 1 + +10 + = &81, &91, &A1, &B1 ; f1 + = "3#3#" ; 3 + = "4$4$" ; 4 + = &85, &95, &A5, &B5 ; f5 + & -1 ; pad 7 + = "````" ; and copyright sign ? + & -1 ; pad - + = &CC, &DC, &EC, &FC ; pad %, now f12 + = &87, &97, &A7, &B7 ; f7 + = &89, &99, &A9, &B9 ; f9 + + & -1,-1,-1,-1,-1,-1 + +; Column 2 + +20 + = "2""2""" ; 2 + = "eE", &05, &05 ; E + = "5%5%" ; 5 + = "6&6&" ; 6 + & -1 ; pad 4 + = "^~", &1E, &1E ; ^ + & -1 ; not fitted + & -1 ; pad 9 + = "8(8(" ; 8 + = "0000" ; 0 + + & -1,-1,-1,-1,-1,-1 + +; Column 3 + +30 + & -1 ; TAB + = "zZ", &1A, &1A ; Z + = "gG", &07, &07 ; G + = "bB", &02, &02 ; B + = &8C, &9C, &AC, &BC ; left arrow + = ":*:*" ; : + & -1 ; not fitted + & -1 ; pad 2 + = "kK", &0B, &0B ; K + = ";+;+" ; ; + + & -1,-1,-1,-1,-1,-1 + +; Column 4 + +40 + & -1 ; CAPS lock + = "xX", &18, &18 ; X + = "vV", &16, &16 ; V + = " " ; SPACE BAR + & -1 ; pad . + = &8B,&9B,&AB,&BB ; AGAIN + & -1 ; not fitted + & -1 ; ENTER + = ",<,<" ; , + = "/?/?" ; / + + & -1,-1,-1,-1,-1,-1 + +; Column 5 + +50 + = &80, &90, &A0, &B0 ; MENU now acts like f0 + = "\|", &1C, &1C ; \ + = "cC", &03, &03 ; C + = "nN", &0E, &0E ; N + = &8E, &9E, &AE, &BE ; down arrow + = &0D, &0D, &0D, &0D ; RETURN + & -1 ; not fitted + & -1 ; pad 3 + = "mM", &0D, &0D ; M + = ".>.>" ; . + + & -1,-1,-1,-1,-1,-1 + +; Column 6 + +60 + = "1!1!" ; 1 + = "qQ", &11, &11 ; Q + = "tT", &14, &14 ; T + = "yY", &19, &19 ; Y + & -1 ; pad 1 + = "[{", &1B, &1B ; [ + & -1 ; not fitted + & -1 ; pad 6 + = "iI", &09, &09 ; I + = "pP", &10, &10 ; P + + & -1,-1,-1,-1,-1,-1 + +; Column 7 + +70 + = &1B, &1B, &1B, &1B ; HELP (another ESC key for Tutu) + = "wW", &17, &17 ; W + = "rR", &12, &12 ; R + = "7'7'" ; 7 + = &8F, &9F, &AF, &BF ; up arrow + = &7F, &7F, &7F, &7F ; DELETE + & -1 ; not fitted + & -1 ; pad 8 + = "9)9)" ; 9 + = "-=-=" ; - + + & -1,-1,-1,-1,-1,-1 + +; Column 8 + +80 + = &8B, &9B, &AB, &BB ; COPY ? + = "aA", &01, &01 ; A + = "dD", &04, &04 ; D + = "hH", &08, &08 ; H + = &8D, &9D, &AD, &BD ; right arrow + = "]}", &1D, &1D ; ] + & -1 ; not fitted + & -1 ; pad + + = "jJ", &0A, &0A ; J + = "lL", &0C, &0C ; L + + & -1,-1,-1,-1,-1,-1 + +; Column 9 + +90 + = "__", &1F, &1F ; _ + = "sS", &13, &13 ; S + = "fF", &06, &06 ; F + = "uU", &15, &15 ; U + & -1 ; pad 0 + & -1 ; not fitted + & -1 ; not fitted + & -1 ; pad 5 + = "oO", &0F, &0F ; O + = "@@", &00, &00 ; @ (and grave accent ?) + + & -1,-1,-1,-1,-1,-1 +99 + ASSERT %10-%00 = 64 + ASSERT %20-%10 = 64 + ASSERT %30-%20 = 64 + ASSERT %40-%30 = 64 + ASSERT %50-%40 = 64 + ASSERT %60-%50 = 64 + ASSERT %70-%60 = 64 + ASSERT %80-%70 = 64 + ASSERT %90-%80 = 64 + ASSERT %99-%90 = 64 + ] +KeyTranEnd + + +; ***************************************************************************** + +; Keyboard table for new keyboard + +KeyTran2 ROUT + [ Keyboard_Type = "A1A500" +; Column 0 + +00 + = &1B, &1B, &1B, &1B ; Escape + = &81, &91, &A1, &B1 ; f1 + = &82, &92, &A2, &B2 ; f2 + = &83, &93, &A3, &B3 ; f3 + = &84, &94, &A4, &B4 ; f4 + = &85, &95, &A5, &B5 ; f5 + = &86, &96, &A6, &B6 ; f6 + = &87, &97, &A7, &B7 ; f7 + = &88, &98, &A8, &B8 ; f8 + = &89, &99, &A9, &B9 ; f9 + = &CA, &DA, &EA, &FA ; f10 (or is it f0) + = &CB, &DB, &EB, &FB ; f11 + = &CC, &DC, &EC, &FC ; f12 + = &80, &90, &A0, &B0 ; Print + & -1 ; Scroll Lock + & -1 ; Break + +; Column 1 + +10 + = &FF, "~", &FF, "~" ; back tick (») and ~ + = "1!1!" ; 1 + = "2@", &00, &00 ; 2 + = "3#3#" ; 3 + = "4$4$" ; 4 + = "5%5%" ; 5 + = "6^", &1E, &1E ; 6 + = "7&7&" ; 7 + = "8*8*" ; 8 + = "9(9(" ; 9 + = "0)0)" ; 0 + = "-_", &1F, &1F ; - + = "=+=+" ; = + & -1 ; pound and currency (ž) + = &08, &08, &08, &08 ; backspace + = &CD, &DD, &ED, &FD ; Insert + +; Column 2 + +20 + = &1E, &1E, &1E, &1E ; Home + = &9F, &8F, &BF, &AF ; Page Up + & -1 ; Num Lock + & -1 ; pad / + & -1 ; pad * + & -1 ; pad # + & -1 ; Tab + = "qQ", &11, &11 ; Q + = "wW", &17, &17 ; W + = "eE", &05, &05 ; E + = "rR", &12, &12 ; R + = "tT", &14, &14 ; T + = "yY", &19, &19 ; Y + = "uU", &15, &15 ; U + = "iI", &09, &09 ; I + = "oO", &0F, &0F ; O + +; Column 3 + +30 + = "pP", &10, &10 ; P + = "[{", &1B, &1B ; [ + = "]}", &1D, &1D ; ] + = "\|", &1C, &1C ; \ + = &7F, &7F, &7F, &7F ; Delete + = &8B, &9B, &AB, &BB ; Copy + = &9E, &8E, &BE, &AE ; Page Down + & -1 ; pad 7 + & -1 ; pad 8 + & -1 ; pad 9 + & -1 ; pad - + & -1 ; Ctrl (left) + = "aA", &01, &01 ; A + = "sS", &13, &13 ; S + = "dD", &04, &04 ; D + = "fF", &06, &06 ; F + +; Column 4 + +40 + = "gG", &07, &07 ; G + = "hH", &08, &08 ; H + = "jJ", &0A, &0A ; J + = "kK", &0B, &0B ; K + = "lL", &0C, &0C ; L + = ";:;:" ; ; + = "'""'""" ; ' + = &0D, &0D, &0D, &0D ; Return + & -1 ; pad 4 + & -1 ; pad 5 + & -1 ; pad 6 + & -1 ; pad + + & -1 ; Shift (left) + & -1 ; not fitted + = "zZ", &1A, &1A ; Z + = "xX", &18, &18 ; X + +; Column 5 + +50 + = "cC", &03, &03 ; C + = "vV", &16, &16 ; V + = "bB", &02, &02 ; B + = "nN", &0E, &0E ; N + = "mM", &0D, &0D ; M + = ",<,<" ; , + = ".>.>" ; . + = "/?/?" ; / + & -1 ; Shift (right) + = &8F, &9F, &AF, &BF ; cursor up + & -1 ; pad 1 + & -1 ; pad 2 + & -1 ; pad 3 + & -1 ; Caps Lock + & -1 ; Alt (left) *** + = " " ; space bar + +; Column 6 + +60 + & -1 ; Alt (right) *** + & -1 ; Ctrl (right) + = &8C, &9C, &AC, &BC ; cursor left + = &8E, &9E, &AE, &BE ; cursor down + = &8D, &9D, &AD, &BD ; cursor right + + [ {FALSE} + & -1 ; pad 0 + & -1 ; pad . + & -1 ; pad Enter + & -1 ; not fitted + & -1 ; not fitted + & -1 ; not fitted + & -1 ; not fitted + & -1 ; not fitted + & -1 ; not fitted + & -1 ; not fitted + & -1 ; not fitted + +; Column 7 + +70 + & -1 ; mouse left + & -1 ; mouse centre + & -1 ; mouse right + ] + ASSERT %10-%00 = 16*4 + ASSERT %20-%10 = 16*4 + ASSERT %30-%20 = 16*4 + ASSERT %40-%30 = 16*4 + ASSERT %50-%40 = 16*4 + ASSERT %60-%50 = 16*4 + ] +KeyTran2End + + +; ***************************************************************************** +; +; Reverse table lookup for INKEY(-ve) +; + +InkeyTran + [ Keyboard_Type = "A1A500" + IKT &FF, &FF, &FF, &37, &97, &24, &84, &51 ; 80-87 + IKT &19, &08, &03, &13, &01, &00, &10, &0570 ; 88-8F + IKT &FF, &FF, &FF, &57, &64, &94, &8045, &49 ; 90-97 + IKT &59, &48, &58, &33, &42, &43, &31, &30 ; 98-9F + IKT &FF, &FF, &FF, &FF, &06, &04, &75, &85 ; A0-A7 + IKT &39, &89, &53, &83, &32, &52, &91, &FF ; A8-AF + IKT &FF, &FF, &FF, &44, &FF, &07, &55, &35 ; B0-B7 + IKT &99, &38, &88, &63, &92, &41, &81, &40 ; B8-BF + IKT &FF, &FF, &07, &47, &16, &87, &74, &65 ; C0-C7 + IKT &69, &98, &93, &23, &72, &82, &20, &60 ; C8-CF + IKT &FF, &FF, &FF, &FF, &27, &77, &54, &90 ; D0-D7 + IKT &29, &78, &68, &73, &62, &21, &71, &50 ; D8-DF + IKT &FF, &09, &17, &04, &14, &67, &34, &25 ; E0-E7 + IKT &79, &18, &28, &02, &22, &12, &11, &61 ; E8-EF + IKT &FF, &FF, &FF, &FF, &0D, &0E, &0F, &0B ; F0-F7 + IKT &0C, &0A, &0B, &0C, &0A, &0B, &0C, &0A ; F8-FF + ] + +InkeyTran2 + [ Keyboard_Type = "A1A500" + IKT &FF, &FF, &FF, &5B, &49, &48, &64, &33 ; 80-87 + IKT &09, &08, &06, &05, &03, &02, &01, &00 ; 88-8F + IKT &FF, &FF, &FF, &5C, &5A, &65, &35, &57 ; 90-97 + IKT &56, &55, &54, &52, &51, &5F, &4E, &26 ; 98-9F + IKT &FF, &4D, &1C, &FF, &24, &25, &34, &32 ; A0-A7 + IKT &45, &44, &53, &41, &40, &50, &3D, &FF ; A8-AF + IKT &46, &36, &22, &66, &FF, &23, &47, &45 ; B0-B7 + IKT &12, &43, &42, &2C, &3F, &4F, &3C, &5D ; B8-BF + IKT &21, &20, &1F, &67, &3A, &4B, &59, &31 ; C0-C7 + IKT &30, &2F, &2D, &16, &2A, &3E, &12, &11 ; C8-CF + IKT &1E, &1D, &10, &0F, &39, &38, &63, &1B ; D0-D7 + IKT &1A, &19, &2E, &17, &2B, &29, &28, &0D ; D8-DF + IKT &0E, &0A, &0C, &0B, &37, &4A, &62, &16 ; E0-E7 + IKT &1B, &07, &18, &04, &15, &14, &13, &27 ; E8-EF + IKT &FF, &FF, &FF, &FF, &72, &71, &70, &60 ; F0-F7 + IKT &61, &58, &5E, &3B, &4C, &5E60, &3B61, &4C58 ; F8-FF + ] + + END diff --git a/s/PMF/mouse b/s/PMF/mouse new file mode 100644 index 0000000000000000000000000000000000000000..ddc4929b94dd73bdaa557477bddc6f622ddc5070 --- /dev/null +++ b/s/PMF/mouse @@ -0,0 +1,395 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.PMF.Mouse + +; Mouse driving code + +; Author: Steve Cormie +; Started: 24-Feb-93 + +; Change history: +; +; Date Who Description +; ---- --- ----------- +; 24-Feb-93 SMC Created. + +; ***************************************************************************** +; +; Mouse initialisation +; +MouseInit + Push "lr" + MOV r11, #KeyWorkSpace + + [ :LNOT: AssemblingArthur + MOV r0, #MouseV + ADRL r1, ReadMouse + SWI OS_Claim + ] + + MOV r0, #MouseStepCMOS ; setup mouse multipliers from CMOS + BL Read + MOV r0, r0, LSL #24 ; sign extend it + MOVS r0, r0, ASR #24 + MOVEQ r0, #1 ; if would be zero, set to 1 + STR r0, MouseXMult + STR r0, MouseYMult + + MOV r0, #0 + STRB r0, MouseButtons + + MOV r0, #MouseCMOS + BL Read + STRB r0, MouseType + + Pull "pc" + +; ***************************************************************************** +; +; MouseButtonChange - Called by keyboard handler when mouse button change +; +; in: R0 = state of buttons (bit0=R, bit1=C, bit2=L) +; R11 -> KeyWorkSpace +; + +MouseButtonChange ROUT + Push "R0-R5, R12, R14" + + VDWS WsPtr + STRB R0, MouseButtons ; save it for ReadMouse calls + MOV R3, R0 + + LDR R1, MouseX + LDR R0, [WsPtr, #OrgX] + SUB R1, R1, R0 ; mouse X + + LDR R2, MouseY + LDR R0, [WsPtr, #OrgY] + SUB R2, R2, R0 ; mouse Y + + [ AssemblingArthur :LOR: Module + MOV R4, #0 + LDR R4, [R4, #MetroGnome] ; use monotonic variable now + | + BYTEWS WsPtr + LDR R4, RealTime ; doesn't exist in my world + ] + + MOV R0, #Event_Mouse + BL OSEVEN + MOV WsPtr, #IOC + + [ :LNOT:MouseBufferManager + [ MouseBufferFix + LDR R0, MouseX + | + MOV R5, R2 ; save mouse Y + MOV R0, R1 + ] + BL MouseInsert ; send mouse X low + BCS %FT10 ; buffer full, so don't send rest + + MOV R0, R0, LSR #8 ; send mouse X high + BL MouseInsert + + [ MouseBufferFix + LDR R0, MouseY + | + MOV R0, R5 + ] + BL MouseInsert ; send mouse Y low + + MOV R0, R0, LSR #8 ; send mouse Y high + BL MouseInsert + + MOV R0, R3 + BL MouseInsert ; send buttons + + MOV R0, R4 + BL MouseInsert ; send realtime(0) + + MOV R0, R4, LSR #8 + BL MouseInsert ; send realtime(1) + + MOV R0, R4, LSR #16 + BL MouseInsert ; send realtime(2) + + MOV R0, R4, LSR #24 + BL MouseInsert ; send realtime(3) + | +; Use buffer manager's 'block insert' function + + [ {TRUE} + +; TMD 26-Feb-93: Fix bug - if X is negative, Y would be inserted in the buffer as -1 + + LDR R0, MouseX ; 16 bits, sign-extended to 32 bits + MOV R0, R0, LSL #16 + LDR R1, MouseY ; ditto + MOV R1, R1, LSL #16 + ORR R0, R1, R0, LSR #16 ; combine, having knocked off the troublesome bits + | + LDR R0, MouseX ; 16 bits + LDR R1, MouseY ; 16 bits + ORR R0, R0, R1, LSL #16 ; R0 = Combined 16bit X/Y mouse position + ] + ORR R1, R3, R4, LSL #8 ; R1 = Combined 8bit buttons and 24 LSB's of time + MOV R2, R4, LSR #24 ; R2 = MSB of time + SUB SP, SP, #3*4 ; Create local mouse data buffer + STMIA SP, {R0,R1,R2} ; Write mouse data to buffer + + MOV R3, #9 ; Mouse packet size + MOV R2, SP ; R2-> block to insert + MOV R1, #(Buff_Mouse:OR:(1:SHL:31)) ; Block insert to mouse buffer + Push "R10,R12" + MOV R10, #INSV ; Insert + BL GoVec2 ; Call the vector in R10 + Pull "R10,R12" + ADD SP, SP, #3*4 ; Destroy mouse data buffer + ] +10 + Pull "R0-R5, R12, PC" + + [ :LNOT:MouseBufferManager +MouseInsert + Push "R10,R12,R14" + MOV R10, #INSV + MOV R1, #Buff_Mouse + B GoVec + ] + +; ***************************************************************************** +; +; Read mouse position +; + +ReadMouse ROUT + Push "R4-R6,R10-R12" + MOV R11, #KeyWorkSpace + + [ :LNOT:MouseBufferManager + MOV R1, #Buff_Mouse + BL KeyREMOVE + BCS %FT10 ; MouseAhead buffer empty + + MOV R4, R2, LSL #16 ; Mouse X Low + BL KeyREMOVE + ORR R4, R4, R2, LSL #24 ; R4 := Mouse X << 16 + + BL KeyREMOVE + MOV R5, R2, LSL #16 ; Mouse Y Low + BL KeyREMOVE + ORR R5, R5, R2, LSL #24 ; R5 := Mouse Y << 16 + + BL KeyREMOVE + MOV R6, R2 ; Button state + + BL KeyREMOVE ; get realtime + MOV R3, R2 + BL KeyREMOVE + ORR R3, R3, R2, LSL #8 + BL KeyREMOVE + ORR R3, R3, R2, LSL #16 + BL KeyREMOVE + ORR R3, R3, R2, LSL #24 + + MOV R0, R4, ASR #16 ; sign extend mouse coords + MOV R1, R5, ASR #16 + MOV R2, R6 + | + SUB SP, SP, #3*4 ; Create 9 byte local mouse data buffer + MOV R3, #9 ; Mouse packet size + MOV R2, SP ; R2-> buffer for data + MOV R1, #(Buff_Mouse:OR:(1:SHL:31)) ; Block remove from mouse buffer + CLRV ; Remove not examine + Push "R10,R12" + MOV R10, #REMV + BL GoVec2 ; Call the vector in R10 + Pull "R10,R12" + + LDMCCIA SP, {R4,R5,R6} + ADD SP, SP, #3*4 ; Destroy mouse data buffer + BCS %FT10 ; Jump if no buffered data + + MOV R0, R4, LSL #16 + MOV R0, R0, ASR #16 ; R0 = sign extended x coord + MOV R1, R4, ASR #16 ; R1 = sign extended y coord + AND R2, R5, #&FF ; R2 = button state + MOV R3, R5, LSR #8 ; R3 = 3 low order bytes of time + ORR R3, R3, R6, LSL #24 ; R3 = time + ] + +; code inserted here 12-Aug-88 to force position read from buffer to be inside +; CURRENT bounding box; this removes the need to flush buffer when changing +; the bounding box. + + ADR R4, MouseBounds + LDMIA R4, {R4-R6,R10} ; R4=LCol; R5=BRow; R6=RCol; R10=TRow; + CMP R0, R4 + MOVLT R0, R4 + CMP R0, R6 + MOVGT R0, R6 + CMP R1, R5 + MOVLT R1, R5 + CMP R1, R10 + MOVGT R1, R10 + + [ MouseBufferFix + B %FT20 ; correct for origin after clipping + | + Pull "R4-R6,R10-R12,PC" + ] + +10 + LDRB R2, MouseButtons + + [ AssemblingArthur :LOR: Module + MOV R3, #0 + LDR R3, [R3, #MetroGnome] ; use monotonic variable now + | + BYTEWS WsPtr + LDR R3, RealTime ; doesn't exist in my world + ] + + LDR R0, MouseX + LDR R1, MouseY +20 + VDWS WsPtr + + LDR R4, [WsPtr, #OrgX] + SUB R0, R0, R4 + + LDR R4, [WsPtr, #OrgY] + SUB R1, R1, R4 + + Pull "R4-R6,R10-R12,PC" + +; ***************************************************************************** +; +; ProcessMouseXY - Called to update mouse position. +; +; in: r2 = signed 32-bit X movement +; r3 = signed 32-bit Y movement +; r11 ->KeyWorkSpace +; out: r2,r3 corrupted +; +ProcessMouseXY + Push "r4,lr" + +; process X movement + CMP r2, #0 + BEQ %FT10 + + MOV r2, r2, LSL #16 ; move delta X to top 16 bits + + LDR r4, MouseXMult + MUL r2, r4, r2 + + LDR r4, MouseX + ADD r2, r2, r4, LSL #16 ; add signed value in top 16 bits + MOV r2, r2, ASR #16 ; sign extend to 32 bits + + LDR r4, MouseBoundLCol ; bound to bounding box + CMP r2, r4 + MOVLT r2, r4 + LDR r4, MouseBoundRCol + CMP r4, r2 + MOVLT r2, r4 + STR r2, MouseX + +10 +; process Y movement + CMP r3, #0 + Pull "r4,pc",EQ + + MOV r3, r3, LSL #16 ; move delta Y to top 16 bits + + LDR r4, MouseYMult + MUL r3, r4, r3 + + LDR r4, MouseY + ADD r3, r3, r4, LSL #16 ; add signed value in top 16 bits + MOV r3, r3, ASR #16 ; sign extend to 32 bits + + LDR r4, MouseBoundBRow ; bound to bounding box + CMP r3, r4 + MOVLT r3, r4 + LDR r4, MouseBoundTRow + CMP r4, r3 + MOVLT r3, r4 + STR r3, MouseY + + Pull "r4,pc" + + [ AssemblePointerV + +; ***************************************************************************** +; +; PollPointer - Called on VSync to get mouse changes. +; +; out: corrupts r0-r3,r9-r11 +; +PollPointer + Push "r12,lr" + MOV r11, #KeyWorkSpace + + MOV r0, #0 ; Request pointer state. + LDRB r1, MouseType + MOV r2, #0 ; Default to no movement. + MOV r3, #0 + MOV r9, pc ; Save current PSR. + TEQP pc, #SVC_mode + I_bit ; Call PointerV in SVC mode, no IRQs. + MOV r10, #PointerV ; Call PointerV to get movements & button states + Push "lr" ; Save SVC lr. + BL CallVector + Pull "lr" ; Restore SVC lr. + TEQP r9, #0 + NOP + + BL ProcessMouseXY + + Pull "r12,pc" + + +; ***************************************************************************** +; +; PointerSWI - Handle SWI OS_Pointer calls (read/set pointer type). +; +PointerSWI + MOV r11, #KeyWorkSpace + TEQ r0, #0 + LDREQB r0, MouseType + BEQ SLVK + + TEQ r0, #1 + BNE %FT10 + + Push "r0,r10,r12,lr" + STRB r1, MouseType + MOV r0, #2 + MOV r10, #PointerV + BL CallVector + Pull "r0,r10,r12,lr" + B SLVK + +10 + ADRL r0, ErrorBlock_BadParameters + [ International + BL TranslateError + ] + B SLVK_SetV + ] + + END diff --git a/s/PMF/osbyte b/s/PMF/osbyte new file mode 100644 index 0000000000000000000000000000000000000000..e024e54c400459c198c7db1668241e86624a856e --- /dev/null +++ b/s/PMF/osbyte @@ -0,0 +1,1389 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.PMF.osbyte +; New version of OSBYTE which claims the ByteV(ector) properly +; PMF 18/9/86 +; Updates: +; Kernel +; Version Date Who Why +; 2.01 15-June-90 JSR Change OS_Byte 124/125/126 to update the CallBack_Flag byte +; correctly, rather than setting it to 1. The bug caused vector +; callbacks to be delayed over much when escape was pressed. + +OsbyteLowLimit * &6A ; osbytes lower than this get Y set to 0 +OsbyteVeryLow * &1A ; osbytes lower than this are all recognised +OsbyteSetCountry * &46 +OsbyteSetAlphKey * &47 +OsbyteWrchDests * &EC ; only OS_Byte variable which isn't pure any more! + +ArthurINKEY256 * &A6 ; INKEY-256 value + +; ***************************************************************************** + + GBLS ByteRegs + GBLA StackOffset + [ AssemblingArthur :LOR: Module +ByteRegs SETS "" +StackOffset SETA 4*4 ; stack offset in osbyte routines to user pc + | +ByteRegs SETS "R11, WsPtr," +StackOffset SETA 6*4 ; stack offset in osbyte routines to user pc + ] + + MACRO + MyOsbyte $cond + B$cond GoMyOsbyte + MEND + + MACRO + MyOsWord $cond + B$cond GoMyOsword + MEND + + MACRO + Unused $cond + MOV$cond PC, R14 ; just return and let the next person have a go + MEND + + MACRO + ByteReturnV $cond + [ AssemblingArthur :LOR: ErrorsInR0 + + ASSERT "$cond"="" :LOR: "$cond"="VS" + + [ "$cond"="" + Pull "R0,R3,$ByteRegs R14,PC", VC + ] + ADDVS R13, R13, #4 ; junk stacked R0 + Pull "R3,$ByteRegs R14,PC", VS + + | + Pull "R0,R3,$ByteRegs R14,PC", $cond ; for GenError systems + ] + MEND + +; Main OSbyte entry point +; R0,R1,R2 are parameters + +OsByte + [ AssemblingArthur :LOR: Module + Push "R0, R3, $ByteRegs R14" + BL OsByteGo ; Call the subsid entry pt. + Pull "R0,R3" + Push "R0-R4" + LDMIA R13, {R2-R4} ; R2=A, R3=X, R4=Y + MOV R1, #Service_UKByte ; osbyte service reason + IssueService + TEQ R1, #0 + STMEQIA R13, {R2-R4} ; if claimed, then update + ; returned R0-R2 + CLRPSR V_bit, R3 ; clear V flag + + Pull R0 + ADRNE R0, BadCommandError ; not claimed, R0 -> error + [ International + BLNE TranslateError + ] + SWINE XOS_GenerateError ; set V if not claimed + Pull "R1-R4, $ByteRegs R14, PC" + +BadCommandError MakeErrorBlock BadCommand + | + Push "R0, R3, $ByteRegs R14" + BL OsByteGo + Pull "R0, R3, $ByteRegs PC" ; no services, so pass it on + ] + +GoMyOsbyte + CLRPSR V_bit, R3 + Pull "R0,R3, $ByteRegs R14,PC" ; pull the world AND the PC to return + + +; ***************************************************************************** + +OsByteGo ROUT + [ :LNOT: AssemblingArthur :LAND: :LNOT: Module + BYTEWS WsPtr + ] + AND R0, R0, #&FF ; no funny business! + SUBS R3, R0, #OsbyteLowLimit ; is it a low one ? + BCS HiOsbyte + MOV R2, #0 ; lo one, so set Y to 0 + CMP R0, #OsbyteVeryLow ; is it one we recognise ? +10 + ADDCC PC, PC, R0, LSL #2 ; then go thru despatch table + B TryInternational ; else issue unknown osbyte service +20 + ASSERT %BT20-%BT10 = 8 + + BAL Osbyte00 + BAL Osbyte01 + BAL Osbyte02 + BAL Osbyte03 + BAL Osbyte04 + BAL Osbyte05 + BAL Osbyte06 + BAL Osbyte07 + + BAL Osbyte08 + BAL Osbyte09 + BAL Osbyte0A + BAL Osbyte0B + BAL Osbyte0C + BAL Osbyte0D + BAL Osbyte0E + BAL Osbyte0F + + BAL Osbyte10 + BAL Osbyte11 + BAL Osbyte12 + BAL Osbyte13 + BAL Osbyte14 + BAL Osbyte15 + BAL Osbyte16 + BAL Osbyte17 + + BAL Osbyte18 + BAL Osbyte19 + +HiOsbyte + CMP R0, #MainVars ; is it a variable ? +30 + ADDCC PC, PC, R3, LSL #2 + B DoOsbyteVar ; yes, then do variable mangling +40 + ASSERT %BT40-%BT30=8 + + BAL Osbyte6A + BAL Osbyte6B + BAL Osbyte6C + BAL Osbyte6D + BAL Osbyte6E + BAL Osbyte6F + + BAL Osbyte70 + BAL Osbyte71 + BAL Osbyte72 + BAL Osbyte73 + BAL Osbyte74 + BAL Osbyte75 + BAL Osbyte76 + BAL Osbyte77 + + BAL Osbyte78 + BAL Osbyte79 + BAL Osbyte7A + BAL Osbyte7B + BAL Osbyte7C + BAL Osbyte7D + BAL Osbyte7E + BAL Osbyte7F + + BAL Osbyte80 + BAL Osbyte81 + BAL Osbyte82 + BAL Osbyte83 + BAL Osbyte84 + BAL Osbyte85 + BAL Osbyte86 + BAL Osbyte87 + + BAL Osbyte88 + BAL Osbyte89 + BAL Osbyte8A + BAL Osbyte8B + BAL Osbyte8C + BAL Osbyte8D + BAL Osbyte8E + BAL Osbyte8F + + BAL Osbyte90 + BAL Osbyte91 + BAL Osbyte92 + BAL Osbyte93 + BAL Osbyte94 + BAL Osbyte95 + BAL Osbyte96 + BAL Osbyte97 + + BAL Osbyte98 + BAL Osbyte99 + BAL Osbyte9A + BAL Osbyte9B + BAL Osbyte9C + BAL Osbyte9D + BAL Osbyte9E + BAL Osbyte9F + + BAL OsbyteA0 + BAL OsbyteA1 + BAL OsbyteA2 + BAL OsbyteA3 + BAL OsbyteA4 + BAL OsbyteA5 + +TryInternational ; special ones in the middle + TEQ R0, #OsbyteSetCountry + BEQ DoOsbyteSetCountry + TEQ R0, #OsbyteSetAlphKey + BEQ DoOsbyteSetAlphKey + MOV PC, R14 + +; ***************************************************************************** + +; The Osbyte routines themselves + + +; Mos version number and title string +; R1 = 0 -> give an error with and string MosTitle +; R1 <>0 -> RETURN with R1 = MosVer + +; R2 is Preserved + +Osbyte00 ROUT + TEQ R1, #0 + MOVNE R1, #MosVer + MyOsbyte NE + ADR R0, FX0Error + SWI XOS_GenerateError + ByteReturnV + +FX0Error + & &F7 + = "$MosTitle",0 + ALIGN + +; ***************************************************************************** + +; Write User Flag +Osbyte01 +V2B156 + ADD R0, R0, #&F0 ; convert 1,5,6 to &F1,&F5,&F6 + B DoOsbyteVar + +; Select input stream +Osbyte02 ROUT + AND R0, R1, #1 ; new buffer id + TEQ R1, #0 ; 0 => disable RXI + [ DriversInKernel + MOVNE R1, #RXEN6850 ; else enable RXI + MOV R2, #(&FF :EOR: RXEN6850) ; AND mask (R1 = EOR mask) + BL ModifyControl6850 ; on exit, R1 = old control reg + LDRB R2, RS423conflag ; R2 = new control reg + Push "R1, R2" + BL RSETX ; try to enable RX interrupts + Pull "R1, R2" + TEQ R1, R2 + BEQ %FT10 ; no change in RXI + + Push R11 ; now purge data register when going + LDR R11, =ACIA ; from disabled -> enabled; (also + LDRB R1, ACIARxData ; does it for enabled -> disabled, this + ; is irrelevant) + Pull R11 +10 + | + Push "r0" + BNE %FT10 ; [enabling serial] + +; disable serial by closing stream + + LDRB r1, SerialInHandle + TEQ r1, #0 + MOVNE r0, #0 ; close file if handle non-zero + STRNEB r0, SerialInHandle ; zero handle first + SWINE XOS_Find + B %FT20 + +; enable serial by opening stream + +10 + LDRB r0, SerialInHandle + TEQ r0, #0 ; if a stream open already + BNE %FT20 ; then skip + + MOV r0, #open_read + open_mustopen + ADR r1, SerialInFilename ; open serial stream for input + SWI XOS_Find + STRVCB r0, SerialInHandle ; if did open then store handle + ; (may store same value if already open, but who cares?) +20 + Pull "r0" + ] + LDRB R1, InputStream ; old input stream + STRB R0, InputStream + MyOsbyte + + LTORG + + [ :LNOT: DriversInKernel +SerialInFilename + = "Serial#Buffer1:", 0 + ALIGN + ] + +; Select output stream +Osbyte03 + +Osbyte04 ; select cursor keys actions +V2B34 + ADD R0, R0, #&E9 ; convert 3,4 to &EC,&ED + B DoOsbyteVar + +; Write Printer driver type +Osbyte05 ROUT + BL MakePrinterDormant ; for netprint + MOV R14, PC ; for restoring I afterwards +10 + MVN R3, #I_bit + TSTP R3, PC ; CLI + TEQP R14, #0 ; restore old I + + MOV R3, #0 + LDRB R3, [R3, #ESC_Status] + TST R3, #&40 + MyOsbyte NE ; ESCAPE, so don't change + + LDR R3, PrinterActive + TEQ R3, #0 + BNE %BT10 ; still active, then loop + +; insert code here to notify UPTVEC of change + + B V2B156 ; R0 = 5, update variable + +; Write Printer Ignore Character +Osbyte06 + STRB R2, NoIgnore ; (R2=0) allow chars to be ignored + B V2B156 + + [ DriversInKernel +; Write RS423 receive rate +Osbyte07 + BL DoOsbyte07 + MyOsbyte + +; Write RS432 transmit rate +Osbyte08 + BL DoOsbyte08 + MyOsbyte + | +; Write RS423 receive rate +; Write RS432 transmit rate +Osbyte07 +Osbyte08 + SUB r0, r0, #2 ; 7 -> 5; 8 -> 6 + SWI XOS_SerialOp + MyOsbyte + ] + + [ DriversInKernel +; Modified 30-Mar-88 to handle new baud rates +; Format of SerULAreg is as follows:- +; Bit Contents +; 7 TX3 ; *** NEW *** +; 6 RX3 ; *** NEW *** +; 5 RX2 +; 4 RX1 +; 3 RX0 +; 2 TX2 +; 1 TX1 +; 0 TX0 + +; FX7/8 RX/TX bits above Baud +; value 3 2 1 0 rate +; +; 1 0 1 1 1 75 +; 2 0 0 1 1 150 +; 3 0 1 0 1 300 +; 4 0 0 0 1 1200 +; 5 0 1 1 0 2400 +; 6 0 0 1 0 4800 +; 7 or 0 0 1 0 0 9600 +; 8 0 0 0 0 19200 +; 9 1 0 1 1 50 +; 10 1 1 0 1 109.92 +; 11 1 0 0 1 134.58 +; 12 1 1 1 0 600 +; 13 1 0 1 0 1800 +; 14 1 1 0 0 3600 +; 15 1 0 0 0 7200 +; 16 1 1 1 1 Undefined + + +DoOsbyte07 ROUT + Push "R11, R14" + LDRB R2, SerULAreg + CMP R1, #16+1 + BCS %FT10 ; invalid + + ADR R3, SerBaudTable ; point to silly serproc table + LDRB R3, [R3, R1] ; get entry + BIC R0, R2, #&78 ; clear old bits + ORR R0, R0, R3, LSL #3 ; or in new bits +DoFx7or8 + STRB R0, SerULAreg + +; first set up the carry flag to indicate whether RX = TX + + AND R1, R0, #&07 ; get Tx bits 0-2 + TST R0, #&80 + ORRNE R1, R1, #&08 ; R1 = Tx bits + EOR R3, R1, R0, LSR #3 ; EOR Rx and Tx bits + AND R3, R3, #15 ; ignore other bits + CMP R3, #1 ; C=1 => different + +; now program both RX and TX (start with TX) + + ADR R3, TxBaudTable ; (R1 = Tx bits) + LDRB R3, [R3, R1] + + MOV R1, R0, LSR #3 ; R1 = RX bits for later + AND R1, R1, #15 + + PHPSEI ; NB preserves carry + LDR R11, =ACIA + LDRB R0, ACIAControl ; replace old baud bits with new + AND R0, R0, #(ACIASBN :OR: ACIAWL1 :OR: ACIAWL0) + ORR R0, R0, R3 ; external RX clock by default + ORRCC R0, R0, #&10 ; if RX=TX use internal RX clock + STRB R0, ACIAControl + + BCC %FT20 ; if RX=TX then we've finished + + ADR R3, RxBaudTable ; point to timer latch values table + LDR R3, [R3, R1, LSL #2] ; get entry + + MOV R0, #IOC + STRB R3, [R0, #Timer2LL] + MOV R3, R3, LSR #8 + STRB R3, [R0, #Timer2LH] + STRB R3, [R0, #Timer2GO] +20 + PLP +10 + MOV R1, R2 ; R1 = R2 = "old serproc contents" + Pull "R11, PC" + +DoOsbyte08 + Push "R11, R14" + LDRB R2, SerULAreg + CMP R1, #16+1 + BCS %BT10 ; invalid + + ADR R3, SerBaudTable ; point to silly serproc table + LDRB R3, [R3, R1] ; get entry + BIC R0, R2, #&87 ; clear old bits + TST R3, #8 ; if bit 3 is set + EORNE R3, R3, #&88 ; then move to bit 7 + ORR R0, R0, R3 ; OR in new bits + B DoFx7or8 + + LTORG + +SerBaudTable + = 4, 7, 3, 5, 1, 6, 2, 4, 0 ; silly table for BBC compat + = 11, 13, 9, 14, 10, 12, 8, 15 + +TxBaudTable ; ordered on values in SerBaudTable + = Baud19200, Baud1200, Baud4800, Baud150 + = Baud9600, Baud300, Baud2400, Baud75 + = Baud7200, Baud135, Baud1800, Baud50 + = Baud3600, Baud110, Baud600, BaudUndef + ALIGN + +RxBaudTable ; ordered on values in SerBaudTable + & 2, 51, 12, 416, 6, 207, 25, 832 + & 8, 463, 34, 1249, 16, 568, 103, 0 + + ] + +; Write First Flash Time +Osbyte09 + MOV R2, #1 +; and drop thru to ... + +; Write Second Flash Time +Osbyte0A ; (R2=0) +Osbyte910 + MOV R0, R1 ; new period + LDRB R1, [R2, #OsbyteVars + :INDEX: SpacPeriod] ; get old state + STRB R0, [R2, #OsbyteVars + :INDEX: SpacPeriod] ; store new + + LDRB R3, FlashCount + TEQ R3, #0 ; are we frozen ? + MyOsbyte NE ; no, then finish + + STRB R0, FlashCount ; kick the counter + STRB R2, FlashState ; force new state + + VDWS WsPtr + + TEQ R2, #0 + BEQ ForceSecondState + + Push "R1,R2" + BL DoFirstFlash + Pull "R1,R2" + MyOsbyte + +ForceSecondState + Push "R1,R2" + BL DoSecondFlash + Pull "R1,R2" + MyOsbyte + + +; Write Keyboard Delay +Osbyte0B +V2BBC + ADD R0, R0, #(&C4-&0B) + B DoOsbyteVar + +; Write Keyboard Rate +Osbyte0C + TEQ R1, #0 + BNE V2BBC + CLRPSR I_bit, R0 ; this may take some time + BL ReadKeyDefaults + MyOsbyte + +; ***************************************************************************** + +; Disable / Enable Events +; R1 = Event number. Decrement/Increment semaphore for this event + +Osbyte0D ROUT +Osbyte0E ROUT + CMP R1, #32 ; if illegal event number + MOVCS R2, #0 ; then return + say was disabled + BCS %FT10 + + ADD R3, WsPtr, #:INDEX: EventSemaphores + LDRB R2, [R3, R1] ; get semaphore for this event + + CMP R0, #13 ; 13 => disable, 14 => enable + SUBEQ R0, R2, #1 ; decrement semaphore + ADDNE R0, R2, #1 ; increment semaphore + + CMP R0, #&100 ; C=1 => wrapped, so don't store back + STRCCB R0, [R3, R1] +10 + MOV R1, R2 ; R1 = R2 = old semaphore + MyOsbyte + +; ***************************************************************************** + +; Flush Buffer +Osbyte0F ROUT + TEQ R1, #0 + BNE FlushInput + BL FlushAll + MyOsbyte + +; flush all buffers + +FlushAll + Push R14 + MOV R1, #(NBuffers-1) +10 + BL FlushThis + SUBS R1, R1, #1 + BPL %BT10 + Pull PC + +; flush input buffer + +FlushInput + LDROSB R1, InputStream ; get buffer id of input stream + BL FlushThis + MyOsbyte + +; ***************************************************************************** + +; Clear out the softkeys +Osbyte12 ROUT + MOV R0, #0 + STRB R0, SoftKeyLen ; purge current expansion + MOV R11, #KeyWorkSpace ; can corrupt R11 + Push R4 + MOV R1, #15 +10 + MOV R3, R1 + BL SetupKeyName ; exits with R0 -> SoftKeyName + MOV R2, #-1 ; destroy variable + MOV R3, #0 ; context pointer 0 + MOV R4, #0 ; type irrelevant + SWI XOS_SetVarVal ; V will be set if not present + SUBS R1, R1, #1 + BPL %BT10 + Pull R4 + MyOsbyte + +; ***************************************************************************** + +; Wait for Vsync + +Osbyte13 ROUT + + MOV R14, PC + + ; bug fix for MED-03165. Having a DPMS-blanked screen stopped printing. + ; The reason is that HSyncs stop and VSyncs stop as a consequence, + ; but the Hourglass module uses this call to wait for the next VSync + ; before animating the hourglass. + ; When the screen is DPMS-blanked this osbyte will now return + ; immediately. This is equivalent to the operation of the DPMSUtils + ; module shipped with OS 3.50. + + VDWS R2 + + LDRB R0, [R2,#ScreenBlankFlag] + LDRB R1, [R2,#ScreenBlankDPMSState] + + TEQ R0, #0 ; NE => blanked + TSTNE R1, #1 ; NE => blanked and DPMS turned off HSyncs + BNE %FT20 ; if true exit immediately + + LDRB R0, CFStime +10 + TEQP R14, #I_bit ; CLI + TEQP R14, #0 ; SEI + LDRB R1, CFStime + TEQ R1, R0 + BEQ %BT10 +20 + MyOsbyte + +; ***************************************************************************** + +; Restore font definitions +Osbyte14 + MOV R1, #1 ; start at character 1*32 + MOV R2, #3 ; do 3 pages + B ResetPartFont + +; ***************************************************************************** + +; Flush Selected Buffer +Osbyte15 ROUT +; +; TMD 24-Apr-92: Don't check buffer number, as this prevents the flushing +; of buffer manager buffers. +; +; CMP R1, #NBuffers +; BCS %FT10 ; invalid buffer number + BL FlushThis +;10 + MyOsbyte + + +FlushThis + +; code inserted here to zero PrinterActive iff you are flushing the printer +; buffer and the print destination is not a stream one + + [ DriversInKernel + TEQ R1, #Buff_Print ; is it the printer buffer ? + BNE %FT15 ; no, then skip + + LDRB R0, PrinterDrivType ; if printer type 0, 1 or 2 + CMP R0, #3 + MOVCC R0, #0 ; then mark printer dormant + STRCC R0, PrinterActive +15 + ] + CMP R1, #Buff_RS423Out ; is it an input buffer ? (not mouse) + BCS %FT20 ; no, then branch + + MOV R0, #0 + STRB R0, SoftKeyLen ; kill soft key expansion + STRB R0, VDUqueueItems ; flush VDU queue +20 + SETV ; indicate purge not count + B CnpEntry + +; Reset Group of font definitions +Osbyte19 ROUT + CMP R1, #8 + MyOsbyte CS ; not in range 0..7, ignore + TEQ R1, #0 + + MOVEQ R1, #1 ; if 0 then start at 1*32, do 7 pages + MOVEQ R2, #7 + + MOVNE R2, #1 ; else start at n*32, do 1 page +ResetPartFont + +; first offer to International module + + Push "R1, R2, R4, R5" + MOV R4, R1, LSL #5 ; R4 = start character + ADD R5, R4, R2, LSL #5 ; R5 = end character+1 + SUB R5, R5, #1 ; R5 = end character + LDRB R3, Alphabet + MOV R2, #Inter_Define + BL OfferInternationalService + Pull "R1, R2, R4, R5" + MyOsbyte EQ ; if claimed, don't use hard font + + ByteToNosbod DoResetFont + MyOsbyte + +; ***************************************************************************** + +; Set country number +; in: R1 = country number + +DoOsbyteSetCountry ROUT + TEQ R1, #&7F ; if 127, just read country + LDREQB R1, Country + MyOsbyte EQ + + BL GetCountry + Push R4 + BL ConvertCNoToANo ; convert country no. to alphabet no. + Pull R4, NE + MOVNE R1, #0 ; if not claimed, return with X=0 + MyOsbyte NE + +; was claimed, so have country number in R1 and R3, alphabet no. in R4 + + LDRB R1, Country ; save old country + STRB R3, Country ; store new country + STRB R4, Alphabet ; and new alphabet + BL NewKeyboard ; R3=new keyboard, R4=alphabet for it + BL SetAlphabet + Pull R4 + MyOsbyte + +SetAlphabet + Push "R1,R5,R14" + MOV R2, #Inter_Define ; now redefine the chars + MOV R3, R4 + MOV R4, #32 + MOV R5, #255 + BL OfferInternationalService + Pull "R1,R5,PC" + +ConvertCNoToANo + MOV R3, R1 ; put country no. in R3 + MOV R2, #Inter_CNoToANo +OfferInternationalService + Push R14 + MOV R1, #Service_International + IssueService + TEQ R1, #0 ; set Z flag if claimed + Pull PC + +; Notify keyboard handler of new keyboard + +NewKeyboard + Push "R1,R4,R14" + STRB R3, Keyboard + STRB R4, KeyAlphabet + MOV R2, #Inter_Keyboard + BL OfferInternationalService + Pull "R1,R4,PC",,^ + +; ***************************************************************************** + +; Set keyboard/alphabet for a particular country + +DoOsbyteSetAlphKey ROUT + TST R1, #&80 ; if set then setting keyboard + BNE %FT10 ; [setting keyboard] + +; setting alphabet + + TEQ R1, #&7F ; 127 => just read alphabet + LDREQB R1, Alphabet + MyOsbyte EQ + +; 20/8/87 added code to do setting of default alphabet + + BL GetCountry + Push R4 + BL ConvertCNoToANo ; try to convert R1 to alphabet number + MOVNE R4, R3 ; if failed, try without converting + BL SetAlphabet ; try to set this alphabet + Pull R4 + MOVNE R1, #0 ; if not claimed, return with X=0 + MyOsbyte NE + + LDRB R1, Alphabet + STRB R3, Alphabet + MyOsbyte + +; setting keyboard + +10 + AND R1, R1, #&7F + TEQ R1, #&7F ; 127 => just read keyboard + LDREQB R1, Keyboard + MyOsbyte EQ + + BL GetCountry + Push R4 + BL ConvertCNoToANo ; validating country no. + Pull R4, NE + MOVNE R1, #0 ; if not claimed, return with X=0 + MyOsbyte NE + + LDRB R1, Keyboard ; load old keyboard + BL NewKeyboard ; R3=new keyboard, R4=alphabet for it + Pull R4 + MyOsbyte + +; ***************************************************************************** + +; All osbytes from &1A to &69 are unused (apart from international ones!) + +; End of unused block + +; Write pointer shape number, mouse linkage +; +; R1 = 0 => pointer off +; R1 = 1..4 => use pointer shape 1..4, linked to mouse +; R1 = &81..&84 => use pointer shape 1..4, unlinked +; + +Osbyte6A + VDWS R0 + LDRB R3, [R0, #PointerShapeNumber] ; get old shape number + AND R2, R1, #&7F ; allow 0..4, &80..&84 + CMP R2, #4+1 + STRCCB R1, [R0, #PointerShapeNumber] + MOV R1, R3 + MyOsbyte + +; Set vdu driver's screen number +Osbyte70 + ByteToNosbod DoSetDriverBank + MyOsbyte + +; Set displayed screen number +Osbyte71 + ByteToNosbod DoSetDisplayBank + MyOsbyte + +; *SHADOW +Osbyte72 + MOV R0, #&EF ; redirect to shadow variable + MOV R2, #0 + B DoOsbyteVar + +; ***************************************************************************** + +; Read VDU Status +Osbyte75 + Push R2 + ByteToNosbod DoReadVDUStatus + Pull R2 + MyOsbyte + +; Reflect Keyboard Status In LEDs +Osbyte76 + MOV R11, #KeyWorkSpace + MOV R12, #IOC + BL UpdateLEDs + MyOsbyte + +; Write Keys Pressed Info +Osbyte78 + BL WriteKeysDown + MyOsbyte + +; Perform Keyboard Scan from 16 +Osbyte7A + MOV R1, #&10 +; and drop thru to ... + +; Perform Keyboard Scan +Osbyte79 + BL BBCScanKeys + MyOsbyte + +; Inform OS Printer Driver going Dormant +Osbyte7B + BL MakePrinterDormant + ByteReturnV + +; Clear Escape Condition +Osbyte7C + BL DoOsbyte7C + MyOsbyte + +; Set Escape Condition +Osbyte7D + BL DoOsbyte7D + MyOsbyte + +DoOsbyte7C + Push "R11, R14" + MOV R11, #0 + B Osbyte7C7D + +DoOsbyte7D + Push "R11, R14" + MOV R11, #&FF +Osbyte7C7D + [ AssemblingArthur :LOR: Module + MOV R12, #EscHan_ws + STRB R11, [R12, #ESC_Status-EscHan_ws] ; set escape flag + MOV R14, PC + LDMIA R12, {R12, PC} + | + MOV R12, #0 + STRB R11, [R12, #ESC_Status] ; set escape flag + MOV R14, PC ; ADRS R14, Exit7D + LDR PC, [R12, #EscHan] + ] +Exit7D + TEQ R12, #1 + [ Version >= 201 + Pull "R11, PC", NE + + MOV R11, PC ; Preserve old processor state + ORR R12, R11, #SVC_mode ; Switch to SVC mode preserving IRQ_bit + TEQP R12, #0 + NOP + Push R14 ; Preserve SVC_R14 + SWI XOS_SetCallBack + ORRVS R11, R11, #V_bit ; Preserve V_bit + Pull R14 ; Restore SVC_R14 + TEQP R11, #0 ; Switch back to original mode, with V_bit intact from SWI + NOP + + Pull "R11, PC" + | + STREQB R12, [R12, #IRQ_CallBack_Flag-1] + ] + Pull "R11, PC" + +; Acknowledge ESCAPE +Osbyte7E ROUT + MOV R3, #0 + LDRB R3, [R3, #ESC_Status] + TST R3, #&40 + BEQ NoESCToAck ; escape flag clear + + LDRB R0, ESCeffect + TEQ R0, #0 + BNE NoESCToAck ; escape effects disabled + + CLRPSR I_bit, R0 ; enable interrupts (doing SOUNDs and + ; closing files may take some time!) + + [ AssemblingArthur :LOR: Module + SWI XSound_QInit + BVS %FT99 ; no noises anyway! + LDR R0, =&01010008 ; channel 8, amplitude &101 + MOV R1, #&00010000 ; pitch 0, duration 1 +10 + SWI XSound_ControlPacked + BVS %FT99 ; (R0 would be corrupted) + SUB R0, R0, #1 ; decrement channel + TST R0, #&FF ; if channel <> 0 then loop + BNE %BT10 +99 + MOV R0, #0 + ] + + STRB R0, PageModeLineCount ; zero line count + + LDRB R1, ExecFileH + CMP R1, #0 ; is EXEC file open (and V:=0) + STRNEB R0, ExecFileH ; if so, zero handle and close + ; (will enable IRQs for me) + SWINE XOS_Find ; (R0=0, R1=handle) + ByteReturnV VS ; if error then bomb out + + BL FlushAll + +NoESCToAck + BL DoOsbyte7C + ANDS R1, R3, #&40 ; set R1 to 0 if wasn't escape, + MOVNE R1, #&FF ; &FF if was + MyOsbyte + + +; Check for EOF +Osbyte7F + MOV R0, #OSArgs_EOFCheck + SWI XOS_Args ; result comes back in R2 + MOV R1, R2 + ByteReturnV + +; ***************************************************************************** + +; Read ADC or buffer status +Osbyte80 + AND R1, R1, #&FF ; no funny business + + TST R1, #&80 ; is it ADVAL(-n) + BEQ AdvalPositive ; no, then do adval(+ve) + EOR R1, R1, #&FF ; convert to buffer number + CLC ; (C:=0 and V:=0) + TEQ R1, #Buff_Mouse ; is it mouse (only input buf >= 2) ? + CMPNE R1, #Buff_RS423Out ; C=1 <=> output buffer, so count spaces + ; V=0, so will do count not purge + + ADR R14, MyOsbyte80 +CnpEntry + Push "R10,R12,R14" + MOV R10, #CNPV + B GoVec + +MyOsbyte80 + MyOsbyte + +AdvalPositive ROUT + TEQ R1, #7 + TEQNE R1, #8 + Unused NE + + Push R11 + + MOV R11, R1 ; save adval number + SWI XOS_Mouse + Pull R11, VS + ByteReturnV VS + + TEQ R11, #7 + MOVEQ R1, R0 ; R1 is required value + + MOV R2, R1, LSR #8 ; put lo in R1, hi in R2 + AND R1, R1, #&FF + AND R2, R2, #&FF + + Pull R11 + MyOsbyte + +; ***************************************************************************** + +; Perform INKEY operation +Osbyte81 ROUT + TST R2, #&80 ; is it negative inkey ? + BEQ %FT10 ; no, then not INKEY-256 + ANDS R1, R1, #&FF ; zero => INKEY(-256) + MOVEQ R1, #ArthurINKEY256 ; then X := OS version number + MOVEQ R2, #0 ; and Y := 0 + MyOsbyte EQ ; if was INKEY-256 then claim +10 + Push R14 ; save return address for if passing on + ADR R14, My81 + Push R14 ; stack 'claiming' return address + BL DoInkeyOp ; R14 = 'passing on' return address +NotMy81 ; DoInkeyOp passed it on + + Pull "R3,R14" ; Throw away 'claiming' return address + ; and restore real passing on return address + Unused ; else pass it on still + +My81 + Pull R14 ; throw away real passing on address + ByteReturnV + + +; ***************************************************************************** + +; Read Machine High Order Address +Osbyte82 + MOV R1, #&FF ; Pretend we're an I/O processor ! + MOV R2, #&FF + MyOsbyte + +; ***************************************************************************** + +; Read OSHWM +Osbyte83 + LDRB R2, OSHWM ; Read from silly variable + MOV R1, #0 ; lo-byte is 0 + MyOsbyte + +; ***************************************************************************** + +; Read Text Cursor Position (input cursor if split) +Osbyte86 + ByteToNosbod DoReadPOSVPOSI ; Results in R1, R2 (i.e. POS, VPOS) + MyOsbyte + +; ***************************************************************************** + +; Read Screen Mode and Character at text cursor position +Osbyte87 + [ Fix6 + LDR R3, [R13, #StackOffset] ; get user's psr + ANDS R3, R3, #I_bit ; EQ => irqs were on + CLRPSR I_bit, R3, EQ ; so clear I_bit now + ] + ByteToNosbod DoOSBYTE87 ; Results in R1, R2 (i.e. char, mode) + MyOsbyte + +; ***************************************************************************** + +; Insert Character Into Buffer +Osbyte8A + BL INSERT + MyOsbyte + +; ***************************************************************************** + +; Write Filing System Options : *OPT +Osbyte8B + MOV R0, #FSControl_OPT + SWI XOS_FSControl + ByteReturnV + +; ***************************************************************************** + +; Issue Paged ROM Service Request +Osbyte8F + IssueService + MyOsbyte + +; ***************************************************************************** + +; Select vertical screen shift and interlace option :*TV +Osbyte90 + LDRB R0, TVVertical + STRB R1, TVVertical + MOV R1, R0 ; old vertical in R1 + + AND R0, R2, #1 + LDRB R2, TVInterlace ; old interlace in R2 + STRB R0, TVInterlace + + MyOsbyte + +; ***************************************************************************** + +; Get Character From Buffer +Osbyte91 + CLRV ; remove not examine +RemVEntry + ADR R14, MyOsbyte80 +REMOVE + Push "R10,R12,R14" + MOV R10, #REMV + B GoVec + +; ***************************************************************************** + +; Examine Buffer Status +Osbyte98 + SETV ; examine not remove + B RemVEntry + +; ***************************************************************************** + +; Insert Character Code Into buffer checking for ESCAPE +Osbyte99 + BL DoInsertESC + MyOsbyte + +; ***************************************************************************** + +; Update pseudo 6850 control register and soft copy + +Osbyte9C + MOV r0, #7 ; OS_SerialOp to modify 6850 control register + SWI XOS_SerialOp + MyOsbyte + +; ***************************************************************************** + +; 'Fast TUBE BPUT' + +Osbyte9D + MOV R0, R1 ; R0 := character + MOV R1, R2 ; R1 := handle + SWI XOS_BPut + ByteReturnV + +; ***************************************************************************** + +; Read VDU Variable (0..15 implemented) +OsbyteA0 + ByteToNosbod DoReadVDUVariable + MyOsbyte + +; ***************************************************************************** + +; Read CMOS RAM +OsbyteA1 ; R1 = address , R2 = result + CLRPSR I_bit, R0 ; this may take some time + MOV R0, R1 + BL Read ; Read CMOS ram at address <R0> + MOV R2, R0 ; Result in R0, return in R2 + MyOsbyte + +; Write CMOS RAM +OsbyteA2 + CLRPSR I_bit, R0 ; this may take some time + ANDS R0, R1, #&FF ; only look at bottom byte + [ ProtectStationID + MyOsbyte EQ + ] + MOV R1, R2 + BL Write + MOV R1, R0 ; R1 is supposed to be preserved + MyOsbyte + +; ***************************************************************************** + +; OsByte 163,... applications call +OsbyteA3 ROUT + TEQ R1, #242 + Unused NE ; not 242 - pass it on + BL %FT10 + MyOsbyte ; if come to here, has been claimed + +10 + Push R14 + ByteToNosbod DoOsbyte163_242 + Pull R14 ; if come to here, wasn't claimed + Unused + +; ***************************************************************************** + +; Read Output cursor Position +OsbyteA5 + ByteToNosbod DoReadPOSVPOSO ; Result in R1,R2 (Horiz,vert) + MyOsbyte + +; ***************************************************************************** +; +; All calls &A6 to &FF are implemented together. +; <NEW VALUE> = (<OLD VALUE> AND R2 ) EOR R1 +; The old value is returned in R1 and the next location is returned in R2 +; +; ***************************************************************************** + +DoOsbyteVar + SUB R0, R0, #MainVars ; Point to this block starting at &A6 + LDRB R3, [WsPtr, R0] ; Load the byte + AND R11, R3, R2 ; Mangle it as required by the law + EOR R11, R11, R1 ; ................................ + MOV R1, R3 ; Return old value in R1 + STRB R11, [R0, WsPtr]! ; R0 +:= WsPtr + LDRB R2, [R0, #1] ; Return contents of next loc in R2 + [ {FALSE} ; This code didn't work in 3.00 because R0 isn't the offset from MainVars + ; anymore - anyway, the code is not needed because the kernel closes the + ; stream on an open request. + TEQ R0, #OsbyteWrchDests-MainVars + MyOsbyte NE ; fast exit if not setting wrch destinations + TST R11, #1 ; is serial output now disabled + MyOsbyte NE + LDRB R1, SerialOutHandle ; see if serial stream open + TEQ R1, #0 ; if it is + MOVNE R0, #0 ; then close it + STRNEB R0, SerialOutHandle ; zeroing handle beforehand + SWINE XOS_Find + ] + MyOsbyte + + LTORG + +; All the unused OS_Byte calls + +; ADC stuff +Osbyte10 ROUT +Osbyte11 ROUT +; Incr/Decr Polling Int +Osbyte16 +Osbyte17 +; Unused +Osbyte18 +; Write 1MHz bus selection +Osbyte6B +; Write Usage of Shadow memory for normal access +Osbyte6C +; Make temporary filing system permanent +Osbyte6D +; &6E and &6F are reserved by 3rd parties +Osbyte6E +Osbyte6F +; &73 and &74 reserved for Electron +Osbyte73 +Osbyte74 +; Close SPOOL(ON) & EXEC files +Osbyte77 +; Read top of USER RAM +Osbyte84 +; Read top of user RAM for given mode +Osbyte85 +; *CODE +Osbyte88 +; *MOTOR +Osbyte89 +; *TAPE +Osbyte8C +; *ROM +Osbyte8D +; Enter Language ROM +Osbyte8E +; Access Mem.Map.IO &92..&97 +Osbyte92 +Osbyte93 +Osbyte94 +Osbyte95 +Osbyte96 +Osbyte97 +; Write to VidULA & COPY +Osbyte9A +Osbyte9B +; Old Style Speech +Osbyte9E +Osbyte9F +; Check Processor Type +OsbyteA4 + Unused + +; ***************************************************************************** +; +; GetCountry - Read country +; +; in: R1 = country number or alphabet number +; +; out: IF R1=0 THEN +; R1:=Configured Country +; IF R1=0 THEN +; R1:=LastKbId +; IF R1>=&20 THEN R1:=0 +; ENDIF +; ENDIF +; +; R0 undefined +; + +GetCountry ROUT + TEQ R1, #0 ; if not setting default, exit + MOVNE PC, R14 + + Push R14 + MOV R0, #CountryCMOS ; read configured country + BL Read + MOVS R1, R0 ; if not Country Default, exit + Pull PC, NE + + MOV R0, #KeyWorkSpace + LDRB R1, [R0, #:INDEX: LastKbId] ; read last valid keyboard id + CMP R1, #&20 ; if <&20 then use this + MOVCS R1, #0 ; else set to 0 + Pull PC + + END diff --git a/s/PMF/oseven b/s/PMF/oseven new file mode 100644 index 0000000000000000000000000000000000000000..7afa0ee96741b854f73b3b4ea245683c4a717378 --- /dev/null +++ b/s/PMF/oseven @@ -0,0 +1,391 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.PMF.oseven + + [ DriversInKernel +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; PrinterIRQ - Process printer acknowledge IRQ +; + +PrinterIRQ ROUT + [ AssemblingArthur + Push R14 ; stack R14 if new MOS IRQ vector + | + BYTEWS WsPtr ; already set up in new IRQ scheme + ] + MOV R0, #pack_bit + STRB R0, [R3, #IOCIRQCLRA] ; clear interrupt even if centronics + ; printer not selected (unlike Master!) + LDRB R1, PrinterDrivType + TEQ R1, #1 ; parallel printer selected ? + BLEQ STROBE ; if so, then try to send another char + Pull PC + +; ***************************************************************************** +; +; STROBE - Remove char from printer buffer and "print" it +; +; in: WsPtr -> OsbyteVars +; MUST be called with IRQs disabled + +STROBE ROUT + MOV R1, #Buff_Print ; printer buffer id + LDRB R0, PrinterDrivType + CMP R0, #3 ; is it user/net ? + MOVCS PC, R14 ; don't do anything + + CMP R0, #1 + BCC FlushThis ; printer sink - flush buffer + BNE %FT10 ; must be RS423 + +; centronics printer + + Push R14 + BL REMOVE ; note V=0 from CMP above + ; so this is remove + MOV R3, #IOC + +; disable FIQs around this bit + + MOV R14, #F_bit + TST R14, PC ; (preserves carry) + MOVNE R14, #0 + TEQP R14, PC + + LDRB R2, [R3, #IOCIRQMSKA] + ORRCC R2, R2, #pack_bit ; if char, enable printer IRQ + BICCS R2, R2, #pack_bit ; else disable printer IRQ + STRB R2, [R3, #IOCIRQMSKA] + + TEQP R14, PC ; restore old F bit + MOVCC R2, #1 ; printer active + MOVCS R2, #0 ; printer dormant + STR R2, PrinterActive + + Pull PC, CS ; no more chars to print + + LDR R2, =PrinterData + STRB R0, [R2] ; write data out + + Push R1 + + MOV R0, #pstrobe_bit ; enable strobe + MVN R1, R0 ; L:= (L AND NOT strobe) EOR strobe + BL UpdateLatchB + + MOV R0, #0 ; and disable it ( >.5 microsecs later) + BL UpdateLatchB ; L:= (L AND NOT strobe) EOR 0 + + Pull "R1,PC" + +10 ; RS423 printer + STR R0, PrinterActive ; mark printer active (R0<>0) +RSBUSY + MOV R0, #0 ; mark RS423 in use (+ve) + STRB R0, RS423use + LDR R0, SerialFlags + TST R0, #(1:SHL:SF_XONXOFFOn) ; if xon/xoff protocol + Push R14, NE + BNE EnableTXI ; then enable TXI regardless +RSETX + Push R14 + BL CountRS + Pull PC, CC ; RX overflow, so exit + + LDR R1, SerialFlags + TST R1, #(1:SHL:SF_XONXOFFOn) ; if not xon/xoff + BEQ EnableTXI ; then enable transmit + ; (pulls PC to exit) + BIC R2, R1, #(1:SHL:SF_IXOFFedHim) ; clear my XOFF bit + STR R2, SerialFlags ; and store back + TST R2, #(1:SHL:SF_UserXOFFedHim) ; if user still XOFFing him + Pull PC, NE ; then return + TST R1, #(1:SHL:SF_IXOFFedHim) ; else if we weren't XOFFing + Pull PC, EQ ; then return + +; we were XOFFing him and user wasn't, so XON him now + + MOV R1, #XONChar + B SendXONXOFF + + LTORG + +; ***************************************************************************** +; +; CheckBusy - Check for printer being busy +; +; in: R12 -> BYTEWS +; +; out: Z=1 => printer wasn't busy, so OK to send char +; Z=0 => printer was busy, so p_ack IRQ has been reenabled +; + +CheckBusy ROUT + LDRB R0, PrinterDrivType ; centronics printer ? + TEQ R0, #1 + ORRNES PC, R14, #Z_bit ; no, then can't be busy + MOV R0, #IOC + LDRB R1, [R0, #IOCIRQSTAA] + TST R1, #pbusy_bit ; 0 => busy + ORRNES PC, R14, #Z_bit ; indicate not busy + + LDRB R1, [R0, #IOCIRQMSKA] ; is busy, so enable + ORR R1, R1, #pack_bit ; pack IRQ + STRB R1, [R0, #IOCIRQMSKA] + + MOV R1, #1 ; and mark printer active + STR R1, PrinterActive + + BICS PC, R14, #Z_bit ; indicate busy + + ] + +; ***************************************************************************** +; +; SWIPrintChar - Entry for SWI OS_PrintChar +; +; in: R0 = character + +SWIPrintChar ROUT + Push "R0-R9, R14" ; save registers + BYTEWS WsPtr + CLRV ; R14 on entry must have V=0 + BL SWIPrintCharEntry + STRVS R0, [R13, #0] ; if error then poke R0 to stack + Pull "R0-R9, R14" + B SLVK_TestV ; return appropriately + +; ***************************************************************************** +; +; MOSDoPrint - Print a character via VDU 1 +; +; in: R0 = character +; +; out: V=0 => printed OK +; V=1 => error, R0 -> error block +; + +MOSDoPrint ROUT + Push "R12,R14" + BYTEWS WsPtr + BL MOSDoPrintWS + Pull "R12,PC" + +MOSDoPrintWS ; entry point when R12-> BYTEWS + BIC R14, R14, #V_bit ; clear V by default + LDRB R1, WrchDest + TST R1, #4 ; is printer disabled ? + MOVNES PC, R14 ; yes, then return (and V:=0) +SWIPrintCharEntry + LDRB R1, PrinterDrivType ; is it user/net ??? + [ DriversInKernel + CMP R1, #3 + BCS FudgePrinterInsert ; then output to stream + + Push R14 + SETPSR I_bit, R2 ; disable IRQs + + MOV R1, #Buff_Print ; printer buffer id + BL WRITE ; write char to buffer, + ; waiting if necessary + Pull R14, CS + MOVCSS PC, R14 ; escape, so bomb out, + ; clearing V and restoring I + + LDR R0, PrinterActive + TEQ R0, #0 ; 0 => dormant + + BLEQ CheckBusy ; check for busy signal + BLEQ STROBE ; dormant, so wake it up + Pull R14 + MOVS PC, R14 ; go back + ; clearing V and restoring I + | + B FudgePrinterInsert + ] + +; ***************************************************************************** +; +; WRITE - Insert character into buffer +; Retries until successful or ESCAPE condition +; +; in: R0 = character +; R1 = buffer number +; + +WRITE ROUT + Push R14 +10 + BL INSRT + Pull PC, CC + +; insert code here to turn LEDs on + + MOV R2, #0 + LDRB R2, [R2, #ESC_Status] + MOVS R2, R2, LSL #(32-6) + Pull PC, CS ; escape + + MVN R2, #I_bit ; mask to clear I_bit + MOV R14, PC + TSTP R2, PC ; CLI + TEQP PC, R14 ; restore I + B %BT10 + +; ***************************************************************************** +; +; FudgePrinterInsert - Write byte to net printer +; +; in: R0 = character to send +; R1 = printer type (3..255) +; R12 -> BYTEWS +; R14 has V_bit clear +; +; out: V=0 => printed OK +; V=1 => error, R0 -> error block +; + +FudgePrinterInsert ROUT + Push R14 + + LDR R2, PrinterActive ; R1=handle for printer stream + TEQ R2, #0 + MOVNE R1, R2 ; already have handle, so can + BNE %FT10 ; corrupt R1 + + Push R0 ; save character + ADR R0, PrinterTypeString + ADR R2, PrinterTypeName +05 + LDRB R3, [R0], #1 ; copy string from ROM to RAM + TEQ R3, #0 + STRNEB R3, [R2], #1 + BNE %BT05 + + BL OutputDecimalR1ToR2 + + MOV R0, #0 ; terminate with 0 + STRB R0, [R2] + ADR R0, PrinterTypeName+1 ; pointer to variable name + MOV R1, R2 ; dummy expansion pointer + ; (saving ptr to end of string!) + MOV R2, #-1 ; don't accept chars + MOV R3, #0 ; no wildcarding + MOV R4, #VarType_Expanded + SWI XOS_ReadVarVal ; on exit, R2=0 => no such var + TEQ R2, #0 + Pull "R0,PC", EQ, ^ ; so ignore this stream (V:=0) + + MOV R0, #">" ; now stick ">",13 on end + STRB R0, [R1], #1 + MOV R0, #13 + STRB R0, [R1] + + ADR R1, PrinterTypeName ; point to "<PrinterType$nnn>" + MOV R0, #(open_write + open_mustopen + open_nodir) + SWI XOS_Find + BLVS StopPrinting ; stop printing + Pull "R1, PC", VS ; exit V set, not corrupting R0 + + MOV R1, R0 ; will always be non-zero + Pull R0 ; restore character + + STR R1, PrinterActive ; store new handle +10 + SWI XOS_BPut ; R0 = byte to send + Pull PC, VC ; no error, so exit + + BL StopPrinting ; preserves R0,R1 + Push R0 ; save error pointer + MOV R0, #0 ; CLOSE reason code + STR R0, PrinterActive ; zero handle + SWI XOS_Find ; close channel + Pull "R0,R14" + ORRS PC, R14, #V_bit ; return V set + + +PrinterTypeString + = "<",PrinterPrefix,0 + ALIGN + +MakePrinterDormant + [ DriversInKernel + LDRB R3, PrinterDrivType + CMP R3, #3 ; only dormitorise user/net (will clear V) + MOVCC PC, R14 + ] + LDR R3, PrinterActive ; printer handle + CMP R3, #0 ; no active handle if 0 (also clears V if zero) + MOVEQ PC, R14 + Push "R0,R1,R14" + MOV R1, R3 ; R1 = handle + MOV R0, #0 ; close reason code + STR R0, PrinterActive ; zero handle + SWI XOS_Find + BLVS StopPrinting + Pull R0, VC ; if no error, preserve R0 + ADDVS R13, R13, #4 ; else junk R0 + Pull "R1,PC" + +; ***************************************************************************** +; +; StopPrinting - Clear bits 3 and 5 of FX3, bit 0 of VduStatus +; +; Preserves all registers (including status) +; + +StopPrinting ROUT + Push "R0,R1" + LDRB R0, WrchDest + BIC R0, R0, #(1:SHL:3) :OR: (1:SHL:5) + STRB R0, WrchDest + VDWS R1 + LDR R0, [R1, #VduStatus] + BIC R0, R0, #1 ; clear VDU 2 bit + STR R0, [R1, #VduStatus] + Pull "R0,R1" + MOVS PC, R14 ; returning preserving flags + +; ***************************************************************************** +; +; OutputDecimalR1ToR2 - Output a decimal byte +; +; in: R1 = number to output +; R2 = buffer to accept chars +; +; out: R0, R3 corrupt + +OutputDecimalR1ToR2 ROUT + MOV R0, #100 ; do hundreds first +10 + MOV R3, #"0" +20 + SUBS R1, R1, R0 + ADDCS R3, R3, #1 + BCS %BT20 + ADD R1, R1, R0 + CMP R3, #"0" ; if digit non-zero + STRNEB R3, [R2], #1 ; then output + TEQ R0, #10 + MOVNE R0, #10 ; then do tens digit + BNE %BT10 + + ORR R1, R1, #"0" + STRB R1, [R2], #1 ; output units digit + MOV PC, R14 + + + END diff --git a/s/PMF/osinit b/s/PMF/osinit new file mode 100644 index 0000000000000000000000000000000000000000..b88106838ba88ec4185e1073946b50862c4dec7d --- /dev/null +++ b/s/PMF/osinit @@ -0,0 +1,1246 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.PMF.osinit + + GBLL ErrorsInR0 +ErrorsInR0 SETL Module ; if FALSE, use XOS_GenerateError for + ; RAM version + ; if TRUE, return error ptr in R0 + + GBLL ProtectStationID ; if TRUE, disallow OSBYTE &A2,0,n +ProtectStationID SETL {TRUE} + +; ***************************************************************************** + +ExecuteInit ROUT + Push R14 + + ; Point to OsbyteVars + ; and initialise them + + BYTEWS WsPtr + + LDRB R1, LastBREAK ; 0 => soft, 1 => power-on, 2 => hard + CMP R1, #1 + ADRCC R2, SoftResetVars + ADREQ R2, PowerOnResetVars + ADRHI R2, HardResetVars + + LDRCCB R3, NoIgnore ; preserve NoIgnore over soft reset + MOVCS R3, #0 ; if hard or power-on reset, zero it + STRCS R3, TimerAlpha +0 ; and zero both copies of TIME + STRCS R3, TimerAlpha +4 + STRCS R3, TimerBeta +0 + STRCS R3, TimerBeta +4 + + MOV R1, WsPtr ; start at the beginning + ADR R11, ByteVarInitTable + +ByteVarInitLoop + LDRB R0, [R11], #1 ; copy a byte from table + STRB R0, [R1], #1 ; to vars + TEQ R1, R2 ; at end ? + BNE ByteVarInitLoop ; [no, then loop] + + STRB R3, NoIgnore ; put NoIgnore back + +; Initialise buffer pointers + + MOV R0, #4*(NBuffers-1) ; index to pointer + MOV R1, #0 ; value to store +BuffPtrInitLoop + STR R1, [R0, #BuffInPtrs] + STR R1, [R0, #BuffOutPtrs] + SUBS R0, R0, #4 + BPL BuffPtrInitLoop + +; mark printer as dormant + + STR R1, PrinterActive ; (R1=0) + +; Initialise event semaphores + + ADR R0, EventSemaphores + ADD R2, R0, #32 +10 + STR R1, [R0], #4 ; clear all 32 event semaphores + TEQ R0, R2 + BNE %BT10 + + STRB R1, FlashState + STRB R1, SerialInHandle ; zero serial handles + STRB R1, SerialOutHandle + +; Initialise LatchB and soft copy + +; MOV R1, #0 ; AND with 0 (was omitted on earlier MOS) ; R1 already zero + MOV R0, #0 ; EOR with 0 + BL UpdateLatchB + + [ DriversInKernel + MOV R1, #DIVRESET6850 ; reset 6551 + MOV R2, #0 + BL ModifyControl6850 + ] + +; set up IOC timer 0 before we read from CMOS (cos it uses timer for delays) + + MOV R1, #IOC + LDR R0, =20000-1 ; R0 = Timer delay (units of 0.5 microsecond) + ; 20000*0.5E-6 = 0.01 Seconds 100Hz + ; TMD 21-May-93: "-1" correction applied + + STRB R0, [R1, #Timer0LL] ; Set up the delay + MOV R0, R0, LSR #8 + STRB R0, [R1, #Timer0LH] + STRB R0, [R1, #Timer0GO] ; and start the ticks + + LDRB R0, LastBREAK + TEQ R0, #0 + BEQ %FT20 + + BL ReadMachineType + BL ReadUniqueID + BL ReadHardCMOSDefaults +20 + BL ReadCMOSDefaults + [ StorkPowerSave + BL PowerHardware ;On Stork, ensure Combo chip, Winnie, Floppy etc are powered + ] + [ IO_Type = "IOMD" + BL Configure37C665 ;RiscPC, Kryten and Stork use only SMC 37C665 + | + BL Configure82C710 ;Earlier code copes with 82C710,82C711 and 37C665 + ] + + [ DriversInKernel +; reset ACIA + + LDR R11, =ACIA + + LDRB R0, ACIAStatus ; set up DCD, DSR bits in SerialFlags + AND R0, R0, #(ACIADSR :OR: ACIADCD) + MOV R0, R0, LSL #DCDDSRShift + STR R0, SerialFlags ; other bits are zero + + LDRB R0, ACIACommand + ORR R0, R0, #ACIADTR ; enable transmit and receive + STRB R0, ACIACommand + ] + + MOV R1, #IOC + + [ :LNOT: NewClockChip + MOV R0, #0 + STRB R0, SecondsTime ; zero seconds and centiseconds + STRB R0, CentiTime + + LDRB R0, [R1, #IOCControl] ; load IOC control register + AND R0, R0, #rtc_minutes_bit + STRB R0, MinTick ; Initialise the minute odd/even flag + + MOV R0, #1 + STRB R0, SecondsDirty ; mark the seconds as dirty (non-zero) + ] + + [ DriversInKernel + MOV R0, #timer0_bit :OR: pack_bit :OR: vsync_bit + | + MOV r0, #timer0_bit :OR: vsync_bit + ] + STRB R0, [R1, #IOCIRQCLRA] ; clear pending tim0, vsync irqs (+ pack irq if appropriate) + LDRB R0, [R1, #IOCIRQMSKA] + ORR R0, R0, #timer0_bit :OR: vsync_bit + STRB R0, [R1, #IOCIRQMSKA] ; Enable timer 0 + vsync irqs + + [ DriversInKernel + LDRB R0, [R1, #IOCIRQMSKB] ; enable 6551 interrupt + ORR R0, R0, #serial_bit + STRB R0, [R1, #IOCIRQMSKB] + ] + + BL CheckYear ; check for year wrap scenario + BL RTCToRealTime + +; insert soft key 10 + + MOV R2, #&CA + BL RDCHS + Pull PC + + LTORG + +; ***************************************************************************** +; +; ReadHardCMOSDefaults - Read CMOS values for a hard/power-on reset +; NB must be called in supervisor mode + +ReadHardCMOSDefaults + Push R14 + + MOV R0, #PigCMOS + BL Read + STRB R0, PrinterIgnore + + MOV R0, #PSITCMOS + BL Read + TST R0, #2 ; NoIgnore bit + MOVEQ R1, #0 + MOVNE R1, #&80 + STRB R1, NoIgnore + + MOV R1, R0, LSR #5 ; printer type now in bits 0..2 + STRB R1, PrinterDrivType + + MOV R0, #MODETVCMOS + BL Read + MOV R2, R0, LSR #4 ; bit0:=interlace, bits 1-3 := vertical + AND R1, R2, #1 + STRB R1, TVInterlace + MOV R2, R2, LSL #31-3 ; bits 29-31 := vertical + MOV R2, R2, ASR #29 ; sign extend + STRB R2, TVVertical + + MOV R0, #DBTBCMOS + BL Read + LDRB R1, StartOptions + TST R0, #&10 ; bit 4 = boot bit + ORREQ R1, R1, #8 ; noboot => set bit 3 + BICNE R1, R1, #8 ; boot => clear bit 3 + STRB R1, StartOptions + + LDR R2, =VduDriverWorkSpace+CursorFlags + ANDS R1, R0, #8 ; noscroll bit - put 0 or 1 + MOVNE R1, #1 ; in bottom byte of CursorFlags + STRB R1, [R2] ; leave other bytes alone + + MOV R0, #CountryCMOS ; read country CMOS and store in var + BL Read ; but don't bind 'Default' to a fixed + STRB R0, Country ; country at this stage + + [ :LNOT: DriversInKernel + BL SetUpPrinterBuffer + ] + Pull PC + +; ***************************************************************************** +; +; ReadCMOSDefaults - Read CMOS values for any reset +; NB must be called in supervisor mode + +ReadCMOSDefaults + Push R14 + + [ DriversInKernel + MOV R0, #PSITCMOS + BL Read + MOV R1, R0, LSR #2 ; baud bits now in bits 0..2 + AND R1, R1, #7 ; 0 => 75, ... ,7 => 19200 + ADD R1, R1, #1 ; 1 => 75, ... ,8 => 19200 + Push R1 + BL DoOsbyte07 + Pull R1 + BL DoOsbyte08 + ] + + MOV R0, #DBTBCMOS + BL Read + TST R0, #2 ; NZ => loud + MOVEQ R1, #&D0 ; (quiet) + MOVNE R1, #&90 ; (LOUD) + STRB R1, BELLinfo + + [ DriversInKernel + MOV R1, R0, LSR #5 ; bits 5..7 -> bits 0..2 + MOV R1, R1, LSL #2 ; put in bits 2..4 + ORR R1, R1, #&42 ; or in default 6850 bits + MOV R2, #0 ; replace old value + BL ModifyControl6850 + ] + + MOV R0, #StartCMOS + BL Read + MOVS R0, R0, LSL #(32-5) ; bit 5 -> carry, bit 4 -> N bit + MOVPL R0, #KBStat_NoShiftLock + KBStat_ShiftEnable ; SHCAPS + MOVMI R0, #KBStat_NoShiftLock + KBStat_NoCapsLock ; NOCAPS + MOVCS R0, #KBStat_NoShiftLock ; CAPS + STRB R0, KeyBdStatus + + [ ModeSelectors + BL Read_Configd_MonitorType + LDR r1, =VduDriverWorkSpace+CurrentMonitorType ; set current to default + STR r0, [r1] + ] + + Pull R14 + +; and drop thru to ... + +ReadKeyDefaults + Push R14 + + MOV R0, #KeyDelCMOS ; Read the default out of CMOS RAM + BL Read ; comes back in R0 + STRB R0, KeyRepDelay + + MOV R0, #KeyRepCMOS ; Read the default out of CMOS RAM + BL Read ; comes back in R0 + STRB R0, KeyRepRate + + Pull PC + +; ***************************************************************************** +; +; PostInit - Called by Sam after modules have been initialised +; + +PostInit ROUT + Push R14 + BYTEWS WsPtr + LDRB R0, LastBREAK ; get reset type + TEQ R0, #0 + BEQ %FT10 ; [soft reset, skip] + + [ StorkPowerSave + SWI XPortable_ReadFeatures + BVC %FT01 +; + MOV R0, #0 + MOV R1, #0 + SWI XPortable_Speed ; attempt to make the portable go fast! + MOVVC R1, #PortableFeature_Speed + MOVVS R1, #0 +01 + AND R0, R1, #(PortableFeature_Speed :OR: PortableFeature_Idle :OR: PortableFeature_Stop) + STRB r0, [r0, #PortableFlags] + | + MOV r0, #0 ; allow SWI Portable_Speed to be issued + STRB r0, [r0, #PortableFlag] + ] + + [ BleedinDaveBell + MOV R0, #1 ; indicate keyboard UK + MOV R1, #101 ; indicate alphabet Latin1 + | + MOV R0, #2 ; indicate keyboard Master + MOV R1, #100 ; indicate alphabet Bfont + ] + STRB R0, Keyboard + STRB R1, Alphabet + STRB R1, KeyAlphabet ; alphabet corresponding to keyboard + +10 + Pull R14 + B KeyPostInit + +; ***************************************************************************** +; +; UpdateLatchB - update latch B and soft copy +; +; LATCHB := (LATCHB AND R1) EOR R0 +; + +UpdateLatchB + Push "R2, R3, R14" + MOV R14, PC + ORR R2, R14, #I_bit + TEQP R2, #0 ; disable IRQ + + MOV R2, #0 + LDRB R3, [R2, #LatchBSoftCopy] + AND R3, R3, R1 + EOR R3, R3, R0 + STRB R3, [R2, #LatchBSoftCopy] + + [ IO_Type <> "IOMD" ; there ain't no Latch B on IOMD! + LDR R2, =LatchB + STRB R3, [R2] + ] + + TEQP R14, #0 + Pull "R2, R3, PC" + + +; ***************************************************************************** +; +; UpdateMonitorTypeLatch - update monitor type latch and soft copy +; +; Returns the result in R4 + +UpdateMonitorTypeLatch + Push "R2, R3, R14" + MOV R14, PC + ORR R2, R14, #I_bit + TEQP R2, #0 ; disable IRQ + + MOV R2, #0 + LDRB R3, [R2, #CLine_Softcopy] + MOV R3, #1 ;Set our bit only + STRB R3, [R2, #CLine_Softcopy] + + MOV R2, #IOMD_Base + STRB R3, [R2, #IOMD_CLINES] ;Write the new reg out + LDRB R3, [R2, #IOMD_CLINES] ;Read it back + + AND R4, R3, #1 ;Clear all but our bit into R4 + + TEQP R14, #0 ;Re-enable IRQ + Pull "R2, R3, PC" + + +; ***************************************************************************** + +; The initial values for all of the osbyte variables +; as decreed by arthur. + +ByteVarInitTable + ; The main osbyte variables, accessed + ; via calls &A6 to &FF + + DCW OsbyteVars-&A6 ; VarStart # 2 ; &A6,&A7 + = 0,0 ; ROMPtr # 2 ; &A8,&A9 + = 0,0 ; ROMInfo # 2 ; &AA,&AB + = 0,0 ; KBTran # 2 ; &AC,&AD + = 0,0 ; VDUvars # 2 ; &AE,&AF + ; + = 0 ; CFStime # 1 ; &B0 + = 0 ; InputStream # 1 ; &B1 + = &FF ; KeyBdSema # 1 ; &B2 + ; + = &00 ; ROMPollSema # 1 ; &B3 + = &80 ; OSHWM # 1 ; &B4 (hi-byte of &8000) + ; + = 1 ; RS423mode # 1 ; &B5 + = 0 ; NoIgnore # 1 ; &B6 + = &00 ; CFSRFS # 1 ; &B7 + = &00,&00 ; VULAcopy # 2 ; &B8,&B9 + ; + = &00 ; ROMatBRK # 1 ; &BA + = &FF ; BASICROM # 1 ; &BB + ; + = &04 ; ADCchanel # 1 ; &BC + = &04 ; ADCmaxchn # 1 ; &BD + = &00 ; ADCconv # 1 ; &BE + ; + = &FF ; RS432use # 1 ; &BF + = &42 ; RS432conflag # 1 ; &C0 + ; + = 0 ;&19 ; FlashCount # 1 ; &C1 /* changed to fx 9 0 by RCM 31/10/91 */ + = &19 ; SpacPeriod # 1 ; &C2 + = 0 ;&19 ; MarkPeriod # 1 ; &C3 /* changed to fx 9 0 by RCM 31/10/91 */ + ; + = &32 ; KeyRepDelay # 1 ; &C4 + = &08 ; KeyRepRate # 1 ; &C5 + ; + = &00 ; ExecFileH # 1 ; &C6 + = &00 ; SpoolFileH # 1 ; &C7 + ; + = &00 ; ESCBREAK # 1 ; &C8 (200) + ; + = &00 ; KeyBdDisable # 1 ; &C9 + = &20 ; KeyBdStatus # 1 ; &CA + ; + = &11 ; RS423HandShake # 1 ; &CB + = &00 ; RS423InputSupr # 1 ; &CC + = &00 ; RS423CFSFlag # 1 ; &CD + ; + = &00 ; EconetOScall # 1 ; &CE + = &00 ; EconetOSrdch # 1 ; &CF + = &00 ; EconetOSwrch # 1 ; &D0 + ; + = &00 ; SpeechSupr # 1 ; &D1 + = &00 ; SoundSupr # 1 ; &D2 + ; + = &01 ; BELLchannel # 1 ; &D3 + = &90 ; BELLinfo # 1 ; &D4 + = &64 ; BELLfreq # 1 ; &D5 + = &06 ; BELLdur # 1 ; &D6 + ; + = &81 ; StartMessSupr # 1 ; &D7 + ; + = &00 ; SoftKeyLen # 1 ; &D8 + ; + = &00 ; PageModeLineCount # 1 ; &D9 + ; + = &00 ; VDUqueueItems # 1 ; &DA + ; + = &09 ; TABch # 1 ; &DB + = &1B ; ESCch # 1 ; &DC + ; + = &01,&D0,&E0,&F0 ; IPbufferCh # 4 ; &DD,&DE,&DF,&E0 + = &01,&80,&90,&00 ; RedKeyCh # 4 ; &E1,&E2,&E3,&E4 + ; + = &00 ; ESCaction # 1 ; &E5 + = &00 ; ESCeffect # 1 ; &E6 + ; + = &00 ; u6522IRQ # 1 ; &E7 + = &00 ; s6850IRQ # 1 ; &E8 + = &00 ; s6522IRQ # 1 ; &E9 + ; + = &00 ; TubeFlag # 1 ; &EA + ; + = &00 ; SpeechFlag # 1 ; &EB + ; + = &00 ; WrchDest # 1 ; &EC + = &00 ; CurEdit # 1 ; &ED + ; + + = &30 ; KeyBase ; &EE + = &01 ; Shadow ; &EF + = &00 ; Country ; &F0 + ; + = &00 ; UserFlag # 1 ; &F1 + ; + = &64 ; SerULAreg # 1 ; &F2 + ; + = &05 ; TimerState # 1 ; &F3 + ; + = &FF ; SoftKeyConsist # 1 ; &F4 + ; + = &01 ; PrinterDrivType # 1 ; &F5 + = &0A ; PrinterIgnore # 1 ; &F6 + ; + = &01,&00,&00 ; BREAKvector # 3 ; &F7,&F8,&F9 + ; + = &00 ; DRIVER ; &FA + = &00 ; DISPLAY ; &FB + ; + = &FF ; LangROM # 1 ; &FC + ; + = &01 ; LastBREAK # 1 ; &FD + ; + = &0F ; KeyOpt # 1 ; &FE + ; + = &08 ; StartOptions # 1 ; &FF + ; + ; +ByteVarInitTableEnd + +ByteVarInitTableSize * ByteVarInitTableEnd - ByteVarInitTable + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + LTORG + +oldirqowner & IRQ + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; ReadMachineType - Determine machine type and store it in IOSystemType +; + +ReadMachineType ENTRY "r0-r12" + [ IO_Type = "IOMD" + [ MorrisSupport + MOV r12, #IOMD_Base + LDRB r0, [r12, #IOMD_ID0] + CMP r0, #&98 + LDRB r0, [r12, #IOMD_ID1] + CMPEQ r0, #&5B + MOVEQ r11, #IOST_7500 ;EQ, Morris + MOVNE r11, #0 ;NE, assume Medusa +; +; On Kryten, Morris pin Event2 is tied low so bit Nevent2 is a ONE +; On Stork, Morris pin Event2 is tied high so bit Nevent2 is a ZERO +; + LDREQB r0, [r12, #IOMD_IRQSTD] ;EQ, Morris + TSTEQ r0, #IOMD_Nevent2_bit + ORREQ r11, r11, #IOST_BATMAN ;EQ, Stork ie Morris & BATMAN + + ORR r0, r11, #IOST_IOEB ; pretend we've got IOEB +; +; r11 holds 0 for IOMD (Risc PC) +; or IOST_7500 for Morris (Kryten) +; or IOST_7500 + IOST_BATMAN for Morris (Stork) + | + MOV r0, #IOST_IOEB ; pretend we've got IOEB + ] + | + TEQP pc, #SVC_mode + I_bit + F_bit ; disable IRQs and FIQs + MOVNV r0, r0 + LDR r1, =IOEB_ASICPresent + MOV r0, #&FA + STRB r0, [r1] + LDRB r0, [r1] + TEQP pc, #SVC_mode + I_bit + AND r0, r0, #&0F + TEQ r0, #5 ; must read 5 is ASIC present + MOVNE r0, #0 ; no IOEB, LC or 82C710 + BNE %FT10 + +; there is an IOEB ASIC present, so it's safe to test for LC ASIC + + LDR r1, =LC_ASICPresent + LDRB r0, [r1] + AND r0, r0, #&0E ; bits 3210 should be 010x + TEQ r0, #&04 + MOVNE r0, #IOST_IOEB ; IOEB but no LC + MOVEQ r0, #IOST_IOEB :OR: IOST_LC ; IOEB and LC +10 + ] + MOV r1, #0 ; normal Hsync and address pointer + STRB r0, [r1, #IOSystemType] + +; now read monitor lead type + + TEQ r0, #0 ; no IOEB + MOVEQ r2, #&FF ; then return all ones for monitor lead type + BEQ %FT90 + + [ VIDC_Type = "VIDC20" + LDR r0, =VIDC ; on VIDC20 we invert HSYNC by writing to External Register + | + LDR r0, =VIDCClockSelect ; on VIDC1 we write to latch instead + ] + [ IO_Type = "IOMD" + LDR r3, =IOMD_MonitorType + | + LDR r3, =IOEB_MonitorType + ] + + [ VIDC_Type = "VIDC20" + LDR r1, =VIDCExternal+Ext_InvertCompVSYNC+Ext_DACsOn+Ext_ERegExt ; normal HSYNC value + STR r1, [r0] + ORR r2, r1, #Ext_InvertHSYNC ; value for inverted HSYNC + | + STRB r1, [r0] ; set up normal Hsync + MOV r2, #4 ; inverted Hsync + ] + + [ MorrisSupport + TST R11, #IOST_7500 + BLNE UpdateMonitorTypeLatch ;Result back in R4 + LDREQB r4, [r3] + | + LDRB r4, [r3] ; base value + ] + AND r4, r4, #&0F ; only use bits 0..3 + MOV r5, #0 ; bits 0..3 = bits which have ever changed + ; bits 4..7 = bits whose deinverted value was high last time + ; bits 8..11 = bits whose deinverted value just went high-low + ; bits 12..15 = bits whose deinverted value just went high-low-low + ; bits 16..19 = bits which could be hsync + ; ie after every high-low there was low-low (after deinversion) + ; bits 20..23 = bits which are definitely random + MOV r10, #&0F ; used inside CheckBits + MOV r12, #256 ; number of iterations +20 + [ VIDC_Type = "VIDC20" + STR r2, [r0] + | + STRB r2, [r0] + ] + + [ MorrisSupport + TST R11, #IOST_7500 + BLNE UpdateMonitorTypeLatch ;Result back in R4 + MOVNE r6, r4 + LDREQB r6, [r3] + | + LDRB r6, [r3] ; read value with inverted sync + ] + + [ VIDC_Type = "VIDC20" + STR r1, [r0] + | + STRB r1, [r0] + ] + + [ MorrisSupport + TST R11, #IOST_7500 + BLNE UpdateMonitorTypeLatch ;Result back in R4 + MOVNE r7,r4 + LDREQB r7,[r3] + | + LDRB r7, [r3] ; read value with normal sync + ] + AND r6, r6, #&0F + AND r7, r7, #&0F + EOR r8, r6, r4 ; bits which have changed from steady value to inverted one + ORR r5, r5, r8 ; OR into mask of bits which have ever changed + EOR r8, r7, r4 ; bits which have changed from steady value to normal one + ORR r5, r5, r8 ; OR into mask of bits which have ever changed + EOR r6, r6, #&0F ; deinvert inverted value + BL CheckBits ; call check routine with first value + MOV r6, r7 + BL CheckBits ; call check routine with second value + SUBS r12, r12, #1 + BNE %BT20 + +; now process result + + [ VIDC_Type = "VIDC20" + LDR r1, =VIDCExternal+Ext_InvertCompVSYNC+Ext_InvertCompHSYNC+Ext_DACsOn+Ext_ERegExt ; put back default value + STR r1, [r0] + ] + + BIC r4, r4, r5 ; don't put port value in for bits that have changed + BIC r5, r5, r5, LSR #16 ; make bits 0..3 of r5 indicate random bits + + ANDS r2, r4, #1 ; for each bit pair 00 => low, 01 => high, 10 => Hsync, 11 => random + TST r5, #1 :SHL: 16 + MOVNE r2, #2 :SHL: 0 + TST r5, #1 + MOVNE r2, #3 :SHL: 0 + + TST r4, #2 + ORRNE r2, r2, #1 :SHL: 2 + TST r5, #2 :SHL: 16 + ORRNE r2, r2, #2 :SHL: 2 + TST r5, #2 + ORRNE r2, r2, #3 :SHL: 2 + + TST r4, #4 + ORRNE r2, r2, #1 :SHL: 4 + TST r5, #4 :SHL: 16 + ORRNE r2, r2, #2 :SHL: 4 + TST r5, #4 + ORRNE r2, r2, #3 :SHL: 4 + + TST r4, #8 + ORRNE r2, r2, #1 :SHL: 6 + TST r5, #8 :SHL: 16 + ORRNE r2, r2, #2 :SHL: 6 + TST r5, #8 + ORRNE r2, r2, #3 :SHL: 6 + + [ IO_Type = "IOMD" + ASSERT IOMD_MonitorIDMask = 1 + AND r2, r2, #3 ; only bit 0 of ID valid on IOMD-based systems + ] + +90 + MOV r1, #0 + STRB r2, [r1, #MonitorLeadType] + EXIT + +CheckBits ROUT + AND r8, r10, r5, LSR #12 ; bits that were H-L-L + BIC r8, r8, r6 ; bits that are H-L-L-L + ORR r5, r5, r8, LSL #16 ; OR into bits that could be hsync + ORR r8, r5, r5, LSR #4 + AND r8, r6, r8, LSR #8 ; bits that just went H-L-H or H-L-L-H + AND r8, r8, r5, LSR #16 ; bits that just went H-L-H or H-L-L-H and could have been hsync + ORR r5, r5, r8, LSL #20 ; they're definitely random now + BIC r5, r5, r8, LSL #16 ; and they're definitely not hsync now + AND r8, r5, #&FF :SHL: 4 ; get H bits, and H-L bits + BIC r8, r8, r6, LSL #4 ; knock out bits that were H and are now H + BIC r8, r8, r6, LSL #8 ; knock out bits that were H-L and are now H + BIC r5, r5, #&FF :SHL: 8 ; knock out all H-L and H-L-L bits + ORR r5, r5, r8, LSL #4 ; put in new H-L and H-L-L bits + BIC r5, r5, #&F :SHL: 4 ; knock out old H bits + ORR r5, r5, r6, LSL #4 ; put in new H bits + BIC r5, r5, r5, LSR #20 ; knock out H bits if we know it's random + MOV pc, lr + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; TranslateMonitorLeadType - Determine monitor type and default mode + sync from monitor lead type +; +; in: Monitor lead type in variable MonitorLeadType (surprisingly!) +; +; out: r3 = default mode to use +; r4 = default monitortype to use +; r5 = default sync to use +; + +TranslateMonitorLeadType ENTRY "r0-r2" + MOV r1, #Service_MonitorLeadTranslation + LDRB r2, [r1, #MonitorLeadType-Service_MonitorLeadTranslation] + SWI XOS_ServiceCall + TEQ r1, #0 ; if service claimed, then exit with these numbers + EXIT EQ + + ADR r0, MonitorLeadList +10 + LDR r14, [r0], #4 + EOR r1, r2, r14, LSR #24 ; differences + EOR r14, r14, #&FF000000 ; make don't cares into zero + TST r14, #&C0000000 + BICEQ r1, r1, #&C0 ; knock out difference pairs if don't care + TST r14, #&30000000 + BICEQ r1, r1, #&30 + TST r14, #&0C000000 + BICEQ r1, r1, #&0C + TST r14, #&03000000 + BICEQ r1, r1, #&03 + TEQ r1, #0 ; if still have differences, then loop + BNE %BT10 + + MOV r0, #&FF + AND r3, r0, r14 ; mode in bits 0..7 + AND r4, r0, r14, LSR #8 ; monitortype in bits 8..15 + AND r5, r0, r14, LSR #16 ; sync in bits 16..23 + EXIT + + MACRO + MonitorLeadItem $lead, $mode, $monitortype, $sync + ASSERT $lead < 256 + ASSERT $mode < 256 + ASSERT $monitortype < 256 + ASSERT $sync < 256 + DCD (($lead):SHL:24):OR:(($sync):SHL:16):OR:(($monitortype):SHL:8):OR:($mode) + MEND + + [ IO_Type = "IOMD" +MonitorLeadList + MonitorLeadItem 4_3330, 27, 3, 0 ; VGA-capable monitors + MonitorLeadItem 4_3333, 12, 0, 1 ; Others - assume TV standard + | +MonitorLead_MonoVGA * 4_3101 +MonitorLead_ColourVGA * 4_3110 +MonitorLead_ColourSVGA * 4_3010 ; should be type 4, but for the LiteOn we bodge it to 1 +MonitorLead_Multisync * 4_3211 +MonitorLead_TV * 4_3112 +MonitorLead_NoConnect * 4_3111 +MonitorLead_Undefined * 4_3333 + +MonitorLeadList + MonitorLeadItem MonitorLead_Multisync, 27, 1, 1 + MonitorLeadItem MonitorLead_MonoVGA, 27, 3, 0 + MonitorLeadItem MonitorLead_ColourVGA, 27, 3, 0 + MonitorLeadItem MonitorLead_ColourSVGA, 27, 1, 0 ; bodge for LiteOn (should be 27, 4, 0) + MonitorLeadItem MonitorLead_Undefined, 12, 0, 1 ; used for all other combinations + ] + + [ StorkPowerSave +; +; List of latch addresses and initial values. +; +PowerTab + DCD HWLatchPA, InitLatchPA + DCD HWLatchPB, InitLatchPB + DCD HWLatchMC, InitLatchMC + DCD HWLatchMA, InitLatchMA + DCD 0 + +PowerHardware ;On Stork, ensure Combo chip, Winnie, Floppy etc are powered + ENTRY "r0,r1" + + MOV r0, #0 + LDRB lr, [r0, #IOSystemType] + TST lr, #IOST_BATMAN + EXIT EQ ;EQ, not Stork, so hardware already powered +; +; On Stork. +; +; Now would be a good time to hit the power control latches +; to ensure everything is powered up. +; + ADR R14, PowerTab +05 + LDMIA R14!, {R0, R1} + TEQ R0, #0 + STRNEB R1, [R0] + BNE %BT05 + +10 + EXIT + ] + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; Configure82C710 - Configure 82C710/82C711/SMC 665 if present +; + +; 82C710 stuff + +CnTbase * &03010000 ; Base address of 82C710 = PC/AT I/O 000H +CRI710 * &0390 +CRI710Off * CRI710*4 ; 82C710 Configuration Register Index port +CAP710Off * CRI710Off +4 ; 82C710 Configuration Access Port (data) +ConRegA710 * &02FA*4 +ConRegB710 * &03FA*4 + +CRI711Off * &03F0*4 ; 82C711 Configuration Register Index port +CAP711Off * CRI711Off +4 ; 82C711 Configuration Access Port (data) + + + [ IO_Type <> "IOMD" +Configure82C710 ENTRY "r0,r1" + MOV r0, #0 + LDRB lr, [r0, #IOSystemType] + TST lr, #IOST_IOEB ; no IOEB, then don't bother + EXIT EQ + + TEQP pc, #SVC_mode + I_bit + F_bit ; Disable FIQ and IRQ + LDR r0, =CnTbase ; R0-> 82C710 base address + +; First try to configure 82C711 or SMC665 + + MOV lr, #&55 + STRB lr, [r0, #CRI711Off] ; Write &55 to CRI711 twice + STRB lr, [r0, #CRI711Off] ; to enter configuration mode + + MOV lr, #&0D ; Check for SMC 665 + STRB lr, [r0, #CRI711Off] + LDRB lr, [r0, #CAP711Off] + TEQ lr, #&65 + ADREQ r1, ConfigSMCTable ; different table for SMC 665 + ADRNE r1, Config711Table ; R1-> 82C711 configuration data + Push "lr" ; need to test for 665 again +20 + LDRB lr, [r1], #1 ; get config index + STRB lr, [r0, #CRI711Off] + TEQ lr, #&AA ; end of table? + LDRNEB lr, [r1], #1 ; if not then get config data + STRNEB lr, [r0, #CAP711Off] ; and write it + BNE %BT20 + + Pull "lr" + TEQ lr, #&65 ; if we configured SMC 665 then + MOVEQ r1, #IOST_37C665 ; set flag in IOSystemType + BEQ %FT30 ; and no need to faff about for 710/711 + +; Now try to configure 82C710 (won't work on 711) + + MOV lr, #&55 ; Magic number from 82C710 data sheet + STRB lr, [r0, #ConRegA710] ; Start configuration mode + MVN lr, lr ; Complement the magic number + STRB lr, [r0, #ConRegB710] + MOV lr, #&36 ; Another magic number from C&T + STRB lr, [r0, #ConRegB710] + MOV r1, #CRI710 /4 ; 82C710 configuration address /4 + STRB r1, [r0, #ConRegB710] ; Write configuration address + MVN lr, r1 ; Complement the data + STRB lr, [r0, #ConRegA710] ; Complete configuration sequence + + ADR r1, Config710Table ; R1-> 82C710 configuration data +10 + LDRB lr, [r1], #1 ; Get next 82C710 config reg index, R1++ + STRB lr, [r0, #CRI710Off] ; Write index + TEQ lr, #&0F ; Configuration register selected? + LDRB lr, [r1], #1 ; Get config data, R1++ + STRB lr, [r0, #CAP710Off] ; Write config data + BNE %BT10 ; Repeat until config register written + +; now if we're on 82C710 then 1st serial port is at &3F8 +; and if we're on 82C711 then 1st serial port is at &2F8 + + STRB lr, [r0, #&2FF * 4] ; store &AA in serial scratchpad register for 82C711 port 1 + MOV lr, #&55 + STRB lr, [r0, #&3FF * 4] ; store &55 in serial scratchpad register for 82C710 + STRB lr, [r0, #CRI711Off] ; Write &55 to CRI711 twice + STRB lr, [r0, #CRI711Off] ; to reenter configuration mode + MOV lr, #&02 ; select config register 2 + STRB lr, [r0, #CRI711Off] + MOV lr, #2_00011100 ; move 1st serial port to &3F8 + STRB lr, [r0, #CAP711Off] + MOV lr, #&AA + STRB lr, [r0, #CRI711Off] ; exit config mode + + MOV r1, #0 ; by default no 82C710 or 82C711 + LDRB lr, [r0, #&3FF * 4] ; read scratchpad register + TEQ lr, #&55 ; &55 => 82C710 + MOVEQ r1, #IOST_82C710 + TEQ lr, #&AA + MOVEQ r1, #IOST_82C711 +30 + MOV r0, #0 + LDRB lr, [r0, #IOSystemType] + BIC lr, lr, #IOST_82C710 :OR: IOST_82C711 :OR: IOST_37C665 + ORR lr, lr, r1 + STRB lr, [r0, #IOSystemType] + + TEQP pc, #SVC_mode + I_bit ; Restore IRQ/FIQ state + EXIT + ] + + [ IO_Type <> "IOMD" +Config710Table ; Index, Data ; 82C710 configuration data + DCB &01, 2_01000000 ; Bi-dir parallel + DCB &02, 2_00001000 ; Default, UART clock + DCB &04, &FE ; Default, UART base address= &3F8 (COM1) + DCB &06, &9E ; Default, Parallel base address= &278 (LPT3) + DCB &09, &9E ; GPCS=&278 (so writes to printer control go to PAL too) + DCB &0A, 2_00001010 ; GPCS A1=1 (to detect printer control), GPCS enabled + DCB &0B, 2_01110000 ; IRQs active lo, GPCS is an o/p + DCB &0C, 2_10100001 ; IDE/FDC enabled, mouse disabled + DCB &0D, 0 ; Default, mouse address + DCB &0E, 2_00000000 ; Default, test modes disabled + DCB &00, 2_10101100 ; Valid config, OSC/BR on, Ser/Par enable + DCB &0F, 0 ; Write config register == end of list + +Config711Table + DCB &01, 2_10000111 ; Enable config read, IRQ active low, parallel powered/extended, default addr. + DCB &02, 2_00001101 ; 2nd serial port disabled, 1st enabled at &2F8 (to be moved to &3F8 later) + DCB &03, 0 ; Test mode disabled + DCB &00, 2_10111011 ; Valid config, OSC/BR on, FDC enabled/powered, IDE AT,enabled + DCB &AA, 0 ; Exit config mode + ] + +ConfigSMCTable + DCB &01, 2_10000111 ; Enable config read, IRQ active low, parallel powered/extended, default addr. + DCB &02, 2_00011100 ; 2nd serial port disabled, 1st enabled at &3F8 + DCB &03, &78 ; extra stuff for SMC + DCB &04, 2_00000011 ; allow extended parallel port modes + DCB &05, 0 + DCB &06, &FF + DCB &07, 0 + DCB &08, 0 + DCB &09, 0 + DCB &0A, 0 + DCB &00, 2_10111011 ; Valid config, OSC/BR on, FDC enabled/powered, IDE AT,enabled + DCB &AA, 0 ; Exit config mode + + ALIGN + + [ IO_Type = "IOMD" +; +; Simplified version of Configure82C710 programs SMC 37C665 only. +; +Configure37C665 ENTRY "r0,r1" + TEQP pc, #SVC_mode + I_bit + F_bit ; Disable FIQ and IRQ + LDR r0, =CnTbase ; R0-> SMC 665 base address + +; First try to configure the SMC665 + + MOV lr, #&55 + STRB lr, [r0, #CRI711Off] ; Write &55 to CRI711 twice + STRB lr, [r0, #CRI711Off] ; to enter configuration mode + + MOV lr, #&0D ; Check for SMC 665 + STRB lr, [r0, #CRI711Off] + LDRB lr, [r0, #CAP711Off] + TEQ lr, #&65 + MOVNE r1, #0 ;NE: not a SMC 665 this should never happen + BNE %FT30 ;NE: on a RiscPC, Kryten or Stork + + ADR r1, ConfigSMCTable ; R1-> SMC 665 configuration data +20 + LDRB lr, [r1], #1 ; get config index + STRB lr, [r0, #CRI711Off] + TEQ lr, #&AA ; end of table? + LDRNEB lr, [r1], #1 ; if not then get config data + STRNEB lr, [r0, #CAP711Off] ; and write it + BNE %BT20 + + MOV r1, #IOST_37C665 +30 + MOV r0, #0 + LDRB lr, [r0, #IOSystemType] + BIC lr, lr, #IOST_82C710 :OR: IOST_82C711 :OR: IOST_37C665 + ORR lr, lr, r1 + STRB lr, [r0, #IOSystemType] + + TEQP pc, #SVC_mode + I_bit ; Restore IRQ/FIQ state + EXIT + ] + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; +; ReadUniqueID - Read unique machine ID +; +; 10-Dec-93 BCockburn Modified to leave raw 64 bit ID from chip in RawMachineID + +defaultlatch * 20000-1 ; TMD 21-May-93: "-1" correction applied + +Tsyc * 5 ; time between frames - minimum of 1µs, so give it a bit more +Trstl * 500 ; time reset pulse held low - minimum of 480µs, so give it a bit more +Trsth * 500 ; time reset pulse held high - minimum of 480µs, so give it a bit more +Tlow0 * 80 ; time for write0 low - min 60µs, max 120µs +Tlow1 * 5 ; time for write1 low - min 1µs, max 15µs +Tslot * 90 ; time for total read/write slot - min 60µs, max 120µs +Trdlow * 5 ; time for read slot low before release - min 1µs, max 15µs +Trddat * 3 ; time after read slot high before read it + + ASSERT Tslot-Tlow0 > Tsyc + ASSERT Trdlow+Trddat < 15 + +; Macro to set wire to a given state, and optionally count transitions (starting at low) while waiting for a given time + + MACRO + SetWire $hilo, $time, $monstate, $count + LCLS reg + [ "$hilo"="LOW" +reg SETS "r4" + | + ASSERT "$hilo"="HIGH" +reg SETS "r5" + ] + [ ($time) = 0 + STRB $reg, [r1, #IOCControl] ; set appropriate level on line + | + ASSERT ($time) < 32768 + MOV r12, #(($time)*2):AND:&FF + STRB r12, [r1, #Timer0LL] ; program low latch + MOV r12, #(($time)*2):SHR:8 + STRB r12, [r1, #Timer0LH] ; program high latch + STRB $reg, [r1, #IOCControl] ; set appropriate level on line + STRB r12, [r1, #Timer0GO] ; and start timer + LDRB r12, [r1, #IOCIRQSTAA] ; dummy instruction to avoid bug in IOC + STRB r11, [r1, #IOCIRQCLRA] ; immediately clear IRQ bit + [ "$monstate"<>"" + MOV $monstate, #0 + ] + [ "$count"<>"" + MOV $count, #0 + ] +10 + LDRB r12, [r1, #IOCIRQSTAA] + TST r12, r11 + [ "$count"<>"" + ADDEQ $count, $count, #1 + ] + [ "$monstate"="" + BEQ %BT10 ; not timed out, so just loop + | + BNE %FT30 ; timed out + LDRB r12, [r1, #IOCControl] + TST r12, #IOEB_unique_machine_ID_bit + BEQ %BT10 ; if still low then loop to 10 + + ADD $monstate, $monstate, #1 ; increment number of transitions +20 + LDRB r12, [r1, #IOCIRQSTAA] + TST r12, r11 + [ "$count"<>"" + ADDEQ $count, $count, #1 + ] + BNE %FT30 ; timed out + LDRB r12, [r1, #IOCControl] + TST r12, #IOEB_unique_machine_ID_bit + BNE %BT20 ; if still high then loop to 20 + ADD $monstate, $monstate, #1 ; increment number of transitions + B %BT10 +30 + ] + ] + MEND + +ReadUniqueID ENTRY "r0-r12" + MOV r0, #0 + LDR r1, =IOC + TEQP pc, #SVC_mode + I_bit + F_bit + LDRB r3, [r0, #IOCControlSoftCopy] + BIC r4, r3, #IOEB_unique_machine_ID_bit ; r4 is value to pull ID line low + ORR r5, r3, #IOEB_unique_machine_ID_bit ; r5 is value to pull ID line high + MOV r11, #timer0_bit + BL SendResetPulse + BVS ResetFailed + BL SendCommandWord + + MOV r7, #-8 ; -no. of bytes to store = 8 bits type + 48 bits ID + 8 bits checksum +10 + BL GetAByte + STRB r6, [r7, #RawMachineID+8] + ADDS r7, r7, #1 + BNE %BT10 + + BL RestoreIOCState + BL CheckCRC + BVS IDError + EXIT + +ResetFailed + BL RestoreIOCState +IDError + MOV r0, #0 + STR r0, [r0, #RawMachineID+0] ; indicate no ID by putting zero here + STR r0, [r0, #RawMachineID+4] + EXIT + +RestoreIOCState ENTRY + STRB r3, [r1, #IOCControl] ; put back old value + MOV r12, #defaultlatch :AND: &FF + STRB r12, [r1, #Timer0LL] ; and restore old timer 0 latch values + MOV r12, #defaultlatch :SHR: 8 + STRB r12, [r1, #Timer0LH] + STRB r12, [r1, #Timer0GO] + TEQP pc, #SVC_mode + I_bit ; restore old interrupt state + EXIT + +SendResetPulse ROUT + SetWire HIGH, Tsyc + SetWire LOW, Trstl,,r6 + SetWire HIGH, Trsth,r10 + TEQ r6, #0 +; ADREQ r0, IOCBugHappenedError + ORREQS pc, lr, #V_bit + CMP r10, #3 ; H-L-H is ok + BICEQS pc, lr, #V_bit +; ADRHI r0, TooManyTransitionsError ; H-L-H-L... +; CMP r10, #2 +; ADREQ r0, NeverWentHighAgainError ; H-L +; CMP r10, #1 +; ADREQ r0, NeverWentLowError ; H +; ADRCC r0, NeverWentHighError ; stayed low permanently even though we released it + ORRS pc, lr, #V_bit + + [ {FALSE} ; only for debugging +NeverWentHighError + = "Never went high", 0 +NeverWentLowError + = "Never went low", 0 +NeverWentHighAgainError + = "Never went high again", 0 +TooManyTransitionsError + = "Too many transitions", 0 +IOCBugHappenedError + = "IOC bug happened", 0 + ALIGN + ] + +SendCommandWord ROUT + LDR r6, =&10F ; &0F is command word +10 + MOVS r6, r6, LSR #1 + BICEQS pc, lr, #V_bit + BCS SendOne + SetWire LOW, Tlow0 + SetWire HIGH, Tslot-Tlow0 + B %BT10 + +SendOne + SetWire LOW, Tlow1 + SetWire HIGH, Tslot-Tlow1 + B %BT10 + +GetAByte ROUT + MOV r6, #&80 +10 + SetWire LOW, Trdlow + SetWire HIGH, Trddat + LDRB r10, [r1, #IOCControl] + SetWire HIGH, Tslot-Trdlow-Trddat + MOVS r10, r10, LSR #IOEB_ID_bit_number+1 ; move bit into carry + MOVS r6, r6, RRX + BCC %BT10 + MOV r6, r6, LSR #24 + BICS pc, lr, #V_bit + +CheckCRC ROUT + LDR r1, =RawMachineID ; pointer to current byte + MOV r2, #0 + MOV r3, #7 ; number of bytes to do +10 + LDRB r4, [r1], #1 + EOR r2, r2, r4 + MOV r4, #8 ; number of bits to do +20 + MOVS r2, r2, LSR #1 ; shift bit out into carry + EORCS r2, r2, #&8C ; feedback carry into other bits + SUBS r4, r4, #1 ; one less bit to do + BNE %BT20 ; loop until done whole byte + SUBS r3, r3, #1 ; one less byte to do + BNE %BT10 ; loop until done all 7 bytes + LDRB r4, [r1], #1 ; read CRC + TEQ r4, r2 ; if incorrect + ORRNES pc, lr, #V_bit ; then exit indicating error + BICS pc, lr, #V_bit + + LTORG + + END diff --git a/s/PMF/osword b/s/PMF/osword new file mode 100644 index 0000000000000000000000000000000000000000..4110cc60e391a18b45b161a5bd312ec00c8a3a0f --- /dev/null +++ b/s/PMF/osword @@ -0,0 +1,1258 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.PMF.osword + +maxword * &16 ; highest known osword + +; ***************************************************************************** + + MACRO + WordReturnV $cond + [ AssemblingArthur :LOR: ErrorsInR0 + + ASSERT "$cond"="" :LOR: "$cond"="VS" + + [ "$cond"="" + Pull "R0-R4,R11,WsPtr,link,PC", VC + ] + ADDVS R13, R13, #4 ; junk stacked R0 + Pull "R1-R4,R11,WsPtr,link,PC", VS + + | + Pull "R0-R4, R11, R12, R14, PC", $cond + ] + MEND + +; Main OsWord entry point +; R0,R1,R2 are parameters + + +OsWord + Push "R0-R4, R11, R12, R14" + CMP R0, #(maxword+1) + BLCC OsWordGo ; Call the subsid entry pt. + LDMIA R13, {R2-R4} ; R2=A, R3=X, R4=Y + MOV R1, #Service_UKWord ; osword service reason + CLRPSR V_bit, R0 ; in case there's no service + IssueService + TEQ R1, #0 + STMEQIA R13, {R2-R4} ; if claimed, then update + ; returned R0-R2 + Pull "R0-R4, R11, R12, PC" ; pass V back from service + +GoMyOsword + CLRPSR V_bit, R4 + Pull "R0-R4, R11, R12, R14, PC" + +; ***************************************************************************** + +OsWordGo ROUT + BYTEWS WsPtr +10 ; Point to despatch table + ADD PC, PC, R0, LSL #2 ; add in the action*4 and go + & 0 + ASSERT DespatchWord-%BT10 = 8 + +; ***************************************************************************** + +DespatchWord + + BAL OsWord00 + BAL OsWord01 + BAL OsWord02 + BAL OsWord03 + BAL OsWord04 + BAL OsWord05 + BAL OsWord06 + BAL OsWord07 + + BAL OsWord08 + BAL OsWord09 + BAL OsWord0A + BAL OsWord0B + BAL OsWord0C + BAL OsWord0D + BAL OsWord0E + BAL OsWord0F + + BAL OsWord10 + BAL OsWord11 + BAL OsWord12 + BAL OsWord13 + BAL OsWord14 + BAL OsWord15 + BAL OsWord16 + +; ***************************************************************************** +; That's All Folks +; ***************************************************************************** + +; ***************************************************************************** +; The OsWord routines themselves +; ***************************************************************************** + +; Osword Zero : Input a line + +OsWord00 ROUT + LDRB R0, [R1, #0] ; lo-byte of address + LDRB R2, [R1, #1] ; hi-byte of address + ORR R0, R0, R2, LSL #8 ; R0 := address + LDRB R2, [R1, #3] ; lo limit + LDRB R3, [R1, #4] ; hi limit + LDRB R1, [R1, #2] ; length of buffer + SWI XOS_ReadLine + WordReturnV VS + + MOV R2, R1 ; put line length into R2 + Pull "R0,R1,R3" ; don't overwrite R2 + Pull "R3, R4, R11, R12, R14, PC" + +; ***************************************************************************** + +; Read/Write System Clock +; entered with IRQs off +; in: R0 = 1 => read clock +; R0 = 2 => write clock + +OsWord01 ROUT +OsWord02 ROUT + CMP R0, #2 ; C=1 <=> write clock + LDRB R0, TimerState + EORCS R0, R0, #&0F ; if writing, then write to other state + ; in case user resets in middle + TEQ R0, #5 ; 5 => alpha, 10 => beta (C preserved) + ADREQ R2, TimerAlpha + ADRNE R2, TimerBeta + Swap R1, R2, CS ; if writing then R2 is destination + MOV R3, #5 +10 + LDRB R4, [R2], #1 + STRB R4, [R1], #1 + SUBS R3, R3, #1 + BNE %BT10 + STRB R0, TimerState ; if writing, switch state + ; (if reading, write current state) + MyOsWord + +; ***************************************************************************** + +; Read/Write Interval Timer +; entered with IRQs off +; in: R0 = 3 => read interval timer +; R0 = 4 => write interval timer + +OsWord03 ROUT +OsWord04 ROUT + CMP R0, #4 ; C=1 => write timer + MOVCS R2, R1 ; if writing then R1 is source + ADRCS R1, IntervalTimer + ADRCC R2, IntervalTimer ; else R2 is source + MOV R0, #5 +10 + LDRB R3, [R2], #1 + STRB R3, [R1], #1 + SUBS R0, R0, #1 + BNE %BT10 + MyOsWord + +; ***************************************************************************** + +; Perform a SOUND command +OsWord07 ROUT + TST R1, #3 + LDMEQIA R1, {R0,R1} + SWIEQ XSound_ControlPacked + MyOsWord EQ + +; Block not word aligned, so push it on the stack + + SUB R13, R13, #8 ; create stack frame of 8 bytes + MOV R0, #7 +10 + LDRB R2, [R1, R0] ; copy block into stack frame + STRB R2, [R13, R0] + SUBS R0, R0, #1 + BCS %BT10 + + Pull "R0, R1" ; then pull stack frame into R0 and R1 + SWI XSound_ControlPacked + MyOsWord + +; ***************************************************************************** +; Read the logical colour of a Pixel ( BASIC'S POINT function) +; Uses SWI ReadPoint + +OsWord09 ROUT + Push R1 ; save pointer + + LDRB R2, [R1, #0] ; X lo-byte + LDRB R0, [R1, #1] ; X hi-byte + ORR R0, R2, R0, LSL #8 + + MOV R0, R0, LSL #16 ; sign extend X + MOV R0, R0, ASR #16 + + LDRB R2, [R1, #2] ; Y lo-byte + LDRB R1, [R1, #3] ; Y hi-byte + ORR R1, R2, R1, LSL #8 + + MOV R1, R1, LSL #16 ; sign extend Y + MOV R1, R1, ASR #16 + + SWI XOS_ReadPoint ; in: R0=X, R1=Y + ; out: R2=colour, R3=tint, R4=0/-1 (on/off) + Pull R1 + STRB R2, [R1, #4] + WordReturnV + +; ***************************************************************************** + +; Read a character definition + +OsWord0A ROUT + ByteToNosbod DoReadFont + MyOsWord + +; ***************************************************************************** + +; Read the palette setting (VDU19,L,P,R,G,B) + +OsWord0B ROUT + ByteToNosbod DoReadPalette + MyOsWord + +; ***************************************************************************** + +; Write the palette setting (see VDU19) + +OsWord0C ROUT + ByteToNosbod DoSetPalette + MyOsWord + +; ***************************************************************************** + +; Read the last two graphics cursor positions + +OsWord0D ROUT + ByteToNosbod DoOsWord13 + MyOsWord + +; ***************************************************************************** + +; Osword 14 (&0E) -- Read Real Time Clock +; Four (was six) different calls + +; Read CMOS clock +OsWord0E ROUT + Push "R5-R8, R14" ; R0-R4 saved by Osword + + MOV R4, R1 ; pointer to the Osword Block + + LDRB R0, [R4, #0] + CMP R0, #1 + BCC OsWord0EAlpha + BEQ OsWord0EBeta + CMP R0, #3 + BCC OsWord0EGamma + BEQ OsWord0EDelta + [ {FALSE} + CMP R0, #5 + BCC OsWord0EEpsilon + BEQ OsWord0EZeta ; this is getting ridiculous ! + ] + + Pull "R5-R8, PC" ; unknown option + +; ***************************************************************************** +; +; StoreHexPair - Store a hex number in R0 at R4+R6 (hi) and R4+R6+1 (lo) +; Corrupts R5,R6 + +StoreHexPair + Push R14 + BL HexToBCD + Pull R14 +StoreBCDPair + MOV R5, R0, LSR #4 + ADD R5, R5, #"0" + STRB R5, [R6, R4]! + AND R5, R0, #&0F + ADD R5, R5, #"0" + STRB R5, [R6, #1] + MOV PC, R14 + +; ***************************************************************************** +; +; StoreTLA - Store 3-letter alpha string in R0 at R4+R6+(0..2), +; uppercasing first character +; +; out: R0, R6 corrupt + +StoreTLA + BIC R0, R0, #&20 ; upper case 1st char + STRB R0, [R6, R4]! ; store 1st char + MOV R0, R0, LSR #8 + STRB R0, [R6, #1] ; store 2nd char + MOV R0, R0, LSR #8 + STRB R0, [R6, #2] ; store 3rd char + MOV PC, R14 + +; ***************************************************************************** +; +; OsWord0EAlpha - Read time as a string in the form +; eg Wed,01 Jan 1986.12:34:56 +; +; in: R1 -> buffer for string +; + +OsWord0EAlpha ROUT + [ {TRUE} + [ Fix7 + +; TMD 30-May-89: We want to enable IRQs here, but OS_ConvertDateAndTime +; loads bytes out of the block, and if IRQs are on it might end using an +; inconsistent value, so we must make a copy of the block on the stack +; and use that. The label OsWord0EDandT was used by a commented out routine +; in file 'RealTime' which will have to be rewritten if it needs to be +; included again. + + ADR R0, RealTime ; load snapshot of 5 bytes of real time + LDMIA R0, {R0, R2} ; while IRQs are still off + Push "R0, R2" ; save on stack + CLRPSR I_bit, R0 ; enable IRQs now +OSWord0EReturnString + MOV R0, R13 ; point to stacked copy + MOV R2, #25 ; 24 + CR terminator + ADR R3, TimeFormat + SWI XOS_ConvertDateAndTime + ADD R13, R13, #8 ; junk stack frame + | + ADR R0, RealTime + MOV R2, #25 ; 24 + CR terminator + ADR R3, TimeFormat +OsWord0EDandT + SWI XOS_ConvertDateAndTime + ] + MOVVC R0, #13 ; if no error + STRVCB R0, [R1] ; overwrite terminating 0 with CR + + Pull "R5-R8,R14" + WordReturnV + +TimeFormat + = "%w3,%dy %m3 %ce%yr.%24:%mi:%se", 0 + ALIGN + + | + CLRPSR I_bit, R0 ; this may take some time + + BL CheckYear ; check for year wrap + + BL ReadTime ; read clock + + Push "R5, R6" ; save year lo and hi + +; do the hours + + MOV R6, #16 ; hours at offset 16 and 17 + BL StoreHexPair + +; do the minutes + + MOV R0, R1 + MOV R6, #19 ; minutes at offset 19 and 20 + BL StoreHexPair + +; do the seconds + + MOV R0, R7 + MOV R6, #22 ; seconds at offset 22 and 23 + BL StoreHexPair + +; do the day of month + + MOV R0, R2 + MOV R6, #4 ; day of month at offset 4 and 5 + BL StoreHexPair + +; now the month number is still in R3 + + ADRL R0, MonthNameTable-4 ; point to the entry + LDR R0, [R0, R3, LSL #2] ; Get the data in the format "jan",0 etc. + MOV R6, #7 ; store month at offsets 7,8,9 + BL StoreTLA + +; do the year + + Pull "R7, R8" ; R7=year lo, R8=year hi + + MOV R0, R7 + MOV R6, #13 ; year(lo) at offsets 13 and 14 + BL StoreHexPair + +; do the high part of the year + + MOV R0, R8 + MOV R6, #11 ; year(hi) at offsets 11 and 12 + BL StoreHexPair + +; now compute day of week from month, date, and year +; at the moment R7 = units of years, R8 = hundreds of years +; we want to compute (year MOD 400) + + MOVS R8, R8, LSL #31 ; C=200, N=100 + ADDCS R7, R7, #200 + ADDMI R7, R7, #100 + +; R7 is now year MOD 400 + + BL DayOfTheWeek ; Returns R0 = 0..6 for Sun..Sat + + ADR R1, DayNameTable ; Point to the correct entry + LDR R0, [R1, R0, LSL #2] ; and get it (word) + MOV R6, #0 ; day of week stored at offsets 0,1,2 + BL StoreTLA + +; do the format characters + + B DoFormatChars + ] + +; ***************************************************************************** +; +; OsWord0EBeta - Read time in BCD format +; +; in: R4 -> parameter block +; +; out: [R4, #0] = year (00-99) +; [R4, #1] = month (01-12) +; [R4, #2] = day of month (01-31) +; [R4, #3] = day of week (01-07) Sun=01 +; [R4, #4] = hours (00-23) +; [R4, #5] = minutes (00-59) +; [R4, #6] = seconds (00-59) +; + +OsWord0EBeta ROUT + + [ {TRUE} ; International version uses Territory manager. + + ADR R0, RealTime ; load snapshot of 5 bytes of real time + LDMIA R0, {R0, R2} ; while IRQs are still off + Push "R0, R2" ; save on stack + CLRPSR I_bit, R0 ; this may take some time + + MOV R0,#-1 + MOV R1,SP + SUB SP,SP,#36 ; Space for ordinals. + MOV R2,SP + SWI XTerritory_ConvertTimeToOrdinals + ADDVS SP,SP,#36+(2*4) + BVS OSWord0Eerror + +; [R2] = CS. ; all values are for LOCAL time +; [R2+4] = Second +; [R2+8] = Minute +; [R2+12] = Hour (out of 24) +; [R2+16] = Day number in month. +; [R2+20] = Month number in year. +; [R2+24] = Year number. +; [R2+28] = Day of week. +; [R2+32] = Day of year + + LDR R0,[R2,#24] ; Get year + LDR R1,=1900 + SUB R0,R0,R1 +01 + CMP R0,#100 + SUBGT R0,R0,#100 + BGT %BT01 ; Get year MOD 100. + + STRB R0,[R4,#0] ; Store it. + LDR R0,[R2,#20] + STRB R0,[R4,#1] + LDR R0,[R2,#16] + STRB R0,[R4,#2] + LDR R0,[R2,#28] + STRB R0,[R4,#3] + LDR R0,[R2,#12] + STRB R0,[R4,#4] + LDR R0,[R2,#8] + STRB R0,[R4,#5] + LDR R0,[R2,#4] + STRB R0,[R4,#6] + + ADD SP,SP,#36+(2*4) ; junk stack frame and 5 byte time. + + | + + + CLRPSR I_bit, R0 ; this may take some time + + BL CheckYear ; check for year wrap + + BL ReadTime ; read the time + + STRB R0, [R4, #4] ; store hours in hex + STRB R1, [R4, #5] ; store minutes in hex + STRB R2, [R4, #2] ; store dayofmonth in hex + STRB R3, [R4, #1] ; store month in hex + STRB R5, [R4, #0] ; store year(lo) in hex + STRB R7, [R4, #6] ; store seconds in hex + + ] + +; now we have the time in hex in the parameter block +; so convert each item into BCD + + MOV R1, #6 ; seven bytes to convert + +10 + LDRB R0, [R4, R1] + BL HexToBCD + STRB R0, [R4, R1] + SUBS R1, R1, #1 + BPL %BT10 + + [ {FALSE} ; Done in territory for international version + + MOV R7, R5 ; R7 = year(lo) + +; now compute day of week from month, date, and year +; at the moment R7 = units of years, R6 = hundreds of years +; we want to compute (year MOD 400) + + MOVS R6, R6, LSL #31 ; C=200, N=100 + ADDCS R7, R7, #200 + ADDMI R7, R7, #100 + +; R7 is now year MOD 400 + + BL DayOfTheWeek ; Returns R0 = 0..6 for Sun..Sat + + ADD R0, R0, #1 ; put into range 1..7 + STRB R0, [R4, #3] ; (hex = BCD) + + ] + + B OsWord0Eend + +; ***************************************************************************** +; +; OsWord0EGamma - Convert time in BCD format (at offsets 1..7) +; into string format at offsets (0..24) +; +; in: R4 -> BCD time +; + +OsWord0EGamma ROUT + + [ {TRUE} ; International version. +;build a block for Territory_ConvertOrdinalsToTime +; [R2] = CS. ; all values are for LOCAL time +; [R2+4] = Second +; [R2+8] = Minute +; [R2+12] = Hour (out of 24) +; [R2+16] = Day number in month. +; [R2+20] = Month number in year. +; [R2+24] = Year number. + + SUB SP,SP,#28 + MOV R2,SP + MOV R0,#0 + STR R0,[R2] + + LDRB R0,[R4,#7] ; Seconds + BL BCDToHex + STR R0,[R2,#4] + + LDRB R0,[R4,#6] ; Minutes + BL BCDToHex + STR R0,[R2,#8] + + LDRB R0,[R4,#5] ; Hours + BL BCDToHex + STR R0,[R2,#12] + + LDRB R0,[R4,#3] ; Day of month + BL BCDToHex + STR R0,[R2,#16] + + LDRB R0,[R4,#2] ; Month + BL BCDToHex + STR R0,[R2,#20] + + + LDRB R0,[R4,#1] ; Year + BL BCDToHex + LDR R1,=1900 + ADD R0,R0,R1 + STR R0,[R2,#24] + + MOV R0,#-1 + ADD R1,SP,#20 ; Put value on satck + SWI XTerritory_ConvertOrdinalsToTime + ADDVS SP,SP,#28 + BVS OSWord0Eerror + + ADD SP,SP,#20 + MOV R1,R4 + B OSWord0EReturnString ; Now we have 5 byte value on stack, + ; use same code as OSWord0EAlpha + | + +; do the seconds + + LDRB R0, [R4, #7] + MOV R6, #22 ; seconds at offset 22 and 23 + BL StoreBCDPair + +; do the minutes + + LDRB R0, [R4, #6] + MOV R6, #19 ; minutes at offset 19 and 20 + BL StoreBCDPair + +; do the hours + + LDRB R0, [R4, #5] + MOV R6, #16 ; hours at offset 16 and 17 + BL StoreBCDPair + +; do the year + + LDRB R0, [R4, #1] + MOV R6, #13 ; year(lo) at offsets 13 and 14 + BL StoreBCDPair + + MOV R0, #"1" + STRB R0, [R4, #11] ; year(hi) at offsets 11 and 12 + MOV R0, #"9" + STRB R0, [R4, #12] + +; do the month + + LDRB R0, [R4, #2] ; get the month number + BL BCDToHex ; make it hex + ADR R3, MonthNameTable-4 ; Point to entry (months start at 1) + LDR R0, [R3, R0, LSL #2] ; Get the data in format "jan",0 etc + MOV R6, #7 ; store month name at offsets 7,8,9 + BL StoreTLA + +; day-of-the-week + + LDRB R3, [R4, #4] ; day number in range 1..7 + ADR R0, DayNameTable-4 ; point to correct dayname eg "Wed",0 + LDR R0, [R0, R3, LSL #2] + MOV R6, #0 ; store day name at offsets 0,1,2 + BL StoreTLA + +; do day of month + + LDRB R0, [R4, #3] + MOV R6, #4 ; day of month at offset 4 and 5 + BL StoreBCDPair + +; do the format characters + +DoFormatChars + MOV R0, #"," + STRB R0, [R4, #3] + MOV R0, #" " + STRB R0, [R4, #6] + STRB R0, [R4, #10] + MOV R0, #"." + STRB R0, [R4, #15] + MOV R0, #":" + STRB R0, [R4, #18] + STRB R0, [R4, #21] + MOV R0, #13 + STRB R0, [R4, #24] + + B OsWord0Eend + +DayNameTable + = "sun",0 + = "mon",0 + = "tue",0 + = "wed",0 + = "thu",0 + = "fri",0 + = "sat",0 + + ] + +; ***************************************************************************** +; +; OsWord0EDelta - Read 5-byte RealTime +; +; in: R4 -> block +; +; out: [R4, #0..4] = RealTime +; + +OsWord0EDelta ROUT + LDR R1, RealTime +0 + STRB R1, [R4, #0] + MOV R1, R1, LSR #8 + STRB R1, [R4, #1] + MOV R1, R1, LSR #8 + STRB R1, [R4, #2] + MOV R1, R1, LSR #8 + STRB R1, [R4, #3] + LDRB R1, RealTime +4 + STRB R1, [R4, #4] + +; and drop thru to ... + +OsWord0Eend + Pull "R5-R8, R14" + MyOsWord + +OSWord0Eerror + Pull "R5-R8, R14" + WordReturnV + +; ***************************************************************************** +; +; GetDecimalPair - Get pair of decimal digits from [R4+R1+0..1] +; +; in: R1 is offset from R4 to find 1st digit +; +; out: if valid, R1=value of pair of digits, C=0 +; if invalid, R1=undefined, C=1 +; R10 is corrupted +; + +GetDecimalPair ROUT + LDRB R10, [R1, R4]! ; get hi-digit + SUB R10, R10, #"0" ; put in range 0..9 + CMP R10, #10 ; C=1 if bad digit + ADD R10, R10, R10, LSL #2 ; R10 = 5*hi + + LDRB R1, [R1, #1] ; get lo-digit + SUB R1, R1, #"0" ; put in range 0..9 + CMPCC R1, #10 ; C=1 if bad digit + ADD R1, R1, R10, LSL #1 ; R1 = lo + 2*(5*hi) + + MOV PC, R14 + +; ***************************************************************************** + +; Osword 15 (&0F) Write the Real Time Clock. +; Three different calls + +OsWord0F ROUT + CLRPSR I_bit, R0 ; this may take some time + + Push "R5-R10, R14" + MOV R4, R1 ; Copy the parameter block pointer + LDRB R0, [R1] + MOV R9, #0 + + TEQ R0, #8 ; write hours, minutes, seconds + MOVEQ R9, #1 + + TEQ R0, #15 ; write day, date, month, year + MOVEQ R9, #2 + + TEQ R0, #24 ; write all of time + MOVEQ R9, #3 + + TEQ R9, #0 + Pull "R5-R10, PC", EQ ; unknown call, pass it on + + [ {TRUE} ; international version uses Territory_ConvertTimeStringToOrdinals + + ADD r10, r0, #3+1 ; round up number of bytes in block to word boundary, including null terminator + BIC r10, r10, #3 + SUB sp, sp, r10 + + ADD r2, r1, #1 ; point at actual string + MOV r1, #0 +02 + LDRB r14, [r2, r1] ; copy string (not terminated) on stack + STRB r14, [sp, r1] + ADD r1, r1, #1 + TEQ r1, r0 ; have we copied all bytes of string? + BNE %BT02 ; loop if not + + MOV r14, #0 ; null terminator + STRB r14, [sp, r0] + + MOV r0,#-1 ; set things up for territory SWI - r0 = -1 for current territory + MOV r1, r9 ; r1 = reason code (1, 2 or 3) + MOV r2, sp ; r2 -> terminated string on stack + SUB sp, sp, #36 ; get space for result. + MOV r3, sp + + SWI XTerritory_ConvertTimeStringToOrdinals + ADDVS sp, sp, #36 ; if error then junk return block + ADDVS sp, sp, r10 ; and junk variable length string on stack + BVS Bad0F + + CMP r9, #2 ; if just writing the date, write it ! + BEQ %FT10 + BGT %FT05 ; if writing everything just get UTC time + +; We only have the time from the string, we now need the date +; because changing the time may change it. + + ADR r0, RealTime + LDMIA r0, {r0,r1} ; LDM is atomic wrt interrupts + + Push "r0,r1" ; put value on stack + MOV r0,#-1 ; use configured territory. + ADD r2, sp, #8 + LDMIA r2, {r3-r6} ; preserve time values from entry string + MOV r1, sp + SWI XTerritory_ConvertTimeToOrdinals ; get ordinals for current time + ADDVS sp, sp, #44 ; 36 From above + 8 for 5 byte time + ADDVS sp, sp, r10 ; and junk string as well + BVS Bad0F + ADD sp, sp, #8 ; dump 5 byte time on TOS + STMIA r2, {r3-r6} ; restore the time we read from the string. + +05 +; Now [SP] -> ordinals in local time, but we want time in UTC +; First convert the ordinals to 5 byte UTC time + + MOV r0, #-1 ; use configured territory. + MOV r2, sp ; r2 -> ordinals block + SUB sp, sp, #8 ; two more words to contain 5 byte time + MOV r1, sp + SWI XTerritory_ConvertOrdinalsToTime + ADDVS sp, sp, #44 ; 36 From above + 8 for 5 byte time. + ADDVS sp, sp, r10 ; and junk string as well + BVS Bad0F + +; Now we have a 5 byte UTC time, convert it to UTC ordinals + + MOV r1, sp ; our 5 byte time + ADD r2, sp, #8 ; place to put ordinals + SWI XTerritory_ConvertTimeToUTCOrdinals + ADDVS sp, sp, #44 ; 36 bytes ordinals + 8 for 5 byte time. + ADDVS sp, sp, r10 ; and junk string as well + BVS Bad0F + + ADD sp, sp, #8 ; discard 5 byte time + +10 +; Load the registers. (SP->Ordinals) + + LDR r8, [sp], #4 ; centiseconds + LDR r7, [sp], #4 ; seconds + LDR r1, [sp], #4 ; minutes + Pull "r0,r2,r3,r5" ; hours, day of month, month, year + ADD sp, sp, #8 ; junk day of week, day of year + ADD sp, sp, r10 ; and string on stack + MOV r4, #100 + DivRem r6, r5, r4, r14 ; r5 = Year (lo), r6 = Year (hi) + + | + +; first set up data in registers as follows :- +; R0 = hours +; R1 = minutes +; R2 = days +; R3 = months +; (R4 -> block) +; R5 = year(lo) +; R6 = year(hi) +; R7 = seconds +; R8 = centiseconds + +; first do the date part, if appropriate + + TST R9, #2 + MOVEQ R2, #-1 ; if not doing date, set days, + MOVEQ R3, #-1 ; months, year(lo), year(hi) to -1 + MOVEQ R5, #-1 + MOVEQ R6, #-1 + BEQ %FT50 ; [not doing date] + +; do the months + + LDRB R1, [R4, #8] ; get first char + ORR R1, R1, #&20 ; lower case it + LDRB R2, [R4, #9] ; get second char + ORR R2, R2, #&20 ; lower case it + ORR R1, R1, R2, LSL #8 ; merge + LDRB R2, [R4, #10] ; get third char + ORR R2, R2, #&20 ; lower case it + ORR R1, R1, R2, LSL #16 ; merge + + ADR R2, MonthNameTable-4 ; months start at 1 + MOV R3, #12 ; try December first +10 + LDR R0, [R2, R3, LSL #2] ; get month word + TEQ R0, R1 + SUBNES R3, R3, #1 ; if not equal, decrement month + BNE %BT10 ; and if non-zero, loop + + TEQ R3, #0 ; failed to match ? + BEQ Bad0F ; then ignore all + +; R3 now contains the month number + +; do the days + + MOV R1, #5 ; offset to days + BL GetDecimalPair + BCS Bad0F ; bad digits + + MOVS R2, R1 + BEQ Bad0F ; zero days not allowed + + ADR R0, MonthLengths ; now validate days against + LDRB R1, [R0, R3] ; maximum number of days in that month + CMP R1, R2 ; (29 for Feb) and eliminate if invalid + BCC Bad0F + +; R2 now contains the days + +; now do the years so we can check whether 29 Feb is legal + + MOV R1, #12 ; offset to year(hi) + BL GetDecimalPair + MOVCC R6, R1 + + MOVCC R1, #14 ; offset to year(lo) + BLCC GetDecimalPair + MOVCC R5, R1 + + BCS Bad0F + +; now check for Feb 29 + + TEQ R3, #2 ; month = Feb ? + TEQEQ R2, #29 ; and day = 29 ? + BNE %FT20 ; [not 29 Feb] + + TST R5, #3 ; is year multiple of 4 + BNE Bad0F ; no, then 29 Feb is bad + + TEQ R5, #0 ; is it a century year ? + BNE %FT20 ; no, then 29 Feb is good + + TST R6, #3 ; is it a multiple of 400 ? + BNE Bad0F ; no, then 29 Feb is bad + +20 + ADD R4, R4, #16 ; move on to time part + +; now do the time part, if appropriate + +50 + TST R9, #1 + MOVEQ R0, #-1 ; if not doing time, set hours, + MOVEQ R1, #-1 ; minutes and seconds to -1 + MOVEQ R7, #-1 + MOVEQ R8, #-1 + BEQ %FT80 ; [not doing time part] + +; do the seconds + + MOV R1, #7 ; offset to seconds + BL GetDecimalPair + CMPCC R1, #60 + MOVCC R7, R1 + +; zero the centiseconds + + MOV R8, #0 + +; do the hours + + MOVCC R1, #1 ; offset to hours + BLCC GetDecimalPair + CMPCC R1, #24 + MOVCC R0, R1 + +; do the minutes + + MOVCC R1, #4 + BLCC GetDecimalPair + CMPCC R1, #60 + + BCS Bad0F +80 + +; we have now completely validated the settings + + ] ;International version. + + BL SetTime ; also updates 5-byte RealTime + +Bad0F ; come here if setting invalid + Pull "R5-R10, R14" + MyOsWord + +; ***************************************************************************** + + [ {FALSE} ; not needed for internationalised kernel +MonthNameTable + = "jan",0 + = "feb",0 + = "mar",0 + = "apr",0 + = "may",0 + = "jun",0 + = "jul",0 + = "aug",0 + = "sep",0 + = "oct",0 + = "nov",0 + = "dec",0 + ] + +; ***************************************************************************** +; +; CheckYear - Check for year wrap (if months have gone down) +; and for leap year fudging +; + +CheckYear ROUT + [ NewClockChip + Push "R0,R1,R2,R14" + MOV R0, #5 ; year address + BL ReadStraight + MOV R1, R0, LSR #6 ; year in range 0..3 + MOV R0, #YearCMOS + BL Read + AND R2, R0, #3 + SUBS R2, R1, R2 ; same year ? + Pull "R0,R1,R2,PC", EQ ; [yes, so no bother] + ADDCC R2, R2, #4 ; if lower, then must be carry + ADD R2, R0, R2 ; new year value + CMP R2, #100 + BCC %FT10 ; no carry thru to next century + + SUB R2, R2, #100 + MOV R0, #YearCMOS +1 + BL Read + ADD R1, R0, #1 + TEQ R1, #100 + MOVEQ R1, #0 ; wrap century + MOV R0, #YearCMOS +1 + BL Write +10 + MOV R1, R2 + MOV R0, #YearCMOS + BL Write + + BL RTCToRealTime + Pull "R0,R1,R2,PC" + + | + Push "R0-R8, R14" + + BL ReadTime ; R3 = clock month (in hex) + + MOV R0, #MonthCMOS + BL Read ; R0 = CMOS RAM month + + CMP R3, R0 + BLCC HappyNewYear ; The months have gone down + +; now make sure that Feb 29th is dealt with correctly + + CMP R3, #3 ; if Jan or Feb then no problem + BCC %FT10 + + MOV R0, #LeapCMOS ; if already fudged it + BL Read ; then no problem + TEQ R0, #0 + BNE %FT10 + + TST R5, #3 ; if year MOD 4 is not zero + BNE %FT10 ; then no problem + + TEQ R5, #0 ; if not century start + BNE %FT20 ; then is leap year + + TST R6, #3 ; else if not mult of 400 + BNE %FT10 ; then no problem + +20 ; it is a leap year + SUBS R2, R2, #1 ; day := day-1 + SUBEQ R3, R3, #1 ; if day=0 then month := month-1 + ADREQ R4, MonthLengths + LDREQB R2, [R4, R3] ; and day := last day of month + + MOV R0, #-1 ; don't change hours + MOV R1, #-1 ; or minutes + MOV R7, #-1 ; or seconds + MOV R8, #-1 ; or centiseconds + BL SetTime + + MOV R1, #1 ; we have now fudged it + MOV R0, #LeapCMOS + BL Write + + MOV R1, R3 ; remember the month + MOV R0, #MonthCMOS + BL Write +10 + Pull "R0-R8, PC" + +; ***************************************************************************** +; +; HappyNewYear - Update the year +; +; in: R3 = months +; R5 = year(lo) +; R6 = year(hi) +; +; out: R5 = new year(lo) +; R6 = new year(hi) + +HappyNewYear ROUT + Push "R0,R1, R14" + + ADD R5, R5, #1 ; R2 := new year(lo) + TEQ R5, #100 + BNE %FT10 ; [don't increment century] + + MOV R5, #0 ; wrap year + ADD R6, R6, #1 ; R1 := new year(hi) + TEQ R6, #100 + MOVEQ R6, #0 ; wrap century + + MOV R1, R6 + MOV R0, #YearCMOS+1 + BL Write ; write year(hi) +10 + MOV R1, R5 + MOV R0, #YearCMOS + BL Write ; write year(lo) + + BL RTCToRealTime ; update 5-byte RealTime + + MOV R1, R3 + MOV R0, #MonthCMOS + BL Write ; write new months + + MOV R1, #0 + MOV R0, #LeapCMOS + BL Write ; clear leapyear flag + + Pull "R0,R1, PC" + + ] + +; ***************************************************************************** + +MonthLengths + ; F J F M A M J J A S O N D + = 28,31,29,31,30,31,30,31,31,30,31,30,31 + ALIGN + +; ***************************************************************************** +; +; DayOfTheWeek - Compute day of the week +; +; in: R2 = day of the month +; R3 = month +; R7 = year MOD 400 +; +; out: R0 = day of week (0..6 = Sun..Sat) (I think!) +; Other registers preserved +; + +DayOfTheWeek + Push "R1,R4-R7, R14" + SUB R0, R2, #1 ; R0 = day of the month starting at 0 + ADR R4, DaysToDate-4 ; adjust cos months start at 1 + LDR R5, [R4, R3, LSL #2] ; get the month start offset + ADD R0, R0, R5 ; number of days since start of year + +; now adjust for this year being leap + + TST R7, #3 + BNE NotLeapYr ; non-multiples of 3 are not leap + + TEQ R7, #100 + TEQNE R7, #200 + TEQNE R7, #300 + BEQ NotLeapYr ; if 100 or 200 or 300 then not leap + +IsLeapYr + CMP R3, #3 ; is leap, so if March 1st or after + ADDCS R0, R0, #1 ; then add extra day +NotLeapYr + TEQ R7, #0 ; if mult of 400 + MOVEQ R7, #400 ; then set to 400 + ADD R0, R0, R7 ; add one for each year + + SUB R7, R7, #1 ; R7 = last year to cope with + ADD R0, R0, R7, LSR #2 ; add one for each leap year + + CMP R7, #100 ; subtract one if counting year 100 + SUBCS R0, R0, #1 + CMP R7, #200 ; subtract one if counting year 200 + SUBCS R0, R0, #1 + CMP R7, #300 ; subtract one if counting year 300 + SUBCS R0, R0, #1 + +; ADD R0, R0, #0 ; fudge factor cos 1 Jan 1986 is Wed + MOV R5, #7 + DivRem R1, R0, R5, R6 + + Pull "R1,R4-R7, PC" + +; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +DaysToDate + & 0,31,59,90,120,151,181,212,243,273,304,334 +; J F M A M J J A S O N D + +; ***************************************************************************** + +; Define hardware cursor size, shape and active point + +OsWord15 + ByteToNosbod DoPointerStuff + MyOsWord + +; ***************************************************************************** + +; Set start of screen address (for VDU drivers and display) +; [R1, #0] = bit mask (bit0 set => change drivers; bit1 set => change display) +; [R1, #1..4] = byte offset from start of screen memory + +OsWord16 + ByteToNosbod DoSetScreenStart + MyOsWord + +; ************************************************************************** + +; All the unused OS_Word calls + +; Read Byte of I/O proc memory +OsWord05 ROUT +; Write byte of I/O proc memory +OsWord06 ROUT +; Define an ENVELOPE +OsWord08 ROUT +; Allocated to the net +OsWord10 +OsWord11 +OsWord12 +OsWord13 +OsWord14 + Unused + + END diff --git a/s/PMF/oswrch b/s/PMF/oswrch new file mode 100644 index 0000000000000000000000000000000000000000..882e3da81ed1567d3569ce34b5f844072c0cd66d --- /dev/null +++ b/s/PMF/oswrch @@ -0,0 +1,199 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.PMF.oswrch + + GBLS WrchLimReg + +; ***************************************************************************** +; +; PMFWrch - Entry point for WriteC vector +; This routine used to be nice and structured before I +; optimised it for plain wrch ! +; +; in: R0 = character +; +; out: All registers preserved +; + + [ {FALSE} +WrchLimReg SETS "R9" ; would like to only push R0-R9, but + ; PMFWrchDirect is called by SWIs like + ; OS_WriteN etc, which need R10-R12 + +PMFWrchDirect + BYTEWS WsPtr ; if called direct, then set up R12 +PMFWrch ROUT + Push "R0-$WrchLimReg" ; if called thru vec, already set up + | +WrchLimReg SETS "R12" ; 0.046N, so need to save R0-R12 + +PMFWrchDirect +PMFWrch ROUT + Push "R0-$WrchLimReg" + BYTEWS WsPtr + ] + + LDRB R1, WrchDest + LDRB R2, SpoolFileH + ORRS R3, R1, R2 + BNE %FT10 + + [ AssemblingArthur + VDWS WsPtr + BL Vdu + | + BL WrchVdu ; call VDU + ] + BVS %FT45 + Pull "R0-$WrchLimReg,PC", CC + B %FT15 + +10 + TST R1, #&22 ; branch if wrch not to VDU + BNE %FT50 ; or wrch to extension vector + + [ AssemblingArthur + VDWS WsPtr + BL Vdu + | + BL WrchVdu ; call VDU + ] +15 + BVS %FT45 ; error from VDU + LDMFD R13, {R0} ; reload R0 with character + BYTEWS WsPtr ; reload workspace pointer + LDRB R1, WrchDest ; and wrch destinations + BCS PrintVdu ; VDU says "Print it" +20 + TST R1, #8 ; printer enabled, independent of + ; CTRL-B and CTRL-C ? + BNE PrintVdu ; yes, then branch +40 + TST R1, #1 ; output to RS423 ? + BNE RS423Vdu ; yes, then do it +42 + LDRB R2, SpoolFileH ; spool file open ? + CMP R2, #0 ; (set V=0 for if we drop thru) + BLNE SpoolVdu ; yes, then go +45 + [ AssemblingArthur :LOR: ErrorsInR0 + Pull "R0-$WrchLimReg, PC", VC + ADD R13, R13, #4 + Pull "R1-$WrchLimReg, PC" + | + Pull "R0-$WrchLimReg, PC" ; that's it (phew!) + ] + +; Come here when Wrch not to VDU or Wrch to VDUXV + +50 + TST R1, #&02 ; wrch not to VDU at all ? + BNE %BT20 ; then skip + ; else must be VDU sent thru VDUXV + MOV R10, #VDUXV + BL GoVec2 ; call vector + B %BT15 + +; ***************************************************************************** + +PrintVdu + TST R1, #&40 ; only print via VDU 1 ? + BNE %BT40 ; yes, then skip + + LDRB R2, PrinterIgnore ; is it ignore character ? + TEQ R0, R2 + LDREQB R2, NoIgnore ; and ignoring enabled ? + TSTEQ R2, #&80 + BEQ %BT40 ; yes, then don't print it + + BL MOSDoPrintWS ; else print it (R12 -> ByteWS) + BVS %BT45 ; error in printing + LDMFD R13, {R0} ; reload R0 with character + LDRB R1, WrchDest ; and reload wrchdest + B %BT40 + +RS423Vdu + [ DriversInKernel + PHPSEI + Push "R0,R1,R14" ; I know what I'm doing, honest! + MOV R1, #Buff_RS423Out ; RS423 output buffer id + SETV ; indicate examine buffer + BL REMOVE + BLCS RSBUSY ; buff empty, so reawaken TXIRQ + LDMFD R13, {R0} ; get char back + MOV R1, #Buff_RS423Out ; RS423 output buffer id + BL WRITE ; write to buffer (waiting) + Pull "R0,R1,R14" + PLP ; restore interrupt state (V preserved) + B %BT42 ; carry on with rest + | + Push "r0,r1" + LDRB r1, SerialOutHandle + TEQ r1, #0 + BNE %FT60 + MOV r0, #open_write + ADR r1, SerialOutFilename + SWI XOS_Find + BVS %FT70 ; if can't open serial output stream, report error + ; and don't put anything in buffer + STRB r0, SerialOutHandle + LDMFD sp, {r0} ; get char back +60 + PHPSEI + Push "r14" ; save IRQ indication + MOV r1, #Buff_RS423Out ; RS423 output buffer id + BL WRITE ; write to buffer (waiting) + Pull "r14" + PLP ; restore IRQ state from lr + Pull "r0,r1" + B %BT42 + +; we got an error from the open, so in order to report it, +; we'd better stop outputting to RS423 + +70 + ADD sp, sp, #4 ; junk stacked r0 + Pull "r1" + BIC r1, r1, #1 ; clear RS423 output bit + STRB r1, WrchDest ; write back to OS_Byte + B %BT45 ; report error + ] + + [ :LNOT: DriversInKernel +SerialOutFilename + = "Serial#Buffer2:", 0 + ALIGN + ] + +SpoolVdu ; entered with V=0 + TST R1, #&10 ; spooling enabled ? + MOVNE PC, R14 ; no, then return + + Push R14 ; cos we're doing a SWI in SVC mode + MOV R1, R2 ; put handle in R1 + SWI XOS_BPut ; put byte to file + Pull PC, VC ; if no error, return with V clear + ; (no need to reload R1, since SPOOL + ; is done last) +SpoolBadExit + Push R0 + MOV R0, #0 ; stop spooling FIRST + STRB R0, SpoolFileH + SWI XOS_Find ; and close file (R0=0, R1=handle) + Pull "R1, R14" + MOVVC R0, R1 ; if closed OK, then restore old error + ORRS PC, R14, #V_bit ; still indicate error + + END diff --git a/s/PMF/realtime b/s/PMF/realtime new file mode 100644 index 0000000000000000000000000000000000000000..9e2dc15def51cbe5b13b878ae15ea0326ba9600c --- /dev/null +++ b/s/PMF/realtime @@ -0,0 +1,331 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.PMF.realtime + +; ***************************************************************************** +; +; RTCToRealTime - Set RealTime from actual RTC +; +; in: R12 -> BYTEWS +; out: all registers preserved +; + + [ {FALSE} +Construct5Byte ROUT + Push R14 + B Construct5ByteEntry + ] + +RTCToRealTime ROUT + Push "R0-R9, R14" + BL ReadTime ; R0 := hours, R1 := minutes + ; R2 := days, R3 := months + ; R5 := year(lo), R6 := year(hi) + ; R7 := seconds, R8 := centiseconds + BL ConvertTo5Byte + BL Store5ByteInRealTime + Pull "R0-R9, PC" + + [ {FALSE} ; not used +RegToRealTime ROUT + Push "R0-R9, R14" + BL ConvertTo5Byte + BL Store5ByteInRealTime + Pull "R0-R9, PC" + ] + +ConvertTo5Byte ROUT + Push R14 + + MOV R4, R5 ; R4 := year MOD 100 + MOV R5, R6 ; R5 := year DIV 100 + MOV R6, R7 ; R6 := seconds + MOV R7, R8 ; R7 := centiseconds + +Construct5ByteEntry + MOV R9, #24 + SUB R2, R2, #1 ; decrement day (day=1 => nowt to add) + MLA R0, R9, R2, R0 ; R0 = hours + day*24 + MOV R9, #60 + MLA R1, R0, R9, R1 ; R1 = mins + hours*60 + MLA R6, R1, R9, R6 ; R6 = secs + mins*60 + MOV R9, #100 + MLA R7, R6, R9, R7 ; R7 = centisecs + secs*100 + + ADR R0, STMonths-4 ; Point to table (month = 1..12) + LDR R1, [R0, R3, LSL #2] ; get word of offset + ADD R7, R7, R1 ; add to total + +; if not had leap day in this year yet, then exclude this year from the +; leap day calculations + + CMP R3, #3 ; if month >= 3 + SBCS R0, R4, #0 ; then R0,R1 = R4,R5 + MOVCC R0, #99 ; else R0,R1 = R4,R5 -1 + SBC R1, R5, #0 + +; want (yl+100*yh) DIV 4 - (yl+100*yh) DIV 100 + (yl+100*yh) DIV 400 +; = (yl DIV 4)+ (25*yh) - yh + (yh DIV 4) +; = (yl >> 2) + 24*yh + (yh >> 2) + + MOV R0, R0, LSR #2 ; yl >> 2 + ADD R0, R0, R1, LSR #2 ; + yh >> 2 + ADD R0, R0, R1, LSL #4 ; + yh * 16 + ADD R0, R0, R1, LSL #3 ; + yh * 8 + +; now subtract off the number of leap days in first 1900 years = 460 + + SUBS R0, R0, #460 + BCC BadYear ; before 1900, so bad + CMP R0, #86 ; if more than 86 days, then it's + BCS BadYear ; after 2248, so bad + + LDR R9, =ticksperday ; multiply by ticksperday and add to + MLA R7, R9, R0, R7 ; total (no overflow possible as this + ; can never be more than 85+31 days) + +; now add on (year-1900)*ticksperyear + + SUBS R5, R5, #19 ; subtract off 1900 + BCC BadYear + MOV R9, #100 + MLA R4, R9, R5, R4 ; R4 = year-1900 + + LDR R0, =ticksperyear ; lo word of amount to add on + MOV R1, #0 ; hi word of amount to add on + MOV R8, #0 ; hi word of result +10 + MOVS R4, R4, LSR #1 + BCC %FT15 + + ADDS R7, R7, R0 ; if bit set then add on amount + ADCS R8, R8, R1 + BCS BadYear ; overflow => bad time value +15 + ADDS R0, R0, R0 ; shift up amount + ADCS R1, R1, R1 + TEQ R4, #0 ; if still bits to add in + BNE %BT10 ; then loop + + CMP R8, #&100 ; R8 must only be a byte + Pull PC, CC + +BadYear + MOV R7, #-1 + MOV R8, #-1 + Pull PC + + +Store5ByteInRealTime + Push R14 + PHPSEI ; disable IRQs for this bit + STR R7, RealTime +0 + STRB R8, RealTime +4 + + [ :LNOT: AssemblingArthur :LAND: :LNOT: Module +; for now, also put into normal time + + LDRB R0, TimerState + TEQ R0, #5 + + ADREQ R3, TimerAlpha +0 + ADRNE R3, TimerBeta +0 + + STR R7, [R3] + STRB R8, [R3, #4] + ] + PLP + + Pull PC + +; ***************************************************************************** + +tickspersecond * 100 +ticksperminute * tickspersecond * 60 +ticksperhour * ticksperminute * 60 +ticksperday * ticksperhour * 24 +ticksperyear * ticksperday * 365 ; &BBF81E00 + +STMonths + & &00000000 ; Jan + & &0FF6EA00 ; Feb + & &1E625200 ; Mar + & &2E593C00 ; Apr + & &3DCC5000 ; May + & &4DC33A00 ; Jun + & &5D364E00 ; Jul + & &6D2D3800 ; Aug + & &7D242200 ; Sep + & &8C973600 ; Oct + & &9C8E2000 ; Nov + & &AC013400 ; Dec + & &F0000000 ; terminator, must be less than this (+1) + + [ {FALSE} +; ***************************************************************************** +; +; DecodeAcornTime - Convert from 5-byte cs representation to +; "01:23:45 on 01-Jan-1988<0D>" format +; +; in: R1 -> block +; [R1, #1..5] = 5-byte centisecond representation +; +; out: [R1, #0..23] = string representation +; + +OsWord0EEpsilon +DecodeAcornTime ROUT + ADD R0, R1, #1 ; R0 -> 5 bytes of centiseconds + MOV R2, #24 + ADR R3, AcornTimeFormat + B OsWord0EDandT ; needs to be recoded if re-included + +AcornTimeFormat + = "%24:%mi:%se on %dy-%m3-%ce%yr", 0 + ALIGN + + LTORG + +; ***************************************************************************** +; +; EncodeAcornTime - Convert string representation (as above) into +; 5-byte centisecond value +; +; in: R1 -> block +; [R1, #1..24] = string representation +; +; out: [R1, #0..4] = 5 byte cs representation +; + +OsWord0EZeta +EncodeAcornTime ROUT + Push "R7-R10" + +; Firstly, the months (into R3) + + LDRB R0, [R1, #16] ; Get first char and lowercase it + ORR R0, R0, #&20 + LDRB R2, [R1, #16+1] ; And the second + ORR R2, R2, #&20 + LDRB R3, [R1, #16+2] ; And the third + ORR R3, R3, #&20 + ORR R0, R0, R2, LSL #8 ; Make a word of the chars + ORR R0, R0, R3, LSL #16 ; eg. 0naj, 0bef etc. + + MOV R3, #0 + ADRL R2, MonthNameTable +10 ADD R3, R3, #1 + CMP R3, #13 + BCS BadEncodeTime + LDR R4, [R2], #4 ; Test month name against list + TEQ R4, R0 + BNE %BT10 + +; Ok, suss the years + + MOV R10, #20 ; Read pair from hundreds/thousands + BL GetPair + BCS BadEncodeTime + MOV R5, R0 + + MOV R10, #20+2 ; And from tens/years + BL GetPair + BCS BadEncodeTime + MOV R4, R0 + +; The days, please + + MOV R10, #13 ; Read pair from days field + BL GetPair + BCS BadEncodeTime + MOV R2, R0 + +; Then the seconds + + MOV R10, #7 ; Read pair from seconds field + BL GetPair + CMPCC R0, #60 ; 00..59 valid + BCS BadEncodeTime + MOV R6, R0 + +; Now the minutes + + MOV R10, #4 ; Read pair from minutes field + BL GetPair + CMPCC R0, #60 ; 00..59 valid + BCS BadEncodeTime + MOV R9, R0 ; Can't disturb R1 yet ! + +; Lastly the hours + + MOV R10, #1 ; Read pair from hours field + BL GetPair + CMPCC R0, #24 ; 00..23 valid + BCS BadEncodeTime + + MOV R10, R1 + MOV R1, R9 ; Get minutes back + MOV R7, #0 ; Centiseconds = 0 + BL Construct5Byte ; Has R0-R7 parameters; R7,R8 on exit +EncodeExit + STRB R7, [R10, #0] + MOV R7, R7, LSR #8 + STRB R7, [R10, #1] + MOV R7, R7, LSR #8 + STRB R7, [R10, #2] + MOV R7, R7, LSR #8 + STRB R7, [R10, #3] + STRB R8, [R10, #4] + + Pull "R7-R10" + B OsWord0Eend + + +BadEncodeTime + MOV R8, #-1 ; Set date to out-of-bounds value + MOV R7, #-1 ; (This would be a command file) + MOV R10, R1 + B EncodeExit + +; ***************************************************************************** +; +; GetPair - Get a pair of decimal digits +; +; in: [R1,R10], [R1,R10+1] contain digits +; +; out: C=0 => R0 = 10*msdigit + lsdigit +; C=1 => invalid pair of digits +; + +GetPair ROUT + Push "R2, R10, R14" + + LDRB R2, [R10, R1]! ; Get msdigit and convert to decimal + SUB R2, R2, #"0" + CMP R2, #10 ; Keep CState for exit + + LDRB R0, [R10, #1] ; Get lsdigit and convert to decimal + SUB R0, R0, #"0" + CMPCC R0, #10 + + ADD R2, R2, R2, LSL #2 ; Multiply msdigit by 5 + ADD R0, R0, R2, LSL #1 ; complete mult by 10 and add + + Pull "R2, R10, PC" + ] + + LTORG + + END diff --git a/s/SWINaming b/s/SWINaming new file mode 100644 index 0000000000000000000000000000000000000000..1b0797b01574e92d837ffd8d95757c906f5fffaf --- /dev/null +++ b/s/SWINaming @@ -0,0 +1,641 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + TTL => SWINaming + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + MACRO +$l AddSwiNameToDecodeTab $name +$l = "$name", 0 +SwisInSystemTable SETA SwisInSystemTable+1 + MEND + +;*********************************************************************** +; +; SWI OS_SWINumberToString +; +; in: R0 = SWI number +; R1 = buffer pointer +; R2 = buffer length +; +; out: Buffer holds SWI name, null-terminated +; + +SWINumberToString_Code ROUT + TEQP pc, #SVC_mode ; interrupts on! + MOV r12, lr ; keep here so subroutines can update flags + Push "r3, r9" + MOV r9, r0 ; r0 to pass back + MOV r3, r2 ; buffer limit + MOV r2, #0 ; characters so far + + TST r0, #Auto_Error_SWI_bit + MOVNE r10, #"X" + BLNE AddChar + BIC r0, r0, #Auto_Error_SWI_bit + CMP r0, #512 + BCS NotASystemSWI ; TMD 11-May-89: changed from GE + + ADR r11, OS_Prefix + BL AddString + MOV r10, #"_" + BL AddChar + + CMP r0, #256 + BCS Swi_Is_WriteI ; TMD 11-May-89: changed from GE + CMP r0, #MaxSwi + BCS SWINotInTable ; TMD 11-May-89: changed from GE + + ADR r11, System_Swi_Names + BL GetStringFromTable + +AddStringAndExit + BL AddString + +ExitSwiSwi + MOV r10, #0 + BL AddChar + + MOV r0, r9 ; error pointer or restoration + Pull "r3, r9" + MOV lr, r12 + ExitSWIHandler + + GBLA SwisInSystemTable +SwisInSystemTable SETA -1 + +OS_Prefix = "OS",0 + +System_Swi_Names + AddSwiNameToDecodeTab WriteC + AddSwiNameToDecodeTab WriteS + AddSwiNameToDecodeTab Write0 + AddSwiNameToDecodeTab NewLine + AddSwiNameToDecodeTab ReadC + AddSwiNameToDecodeTab CLI + AddSwiNameToDecodeTab Byte + AddSwiNameToDecodeTab Word + AddSwiNameToDecodeTab File + AddSwiNameToDecodeTab Args + AddSwiNameToDecodeTab BGet + AddSwiNameToDecodeTab BPut + AddSwiNameToDecodeTab GBPB + AddSwiNameToDecodeTab Find + AddSwiNameToDecodeTab ReadLine + AddSwiNameToDecodeTab Control + AddSwiNameToDecodeTab GetEnv + AddSwiNameToDecodeTab Exit + AddSwiNameToDecodeTab SetEnv + AddSwiNameToDecodeTab IntOn + AddSwiNameToDecodeTab IntOff + AddSwiNameToDecodeTab CallBack + AddSwiNameToDecodeTab EnterOS + AddSwiNameToDecodeTab BreakPt + AddSwiNameToDecodeTab BreakCtrl + AddSwiNameToDecodeTab UnusedSWI + AddSwiNameToDecodeTab UpdateMEMC + AddSwiNameToDecodeTab SetCallBack + AddSwiNameToDecodeTab Mouse + + AddSwiNameToDecodeTab Heap + AddSwiNameToDecodeTab Module + AddSwiNameToDecodeTab Claim + AddSwiNameToDecodeTab Release + AddSwiNameToDecodeTab ReadUnsigned + AddSwiNameToDecodeTab GenerateEvent + AddSwiNameToDecodeTab ReadVarVal + AddSwiNameToDecodeTab SetVarVal + AddSwiNameToDecodeTab GSInit + AddSwiNameToDecodeTab GSRead + AddSwiNameToDecodeTab GSTrans + AddSwiNameToDecodeTab BinaryToDecimal + AddSwiNameToDecodeTab FSControl + AddSwiNameToDecodeTab ChangeDynamicArea + AddSwiNameToDecodeTab GenerateError + AddSwiNameToDecodeTab ReadEscapeState + AddSwiNameToDecodeTab EvaluateExpression + AddSwiNameToDecodeTab SpriteOp + AddSwiNameToDecodeTab ReadPalette + AddSwiNameToDecodeTab ServiceCall + AddSwiNameToDecodeTab ReadVduVariables + AddSwiNameToDecodeTab ReadPoint + AddSwiNameToDecodeTab UpCall + AddSwiNameToDecodeTab CallAVector + AddSwiNameToDecodeTab ReadModeVariable + AddSwiNameToDecodeTab RemoveCursors + AddSwiNameToDecodeTab RestoreCursors + AddSwiNameToDecodeTab SWINumberToString + AddSwiNameToDecodeTab SWINumberFromString + AddSwiNameToDecodeTab ValidateAddress + AddSwiNameToDecodeTab CallAfter + AddSwiNameToDecodeTab CallEvery + AddSwiNameToDecodeTab RemoveTickerEvent + AddSwiNameToDecodeTab InstallKeyHandler + AddSwiNameToDecodeTab CheckModeValid + AddSwiNameToDecodeTab ChangeEnvironment + AddSwiNameToDecodeTab ClaimScreenMemory + AddSwiNameToDecodeTab ReadMonotonicTime + AddSwiNameToDecodeTab SubstituteArgs + AddSwiNameToDecodeTab PrettyPrint + AddSwiNameToDecodeTab Plot + AddSwiNameToDecodeTab WriteN + AddSwiNameToDecodeTab AddToVector + AddSwiNameToDecodeTab WriteEnv + AddSwiNameToDecodeTab ReadArgs + AddSwiNameToDecodeTab ReadRAMFsLimits + AddSwiNameToDecodeTab ClaimDeviceVector + AddSwiNameToDecodeTab ReleaseDeviceVector + AddSwiNameToDecodeTab DelinkApplication + AddSwiNameToDecodeTab RelinkApplication + AddSwiNameToDecodeTab HeapSort + AddSwiNameToDecodeTab ExitAndDie + AddSwiNameToDecodeTab ReadMemMapInfo + AddSwiNameToDecodeTab ReadMemMapEntries + AddSwiNameToDecodeTab SetMemMapEntries + AddSwiNameToDecodeTab AddCallBack + AddSwiNameToDecodeTab ReadDefaultHandler + AddSwiNameToDecodeTab SetECFOrigin + AddSwiNameToDecodeTab SerialOp + AddSwiNameToDecodeTab ReadSysInfo + AddSwiNameToDecodeTab Confirm + AddSwiNameToDecodeTab ChangedBox + AddSwiNameToDecodeTab CRC + AddSwiNameToDecodeTab ReadDynamicArea + AddSwiNameToDecodeTab PrintChar + AddSwiNameToDecodeTab ChangeRedirection + AddSwiNameToDecodeTab RemoveCallBack + AddSwiNameToDecodeTab FindMemMapEntries + AddSwiNameToDecodeTab SetColour + AddSwiNameToDecodeTab ClaimSWI ; These two are not actually + AddSwiNameToDecodeTab ReleaseSWI ; kernel SWIs. + AddSwiNameToDecodeTab Pointer + AddSwiNameToDecodeTab ScreenMode + AddSwiNameToDecodeTab DynamicArea + AddSwiNameToDecodeTab AbortTrap + AddSwiNameToDecodeTab Memory + AddSwiNameToDecodeTab ClaimProcessorVector + AddSwiNameToDecodeTab Reset + AddSwiNameToDecodeTab MMUControl + = 0 + + [ SwisInSystemTable+1 <> MaxSwi + ! 1, :CHR:10:CC::CHR:13:CC::CHR:7:CC::CHR:7:CC:"Swi Disassembly table not consistent with despatch table":CC::CHR:10:CC::CHR:13 + ] + +convswitab = "OS",0 + +Conversion_Swi_Names + AddSwiNameToDecodeTab ConvertHex1 + AddSwiNameToDecodeTab ConvertHex2 + AddSwiNameToDecodeTab ConvertHex4 + AddSwiNameToDecodeTab ConvertHex6 + AddSwiNameToDecodeTab ConvertHex8 + AddSwiNameToDecodeTab ConvertCardinal1 + AddSwiNameToDecodeTab ConvertCardinal2 + AddSwiNameToDecodeTab ConvertCardinal3 + AddSwiNameToDecodeTab ConvertCardinal4 + AddSwiNameToDecodeTab ConvertInteger1 + AddSwiNameToDecodeTab ConvertInteger2 + AddSwiNameToDecodeTab ConvertInteger3 + AddSwiNameToDecodeTab ConvertInteger4 + AddSwiNameToDecodeTab ConvertBinary1 + AddSwiNameToDecodeTab ConvertBinary2 + AddSwiNameToDecodeTab ConvertBinary3 + AddSwiNameToDecodeTab ConvertBinary4 + AddSwiNameToDecodeTab ConvertSpacedCardinal1 + AddSwiNameToDecodeTab ConvertSpacedCardinal2 + AddSwiNameToDecodeTab ConvertSpacedCardinal3 + AddSwiNameToDecodeTab ConvertSpacedCardinal4 + AddSwiNameToDecodeTab ConvertSpacedInteger1 + AddSwiNameToDecodeTab ConvertSpacedInteger2 + AddSwiNameToDecodeTab ConvertSpacedInteger3 + AddSwiNameToDecodeTab ConvertSpacedInteger4 + AddSwiNameToDecodeTab ConvertFixedNetStation + AddSwiNameToDecodeTab ConvertNetStation + AddSwiNameToDecodeTab ConvertFixedFileSize + AddSwiNameToDecodeTab ConvertFileSize + = 0 + ALIGN + + +SWINotInTable + SUB r11, r0, #OS_ConvertHex1 + CMP r11, #OS_ConvertFileSize - OS_ConvertHex1 + BHI %FT10 + + MOV r0, r11 + addr r11, Conversion_Swi_Names + BL GetStringFromTable + B AddStringAndExit + +10 + ADR r11, %FT01 + CMP r0, #OS_ConvertStandardDateAndTime + ADREQ r11, %FT05 + CMP r0, #OS_ConvertDateAndTime + ADREQ r11, %FT06 + B AddStringAndExit +01 + = "Undefined", 0 + +othersysswitab + = "OS", 0 +05 + = "ConvertStandardDateAndTime", 0 +06 + = "ConvertDateAndTime", 0 + = 0 + +02 + = "User", 0 + +andfiddleaboutwithWriteI + = "OS", 0 + = "WriteI", 0 + = 0 +03 + = "WriteI+", 0 + + ALIGN + +NotASystemSWI + Push "r9, r12" + BIC r10, r0, #Module_SWIChunkSize-1 + ModSWIHashvalOffset r9, r10 + LDR r9, [r9, #ModuleSWI_HashTab] +lohc + CMP r9, #0 + BEQ giveemaboringname + LDR r12, [r9, #ModSWINode_Number] + CMP r10, r12 + LDRNE r9, [r9, #ModSWINode_Link] + BNE lohc + + LDR r12, [r9, #ModSWINode_MListNode] + LDR r9, [r12, #Module_code_pointer] + LDR r10, [r9, #Module_NameTable] + LDR r14, [r9, #-4] ; get module size + CMP r10, #1 ; must be non-zero + CMPCS r14, r10 ; and must be within code + BLS trymodule_SWIdecode_code + ADD r11, r10, r9 + Pull "r9, r12" + BL AddString + MOV r10, #"_" + BL AddChar + AND r0, r0, #Module_SWIChunkSize-1 + Push "r0" + BL GetStringFromTable + Pull "r0" + BVC AddStringAndExit + B AddNumericBit ; not in table + +trymodule_SWIdecode_code + LDR r10, [r9, #Module_NameCode] + TST r10, #12,2 ; test bottom 2 bits and clear carry + CMPEQ r10, #1 ; must be non-zero + CMPCS r14, r10 ; and must be within code + BLS usethemoduletitle + +; got r0 is SWI number, r1 buffer pointer, r2 is buffer offset to use +; r3 is buffer limit + CMP r2, r3 + BGE dont_confuse_the_poor_dears + Push "r4-r6" + AND r0, r0, #Module_SWIChunkSize - 1 + LDR r12, [r12, #Module_incarnation_list] + ADDS r12, r12, #Incarnation_Workspace ; force V clear + MOV lr, pc + ADD pc, r9, r10 + Pull "r4-r6, r9, r12" + BVC ExitSwiSwi + +dont_confuse_the_poor_dears + [ International + Push "r0" + ADRL r0, BufferOFloError + BL TranslateError + MOV r9,r0 + Pull "r0" + | + ADRL r9, BufferOFloError + ] + ORR r12, r12, #V_bit + B ExitSwiSwi + +usethemoduletitle + LDR r10, [r9, #Module_Title] + ADD r11, r10, r9 + Pull "r9, r12" + BL AddString + MOV r10, #"_" + BL AddChar + AND r0, r0, #Module_SWIChunkSize-1 + B AddNumericBit + +giveemaboringname ; not found anywhere interesting + Pull "r9, r12" + ADR r11, %BT02 + B AddStringAndExit + +Swi_Is_WriteI + ADR r11, %BT03 + BL AddString + + AND r0, r0, #255 + CMP r0, #32 + BLT AddNumericBit + CMP r0, #127 + BCS AddNumericBit + MOV r10, #"""" + BL AddChar + MOV r10, r0 + BL AddChar + MOV r10, #"""" + BL AddChar + B ExitSwiSwi + +AddNumericBit + Push "r1, r2" + ADD r1, r1, r2 ; point at remaining buffer + SUB r2, r3, r2 ; buffer left + SWI XOS_BinaryToDecimal + ORRVS r12, r12, #V_bit + MOVVS r9, r0 + MOV r0, r2 + Pull "r1, r2" + ADD r2, r2, r0 ; adjust chars given + B ExitSwiSwi + +; AddChar +; +; in: R1 = buffer pointer +; R2 = buffer position +; R3 = buffer size +; R10 = character +; +; out: If overflow, V_bit set in R12, and R9 -> error +; PSR preserved + +AddChar ROUT + CMP r2, r3 + BGE %FT01 + STRB r10, [r1, r2] + ADD r2, r2, #1 + MOVS pc, lr + +01 + [ International + Push "r0,lr" + ADRL r0, BufferOFloError + BL TranslateError + MOV r9,r0 + Pull "r0,lr" + | + ADRL r9, BufferOFloError + ] + ORR r12, r12, #V_bit + MOVS pc, lr + +; AddString +; +; in: R11 points at string to add +; +; out: R10, R11 corrupted + +AddString ENTRY +01 + LDRB r10, [r11], #1 + CMP r10, #0 + BLNE AddChar + BNE %BT01 + EXIT + +; GetStringFromTable +; +; in: R0 is table offset +; R11 points at first SWI name in table +; +; out: R11 -> string or V set if not in table +; R0, R10 corrupted + +GetStringFromTable ROUT + LDRB r10, [r11] + CMP r10, #0 + ORREQS pc, lr, #V_bit ; end of table + SUBS r0, r0, #1 + BICMIS pc, lr, #V_bit +01 + LDRB r10, [r11], #1 + CMP r10, #0 + BNE %BT01 + B GetStringFromTable + +;*********************************************************************** + +; R1 pointer to name terminated by char <= " " +; return R0 as SWI number + +SWINumberFromString_Code ENTRY "r1,r2" + + TEQP pc, #SVC_mode ; enable interrupts + LDRB R10, [R1] + CMP R10, #"X" + MOVEQ R0, #Auto_Error_SWI_bit + ADDEQ R1, R1, #1 + MOVNE R0, #0 + + MOV r10, #0 ; indicate doing OS SWIs, so disallow OS_<number> + ADRL r11, OS_Prefix ; point at system table + BL LookForSwiName + BVC GotTheSWIName + + BIC r0, r0, #255 + ADRL r11, othersysswitab + BL LookForSwiName + ORRVC r0, r0, #OS_ConvertStandardDateAndTime + BVC GotTheSWIName + + BIC r0, r0, #255 + ADRL r11, convswitab + BL LookForSwiName + ADDVC r0, r0, #OS_ConvertHex1 + BVC GotTheSWIName + + BIC r0, r0, #255 + ADRL r11, andfiddleaboutwithWriteI + BL LookForSwiName + ORRVC r0, r0, #OS_WriteI + BVC GotTheSWIName + + MOV r12, #Module_List +10 + LDR r12, [r12] + CMP r12, #0 + BEQ this_swi_nexiste_pas + LDR r10, [r12, #Module_code_pointer] + LDR r11, [r10, #Module_SWIChunk] ; first validate swi chunk + BICS r11, r11, #Auto_Error_SWI_bit + BEQ %BT10 ; SWI chunk zero not allowed + TST r11, #Module_SWIChunkSize-1 + TSTEQ r11, #&FF000000 + BNE %BT10 ; invalid SWI chunk + + LDR r2, [r10, #-4] + LDR r11, [r10, #Module_SWIEntry] + TST r11, #12,2 ; test bottom 2 bits and clear carry + CMPEQ r11, #1 ; must be non-zero + CMPCS r2, r11 ; and must be within code + BLS %BT10 + + LDR r11, [r10, #Module_NameTable] + CMP r11, #1 ; must be non-zero + CMPCS r2, r11 ; and must be within code + BLS %FT20 ; if no name table, try name code + + ADD r11, r10, r11 + BIC r0, r0, #Module_SWIChunkSize-1 + BL LookForSwiName + BVS %FT20 +gotmodulejobbie + LDR r11, [r10, #Module_SWIChunk] + BIC r11, r11, #Auto_Error_SWI_bit + ORR r0, r0, r11 + B GotTheSWIName + +; call module code if it exists + +20 + LDR r11, [r10, #Module_NameCode] + TST r11, #12,2 ; test bottom 2 bits and clear carry + CMPEQ r11, #1 ; must be non-zero + CMPCS r2, r11 ; and must be within code + BLS %FT30 ; try <module-title>_<numeric> + +; got R1 string pointer + + Push "r0-r6, r12" + MOV r0, #-1 ; indicate string being given + LDR r12, [r12, #Module_incarnation_list] + ADDS r12, r12, #Incarnation_Workspace ; force V clear + MOV lr, pc + ADD pc, r11, r10 + ADDS r2, r0, #0 ; NB clears V for SWI return + Pull "r0" + ADDPL r0, r0, r2 + Pull "r1-r6, r12" + BPL gotmodulejobbie + +; check against module title + +30 + LDR r11, [r10, #Module_Title] + ADD r11, r10, r11 + Push r10 + MOV r10, #1 ; indicate only check for prefix_numeric + BL LookForSwiName + Pull r10 + BVS %BT10 + B gotmodulejobbie + +this_swi_nexiste_pas + SETV +GotTheSWIName + PullEnv + ADRVS r0, ErrorBlock_NoSuchSWI2 + [ International + Push "lr",VS + BLVS TranslateError + Pull "lr",VS + ] + B SLVK_TestV + + MakeErrorBlock NoSuchSWI2 + + +LookForSwiName ROUT +; R11 points at name table +; R1 points at name +; R10 = 0 => allow only prefix_name (for OS_SWI) +; R10 = 1 => allow only prefix_numeric (for checking moduletitle_numeric) +; otherwise => allow prefix_name or prefix_numeric +; return R0 ORed with number if found +; V set if not + + Push "r8,r9, r12, lr" + MOV r12, #0 ; offset in name + +; first check that prefix matches +10 + LDRB r14, [r1, r12] + CMP r14, #" " ; if we terminate before we get an "_", then fail + BLE %FT50 + ADD r12, r12, #1 + LDRB r9, [r11], #1 + CMP r9, r14 + BEQ %BT10 + + CMP r14, #"_" ; check correct terminators + CMPEQ r9, #0 + BNE %FT50 + +; prefix OK: scan table for rest of name + + TEQ r10, #1 ; if doing modulename_numeric + BEQ CheckForNumericPostFix ; don't look for any names + MOV r8, r12 ; keep pointer to after prefix +20 + LDRB r14, [r11], #1 + CMP r14, #0 + BEQ CheckForNumericPostFix +30 + LDRB r9, [r1, r12] + ADD r12, r12, #1 + CMP r14, #0 + CMPEQ r9, #" " + Pull "r8,r9, r12, lr", LE + BICLES pc, lr, #V_bit + + CMP r9, r14 + LDREQB r14, [r11], #1 + BEQ %BT30 + + MOV r12, r8 ; restore name pointer + ADD r0, r0, #1 ; step SWI number +40 + CMP r14, #0 ; find end of failed name + LDRNEB r14, [r11], #1 + BNE %BT40 + B %BT20 + +50 + Pull "r8,r9, r12, lr" ; restore registers + ORRS pc, lr, #V_bit ; and exit V set + +CheckForNumericPostFix +; [R1, R12] points at postfix + Push "r0-r2" + ADD r1, r1, r12 + CMP r10, #0 ; if OS SWI then EQ,VC else NE,VC + SETV EQ ; if OS SWI then VS else VC + MOVVC r0, #10 + (1 :SHL: 29) + MOVVC r2, #Module_SWIChunkSize -1 + SWIVC XOS_ReadUnsigned + Pull "r0" + BIC r0, r0, #Module_SWIChunkSize -1 + ADDVC r0, r0, r2 + Pull "r1, r2, r8,r9, r12, pc" + + END diff --git a/s/Super1 b/s/Super1 new file mode 100644 index 0000000000000000000000000000000000000000..16e1a3038323e7a4afeadb8f65f419749c72e3f5 --- /dev/null +++ b/s/Super1 @@ -0,0 +1,99 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + TTL => Super1 + +CliDPrompt = "CLI$Prompt",0 +DefaultPrompt = "*" + ALIGN + +StartSuper ; Start entry for UtilModule + BL DEFHAN ; set error handler in case spooling + [ International ; We are in USR mode and have no stack ... + ADR R0,KernelMessagesBlock+4 + ADR R1,%FT11 + MOV R2,#0 + SWI XMessageTrans_Lookup + MOVVS R2,R1 +01 + LDRB R0,[R2],#1 + CMP R0,#31 + SWIGT OS_WriteC + BGT %BT01 + SWI OS_NewLine + SWI OS_NewLine + B CLILOP +11 + = "Supervisor",0 + ALIGN + | + SWI OS_WriteS + = "Supervisor",10,13,10,13,0 + ALIGN + B CLILOP + ] + + +CLIEXIT BL DEFHN2 ; restore all our world + +GOSUPV TEQP PC, #0 + BL DEFHAN ; including error handler! + +CLILOP ROUT + + ADR R0, CliDPrompt ; try looking it up + LDR R1, =GeneralMOSBuffer + MOV R2, #?GeneralMOSBuffer + MOV R3, #0 + MOV R4, #VarType_Expanded + SWI XOS_ReadVarVal + ADRVS r1, DefaultPrompt ; gnot gthere or gnaff + MOVVS r2, #1 + MOV r0, r1 + MOV r1, r2 + SWI OS_WriteN + LDR R0, =GeneralMOSBuffer + LDR R1, =?GeneralMOSBuffer-1 + MOV R2, #" " + MOV R3, #255 + SWI OS_ReadLine + BCS ESCAPE + MOV lr, pc ; construct lr for wallies to return to + SWI XOS_CLI + BVC CLILOP + + SWI XOS_NewLine + BL PrintError + B CLILOP + + LTORG + +ESCAPE MOV R0, #&7E + SWI OS_Byte ; May yield error + [ International + SWI XOS_EnterOS ; GO into SVC mode to get some stack + SWI OS_NewLine + BLVC WriteS_Translated + = "Escape:Escape",10,13,0 + ALIGN + TEQP PC,#0 ; Back to user mode. + MOV R0,R0 + | + SWI OS_WriteS + = 10,13, "Escape", 10,13, 0 + ALIGN + ] + B CLILOP + + END diff --git a/s/SysComms b/s/SysComms new file mode 100644 index 0000000000000000000000000000000000000000..4f1e180a6e9d8db38646fb6b67135a33b110da4d --- /dev/null +++ b/s/SysComms @@ -0,0 +1,1725 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + TTL => SysComms , the system commands file: Load save dump etc. + +TAB * 9 +FSUTtemp RN r10 + + GBLS UtilRegs ; Save the same set so we can common up exits +UtilRegs SETS "r7-r10" ; Sam will preserve r0-r6 on module star entry + +AnyNoParms * &FF0000 ; Between 0 and 255 parameters: all flags clear + + +SysCommsModule ROUT + +Module_BaseAddr SETA SysCommsModule + + & 0 ; No Start entry + & 0 ; Not initialised + & 0 + & 0 + & 0 + & SysTitle-SysCommsModule + & SCHCTab-SysCommsModule + & 0 + & 0 + & 0 + & 0 + [ International_Help <> 0 + & MessageFileName-SysCommsModule + | + & 0 + ] + +SysTitle + = "$SystemName", 9 + [ :LEN: "$SystemName" < 8 + = 9 + ] + = "$VersionNo", 0 + +SCHCTab ; Alphabetically ordered so it's easier to find stuff + + Command Append, 1, 1, International_Help + Command Build, 1, 1, International_Help + Command Close, 0, 0, International_Help + Command Create, 4, 1, International_Help + Command Delete, 1, 1, International_Help + Command Dump, 3, 1, International_Help + Command Exec, 1, 0, International_Help + Command FX, 5, 1, International_Help ; 1-3 parms, but up to 2 commas may be there + Command GO, 255, 0, International_Help +HelpText + Command Help, 255, 0, International_Help + Command Key, 255, 1, International_Help + Command Load, 2, 1, International_Help ; Fudge order for compatibility (*L.) + Command List, 3, 1, International_Help + Command Opt, 2, 0, International_Help + Command Print, 1, 1, International_Help + Command Quit, 0, 0, International_Help + Command Remove, 1, 1, International_Help + Command Save, 6, 2, International_Help ; *SAVE Fn St + Le Ex Lo (compatibility) + Command Shadow, 1, 0, International_Help + Command Spool, 1, 0, International_Help + Command SpoolOn, 1, 0, International_Help + Command TV, 3, 0, International_Help + Command Type, 3, 1, International_Help ; -file fred -tabexpand + = 0 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Most help and syntax messages go together to save ALIGNing wastage + + GET s.MosDict + GET s.TMOSHelp + +GO_Syntax * Module_BaseAddr +Help_Syntax * Module_BaseAddr + + ALIGN ; Just the one, please ! + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +HelpBufferSize * 512 + +Help_Code ROUT ; got R0 ptr to commtail, R1 no parameters + Push "r7, lr" + +; first pass round a service call to let wally user code do things. + MOV r2, r1 + MOV r1, #Service_Help + BL Issue_Service + CMP r1, #0 + Pull "r7, pc", EQ + + CMP r2, #0 + MOVNE r6, r0 + addr r6, HelpText, EQ + + MOV r0, #117 ; Read current VDU status + SWI XOS_Byte ; Won't fail + SWI XOS_WriteI+14 ; paged mode on. + Pull "r7, pc", VS ; Wrch can fail + + Push "r1" ; Save page mode state + MOV r0, r6 + MOV r7, #0 ; anyhelpdoneyet flag + +DoHelpOnNextKeyWord +; now look at syscomms module. + addr r1, SysCommsModule + BL ShowHelpInModule + BVS %FT67 + +; now try looking round the modules. + MOV R2, #Module_List +11 LDR R2, [R2] + CMP R2, #0 + BEQ tryagainstmodulename + LDR R1, [R2, #Module_code_pointer] + LDR R12, [R2, #Module_incarnation_list] + ADD R12, R12, #Incarnation_Workspace + BL ShowHelpInModule + BVS %FT67 + B %BT11 + +tryagainstmodulename + Push "r0" + MOV r1, #0 + MOV r2, #0 +tamn_loop + MOV r0, #ModHandReason_GetNames + SWI XOS_Module + Pull r0, VS + BVS %FT02 + LDR r0, [stack] ; kword ptr + Push "r1, r2" + LDR r4, [r3, #Module_Title] + CMP r4, #0 + BEQ tamn_notit + ADD r4, r4, r3 + MOV R5, #0 ; offset +tamn_chk + LDRB R1, [R0, R5] + LDRB R2, [R4, R5] + CMP R1, #32 + CMPLE R2, #32 + BLE tamn_dojacko ; matched at terminator + UpperCase R1, R6 + UpperCase R2, R6 + CMP R1, R2 + ADDEQ R5, R5, #1 + BEQ tamn_chk + RSBS R2, R2, #33 ; only if not terminated + CMPLE R1, #"." ; success if abbreviation + BNE tamn_notit +tamn_dojacko + BL ModuleJackanory + STRVS r0, [stack, #2*4] +tamn_notit + Pull "r1, r2" + Pull r0, VS + BVS %FT67 + CMP r2, #0 + ADDNE r1, r1, #1 + MOVNE r2, #0 + B tamn_loop + +02 LDRB R1, [R0], #1 + CMP R1, #"." + CMPNE R1, #" " + BGT %BT02 + CMP R1, #" " + BLT %FT67 +66 LDRB R1, [R0], #1 + CMP R1, #" " + BEQ %BT66 + SUBGT R0, R0, #1 + BGT DoHelpOnNextKeyWord +67 BLVC testnohelpdone + Pull "R1" + MOV r6, pc + TST R1, #5 + SWIEQ XOS_WriteI+15 ; paged mode off + TEQP PC, r6 ; restore V state + MOVNV r0, r0 + Pull "r7, PC" + +testnohelpdone + CMP r7, #0 + MOVNES pc, lr + MOV r7, lr + [ International + BL WriteS_Translated + = "NoHelp:No help found.",10,13,0 + ALIGN + | + SWI XOS_WriteS + = "No help found.",10,13,0 + ALIGN + ] + MOV pc, r7 + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +ModuleJackanory ROUT ; give summary of info in module @ r3 + Push "r0, lr" + CheckSpaceOnStack HelpBufferSize+256, modjack_noroom, r6 + SUB stack, stack, #HelpBufferSize + MOV r2, r3 + LDR r3, [r2, #Module_Title] + CMP r3, #0 + ADDNE r3, r3, r2 + ADREQL r3, NoRIT + BL PrintMatch + BVS %FT99 + LDR r3, [r2, #Module_HelpStr] + CMP r3, #0 + BEQ nohstring + STMDB sp!, {r2, r3} + MOV r0, #0 ; Try our message file before Global. + LDR r0, [r0, #KernelMessagesBlock] + TEQ r0, #0 + ADRNE r0, KernelMessagesBlock+4 + ADRL r1, modjack_hstr + MOV r2, #0 + SWI XMessageTrans_Lookup + SWIVC XMessageTrans_Dictionary + MOVVC r1, r0 + MOVVC r0, r2 + SWIVC XOS_PrettyPrint + SWIVC XOS_WriteI + 32 + LDMIA sp!, {r2, r3} + ADDVC r0, r2, r3 + SWIVC XOS_PrettyPrint + BVS %FT99 +nohstring + MOV r3, stack ; buffer address + MOV r1, #0 ; flags for commands + ADRL r0, modjack_comms + BL OneModuleK_Lookup + MOVVC r1, #FS_Command_Flag + ADRVCL r0, modjack_filecomms + BLVC OneModuleK_Lookup + MOVVC r1, #Status_Keyword_Flag + ADRVCL r0, modjack_confs + BLVC OneModuleK_Lookup + MOVVC r1, #-1 + ADRVCL r0, modjack_aob + BLVC OneModuleK_Lookup +99 ADD stack, stack, #HelpBufferSize + SWIVC XOS_NewLine +98 STRVS r0, [stack] + Pull "r0, PC" +modjack_noroom + ADRL r0, ErrorBlock_StackFull + [ International + BL TranslateError + | + SETV + ] + B %BT98 + +OneModuleK_Lookup + STMDB sp!, {r1-r3, lr} + MOV r1, r0 + MOV r0, #0 ; Try our message file before Global. + LDR r0, [r0, #KernelMessagesBlock] + TEQ r0, #0 + ADRNE r0, KernelMessagesBlock+4 + MOV r2, #0 + SWI XMessageTrans_Lookup + MOVVC r0, r2 + LDMIA sp!, {r1-r3, lr} + MOVVS pc, lr + B OneModuleK + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Print match header, keyword @ r3 + +PrintMatch ROUT + [ International + Push "r0-r4, lr" + SWI XOS_ReadEscapeState + BLCS AckEscape + + SWI XOS_WriteI+CR + MOVVC r4,r3 + BL WriteS_Translated_UseR4 + = "HelpFound:==> Help on keyword %0",0 + ALIGN + SWIVC XOS_NewLine + STRVS R0, [stack] + MOV R7, #1 + Pull "r0-r4, PC" + | + Push "r0-r2, lr" + SWI XOS_ReadEscapeState + BLCS AckEscape + ADRVC r0, HelpMatchString + MOV r2, r3 + SWIVC XOS_PrettyPrint ; print matched keyword + SWIVC XOS_NewLine + STRVS R0, [stack] + MOV R7, #1 + Pull "r0-r2, PC" + +HelpMatchString = CR, "==> Help on keyword ",TokenEscapeChar,Token0, 0 + ALIGN + ] + +;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +ShowHelpInModule ROUT ; take module ptr in R1, give relevant help. + + Push "R2-R6, lr" + + LDR R2, [R1, #Module_HC_Table] + CMP R2, #0 + Pull "R2-R6, PC", EQ + + ADD R2, R1, R2 ; point at table +fujjnulltables + LDRB R5, [R2] + CMP R5, #0 + BNE %FT21 + Pull "R2-R6, PC" ; finished + +21 MOV R3, #0 ; offset +22 LDRB R4, [R0, R3] + LDRB R5, [R2, R3] + CMP R4, #32 + CMPLE R5, #32 + BLE %FT25 ; matched at terminator + UpperCase R4, R6 + UpperCase R5, R6 + CMP R4, R5 + ADDEQ R3, R3, #1 + BEQ %BT22 + RSBS R5, R5, #33 ; only if not terminated + CMPLE R4, #"." ; success if abbreviation + BEQ %FT25 + ADD R2, R2, R3 +23 LDRB R5, [R2], #1 + CMP R5, #32 + BGT %BT23 ; skip to terminator + ADD R2, R2, #3 + BIC R2, R2, #3 ; ALIGN +24 ADD R2, R2, #16 + B fujjnulltables + +25 ADD R2, R2, R3 + SUB R3, R2, R3 ; hang on to keyword ptr +28 LDRB R5, [R2], #1 + CMP R5, #0 + BNE %BT28 ; demand null terminator + ADD R2, R2, #3 + BIC R2, R2, #3 ; ALIGN + + LDR R5, [R2, #12] ; get help offset + CMP R5, #0 + BEQ %BT24 ; no help. + + BL PrintMatch ; r3 -> keyword + Pull "R2-R6, PC", VS + + LDR R6, [R2, #4] ; get info word + TST R6, #Help_Is_Code_Flag + BNE CallHelpKeywordCode + + Push "R0-r3" + TST R6, #International_Help + BEQ %FT35 + SUB sp, sp, #16 + LDR r2, [r1, #-4] + LDR r0, [r1, #Module_MsgFile] + TST r0, #12,2 + CMPEQ r0, #1 + CMPCS r2, r0 + MOVLS r0, #0 + BLS %FT29 + ADD r1, r1, r0 + MOV r2, #0 + MOV r0, sp + SWI XMessageTrans_OpenFile + MOVVS r0, #0 +29 MOV r6, r0 + LDR r1, [sp, #16 + 1 * 4] + ADD r1, r5, r1 + MOV r2, #0 + SWI XMessageTrans_Lookup + ADDVS r2, r0, #4 + SWI XMessageTrans_Dictionary + MOVVS r0, #0 + MOV r1, r0 + MOV r0, r2 + LDR r2, [sp, #16 + 3 * 4] + SWI XOS_PrettyPrint ; Error check not done yet + SWI XOS_NewLine + MOV r0, r6 + LDR r2, [sp, #16 + 2 * 4] + LDR R5, [r2, #8] + CMP R5, #0 + BEQ %FT30 ; Should print default message? + LDR r1, [sp, #16 + 1 * 4] + ADD r1, r5, r1 + MOV r2, #0 + SWI XMessageTrans_Lookup + ADDVS r2, r0, #4 + SWI XMessageTrans_Dictionary + MOVVS r0, #0 + MOV r1, r0 + MOV r0, r2 + LDR r2, [sp, #16 + 3 * 4] + SWI XOS_PrettyPrint ; No Error check!!! + SWI XOS_NewLine +30 MOVS r0, r6 + SWINE XMessageTrans_CloseFile + ADD sp, sp, #16 + Pull "R0-R3" + B %BT24 + +35 ADD R0, R5, R1 + MOV r1, #0 + MOV r2, r3 + SWI XOS_PrettyPrint + SWIVC XOS_NewLine + STRVS R0, [stack] + Pull "R0-r3" + Pull "R2-R6, PC", VS + B %BT24 + +helpnostack + ADRL R0, ErrorBlock_StackFull + [ International + BL TranslateError + ] + Pull "R2-R6, lr" + ORRS PC, lr, #V_bit + +CallHelpKeywordCode + CheckSpaceOnStack HelpBufferSize+256, helpnostack, R6 + SUB stack, stack, #HelpBufferSize + Push "R0-R2, R12" ; code allowed to corrupt R1-R6, R12 + MOV R2, R1 + ADD R0, stack, #4*4 + MOV R1, #HelpBufferSize + MOV lr, PC ; R12 set by our caller + ADD PC, R5, R2 + BVS hkc_threwawobbly + CMP R0, #0 + MOVNE r1, #0 + SWINE XOS_PrettyPrint + SWIVC XOS_NewLine +hkc_threwawobbly + STRVS R0, [stack] + Pull "R0-R2, R12" + ADD stack, stack, #HelpBufferSize + BVC %BT24 + Pull "R2-R6, PC" + +;************************************************************************** + +GO_Code ROUT + Push "R7, lr" + MOV R4, R0 + BL SPACES + CMP R5, #13 + TEQNE R5, #";" + MOVLS R7, #UserMemStart + BCC GOEX + BEQ GOEX0 + BL ReadHex + MOVVS R7, #UserMemStart + BL SPACES +GOEX0 TEQ R5, #";" + BLEQ SPACES +GOEX SUB R1, R4, #1 + MOV R0, #FSControl_StartApplication + MOV R2, R7 + ADR R3, GOSMUDGE + SWI XOS_FSControl + Pull "R7, PC", VS + + LDR sp_svc, =SVCSTK ; remove supervisor stuff + BICS PC, R7, #ARM_CC_Mask + +GOSMUDGE = "GO ", 0 + ALIGN + +ReadHex Push "R0-R2, lr" + MOV R0, #16 + SUB R1, R4, #1 + SWI XOS_ReadUnsigned + MOV R4, R1 + MOV R7, R2 + Pull "R0-R2, PC" + +SPACES LDRB R5, [R4], #1 + TEQ R5, #" " + BEQ SPACES + MOV PC, R14 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Close_Code ENTRY + + MOV R0, #0 + MOV R1, #0 + SWI XOS_Find + EXIT + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +FX_Code ENTRY + + MOV R1, #0 + MOV R2, #0 + Push "R1-R2" ; Put optional parms (default 0, 0) on stack + MOV R1, R0 + MOV R0, #10 + SWI XOS_ReadUnsigned + Push "R2" ; Pulled as R0 when OSByte called + BVS %FT90 + BL %FT10 + +TV_EntryPoint + + MOV R0, #10 + SWI XOS_ReadUnsigned + BVS %FT90 + STR R2, [stack, #4] + BL %FT10 + MOV R0, #10 + SWI XOS_ReadUnsigned + BVS %FT90 + STR R2, [stack, #8] + + BL %FT10 ; check for EOL: goes to 05 if end + ADR R0, ErrorBlock_TooManyParms + [ International + BL TranslateError + | + SETV + ] +90 ADD sp, sp, #12 ; Error before we'd pulled r0-r2 for osbyte + EXIT + + MakeErrorBlock TooManyParms + +05 + Pull "R0-R2" + SWI XOS_Byte + EXIT + +; Skip leading spaces and optional comma + +10 LDRB R2, [R1], #1 + CMP R2, #" " + BEQ %BT10 + CMP R2, #"," + MOVEQ PC, lr ; Let ReadUnsigned strip leading spaces. + CMP R2, #CR + CMPNE R2, #LF + CMPNE R2, #0 + BEQ %BT05 ; Terminated command, so execute the osbyte + SUB R1, R1, #1 ; Back to first char + MOV PC, lr + + +TV_Code ALTENTRY ; must be same as FX_Code ! + + MOV R1, #144 ; OSBYTE number + MOV R2, #0 + MOV R14, #0 + Push "R1, R2, lr" + MOV R1, R0 + B TV_EntryPoint + + +Shadow_Code ENTRY + + CMP R1, #0 + MOV R1, R0 + MOV R0, #10 + (1:SHL:30) + SWINE XOS_ReadUnsigned + MOVEQ R2, #0 + EXIT VS + BL CheckEOL + BNE ShadowNaff + MOV R0, #114 + MOV R1, R2 + SWI XOS_Byte + EXIT + +ShadowNaff + ADRL R0, ErrorBlock_BadNumb + [ International + BL TranslateError + | + SETV + ] + EXIT + +CheckEOL + LDRB R0, [R1], #1 + CMP R0, #" " + CMPNE R0, #13 + CMPNE R0, #10 + CMPNE R0, #0 + MOV PC, lr + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Key_Code ENTRY + + SUB sp, sp, #32 + MOV R1, R0 + MOV r6, sp + LDR R2, %FT02 ; Load 'Key$' + STR R2, [R6], #4 + MOV R0, #10 + (1 :SHL: 29) ; default base + MOV R2, #15 ; maximum key + SWI XOS_ReadUnsigned + BVS %FT90 + CMP R2, #10 + MOVGE R4, #"1" + STRGEB R4, [R6], #1 + SUBGE R2, R2, #10 + ADD R2, R2, #"0" + STRB R2, [R6] + MOV R2, #0 + STRB R2, [R6, #1] + MOV R0, sp + MOV R3, #0 + MOV R4, #VarType_String + SWI XOS_SetVarVal + +80 ADD sp, sp, #32 + EXIT + +90 ADR r0, ErrorBlock_BadKey + [ International + BL TranslateError + | + SETV ; It needs setting here ! + ] + B %BT80 + + MakeErrorBlock BadKey +02 + DCB "Key$" ; Must be aligned + ALIGN + + LTORG + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Exec, Spool and SpoolOn share a common body + +Exec_Code ENTRY "$UtilRegs" + + MOV r3, #&40 ; OPENIN exec + MOV r4, #198 ; r0b for osbyte exec + B %FT01 + + +Spool_Code ALTENTRY + + MOV r3, #&80 ; OPENOUT spool + B %FT00 + + +SpoolOn_Code ALTENTRY + + MOV r3, #&C0 ; OPENUP spoolon + +00 MOV r4, #199 ; r0b for osbyte spool/spoolon + +01 MOV r5, r0 ; Save filename^ + MOV r6, r1 ; Save n parms + + MOV r0, r4 ; Read old exec/spool handle + MOV r1, #0 ; Write 0 as handle; we may be just closing + MOV r2, #0 ; and keep zero if open error (cf. RUN) + SWI XOS_Byte ; Won't cause error + BL CloseR1 + EXIT VS + + CMP r6, #0 ; No filename present ? + EXIT EQ ; ie. just closing down exec/spool ? + + MOV r1, r5 ; -> filename + MOV r0, r3 ; OPENIN exec/OPENUP spoolon/OPENOUT spool + BL OpenFileWithWinge + EXIT VS + + CMP r3, #&C0 ; Doing SPOOLON ? VClear + BLEQ MoveToEOF ; PTR#r1:= EXT#r1 + + MOV r0, r4 ; Write new exec/spool handle (r1) + MOV r2, #0 + SWIVC XOS_Byte ; May have got error in moving to EOF + EXIT + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; List, Print and Type share a common body + +listopt RN r2 +lastchar RN r3 +linecount RN r4 +charcount RN r5 + +lnum * 2_01 ; Line numbers +type * 2_10 ; GSREAD format ? + +filterprinting * 2_10000000 ; Bits controlling printing +linenumbering * 2_01000000 +expandtabs * 2_00100000 + +forcetbsrange * 2_00001000 +allowtbschar * 2_00000100 +unprintangle * 2_00000010 +unprinthex * 2_00000001 +unprintdot * 2_00000001 + +Print_Code ENTRY "$UtilRegs" + + MOV listopt, #0 ; No line numbers, raw ASCII + B %FT01 + + +List_Code ALTENTRY + + MOV listopt, #(filterprinting + linenumbering) + MOV linecount, #0 + B %FT00 + + +TypeArgs = "File/A,TabExpand/S",0 + ALIGN + +Type_Code ALTENTRY + + MOV listopt, #filterprinting + +00 MOV r6, r1 ; no. params + BL ReadGSFormat ; Read configured GSFormat bits + EXIT VS ; I2C could be faulty ! File not open + ORR listopt, listopt, r1 + + CMP r6, #1 + BEQ %FT01 + Push "R2, R3" + MOV R1, R0 ; args given + ADR R0, TypeArgs + LDR R2, =ArgumentBuffer + MOV R3, #256 + SWI XOS_ReadArgs + Pull "R2, R3", VS + EXIT VS + LDR R0, [R2, #4] ; tabflag + CMP R0, #0 + LDR R0, [R2, #0] ; filename ptr + Pull "R2, R3" + ORRNE listopt, listopt, #expandtabs + +01 MOV lastchar, #0 ; Reset NewLine indicator + + MOV r1, r0 ; Point to filename + MOV r0, #&40 ; han := OPENIN <filename> + BL OpenFileWithWinge + EXIT VS + +10 SWI XOS_ReadEscapeState ; Won't cause error + BCS CloseThenAckEscape + + MOV charcount, #0 ; No characters printed this line + + SWI XOS_BGet ; Get first character of line + BVS UtilityExitCloseR1 + BCS UtilityExitCloseR1 ; EOF ? + + TST listopt, #linenumbering ; Do we want to print the line number ? + BLNE LineNumberPrint + BVS UtilityExitCloseR1 + +; Doing ASCII (print) or GSREAD (type, list) ? + +30 TST listopt, #filterprinting + BEQ %FT35 + +; GSREAD format printing + + CMP r0, #CR ; CR and LF both line terminators + CMPNE r0, #LF + BEQ %FT70 + + CMP r0, #TAB + BNE %FT31 + TST listopt, #expandtabs + BEQ %FT31 + +; simple tab expansion: 8 spaces + SWI XOS_WriteS + = " ",0 + ALIGN + B %FT32 + +31 MOV lastchar, r0 + CMP r0, #"""" ; Don't display quotes in GSREAD though + CMPNE r0, #"<" ; Or left angle + BEQ %FT35 + BL PrintCharInGSFormat + +32 BVC %FT40 + +35 SWIVC XOS_WriteC + BVS UtilityExitCloseR1 + ADD charcount, charcount, #1 + +40 SWI XOS_ReadEscapeState ; Won't cause error + BCS CloseThenAckEscape + + SWI XOS_BGet ; Get another character on this line + BVS UtilityExitCloseR1 + BCC %BT30 ; Loop if not EOF + +50 TST listopt, #filterprinting + SWINE XOS_NewLine ; Terminate with NewLine if not *Print + B UtilityExitCloseR1 + + +; Hit LF or CR in GSFormat mode, decide whether to give a NewLine or not + +70 CMP r0, lastchar ; NewLine if same as last time eg LF,LF + SWIEQ XOS_NewLine + BVS UtilityExitCloseR1 + BEQ %BT10 ; Loop back and do another line + + CMP lastchar, #CR ; Don't give another NewLine if we've + CMPNE lastchar, #LF ; had CR, LF or LF, CR + MOVEQ lastchar, #0 ; Reset NewLine indicator so more will + BEQ %BT40 ; Loop and do more chars in this line + + MOV lastchar, r0 ; Save char forcing this NewLine + SWI XOS_NewLine ; Do NewLine then another line + BVC %BT10 + B UtilityExitCloseR1 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Dump_Code ENTRY "$UtilRegs" + + MOV r7, r1 ; Remember nparms + MOV r8, r0 ; Remember filename^ for below + MOV r1, r0 ; -> filename + + MOV r0, #&40 ; han := OPENIN <filename> + BL OpenFileWithWinge + EXIT VS ; File not yet open + MOV r9, r1 ; Save handle + + MOV r0, #OSFile_ReadInfo ; Read file info + MOV r1, r8 ; Restore filename^ + SWI XOS_File ; Must exist and be a file now + MOV r1, r9 ; Restore handle in case of error/exit + BVS UtilityExitCloseR1 + + CMP r4, #0 ; Zero length ? + BEQ UtilityExitCloseR1 ; Nothing to do then ! VClear + + MOV r5, r9 ; Standard place for handle below + +; Default display at load addr of file (r2) unless special + + BL ReadGSFormat ; Only interested in some bits + BVS UtilityExitCloseR1 + AND r10, r1, #forcetbsrange + allowtbschar + + CMP r2, #0 ; Command file ? + CMPEQ r3, #-1 + BEQ %FT04 + + MOV r14, r2, ASR #(32-12) ; Date stamped file ? + CMP r14, #-1 ; &FFFtttdd +04 MOVEQ r2, #0 ; Display start = 0 + + MOV r3, #0 ; Default PTR# = 0 + ; Funny order 'cos of ReadOptLoadAndExe + + CMP r7, #1 ; Only filename specified ? + BEQ %FA10 ; If so, use loadaddr and ptr=0 + + MOV r1, r8 ; Get back filename^ + BL SkipToSpace ; Over the filename + BL ReadOptionalLoadAndExec ; Abuse ! r3 := start, r2 := disp start + MOVVS r1, r5 + BVS UtilityExitCloseR1 + + ADD r2, r3, r2 ; Display offset = disparm/loadaddr+ptr + +10 Swap r2, r3 ; r2 := start, r3 := disp start + CMP r2, r4 ; Is ptr > ext ? VClear + MOVHS r1, r5 + BLHS SetErrorOutsideFile + + MOVVC r0, #OSArgs_SetPTR + MOVVC r1, r5 + SWIVC XOS_Args ; PTR#r1 := start offset + MOVVC r7, #0 + + BLVC ReadWindowWidth + BVS UtilityExitCloseR1 + + SUB r9, r0, #12+1 ; -ExtraFields (address and separators) + MOV r9, r9, LSR #2 ; Two nibbles, one space and one char per byte + + Push r10 ; Save format bits + MOV r10, #(1 :SHL: 31) ; Move 1 bit down until not zero +12 MOVS r10, r10, LSR #1 + MOVEQ r9, #1 ; Always 1 byte per line at least + BEQ %FT15 + TST r10, r9 ; Mask against r9 (byte count) + BEQ %BT12 ; Not hit yet ? + + AND r9, r9, r10, LSR #1 ; Take the bit one lower down + ORR r9, r9, r10 ; And the bit we matched. Yowzay ! + +15 MOV r1, r5 ; Get handle back + Pull r10 ; Get format back + + + SUB sp, sp, #256 ; Need temp frame now + +; Main Dump loop + +30 SWI XOS_ReadEscapeState ; Won't cause error + ADDCS sp, sp, #256 + BCS CloseThenAckEscape + +; Get line of data (r9 bytes). Keep track of how many bytes were read in r4 + + MOV r2, sp ; Temp buffer + MOV r4, #0 +35 SWI XOS_BGet ; Fall out of loop if EOF + BVS UtilityExitCloseR1_256 + STRCCB r0, [r2, r4] + ADDCC r4, r4, #1 + CMPCC r4, r9 + BCC %BT35 + + CMP r4, #0 ; No bytes to do this line ? + BEQ UtilityExitCloseR1_256 + +; Must preserve r4 till end for testing + + ANDS r7, r7, #15 ; Print title every 16 lines of data + BNE %FT54 + + + [ International + SWI XOS_NewLine + BL WriteS_Translated + DCB "Address:Address :",0 + ALIGN + | + SWI XOS_WriteS ; Print title start + DCB LF, CR + DCB "Address :", 0 + ALIGN + ] + BVS UtilityExitCloseR1_256 + + MOV r8, #0 +50 ADD r0, r3, r8 ; Print byte == LSB of + SWI XOS_WriteI+" " ; display across page + BLVC HexR0Byte + BVS UtilityExitCloseR1_256 + ADD r8, r8, #1 + CMP r8, r9 + BNE %BT50 + + CMP r9, #11 ; No room to print title end ? + BLO %FT52 ; VClear + + SWI XOS_WriteS + DCB " : ", 0 + ALIGN + BVS UtilityExitCloseR1_256 + + SUB r8, r9, #10 ; Centre 'ASCII data' over data + MOVS r8, r8, LSR #1 +51 SUBS r8, r8,#1 ; VClear + SWI XOS_WriteI+" " + BVS UtilityExitCloseR1_256 + BPL %BT51 + + [ International + BL WriteS_Translated + DCB "ASCII:ASCII data",0 + ALIGN + | + SWI XOS_WriteS + DCB "ASCII data", 0 + ALIGN + ] + +52 SWIVC XOS_NewLine + SWIVC XOS_NewLine + +54 MOVVC r0, r3 ; Print start of line address + BLVC HexR0LongWord + SWIVC XOS_WriteI+" " + SWIVC XOS_WriteI+":" + BVS UtilityExitCloseR1_256 + +; Print line of data in hex + + MOV r5, #0 +55 LDRB r0, [r2, r5] + SWI XOS_WriteI+" " + BVS UtilityExitCloseR1_256 + CMP r5, r4 ; Byte valid ? + SWICS XOS_WriteI+" " + BVS UtilityExitCloseR1_256 + SWICS XOS_WriteI+" " + BVS UtilityExitCloseR1_256 + BLCC HexR0Byte ; Alters C, so do last + BVS UtilityExitCloseR1_256 + ADD r5, r5, #1 + CMP r5, r9 + BCC %BT55 + + SWI XOS_WriteS + DCB " : ", 0 + ALIGN + BVS UtilityExitCloseR1_256 + +; Print line of data in ASCII + + MOV r5, #0 +65 LDRB r0, [r2, r5] + TST r10, #forcetbsrange ; Forcing into 00..7F ? + BICNE r0, r0, #&80 + TST r10, #allowtbschar + BEQ %FT66 + CMP r0, #&80 ; Print tbs unmolested + BHS %FT67 +66 CMP r0, #" " ; Space through twiddle are valid + RSBGES r14, r0, #&7E + MOVLT r0, #"." +67 SWI XOS_WriteC + BVS UtilityExitCloseR1_256 + ADD r5, r5, #1 + CMP r5, r4 + BCC %BT65 + + SWI XOS_NewLine + BVS UtilityExitCloseR1_256 + ADD r7, r7, #1 ; Increment line count + ADD r3, r3, r9 ; Increment display address by r9 bytes + CMP r4, r9 ; Loop till we couldn't fill a line + BEQ %BT30 + +; ............................................................................. + +UtilityExitCloseR1_256 + + ADD sp, sp, #256 ; Kill temp frame + +; ............................................................................. + +UtilityExitCloseR1 + + BL CloseR1 ; Accumulates V + + Pull "$UtilRegs, pc" ; Back to *Command handler + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Append and Build share a common body + +Append_Code ENTRY "$UtilRegs" + + MOV r1, r0 ; -> filename + MOV r0, #&C0 ; OPENUP + B %FT01 + + +Build_Code ALTENTRY + + MOV r1, r0 ; -> filename + MOV r0, #&80 ; OPENOUT + +01 BL OpenFileWithWinge + EXIT VS + + SUB sp, sp, #256 + + MOV r5, r1 ; Save handle for later + BL MoveToEOF ; Can do this anyhow as ext#(openout)=0 + + MOV linecount, #0 + +10 BLVC LineNumberPrint ; Escape is tested for on OS_ReadLine.Err below + BVS UtilityExitCloseR1_256 + + MOV r0, sp ; Get a line from Joe Punter + MOV r1, #256-1 ; -1 for terminator + MOV r2, #" " + MOV r3, #&FF + SWI XOS_ReadLine + MOVVS r1, r5 + BVS UtilityExitCloseR1_256 + MOV r3, #CR ; Terminate source string + STRB r3, [r0, r1] + MOVCC FSUTtemp, #0 ; Ended with ESCAPE ? + MOVCS FSUTtemp, #-1 + MOVCS r0, #&7E ; Ack. ESCAPE, not error + SWICS XOS_Byte + BVS UtilityExitCloseR1_256 + + MOV r2, sp ; r2 -> buffer to translate + MOV r1, r5 ; Get handle back +18 LDRB r0, [r2], #1 ; Put all the spaces out ourselves ! + CMP r0, #" " ; VClear + SWIEQ XOS_BPut + BVS UtilityExitCloseR1_256 + BEQ %BT18 + + SUB r0, r2, #1 ; r0 -> past spaces, rest to translate + MOV r2, #(1 :SHL: 31) ; No quote funnies, don't end on space, do | + SWI XOS_GSInit + +20 SWIVC XOS_GSRead ; Get a char + MOVVS R1, R5 + BVS UtilityExitCloseR1_256 + BCS %FT30 ; End of string ? + MOV r3, r0 ; Save GSState + MOV r0, r1 ; Char from GSRead + MOV r1, r5 ; Get handle back + SWI XOS_BPut + BVS UtilityExitCloseR1_256 + MOV r0, r3 ; Restore GSState + B %BT20 ; And loop + +30 CMP FSUTtemp, #0 ; Did we read ESCAPE ? VClear + MOV r1, r5 ; In any case, we want r1 handle + MOV r0, #CR ; If not, stick a CR on eoln + SWIEQ XOS_BPut + BEQ %BT10 ; Finished if ESCAPE was pressed + ; Catch error back there too + + SWIVC XOS_NewLine + + B UtilityExitCloseR1_256 + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; OSFile routines: Load, Save, Create, Delete and Remove + +Load_Code ENTRY "$UtilRegs" + + MOV r7, r0 ; -> filename + CMP r1, #1 ; Just filename (1 parm) ? + MOVEQ r3, #&FF ; Load at its own address if so + BEQ %FT90 + + BL SkipNameAndReadAddr + EXIT VS + BLCS SetErrorBadAddress ; Must check for trailing junk + MOVVC r3, #0 ; Got load address from command line + +90 MOVVC r0, #OSFile_Load + MOVVC r1, r7 ; Get filename^ back + SWIVC XOS_File + EXIT + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Save_Error + DCD ErrorNumber_Syntax + [ International + DCB "BadSav:Bad parameters for *Save", 0 + ] + ALIGN + +Save_Code ENTRY "$UtilRegs" + + BL SkipNameAndReadAddr + EXIT VS + + MOV r4, r2 ; Got start address + BL SkipSpaces + MOV r5, r0 ; Preserve state + CMP r0, #"+" ; Is it a +<length> parm ? + ADDEQ r1, r1, #1 ; Skip '+' then + BLEQ SkipSpaces ; And any trailing spaces + BL ReadAtMost8Hex ; Read a word anyway + EXIT VS + + CMP r5, #"+" + MOVNE r5, r2 ; <end addr> ? + ADDEQ r5, r2, r4 ; Form <end addr> := <start addr> + <length> + MOV r2, r4 ; r2, r3 := both r4 by default + MOV r3, r4 + BL ReadOptionalLoadAndExec + SETV CS + ADRVS R0, Save_Error ; If there's anything on the end, it's an error + [ International + BLVS TranslateError + ] + MOVVC r0, #OSFile_Save + MOVVC r1, r7 ; Get filename^ back + SWIVC XOS_File + EXIT + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Create_Code ENTRY "r1, $UtilRegs" + + CMP r1, #1 ; Filename only -> length 0, dated + MOVEQ r7, r0 ; Filename^ + MOVEQ r2, #0 ; Will be copied to r5 in a bit + BLNE SkipNameAndReadAddr + EXIT VS + MOV r5, r2 ; Got length, put in as end address + MOV r4, #0 ; So start addr shall be .. 0 ! + + LDR r14, [sp] ; No load, exec -> datestamp FFD + CMP r14, #3 + MOVLO r0, #OSFile_CreateStamp + LDRLO r2, =&FFFFFFFD ; Only bottom 12 bits are of interest + MOVHS r0, #OSFile_Create ; Makes it an immediate constant + MOVHS r2, #0 ; Load/Exec default to 0 + MOVHS r3, #0 + BLHS ReadOptionalLoadAndExec + + MOVVC r1, r7 ; Get filename^ back + SWIVC XOS_File + EXIT + + LTORG + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Delete and Remove share a common body + +Delete_Code ENTRY + + MOV r6, #0 ; Give error if file doesn't exist + B %FT01 ; Use a reg. not affected by OSFile ! + +Remove_Code ALTENTRY + + MOV r6, #-1 ; Don't winge + +01 MOV r1, r0 ; -> filename + MOV r0, #OSFile_Delete + SWI XOS_File + EXIT VS + + CMP r0, r6 ; Are we going to winge ? + MOVEQ r0, #OSFile_MakeError ; Give pretty error now, says Tutu + MOVEQ r2, #object_nothing + SWIEQ XOS_File + EXIT + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Gosh, doesn't use UtilRegs !!! + +Opt_Code ENTRY + + MOV r3, #0 ; Default parms are 0, 0 + MOV r4, #0 + CMP r1, #0 ; No parms ? VClear + BEQ %FT50 + + MOV r1, r0 + MOV r0, #10 ; Default base 10, allow naff term ',' + SWI XOS_ReadUnsigned ; Read first parm + EXIT VS + MOV r3, r2 + + BL FS_SkipSpaces ; Try getting another parm anyway + BCC %FT50 ; End of the line + + TEQ r0, #"," ; commas too ! + ADDEQ r1, r1, #1 + BLEQ FS_SkipSpaces + CMP r0, #space ; Anything here ? + BEQ %FT99 + + MOV r0, #(1 :SHL: 31) + 10 ; Default base 10, no bad terms + SWI XOS_ReadUnsigned ; Read second parm + MOVVC r4, r2 + +50 MOVVC r0, #FSControl_Opt + MOVVC r1, r3 + MOVVC r2, r4 + SWIVC XOS_FSControl + EXIT + +99 ADR r0, SyntaxError_StarOpt + [ International + BL TranslateError + | + SETV + ] + EXIT + + +SyntaxError_StarOpt + DCD ErrorNumber_Syntax + DCB "OptErr:Syntax: *Opt [<x> [[,] <y>]]", 0 + ALIGN + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; H o r r i b l e l i t t l e s u b r o u t i n e s +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Variegated output routines + +HexR0LongWord ENTRY "r0" + + MOV r0, r0, ROR #16 + BL HexR0Word + MOVVC r0, r0, ROR #32-16 + BLVC HexR0Word + STRVS r0, [sp] + EXIT + + +HexR0Word ENTRY "r0" + + MOV r0, r0, ROR #8 + BL HexR0Byte + MOVVC r0, r0, ROR #32-8 + BLVC HexR0Byte + STRVS r0, [sp] + EXIT + + +HexR0Byte ENTRY "r0" + + MOV r0, r0, ROR #4 + BL HexR0Nibble + MOVVC r0, r0, ROR #32-4 + BLVC HexR0Nibble + STRVS r0, [sp] + EXIT + + +HexR0Nibble ENTRY "r0" + + AND r0, r0, #15 + CMP r0, #10 + ADDCC r0, r0, #"0" + ADDCS r0, r0, #"A"-10 + SWI XOS_WriteC + STRVS r0, [sp] + EXIT + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +SkipOverNameAndSpaces + Push lr + BL SkipToSpace + Pull lr + +SkipSpaces ROUT + +10 LDRB r0, [r1], #1 + CMP r0, #" " ; Leave r1 -> ~space + BEQ %BT10 + SUB r1, r1, #1 + BICS pc, lr, #V_bit ; r0 = first ~space. Can't really fail + + +SkipToSpace ENTRY "r0" + +10 LDRB r0, [r1], #1 + CMP r0, #&7F + CMPNE r0, #" " ; Leave r1 -> space or CtrlChar + BHI %BT10 + SUB r1, r1, #1 + EXITS + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r1 -> string + +; Out flags from CMP r0, #space for eol detection + +FS_SkipSpaces ROUT + +10 LDRB r0, [r1], #1 + CMP r0, #space ; Leave r1 -> ~space + BEQ %BT10 + SUB r1, r1, #1 + MOV pc, lr ; r0 = first ~space + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r0 = open mode +; r1 -> filename + +; Out VC: r0 = r1 = handle +; VS: r0 -> error (FilingSystemError or 'NotFound') + +OpenFileWithWinge ENTRY + + ORR r0, r0, #(open_mustopen :OR: open_nodir) ; Saves us code here + SWI XOS_Find + MOVVC r1, r0 + EXIT + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; PTR#handle := EXT#handle + +; In r1 = handle to use + +; Out VC: PTR moved +; VS: r0 -> Filing System Error + +MoveToEOF ENTRY "r0, r2" + + MOV r0, #OSArgs_ReadEXT + SWI XOS_Args + MOVVC r0, #OSArgs_SetPTR + SWIVC XOS_Args + STRVS r0, [sp] + EXIT + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +CloseThenAckEscape + + BL CloseR1 + + BL AckEscape + Pull "$UtilRegs, pc" ; Common exit - back to MOS + + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r1 = handle to close, or 0 means don't do anything + +; Out VC: file closed, or nothing done +; VS: r0 -> Filing System Error, or VSet on entry + +CloseR1 ENTRY "r0" + + CMP r1, #0 ; Is there a handle to close ? VClear + MOVNE r0, #0 ; CLOSE#han + SWINE XOS_Find + EXITS VC ; Accumulate V + + STR r0, [sp] + EXIT + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Increment then print a line number in decimal + +LineNumberPrint ENTRY "r0-r1" + + ADD linecount, linecount, #1 ; r0 := ++linecount + MOV r0, linecount + MOV r1, #1 ; Print leading spaces + BL PrintR0Decimal + SWIVC XOS_WriteI+" " + STRVS r0, [sp] + EXIT + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r0 = number to print +; r1 = 0 -> strip spaces +; 1 -> print leading spaces + +; Number gets printed RJ in a field of 4 if possible, or more as necessary + +PrintR0Decimal ENTRY "r0-r3" + + SUB sp, sp, #32 + MOV r3, r1 ; Save flag + MOV r1, sp + MOV r2, #32 + SWI XOS_BinaryToDecimal ; No errors from this + CMP r3, #0 ; If not doing spaces or >= 4 chars + CMPNE r2, #4 ; in the number, son't print any + + ADRLT r0, %FT98-1 ; Point to right amount of spaces + ADDLT r0, r0, r2 + SWILT XOS_Write0 + +10 LDRVCB r0, [r1], #1 + SWIVC XOS_WriteC + BVS %FT99 + SUBS r2, r2, #1 + BNE %BT10 + +99 ADD sp, sp, #32 + STRVS r0, [sp] + EXIT + +98 + DCB " ", 0 ; Three spaces, null + ALIGN + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Read configured info of Tutu's wally byte + +; Out r1 = bits read from CMOS ram + +ReadGSFormat ENTRY "r0, r2" + + MOV r0, #ReadCMOS + MOV r1, #TutuCMOS + SWI XOS_Byte + ANDVC r1, r2, #2_1111 ; Mask out all but my bits + STRVS r0, [sp] + EXIT + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r0b = char to print using current listopt + +; Out r0 corrupt + +PrintCharInGSFormat ENTRY "r1, listopt" + + AND r0, r0, #&FF ; Just in case + TST listopt, #forcetbsrange ; Forcing tbs into 00..7F ? + BIC listopt, listopt, #forcetbsrange + BICNE r0, r0, #&80 ; Take top bit out if so + + CMP r0, #" " ; Do we need to do this at all ? + RSBGES r14, r0, #&7E + BLT %FT10 ; LT if not in range &20-&7E + CMP r0, #"|" ; Solidus ? VClear + CMPNE r0, #"""" ; Quote ? + CMPNE r0, #"<" ; Left angle ? + SWINE XOS_WriteC ; Nope, so let's print the char and exit + EXIT VS + EXIT NE + + +10 TST listopt, #allowtbschar ; International format bit ? + BIC listopt, listopt, #allowtbschar + BEQ %FT15 + CMP r0, #&80 + BHS %FT45 ; Print tbs char and exit + +15 TST listopt, #unprintangle ; Angle bracket format ? + BNE %FT50 + + TST listopt, #unprintdot ; Doing unprintable dot format (2_01) ? + BEQ %FT16 + + CMP r0, #" " ; Only space to twiddle are printable + RSBGES r14, r0, #&7E + MOVLT r0, #"." ; All others are dot + B %FT45 ; Print char and exit + + +; Normal BBC GSREAD format (2_00) + +16 CMP r0, #&80 ; Deal with tbs first + BIC r0, r0, #&80 + BLO %FT17 + SWI XOS_WriteI+"|" + SWIVC XOS_WriteI+"!" + EXIT VS + +17 CMP r0, #&7F ; Delete ? -> |?. VClear + MOVEQ r0, #"?" + CMPNE r0, #"""" ; Quote ? -> |" + CMPNE r0, #"|" ; Solidus ? -> || + SWIEQ XOS_WriteI+"|" + EXIT VS + CMP r0, #&1F ; CtrlChar ? -> |<char+@>. VClear + ADDLS r0, r0, #"@" + SWILS XOS_WriteI+"|" + +45 SWI XOS_WriteC ; Used from above + EXIT + + +50 ; Angle bracket format, either hex (2_11) or decimal (2_10) + + SWI XOS_WriteI+"<" + TST listopt, #unprinthex + BNE %FT60 + MOV r1, #0 ; Strip leading spaces + BLVC PrintR0Decimal + SWIVC XOS_WriteI+">" + EXIT + + +60 SWIVC XOS_WriteI+"&" + BLVC HexR0Byte + SWIVC XOS_WriteI+">" + EXIT + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r0 -> filename. Used by most MOS OSFile routines for initial decoding + +; Out r1 -> past address read +; r2 = address read +; r7 = initial filename^ +; VS : failed to read address, r0 -> error +; CS : text present comes immediately after address + +SkipNameAndReadAddr ENTRY + + MOV r7, r0 ; Save filename^ + MOV r1, r0 ; -> filename + BL SkipToSpace ; Over the filename + BL SkipSpaces ; To the address + BL ReadAtMost8Hex ; Go read it Floyd ! + LDRVCB r0, [r1] ; Anything on the end ? + CMPVC r0, #" "+1 ; CtrlChar + space ok + EXIT ; VC/VS from readhex or VC, CC/CS from CMP + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; In r2, r3 = load/exec addresses to use if none provided. r1 -> string + +; Out r2, r3 conditionally updated, r1 updated, past any trailing spaces +; VS if failed, error ('Bad Address' or whatever) set +; CS if something comes afterwards ... + +ReadOptionalLoadAndExec ENTRY "r0, FSUTtemp" + + MOV FSUTtemp, r2 ; Save initial value + + BL SkipSpaces + CMP r0, #" " ; No more parms ? + EXIT LO ; VClear, r2, r3 unaffected + + BL ReadAtMost8Hex + BVS %FT99 + MOV r3, r2 + MOV r2, FSUTtemp + BL SkipSpaces + CMP r0, #" " ; No more parms ? + EXIT LO ; VClear, r2 unaffected, r3 updated + + BL ReadAtMost8Hex + BLVC SkipSpaces ; Anything on the end ? + CMPVC r0, #" " +99 STRVS r0, [sp] + EXIT ; VC/VS from readhex or VC, CC/CS from CMP + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Read a hex (default) address from a string + +; In r1 -> string + +; Out VC: r1 -> first char not used in building number, r2 = number +; VS: error ('Bad Address') set + +ReadAtMost8Hex ENTRY "r0, r3-r4" + + MOV R0, #16 ; default base, don't trap bad terms + SWI XOS_ReadUnsigned + STRVS r0, [sp] + EXIT ; VClear -> good hex number / VSet -> bad + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; Set various errors: VSet always on exit + +SetErrorBadAddress + + ADR r0, ErrorBlock_BadAddress + [ International + Push "lr" + BL TranslateError + Pull "lr" + ] + ORRS pc, lr, #V_bit + + MakeErrorBlock BadAddress + + +SetErrorOutsideFile + + ADR r0, ErrorBlock_OutsideFile + [ International + Push "lr" + BL TranslateError + Pull "lr" + ] + ORRS pc, lr, #V_bit + + MakeErrorBlock OutsideFile + + +SetErrorEscape + + ADR r0, ErrorBlock_Escape + [ International + Push "lr" + BL TranslateError + Pull "lr" + ] + ORRS pc, lr, #V_bit + + MakeErrorBlock Escape + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +AckEscape + Push "r1-r2, lr" + MOV r0, #&7E + SWI XOS_Byte + + BLVC SetErrorEscape ; Only set ESCAPE error if no override + Pull "r1-r2, pc" + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + END diff --git a/s/TMOSHelp b/s/TMOSHelp new file mode 100644 index 0000000000000000000000000000000000000000..82300e707720391622af155b4352703ac52b706c --- /dev/null +++ b/s/TMOSHelp @@ -0,0 +1,880 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + TTL ==> s.TMOSHelp + + SUBT => HelpStrs + + [ International_Help=0 +Break_Help + ;= "The ",TokenEscapeChar,Token0," key either acts like Escape, or" + = "The ",TokenEscapeChar,Token0," key either acts like Escape, " + = "or like",TokenEscapeChar,Token2,"Reset key. ", 13 + ;= " like the Reset key. ",13 + +Reset_Help + ;= "When Reset is pressed, the following " + = "When Reset",TokenEscapeChar,Token41,"pressed," + = TokenEscapeChar,Token2,"following keys have an effect:", 13 + = "SHIFT causes an autoboot (unless Boot",TokenEscapeChar,Token41 + = "configured).", 13,"CTRL causes more of",TokenEscapeChar,Token2 + = "machine",TokenEscapeChar,Token40,"be reset.", 13,"keypad-* ca" + = "uses",TokenEscapeChar,Token2,"supervisor" + = TokenEscapeChar,Token40,"be run rather than" + = TokenEscapeChar,Token2,"configured language.", 13,"See also " + = "*Help PowerOn.", 0 + ;= " keys have an effect:",13 + ;= "SHIFT causes an autoboot (unless Boot is configured).",13 + ;= "CTRL causes more of the machine to be reset.",13 + ;= "keypad-* causes the supervisor to be run rather than the configured" + ;= " language.",13 + ;= "See also *Help PowerOn.",0 + +PowerOn_Help + ;= "When the machine is switched on, the following " + = "When",TokenEscapeChar,Token2,"machine",TokenEscapeChar,Token41 + = "switched on,",TokenEscapeChar,Token2,"following keys have a" + = "n effect:", 13,"R causes",TokenEscapeChar,Token2,"operating " + = "system's CMOS RAM",TokenEscapeChar,Token40,"be reset.", 13,"D" + = "ELETE causes",TokenEscapeChar,Token38,"the machine's CMOS RAM" + = TokenEscapeChar,Token40,"be reset.", 13,"T" + = TokenEscapeChar,Token16,"COPY are similar" + = TokenEscapeChar,Token40,"R",TokenEscapeChar,Token16,"DELETE," + = " but set",TokenEscapeChar,Token2,"opposite configured sync.", 13 + = "0",TokenEscapeChar,Token40,"9 on",TokenEscapeChar,Token2,"k" + = "eypad reset (just)",TokenEscapeChar,Token2,"configured monit" + = "or type. Keypad dot ",TokenEscapeChar,Token19,"configured mod" + = "e, sync",TokenEscapeChar,Token16,"monitor type" + = TokenEscapeChar,Token40,"Auto.", 13,"See also *Help Reset" + = TokenEscapeChar,Token16,"*Help Break.", 0 + ;= " keys have an effect:",13 + ;= "R causes the operating system's CMOS RAM to be reset.",13 + ;= "DELETE causes all the machine's CMOS RAM to be reset.",13 + ;= "T and COPY are similar to R and DELETE, but set the opposite" + ;= " configured sync.",13 + ;= "0 to 9 on the keypad reset (just)" + ;= " the configured monitor type." + ;= " Keypad dot sets the configured mode, sync and monitor type to Auto." + ;= 13,"See also *Help Reset and *Help Break."0 + +RMEnsure_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," checks that a module" + = TokenEscapeChar,Token41,"present",TokenEscapeChar,Token16,"i" + = "s",TokenEscapeChar,Token2,"given version, or a more modern o" + = "ne. The command",TokenEscapeChar,Token41,"executed if this" + = TokenEscapeChar,Token41,"not",TokenEscapeChar,Token2,"case." + = 13 + ;= " checks that a module is present and is the given version," + ;= " or a more modern one." + ;= " The command is executed if this is not the case.",13 +RMEnsure_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token14,"moduletitle> <version " + = TokenEscapeChar,Token13,"> [<*command>]", 0 + ;= " <moduletitle> <version number> [<*command>]",0 + +Syntax_Help + ;= "Symbols used in syntax descriptions:",13 + = "Symbols used in syntax descrip",TokenEscapeChar,Token9,"s:", 13 + = "<> mark sec",TokenEscapeChar,Token9,"s",TokenEscapeChar,Token40 + = "be filled in, eg. <",TokenEscapeChar,Token7 + = TokenEscapeChar,Token11,"> indicates that a " + = TokenEscapeChar,Token7,TokenEscapeChar,Token11," should be" + = " supplied here.", 13,"[] mark op",TokenEscapeChar,Token9,"al" + = " sec",TokenEscapeChar,Token9,"s.", 13,"| indicates a choice," + = " e.g. ""A|B"" means ""A or B"".", 0 + ;= "<> mark sections to be filled in, eg. <filename> indicates" + ;= " that a filename should be supplied here.",13 + ;= "[] mark optional sections.",13 + ;= "| indicates a choice, e.g. ""A|B"" means ""A or B"".", 0 + +Quit_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," leaves",TokenEscapeChar,Token2 + = TokenEscapeChar,Token5," applica",TokenEscapeChar,Token9,"." + = 13 + ;= " leaves the current application.",13 + +GOS_Syntax +Modules_Syntax +Quit_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0, 0 + = TokenEscapeChar,Token1, 0 + +RMFaster_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," moves a module from ROM" + = TokenEscapeChar,Token40,"RAM.", 13 + ;= " moves a module from ROM to RAM.",13 +RMFaster_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token14,"moduletitle>", 0 + ;= " <moduletitle>", 0 + +RMKill_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," kills",TokenEscapeChar,Token16,"d" + = "eletes a ",TokenEscapeChar,Token17,".", 13 + ;= " kills and deletes a relocatable module.",13 +RMKill_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token14,"moduletitle>", 0 + ;= " <moduletitle>", 0 + +RMLoad_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," loads",TokenEscapeChar,Token16,"i" + = "nitialises a ",TokenEscapeChar,Token17,".", 13 + ;= " loads and initialises a relocatable module.",13 +RMLoad_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token27, 0 + ;= " <filename>", 0 + +RMRun_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," runs a ",TokenEscapeChar,Token17 + = ".", 13 + ;= " runs a relocatable module.",13 +RMRun_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token27, 0 + ;= " <filename>", 0 + +RMTidy_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," compacts",TokenEscapeChar,Token2 + = "RMA",TokenEscapeChar,Token16,"reinitialises" + = TokenEscapeChar,Token38,"the modules.", 13 + ;= " compacts the RMA and reinitialises all the modules.",13 +RMTidy_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0, 0 + = TokenEscapeChar,Token1, 0 + +RMClear_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," deletes",TokenEscapeChar,Token38 + = TokenEscapeChar,Token17,"s from",TokenEscapeChar,Token2,"RM" + = "A.", 13 + ;= " deletes all relocatable modules from the RMA.",13 +RMClear_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0, 0 + = TokenEscapeChar,Token1, 0 + +RMReInit_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," reinitialises a " + = TokenEscapeChar,Token17,", reversing",TokenEscapeChar,Token2 + = "ac",TokenEscapeChar,Token9," of *Unplug if appropriate.", 13 + ;= " reinitialises a relocatable module," + ;= " reversing the action of *Unplug if appropriate.",13 +RMReInit_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token14,"moduletitle>", 0 + ;= " <moduletitle>", 0 + +ROMModules_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," lists",TokenEscapeChar,Token2 + = TokenEscapeChar,Token17,"s ",TokenEscapeChar,Token5,"ly in " + = "ROM, along with their status.", 13,"See also *Modules.", 13 + ;= " lists the relocatable modules currently in ROM, along with" + ;= " their status.",13 + ;= "See also *Modules.",13 +ROMModules_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0, 0 + = TokenEscapeChar,Token1, 0 + +Set_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," assigns a string value" + = TokenEscapeChar,Token40,"a system variable. Other types of va" + = "lue can be assigned with *",TokenEscapeChar,Token0,"Eval" + = TokenEscapeChar,Token16,"*",TokenEscapeChar,Token0,"Macro.", 13 + ;= " assigns a string value to a system variable." + ;= " Other types of value can be assigned with *",TokenEscapeChar,Token0 + ;= "Eval and *",TokenEscapeChar,Token0 + ;= "Macro.",13 +Set_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token14,"var",TokenEscapeChar,Token11,"> <va" + = "lue>", 0 + ;= " <varname> <value>", 0 + +SetMacro_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," assigns a macro value" + = TokenEscapeChar,Token40,"a system variable. Other types of va" + = "lue can be assigned with *Set",TokenEscapeChar,Token16,"*SetE" + = "val.", 13 + ;= " assigns a macro value to a system variable." + ;= " Other types of value can be assigned with *Set and *SetEval.",13 +SetMacro_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token14,"var",TokenEscapeChar,Token11,"> <va" + = "lue>", 0 + ;= " <varname> <value>", 0 + +SetEval_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," evaluates an e" + = TokenEscapeChar,Token29,TokenEscapeChar,Token16,"assigns it" + = TokenEscapeChar,Token40,"a system variable. Other types of va" + = "lue can be assigned with *Set",TokenEscapeChar,Token16,"*SetM" + = "acro.", 13,"""*Help Eval"" describes",TokenEscapeChar,Token2,"e" + = TokenEscapeChar,Token29," syntax.", 13 + ;= " evaluates an expression and assigns it to a system variable." + ;= " Other types of value can be assigned with *Set and *SetMacro.",13 + ;= """*Help Eval"" describes the expression syntax.",13 +SetEval_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token14,"var",TokenEscapeChar,Token11,"> <e" + = TokenEscapeChar,Token29,">", 0 + ;= " <varname> <expression>", 0 + +Show_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," lists system variables matching" + = TokenEscapeChar,Token2,TokenEscapeChar,Token11," given, or" + = TokenEscapeChar,Token38,"system variables if no " + = TokenEscapeChar,Token11,TokenEscapeChar,Token41,"specified." + = " Variables can be set with *Set, *SetEval",TokenEscapeChar,Token16 + = "*SetMacro.", 13 + ;= " lists system variables matching the name given," + ;= " or all system variables if no name is specified." + ;= " Variables can be set with *Set, *SetEval and *SetMacro.",13 +Show_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token30,"<variablespec>]", 0 + ;= " [<variablespec>]", 0 + +Time_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0,TokenEscapeChar,Token32 + = TokenEscapeChar,Token2,"time",TokenEscapeChar,Token16,"date" + = ".", 13 + ;= " displays the time and date.",13 +Time_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0,0 + = TokenEscapeChar,Token1, 0 + +Unset_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," deletes a system variable.", 13 + ;= " deletes a system variable.",13 +Unset_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token14,"var",TokenEscapeChar,Token11,">", 0 + ;= " <varname>", 0 + +Echo_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," sends a string to" + = TokenEscapeChar,Token2,"VDU, after transforma" + = TokenEscapeChar,Token9," by GSRead.", 13 + = TokenEscapeChar,Token14,"string>", 0 + ;= " sends a string to the VDU, after transformation by GSRead.",13 + ;= "Syntax: *",TokenEscapeChar,Token0 + ;= " <string>",0 + +Ignore_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," ",TokenEscapeChar,Token19 + = TokenEscapeChar,Token26,"r ignore character.", 13 + ;= " sets the printer ignore character.",13 +Ignore_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token30,"<",TokenEscapeChar,Token13,">]", 0 + ;= " [<number>]",0 + +IF_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," condi",TokenEscapeChar,Token9,"a" + = "lly executes another command depending on",TokenEscapeChar,Token2 + = "value of an e",TokenEscapeChar,Token29,".", 13 + ;= " conditionally executes another command" + ;= " depending on the value of an expression.",13 +IF_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token14,"e",TokenEscapeChar,Token29,"> THEN " + = "<command> [ELSE <command>]", 0 + ;= " <expression> THEN <command> [ELSE <command>]", 0 + +Status_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," shows",TokenEscapeChar,Token2,"s" + = "elected CMOS RAM op",TokenEscapeChar,Token9,"s. Use " + = TokenEscapeChar,Token10,"to set",TokenEscapeChar,Token2,"op" + = TokenEscapeChar,Token9,"s.", 13,TokenEscapeChar,Token30,"<" + = "op",TokenEscapeChar,Token9,">]", 0 + ;= " shows the selected CMOS RAM options." + ;= " Use *Configure to set the options.",13 + ;= "Syntax: *",TokenEscapeChar,Token0 + ;= " [<option>]",0 + +Unplug_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," stops",TokenEscapeChar,Token2,"g" + = "iven ROM module being initialised.", 13,"*" + = TokenEscapeChar,Token0," with no argument lists" + = TokenEscapeChar,Token2,"unplugged ROM modules.", 13 + ;= " stops the given ROM module being initialised.",13 + ;= "*",TokenEscapeChar,Token0 + ;= " with no argument lists the unplugged ROM modules.",13 +Unplug_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token30,"<moduletitle> [<podule " + = TokenEscapeChar,Token13,">]]", 0 + ;= " [<moduletitle> [<podule number>]]",0 + +RMInsert_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," reverses",TokenEscapeChar,Token2 + = "effect of *Unplug, but does not reinitialise" + = TokenEscapeChar,Token2,"specified ROM module.", 13 + ;= " reverses the effect of *Unplug, but does not reinitialise" + ;= " the specified ROM module.",13 +RMInsert_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token14,"moduletitle> [<podule " + = TokenEscapeChar,Token13,">]", 0 + ;= " <moduletitle> [<podule number>]",0 + +Error_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," generates an error with" + = TokenEscapeChar,Token2,"given ",TokenEscapeChar,Token13 + = TokenEscapeChar,Token16,"text. ", 13 + ;= " generates an error with the given number and text. ",13 +Error_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token30,"<",TokenEscapeChar,Token13,">] <tex" + = "t>", 0 + ;= " [<number>] <text>",0 + +Eval_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," evaluates an integer or string e" + = TokenEscapeChar,Token29,". ", 13,"The e",TokenEscapeChar,Token29 + = " analyser has",TokenEscapeChar,Token2,"following operators:", 13 + = "+", 9, 9, 9,"addi",TokenEscapeChar,Token9," or string c" + = "oncatena",TokenEscapeChar,Token9, 13,"-, *, /, MOD", 9, 9 + = "integer opera",TokenEscapeChar,Token9,"s", 13,"=, <, >, <=, " + = ">=, <>", 9,"string or integer comparison", 13,">>, <<", 9, 9 + = 9,"arithmetic shift right",TokenEscapeChar,Token16,"left", 13 + = ">>>", 9, 9, 9,"logical shift right", 13,"STR, VAL", 9, 9 + = "conversion between strings",TokenEscapeChar,Token16,"integers" + = 13,"AND, OR, EOR, NOT", 9,"(bitwise) logical operators", 13,"R" + = "IGHT, LEFT", 9, 9,"substring extrac",TokenEscapeChar,Token9 + = 13,"LEN", 9, 9, 9,"length of a string", 13, 13,"Bracket" + = "s can also be used.", 0 + ;= " evaluates an integer or string expression. ",13 + ;= "The expression analyser has the following operators:",13 + ;= "+",9,9,9,"addition or string concatenation",13 + ;= "-, *, /, MOD",9,9,"integer operations",13 + ;= "=, <, >, <=, >=, <>",9,"string or integer comparison",13 + ;= ">>, <<",9,9,9,"arithmetic shift right and left",13 + ;= ">>>",9,9,9,"logical shift right",13 + ;= "STR, VAL",9,9,"conversion between strings and integers",13 + ;= "AND, OR, EOR, NOT",9,"(bitwise) logical operators",13 + ;= "RIGHT, LEFT",9,9,"substring extraction",13 + ;= "LEN",9,9,9,"length of a string",13,13 + ;= "Brackets can also be used.", 0 +Eval_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token14,"e",TokenEscapeChar,Token29,">", 0 + ;= " <expression>",0 + +GO_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," [<address>] [; environment] - g" + = "o",TokenEscapeChar,Token40,"address (hexadecimal), " + = TokenEscapeChar,Token8,"&8000. Text after ';'" + = TokenEscapeChar,Token41,"environment string.", 0 + ;= " [<address>] [; environment] " + ;= " - go to address (hexadecimal), default &8000. " + ;= " Text after ';' is environment string.", 0 + +GOS_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," enters",TokenEscapeChar,Token2 + = "supervisor. Use *Quit",TokenEscapeChar,Token40,"exit.", 0 + ;= " enters the supervisor. Use *Quit to exit.", 0 + +Append_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," opens an existing " + = TokenEscapeChar,Token7,TokenEscapeChar,Token16,"subsequent" + = " lines of keyboard input are appended",TokenEscapeChar,Token40 + = "it, input being terminated by ESCAPE.", 13 + ;= " opens an existing file and subsequent lines of keyboard input are" + ;= " appended to it, input being terminated by ESCAPE.",13 +Append_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token27, 0 + ;= " <filename>", 0 + +Build_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," opens a new " + = TokenEscapeChar,Token7,TokenEscapeChar,Token16,"subsequent" + = " lines of keyboard input are directed",TokenEscapeChar,Token40 + = "it, input being terminated by ESCAPE.", 13 + ;= " opens a new file and subsequent lines of keyboard input are" + ;= " directed to it, input being terminated by ESCAPE.",13 +Build_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token27, 0 + ;= " <filename>", 0 + +Close_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," closes",TokenEscapeChar,Token38 + = TokenEscapeChar,Token7,"s on",TokenEscapeChar,Token2 + = TokenEscapeChar,Token5," ",TokenEscapeChar,Token4,".", 13 + ;= " closes all files on the current filing system.",13 +Close_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0,0 + = TokenEscapeChar,Token1, 0 + +Create_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," reserves space for" + = TokenEscapeChar,Token2,TokenEscapeChar,Token11,"d " + = TokenEscapeChar,Token7,", op",TokenEscapeChar,Token9,"ally" + = " giving it load",TokenEscapeChar,Token16,"execu" + = TokenEscapeChar,Token9," addresses. No data" + = TokenEscapeChar,Token41,"transferred",TokenEscapeChar,Token40 + = "the ",TokenEscapeChar,Token7,". Length",TokenEscapeChar,Token16 + = "addresses are in hexadecimal.", 13 + ;= " reserves space for the named file, optionally giving it" + ;= " load and execution addresses. No data is transferred to the file." + ;= " Length and addresses are in hexadecimal.",13 +Create_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token27," [<length> [<exec addr> [<load addr>" + = "]]]", 0 + ;= " <filename> [<length> [<exec addr> [<load addr>]]]", 0 + +Delete_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," tries",TokenEscapeChar,Token40,"d" + = "elete",TokenEscapeChar,Token2,TokenEscapeChar,Token11,"d " + = TokenEscapeChar,Token7,", returning an error if" + = TokenEscapeChar,Token2,TokenEscapeChar,Token7," does not " + = "exist.", 13,"See also *Remove",TokenEscapeChar,Token16,"*Wipe" + = ".", 13 + ;= " tries to delete the named file, returning an error if the file" + ;= " does not exist.",13 + ;= "See also *Remove and *Wipe.",13 +Delete_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token27, 0 + ;= " <filename>", 0 + +Dump_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0,TokenEscapeChar,Token32 + = TokenEscapeChar,Token2,"contents of",TokenEscapeChar,Token2 + = TokenEscapeChar,Token7," as a hex",TokenEscapeChar,Token16,"A" + = "SCII dump. The ",TokenEscapeChar,Token7," offset" + = TokenEscapeChar,Token16,"start address are in hexadecimal.", 13 + ;= " displays the contents of the file as a hex and ASCII dump." + ;= " The file offset and start address are in hexadecimal.",13 +Dump_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token27," [<",TokenEscapeChar,Token7," offs" + = "et> [<start address>]]", 0 + ;= " <filename> [<file offset> [<start address>]]", 0 + +Exec_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," <",TokenEscapeChar,Token7 + = TokenEscapeChar,Token11,"> directs",TokenEscapeChar,Token2,"o" + = "perating system",TokenEscapeChar,Token40,"take further input " + = "from",TokenEscapeChar,Token2,"given ",TokenEscapeChar,Token7 + = ".", 13,"*",TokenEscapeChar,Token0," with no " + = TokenEscapeChar,Token7,TokenEscapeChar,Token11," causes" + = TokenEscapeChar,Token2,"exec ",TokenEscapeChar,Token7 + = TokenEscapeChar,Token40,"be closed.", 13 + ;= " <filename> directs the operating system to take further input" + ;= " from the given file.",13 + ;= "*",TokenEscapeChar,Token0 + ;= " with no filename causes the exec file to be closed.",13 +Exec_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token30,"<",TokenEscapeChar,Token7 + = TokenEscapeChar,Token11,">]", 0 + ;= " [<filename>]", 0 + +FX_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," r0 [[,] r1 [[,] r2]] calls OS_By" + = "te.", 0 + ;= " r0 [[,] r1 [[,] r2]] calls OS_Byte.", 0 + +FX_Syntax + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," needs 1",TokenEscapeChar,Token40 + = "3 numeric ",TokenEscapeChar,Token36,"s.", 0 + ;= " needs 1 to 3 numeric parameters.", 0 + +Key_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," ",TokenEscapeChar,Token19,"func" + = TokenEscapeChar,Token9," keys.", 13 + ;= " sets the function keys.",13 +Key_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token14,"key",TokenEscapeChar,Token13,"> [<v" + = "alue>]", 0 + ;= " <keynumber> [<value>]", 0 + +List_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0,TokenEscapeChar,Token32 + = TokenEscapeChar,Token2,"contents of",TokenEscapeChar,Token2 + = TokenEscapeChar,Token7," in",TokenEscapeChar,Token2,"confi" + = "gured GSRead format. Each line",TokenEscapeChar,Token41,"prec" + = "eded with a line ",TokenEscapeChar,Token13,".", 13,"See also " + = "*Print",TokenEscapeChar,Token16,"*Type.", 13 + ;= " displays the contents of the file in the configured GSRead format." + ;= " Each line is preceded with a line number.",13 + ;= "See also *Print and *Type.",13 +List_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token30,"-File] <",TokenEscapeChar,Token7 + = TokenEscapeChar,Token11,"> [-TabExpand]", 0 + ;= " [-File] <filename> [-TabExpand]", 0 + +Load_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," with no specified address loads" + = TokenEscapeChar,Token2,TokenEscapeChar,Token11,"d " + = TokenEscapeChar,Token7," at its own load address. If a load " + = "address (hexadecimal)",TokenEscapeChar,Token41,"specified, it" + = " will be used instead.", 13 + ;= " with no specified address loads the named file at its own" + ;= " load address. If a load address (hexadecimal) is specified," + ;= " it will be used instead.",13 +Load_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token27," [<load addr>]", 0 + ;= " <filename> [<load addr>]", 0 + +Print_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0,TokenEscapeChar,Token32 + = TokenEscapeChar,Token2,"contents of a ",TokenEscapeChar,Token7 + = " by sending each byte",TokenEscapeChar,Token40,"the VDU.", 13 + = "See also *List",TokenEscapeChar,Token16,"*Type.", 13 + ;= " displays the contents of a file by sending each byte to the VDU.",13 + ;= "See also *List and *Type.",13 +Print_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token27, 0 + ;= " <filename>", 0 + +Opt_Help + ;= "*" + = "*",TokenEscapeChar,Token0," controls various " + = TokenEscapeChar,Token4," ac",TokenEscapeChar,Token9,"s.", 13 + = "Opt 1 <n>", 31,"Set",TokenEscapeChar,Token2 + = TokenEscapeChar,Token4," message level (for Load/Save/Create" + = "):", 13, 9,"0", 9,"No ",TokenEscapeChar,Token4," messages" + = 13, 9,"1", 9,"File",TokenEscapeChar,Token11," " + = TokenEscapeChar,Token26,"d", 13, 9,"2", 9,"File" + = TokenEscapeChar,Token11,",hexadecimal addresses" + = TokenEscapeChar,Token16,"length ",TokenEscapeChar,Token26,"d" + = 13, 9,"3", 9,"File",TokenEscapeChar,Token11,",datestamp" + = TokenEscapeChar,Token16,"length ",TokenEscapeChar,Token26,"d" + = 13,"Opt 4 <n>", 31,"Set",TokenEscapeChar,Token2 + = TokenEscapeChar,Token4," boot op",TokenEscapeChar,Token9,":" + = 13, 9,"0", 9,"No boot ac",TokenEscapeChar,Token9, 13, 9 + = "1", 9,"*Load boot ",TokenEscapeChar,Token7, 13, 9,"2", 9 + = "*Run boot ",TokenEscapeChar,Token7, 13, 9,"3", 9,"*Exec " + = "boot ",TokenEscapeChar,Token7, 13 + ;= TokenEscapeChar,Token0 + ;= " controls various filing system actions." + ;= 13,"Opt 1 <n>",31 + ;= "Set the filing system message level (for Load/Save/Create):" + ;= 13,9,"0",9,"No filing system messages" + ;= 13,9,"1",9,"Filename printed" + ;= 13,9,"2",9,"Filename,hexadecimal addresses and length printed" + ;= 13,9,"3",9,"Filename,datestamp and length printed" + ;= 13,"Opt 4 <n>",31 + ;= "Set the filing system boot option:" + ;= 13,9,"0",9,"No boot action" + ;= 13,9,"1",9,"*Load boot file" + ;= 13,9,"2",9,"*Run boot file" + ;= 13,9,"3",9,"*Exec boot file" + ;= 13 +Opt_Syntax + ;= "Syntax: *" + = TokenEscapeChar,Token30,"<x> [[,] <y>]]", 0 + ;= TokenEscapeChar,Token0 + ;= " [<x> [[,] <y>]]",0 + +Remove_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," tries",TokenEscapeChar,Token40,"d" + = "elete",TokenEscapeChar,Token2,TokenEscapeChar,Token11,"d " + = TokenEscapeChar,Token7," without returning an error if" + = TokenEscapeChar,Token2,TokenEscapeChar,Token7," does not " + = "exist.", 13,"See also *Delete",TokenEscapeChar,Token16,"*Wipe" + = ".", 13 + ;= " tries to delete the named file without returning an error" + ;= " if the file does not exist.",13 + ;= "See also *Delete and *Wipe.",13 +Remove_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token27, 0 + ;= " <filename>", 0 + +Save_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," copies",TokenEscapeChar,Token2 + = "given area of memory",TokenEscapeChar,Token40,"the " + = TokenEscapeChar,Token11,"d ",TokenEscapeChar,Token7,". Leng" + = "th",TokenEscapeChar,Token16,"addresses are in hexadecimal.", 13 + = TokenEscapeChar,Token27," <start addr> <end addr> [<exec addr" + = "> [<load addr>]]", 13, 31, 31, 31, 31," or *" + = TokenEscapeChar,Token0," <",TokenEscapeChar,Token7 + = TokenEscapeChar,Token11,"> <start addr> + <length> [<exec add" + = "r> [<load addr>]]", 0 + ;= " copies the given area of memory to the named file." + ;= " Length and addresses are in hexadecimal.",13 + ;= "Syntax: *",TokenEscapeChar,Token0 + ;= " <filename> <start addr>" + ;= " <end addr> [<exec addr> [<load addr>]]",13 + ;= 31, 31, 31, 31, " or *",TokenEscapeChar,Token0 + ;= " <filename> <start addr>" + ;= " + <length> [<exec addr> [<load addr>]]", 0 + +Shadow_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," makes subsequent mode changes us" + = "e",TokenEscapeChar,Token2,"other screen bank.", 13 + ;= " makes subsequent mode changes use the other screen bank.",13 +Shadow_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token30,"0|1]", 0 + ;= " [0|1]", 0 + +Spool_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," <",TokenEscapeChar,Token7 + = TokenEscapeChar,Token11,"> opens a new ",TokenEscapeChar,Token7 + = TokenEscapeChar,Token16,"causes subsequent VDU output" + = TokenEscapeChar,Token40,"be directed",TokenEscapeChar,Token40 + = "it, subject to",TokenEscapeChar,Token2,TokenEscapeChar,Token5 + = " *fx 3 status.", 13,"*",TokenEscapeChar,Token0," with no " + = TokenEscapeChar,Token7,TokenEscapeChar,Token11," causes" + = TokenEscapeChar,Token2,"spool ",TokenEscapeChar,Token7 + = TokenEscapeChar,Token40,"be closed.", 13 + ;= " <filename> opens a new file and causes subsequent VDU output" + ;= " to be directed to it, subject to the current *fx 3 status.",13 + ;= "*",TokenEscapeChar,Token0 + ;= " with no filename causes the spool file to be closed.",13 +Spool_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token30,"<",TokenEscapeChar,Token7 + = TokenEscapeChar,Token11,">]", 0 + ;= " [<filename>]", 0 + +SpoolOn_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," <",TokenEscapeChar,Token7 + = TokenEscapeChar,Token11,"> opens an existing " + = TokenEscapeChar,Token7,TokenEscapeChar,Token16,"causes sub" + = "sequent VDU output",TokenEscapeChar,Token40,"be appended" + = TokenEscapeChar,Token40,"it, subject to",TokenEscapeChar,Token2 + = TokenEscapeChar,Token5," *fx 3 status.", 13,"*" + = TokenEscapeChar,Token0," with no ",TokenEscapeChar,Token7 + = TokenEscapeChar,Token11," causes",TokenEscapeChar,Token2,"s" + = "pool ",TokenEscapeChar,Token7,TokenEscapeChar,Token40,"be " + = "closed.", 13 + ;= " <filename> opens an existing file and causes subsequent VDU output" + ;= " to be appended to it, subject to the current *fx 3 status.",13 + ;= "*",TokenEscapeChar,Token0 + ;= " with no filename causes the spool file to be closed.",13 +SpoolOn_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token30,"<",TokenEscapeChar,Token7 + = TokenEscapeChar,Token11,">]", 0 + ;= " [<filename>]", 0 + +TV_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," [<vertical posi" + = TokenEscapeChar,Token9,"> [[,] <interlace>]] " + = TokenEscapeChar,Token19,"posi",TokenEscapeChar,Token9," of" + = TokenEscapeChar,Token2,"display on",TokenEscapeChar,Token2 + = "screen.", 0 + ;= " [<vertical position> [[,] <interlace>]]" + ;= " sets the position of the display on the screen.", 0 + +TV_Syntax + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," needs 0",TokenEscapeChar,Token40 + = "2 ",TokenEscapeChar,Token36,"s.", 0 + ;= " needs 0 to 2 parameters.", 0 + +Type_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0,TokenEscapeChar,Token32 + = TokenEscapeChar,Token2,"contents of",TokenEscapeChar,Token2 + = TokenEscapeChar,Token7," in",TokenEscapeChar,Token2,"confi" + = "gured GSRead format.", 13,"See also *List",TokenEscapeChar,Token16 + = "*Print.", 13 + ;= " displays the contents of the file" + ;= " in the configured GSRead format.",13 + ;= "See also *List and *Print.",13 +Type_Syntax + ;= "Syntax: *",TokenEscapeChar,Token0 + = TokenEscapeChar,Token30,"-File] <",TokenEscapeChar,Token7 + = TokenEscapeChar,Token11,"> [-TabExpand]", 0 + ;= " [-File] <filename> [-TabExpand]", 0 + +Help_Help + ;= "*",TokenEscapeChar,Token0 + = "*",TokenEscapeChar,Token0," <subjects> attempts" + = TokenEscapeChar,Token40,"give useful informa" + = TokenEscapeChar,Token9," on",TokenEscapeChar,Token2,"selec" + = "ted topics. Special keywords include:", 13,"Commands", 9,"Lis" + = "t",TokenEscapeChar,Token38,"the available utility commands", 13 + = "FileCommands", 9,"List all",TokenEscapeChar,Token2 + = TokenEscapeChar,Token4,"-specific commands", 13,"Modules", 9 + = 9,"List",TokenEscapeChar,Token2,"module titles", 13,"Synta" + = "x", 9, 9,"Explain",TokenEscapeChar,Token2,"syntax message" + = " format", 0 + ;= " <subjects> attempts to give useful information" + ;= " on the selected topics. Special keywords include:",13 + ;= "Commands", 9, "List all the available utility commands",13 + ;= "FileCommands", 9 + ;= "List all the filing system-specific commands",13 + ;= "Modules", 9, 9, "List the module titles",13 + ;= "Syntax", 9, 9, "Explain the syntax message format",0 + | +Break_Help DCB "HUTMBRK", 0 +Reset_Help DCB "HUTMRES", 0 +PowerOn_Help DCB "HUTMPOW", 0 +RMEnsure_Help DCB "HUTMRME", 0 +RMEnsure_Syntax DCB "SUTMRME", 0 +Syntax_Help DCB "HUTMSYN", 0 +Quit_Help DCB "HUTMQUI", 0 +GOS_Syntax DCB "SUTMGOS", 0 +Modules_Syntax DCB "SUTMMOD", 0 +Quit_Syntax DCB "SUTMQUI", 0 +RMFaster_Help DCB "HUTMRMF", 0 +RMFaster_Syntax DCB "SUTMRMF", 0 +RMKill_Help DCB "HUTMRMK", 0 +RMKill_Syntax DCB "SUTMRMK", 0 +RMLoad_Help DCB "HUTMRML", 0 +RMLoad_Syntax DCB "SUTMRML", 0 +RMRun_Help DCB "HUTMRRN", 0 +RMRun_Syntax DCB "SUTMRRN", 0 +RMTidy_Help DCB "HUTMRMT", 0 +RMTidy_Syntax DCB "SUTMRMT", 0 +RMClear_Help DCB "HUTMRMC", 0 +RMClear_Syntax DCB "SUTMRMC", 0 +RMReInit_Help DCB "HUTMRMR", 0 +RMReInit_Syntax DCB "SUTMRMR", 0 +ROMModules_Help DCB "HUTMROM", 0 +ROMModules_Syntax DCB "SUTMROM", 0 +Set_Help DCB "HUTMSET", 0 +Set_Syntax DCB "SUTMSET", 0 +SetMacro_Help DCB "HUTMSTM", 0 +SetMacro_Syntax DCB "SUTMSTM", 0 +SetEval_Help DCB "HUTMSTE", 0 +SetEval_Syntax DCB "SUTMSTE", 0 +Show_Help DCB "HUTMSHO", 0 +Show_Syntax DCB "SUTMSHO", 0 +Time_Help DCB "HUTMTIM", 0 +Time_Syntax DCB "SUTMTIM", 0 +Unset_Help DCB "HUTMUNS", 0 +Unset_Syntax DCB "SUTMUNS", 0 +Echo_Help DCB "HUTMECH", 0 +Ignore_Help DCB "HUTMIGN", 0 +Ignore_Syntax DCB "SUTMIGN", 0 +IF_Help DCB "HUTMIF", 0 +IF_Syntax DCB "SUTMIF", 0 +Status_Help DCB "HUTMSTA", 0 +Unplug_Help DCB "HUTMUNP", 0 +Unplug_Syntax DCB "SUTMUNP", 0 +RMInsert_Help DCB "HUTMRMI", 0 +RMInsert_Syntax DCB "SUTMRMI", 0 +Error_Help DCB "HUTMERR", 0 +Error_Syntax DCB "SUTMERR", 0 +Eval_Help DCB "HUTMEVL", 0 +Eval_Syntax DCB "SUTMEVL", 0 +GO_Help DCB "HUTMGO", 0 +GOS_Help DCB "HUTMGOS", 0 +Append_Help DCB "HUTMAPP", 0 +Append_Syntax DCB "SUTMAPP", 0 +Build_Help DCB "HUTMBUI", 0 +Build_Syntax DCB "SUTMBUI", 0 +Close_Help DCB "HUTMCLO", 0 +Close_Syntax DCB "SUTMCLO", 0 +Create_Help DCB "HUTMCRE", 0 +Create_Syntax DCB "SUTMCRE", 0 +Delete_Help DCB "HUTMDEL", 0 +Delete_Syntax DCB "SUTMDEL", 0 +Dump_Help DCB "HUTMDMP", 0 +Dump_Syntax DCB "SUTMDMP", 0 +Exec_Help DCB "HUTMEXE", 0 +Exec_Syntax DCB "SUTMEXE", 0 +FX_Help DCB "HUTMFX", 0 +FX_Syntax DCB "SUTMFX", 0 +Key_Help DCB "HUTMKEY", 0 +Key_Syntax DCB "SUTMKEY", 0 +List_Help DCB "HUTMLST", 0 +List_Syntax DCB "SUTMLST", 0 +Load_Help DCB "HUTMLOD", 0 +Load_Syntax DCB "SUTMLOD", 0 +Print_Help DCB "HUTMPRI", 0 +Print_Syntax DCB "SUTMPRI", 0 +Opt_Help DCB "HUTMOPT", 0 +Opt_Syntax DCB "SUTMOPT", 0 +Remove_Help DCB "HUTMREM", 0 +Remove_Syntax DCB "SUTMREM", 0 +Save_Help DCB "HUTMSAV", 0 +Save_Syntax DCB "SUTMSAV", 0 +Shadow_Help DCB "HUTMSHA", 0 +Shadow_Syntax DCB "SUTMSHA", 0 +Spool_Help DCB "HUTMSPL", 0 +Spool_Syntax DCB "SUTMSPL", 0 +SpoolOn_Help DCB "HUTMSPO", 0 +SpoolOn_Syntax DCB "SUTMSPO", 0 +TV_Help DCB "HUTMTV", 0 +TV_Syntax DCB "SUTMTV", 0 +Type_Help DCB "HUTMTYP", 0 +Type_Syntax DCB "SUTMTYP", 0 +Help_Help DCB "HUTMHLP", 0 + ] + +modules_help1 DCB "HUTMMOD", 0 +commands_helpstr + DCB "HUTMCOM", 0 +fscommands_helpstr + DCB "HUTMFSC", 0 +modjack_hstr DCB "HUTMMD", 0 +modjack_comms DCB "HUTMCM", 0 +modjack_filecomms + DCB "HUTMFS", 0 +modjack_confs DCB "HUTMCK", 0 +modjack_aob DCB "HUTMHK", 0 + + END diff --git a/s/TickEvents b/s/TickEvents new file mode 100644 index 0000000000000000000000000000000000000000..6907bb431d2f55a9874c9395dccf2a5700cd3388 --- /dev/null +++ b/s/TickEvents @@ -0,0 +1,249 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + TTL => TickEvents + +; This file revised by TMD 28-Jan-94 to +; a) Correct internals to time n ticks not n+1 +; b) Change externals to add 1 to compensate for user subtracting 1 +; c) Fix RemoveTickerEvent to add this nodes time onto the next one +; These fix bug MED-02498. + +; There are two (centisecond) ticker SWIs : +; SWI CallAfter calls the given address once, after the given number of ticks +; SWI CallEvery " " " " every N centiseconds + +; In : R0 is (signed) number of centiseconds +; R1 is address to call +; R2 is value of R12 to pass to code + +CallAfter_Code ROUT + MOV r10, #0 +TickTockCommon + Push "r0-r3, lr" + CMP r0, #0 + BLE %FT99 + + MOV r3, #TickNodeSize + BL ClaimSysHeapNode + BVS %FT97 + + MOV r3, r2 + LDMFD stack, {r0-r2} + STR r1, [r3, #TickNodeAddr] + STR r10, [r3, #TickNodeRedo] + STR r2, [r3, #TickNodeR12] + MOV r1, r3 + + ADD r0, r0, #1 ; compensate for n+1 bug + BL InsertTickerEvent + + Pull "r0-r3, lr" + ExitSWIHandler + +99 ADR r0, ErrorBlock_BadTime + [ International + BL TranslateError + ] +97 + [ Fix14 + ADD sp, sp, #1*4 ; junk old R0 + Pull "r1-r3, lr" + | + Pull "r0-r3, lr" + ] + B SLVK_SetV + + MakeErrorBlock BadTime + +CallEvery_Code + ADD r10, r0, #1 ; compensate for n+1 bug + B TickTockCommon + +; Data structure : +; chain of nodes +; +; +----------------------------------+ +; | Link to next node or 0 | +; +----------------------------------+ +; | Reload flag | +; +----------------------------------+ +; | Address to call | +; +----------------------------------+ +; | Value of R12 | +; +----------------------------------+ +; | No of ticks to go before call | +; +----------------------------------+ +; +; The head node's no of ticks is decremented until 0 +; Subsequent nodes contain the no of ticks to wait when they reach the +; chain head. +; If the reload flag is non-0, the node is reinserted at that number of ticks +; down the chain after every use. + + ^ 0 +TickNodeLink # 4 ; +TickNodeRedo # 4 ; These are together +TickNodeAddr # 4 ; +TickNodeR12 # 4 ; so can LDM them + +TickNodeLeft # 4 + +TickNodeSize # 0 + +InsertTickerEvent ROUT +; R1 is node pointer, R0 ticks to wait +; R10-R12 corrupted + + Push "r0" + MOV r10, pc + ORR r10, r10, #I_bit + TEQP r10, #0 + LDR r10, =TickNodeChain +01 + MOV r11, r10 + LDR r10, [r11, #TickNodeLink] + CMP r10, #0 + BEQ %FT02 ; end of chain + LDR r12, [r10, #TickNodeLeft] + SUBS r0, r0, r12 + BGE %BT01 + ADD r0, r0, r12 + SUB r12, r12, r0 + STR r12, [r10, #TickNodeLeft] +02 + STR r1, [r11, #TickNodeLink] + STR r0, [r1, #TickNodeLeft] + STR r10, [r1, #TickNodeLink] + + Pull "r0" + MOVS pc, lr + +ProcessTickEventChain ROUT +; R0-R3, R10-R12 corruptible + LDR r3, =TickNodeChain + + LDR r1, [r3, #MetroGnome-TickNodeChain] + ADD r1, r1, #1 + STR r1, [r3, #MetroGnome-TickNodeChain] + + LDR r1, [r3, #TickNodeLink] + CMP r1, #0 + MOVEQ pc, lr ; no timers + + LDR r2, [r1, #TickNodeLeft] + SUBS r2, r2, #1 + STR r2, [r1, #TickNodeLeft] + MOVGT pc, lr ; nothing to call yet (was MOVPL) + + Push "lr" ; save IRQ_lr + [ TickIrqReenter + TEQP pc, #SVC_mode+I_bit ; switch to SVC mode, IRQ's off + NOP + Push "lr" ; save SVC_lr + ] +01 + LDMIA r1, {r2, r10, r11, r12} ; load next ptr, redo state, + ; address and R12val + STR r2, [r3] ; de-link from chain + MOV lr, pc + MOV pc, r11 ; call event handler + + LDR r0, [r1, #TickNodeRedo] + CMP r0, #0 ; CallEvery? + BLGT InsertTickerEvent ; yes, then re-insert timer + BGT %FT10 + +; Return spent ticker node to heap + + [ TickIrqReenter + TEQP pc, #SVC_mode ; IRQ's ON for the S L O W bit + MOV r2, r1 ; R2->node to free + LDR r1, =SysHeapStart + MOV r0, #HeapReason_Free + SWI XOS_Heap + TEQP pc, #SVC_mode+I_bit ; IRQ's off again + +; Check for more events down the list +10 + LDR r1, [r3, #TickNodeLink] ; get top of list + CMP r1, #0 ; list empty? + BEQ %FT02 ; yes then exit + + LDR r0, [r1, #TickNodeLeft] + CMP r0, #0 ; timed out? + BLE %BT01 ; yes then jump +02 + Pull "lr" ; restore SVC_lr + TEQP pc, #IRQ_mode+I_bit ; back to IRQ mode + NOP + Pull "pc" ; pull IRQ_lr from IRQ stack + | + TEQP pc, #SVC_mode+I_bit + MOV r0, #HeapReason_Free + Push "r2, lr" + MOV r2, r1 + LDR r1, =SysHeapStart + SWI XOS_Heap + Pull "r2, lr" + TEQP pc, #IRQ_mode+I_bit +10 + CMP r2, #0 ; end of list? + BEQ %FT02 ; yes then exit + LDR r0, [r2, #TickNodeLeft] + CMP r0, #0 + MOVLE r1, r2 + BLE %BT01 +02 + Pull "pc" + ] + +RemoveTickerEvent_Code +; R0 is address of code to remove, R1 the R12 value + TEQP pc, #SVC_mode+I_bit + LDR r10, =TickNodeChain +01 + LDR r11, [r10] + CMP r11, #0 + ExitSWIHandler EQ + LDR r12, [r11, #TickNodeAddr] + CMP r12, r0 + LDREQ r12, [r11, #TickNodeR12] + CMPEQ r12, r1 + MOVNE r10, r11 + BNE %BT01 + + Push "r0-r2, lr" + MOV r2, r11 + LDR r11, [r11, #TickNodeLink] ; prev->link = this->link + STR r11, [r10] + + TEQ r11, #0 ; if next node exists + LDRNE r14, [r11, #TickNodeLeft] ; then add our time-to-go onto its + LDRNE r0, [r2, #TickNodeLeft] + ADDNE r14, r14, r0 + STRNE r14, [r11, #TickNodeLeft] + + BL FreeSysHeapNode + Pull "r0-r2, lr" + B %BT01 + +ReadMetroGnome + MOV r0, #0 + LDR r0, [r0, #MetroGnome] + ExitSWIHandler + + LTORG + + END diff --git a/s/UnSqueeze b/s/UnSqueeze new file mode 100644 index 0000000000000000000000000000000000000000..1536493dc1eeb7d904377854ba7d1f6b84d53857 --- /dev/null +++ b/s/UnSqueeze @@ -0,0 +1,352 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; +; s.UnSqueeze by RCC 25-Aug-87 +; This is a bit of code to be included in self-decompressing images to +; expand the image in place. See elsewhere for details of the compression +; algorithm. +; +; *********************************** +; *** C h a n g e L i s t *** +; *********************************** + +; Date Name Description +; ---- ---- ----------- +; 13-Feb-90 TDobson Minor optimisation which saves 1 instruction for +; every output word that isn't a "short" or a "long". +; 15-Feb-90 TDobson Started conversion for inclusion in RISC OS kernel + +; GET Hdr:Debug + +; Constants defining partition of nibble value space: these must match +; corresponding values in mod.squeeze. + +NibsLong * 7 +NibsShort * (14-NibsLong) +MinShort * (2+NibsLong) +MinLong * 2 + +; ************************************************************************** +; +; CheckForSqueezedModule - Check whether a module is squeezed, and +; unsqueeze it if it is +; +; in: R9 -> module node +; R10 -> environment string +; R12 -> incarnation node +; +; out: R9 preserved, but module node pointed to may have code entry changed +; to point to expanded copy of module +; R10, R12 preserved +; R0-R6 may be corrupted +; +; If offset to init entry is negative, then (offset BIC &80000000) is the +; offset from the size of the encoded module. The last 5 words of this are +; as follows + + ^ -5*4 +Squeeze_DecodedSize # 4 ; size of decoded image (bytes) +Squeeze_EncodedSize # 4 ; size of encoded image (--"--) +Squeeze_TablesSize # 4 ; size of short+long tables (--"--) +Squeeze_NShorts # 4 ; number of "short" entries +Squeeze_NLongs # 4 ; number of "long" entries + ASSERT @=0 + +CheckForSqueezedModule ROUT + BIC lr, lr, #V_bit ; prepare for normal exit (V clear) + LDR R6, [R9, #Module_code_pointer] ; R6 -> module code + LDR R5, [R6, #Module_Init] ; R5 = offset to init entry + EORS R5, R5, #&80000000 ; take off top bit + MOVMIS PC, lr ; if -ve now, then it's a normal module, so exit doing nothing + +; it's a squeezed module, R5 = size of compressed module + + Push "R6-R12,lr" ; save other registers (and pointer to module base) + +; DLINE "Unsqueezing module" + + ADD R5, R6, R5 ; R5 -> byte after end of module + LDMDB R5!, {R8-R12} ; load all the data - R8=decoded size, R9=encoded size + ; R10=tables size, R11=no. of shorts, R12=no. of longs + + SUB R10, R5, R10 ; R10 -> start (lowest address) of encoded tables + ; = highest address +1 of encoded data + SUB R9, R10, R9 ; R9 -> lowest address of encoded data + +; DREG R8, "Claiming block for module of size " + + MOV R3, R8 ; now claim a block for the expanded code + BL RMAClaim_Chunk + BVS ExpandFailed1 + +; DREG R2, "Successfully claimed block for expanded code at " + + MOV R7, R2 ; R7 -> start of expanded module + + ADD R3, R11, R12 ; R3 = no. of shorts and longs + MOV R3, R3, LSL #2 ; convert to bytes + +; DREG R3, "Claiming block for shorts+longs of size " + + BL RMAClaim_Chunk + BVS ExpandFailed2 ; must free module block before exiting! + +; DREG R2, "Successfully claimed block for shorts+longs at " + + MOV R6, R2 ; R6 -> start of expanded table of shorts+longs + + ADD R8, R7, R8 ; R8 -> highest address of decoded image +1 + +; We only need nLongs and nShorts while we are decoding the tables. +; Afterwards we will re-use the registers for pointers to start of tables. + + MOV R5, R10 ; R5 is ptr into encoded tables + MOV R4, #0 ; this is the first table el + +; DLINE "Expanding shorts+longs table" + +decodeTab + ; Require: R11 -- no of els left to decode + ; R6 -- ptr into decoded table + ; R5 -- ptr into encoding + ; R4 -- = 0 iff this is the shorts table (i.e. 4-byte vals) + +; I believe this loop could be made good deal smaller and possibly +; faster, but it's only a couple of hundred bytes and it works. + + MOV R2, R6 ; stash away base of first table + MOV R3, #-1 ; start as if previous entry was -1 +decodeEntry + SUBS R11, R11, #1 ; while (--nEntries >= 0) { + BLT decodedTab ; assert: previous word is in R3 + LDRB R1, [R5], #1 ; byte = *p++ + SUBS R0, R1, #10 + BGE greaterThan9 +literalOrOnes + CMPS R1, #0 + BNE ones +literal + LDRB R0, [R5], #1 + LDRB R1, [R5], #1 + ORR R0, R0, R1, LSL #8 + LDRB R1, [R5], #1 + ORR R0, R0, R1, LSL #16 + CMPS R4, #0 ; in the 4-byte (short encodings) table? + LDREQB R1, [R5], #1 ; yes, so include the 4th byte + ORREQ R0, R0, R1, LSL #24 ; in the resultant word + ADD R3, R3, R0 + STR R3, [R6], #4 + B decodeEntry +ones + SUB R11, R11, R1 + ADD R11, R11, #1 +anotherOne ; Have number of increment-by-ones in R1 + ADD R3, R3, #1 + STR R3, [R6], #4 + SUBS R1, R1, #1 + BGT anotherOne + B decodeEntry +greaterThan9 + CMPS R1, #92 + ADDLT R3, R3, R0 + STRLT R3, [R6], #4 + BLT decodeEntry +greaterThan91 + SUBS R0, R1, #174 + BLT oneMore +twoMore + LDRB R1, [R5], #1 + ORR R0, R1, R0, LSL #16 + LDRB R1, [R5], #1 + ORR R0, R0, R1, LSL #8 + ADD R3, R3, R0 + STR R3, [R6], #4 + B decodeEntry +oneMore + SUBS R0, R1, #92 + LDRB R1, [R5], #1 + ORR R0, R1, R0, LSL #8 + ADD R3, R3, R0 + STR R3, [R6], #4 + B decodeEntry ; } /* end while (--nEntries >= 0) { */ + +decodedTab + CMPS R4, #0 ; if isShorts then + BNE finishLongs ; else finishLongs +finishShorts + MOV R11, R12 ; no of els to decode = nLongs + MOV R12, R2 ; R12 = &shorts[0] + MOV R2, R6 ; stash away start of longs table + MOV R4, #1 ; next table is longs + B decodeTab +finishLongs + MOV R11, R2 ; R11 = &longs[0] + +; DLINE "Finished expanding shorts+longs table" + +decodedBothTabs + ; Now have: R12 = &shorts[0] + ; R11 = &longs[0] + ; R10 = highest address +1 of encoded data + ; R9 = lowest address of encoded data + ; R8 = highest address +1 of decoded data + ; + ; R0..R7 are free for workspace + +; DREG R12, "Shorts table at " +; DREG R11, "Longs table at " +; DREG R9, "Encoded data start " +; DREG R10, "Encoded data end+1 " +; DREG R8, "Decoded data end+1 " + +decodePair + CMPS R10, R9 ; Have we reached the base ? + BLE doneDecode + LDRB R6, [R10, #-1]! ; byte value + ; The words will be put in R4 and R5, to be STMDB'd + AND R3, R6, #15 ; first nibble + SUBS R0, R3, #MinShort ; idx = (val - 8) + BLT notshort0 +short0 + LDRB R1, [R10, #-1]! + ORR R0, R1, R0, LSL #8 + LDR R4, [R12, R0, LSL #2] ; w = shorts[(nibble-8)<<8 | *p--] + B gotFirst +notshort0 + SUBS R0, R3, #MinLong ; idx = (val - 2) + BLT notlong0 +long0 + LDRB R1, [R10, #-1]! + ORR R0, R1, R0, LSL #8 + LDR R0, [R11, R0, LSL #2] ; w = longs[(nibble-2)<<8 | *p--] + LDRB R1, [R10, #-1]! + ORR R4, R1, R0, LSL #8 + B gotFirst +notlong0 + MOVS R4, R3 ; TMD 13-Feb-90: combine 2 instructions here + ; used to be CMPS R3,#0; MOVEQ R4,R3 + BEQ gotFirst +literal0 + LDRB R0, [R10, #-1]! + LDRB R1, [R10, #-1]! + ORR R0, R0, R1, LSL #8 + LDRB R1, [R10, #-1]! + ORR R0, R0, R1, LSL #16 + LDRB R1, [R10, #-1]! + ORR R4, R0, R1, LSL #24 + +gotFirst + ; Phew! We have the first word of the pair (in R4), now we have + ; to do (almost) the same again, result in R5, and STMDB. + + MOV R3, R6, LSR #4 ; second nibble + SUBS R0, R3, #MinShort ; idx = (val - 8) + BLT notshort1 +short1 + LDRB R1, [R10, #-1]! + ORR R0, R1, R0, LSL #8 + LDR R5, [R12, R0, LSL #2] ; w = shorts[(nibble-8)<<8 | *p--] + STMDB R8!, {R4,R5} + B decodePair +notshort1 + SUBS R0, R3, #MinLong ; idx = (val - 2) + BLT notlong1 +long1 + LDRB R1, [R10, #-1]! + ORR R0, R1, R0, LSL #8 + LDR R0, [R11, R0, LSL #2] ; w = longs[(nibble-2)<<8 | *p--] + LDRB R1, [R10, #-1]! + ORR R5, R1, R0, LSL #8 + STMDB R8!, {R4,R5} + B decodePair +notlong1 + MOVS R5, R3 ; TMD 13-Feb-90: combine 2 instructions here + ; used to be CMPS R3,#0; MOVEQ R5,R3 + + ; This doesn't pay off much + STMEQDB R8!, {R4,R5} ; might be better to swap round + BEQ decodePair ; literal and zero, to save 3S on +literal1 ; the longer path ? + LDRB R0, [R10, #-1]! + LDRB R1, [R10, #-1]! ; If I had the right byte-sex and + ORR R0, R0, R1, LSL #8 ; a couple of registers to spare, + LDRB R1, [R10, #-1]! ; could do this in 15S instead of 22S + ORR R0, R0, R1, LSL #16 ; using the load non-aligned word code + LDRB R1, [R10, #-1]! ; given in ARM CPU Manual. + ORR R5, R0, R1, LSL #24 + STMDB R8!, {R4,R5} + B decodePair + +doneDecode + +; DREG R8, "Finished decoding, module at " + +; now R8 -> the completely unsqueezed module + +; so first, free the shorts+longs table block +; R12 -> shorts, which is first of the two + + MOV R2, R12 + +; DREG R2, "Freeing shorts+longs table at " + + BL FreeRMABlock + +; ignore any error from this + MOV R3, R8 ; save pointer to expanded module + Pull "R2,R7-R12" ; pull pointer to original module base into R2 and restore other registers + +; DREG R2, "Freeing original module block at " + + BL FreeRMABlock ; may fail because original module is in ROM, so ignore error + +; DLINE "Returning new module to OS" + + STR R3, [R9, #Module_code_pointer] ; point module node at expanded module + Pull PC,,^ ; exit (VC) + +; come here if failed to claim block for tables + +ExpandFailed2 + +; DLINE "Failed to claim table block, freeing module block" + + Push R0 ; save original error pointer + MOV R2, R7 + BL FreeRMABlock + Pull R0 ; restore error pointer, and drop thru to ... + +; come here if failed to claim block for expanded module + +ExpandFailed1 + Pull "R6-R12, lr" ; restore registers + ORRS PC, lr, #V_bit ; and exit V set + +; subroutine to free a block in RMA +; in: R2 -> block +; out: R0,R1 corrupted + +FreeRMABlock ENTRY +; LDR R0, [R2, #-4] +; DREG R0, "FreeRMABlock called, block size purports to be " + + MOV R0, #HeapReason_Free + MOV R1, #RMAAddress + SWI XOS_Heap + EXIT + +; InsertDebugRoutines + + END diff --git a/s/Utility b/s/Utility new file mode 100644 index 0000000000000000000000000000000000000000..e2b8e2259f0375d5929b211df7292492724fd018 --- /dev/null +++ b/s/Utility @@ -0,0 +1,755 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; + TTL => Utility + + +; ***************************************************************************** +; Arthur Utility commands + +SysModules_Info ROUT ; start of ROM modules chain + & EndOfKernel-SysModules_Info + +UtilityMod + & StartSuper-UtilityMod + & 0 ; no initialisation + & Util_Die-UtilityMod + [ DriversInKernel + & 0 ; no services ta + | + & Util_Service-UtilityMod ; code to register printer buffer with Buffer manager + ] + & UtilModTitle-UtilityMod + & UtilHelpStr-UtilityMod + & UtilHelpTab-UtilityMod + & 0 + & 0 + & 0 + & 0 + [ International_Help <> 0 + & MessageFileName-UtilityMod + | + & 0 + ] + +Module_BaseAddr SETA UtilityMod + + [ :LNOT: DriversInKernel +Util_Service ROUT + TEQ r1, #Service_BufferStarting + TEQNE r1, #Service_DeviceFSCloseRequest + MOVNES pc, lr + + TEQ r1, #Service_BufferStarting + BNE %FT10 + Push "r0-r3,lr" + +; Register buffers with buffer manager in order of speed - first is fast + + [ MouseBufferManager + MOV r0, #BufferFlags_GenerateInputFull + LDR r1, =MouseBuff + LDR r2, =MouseBuff + MouseBuffSize + MOV r3, #Buff_Mouse + SWI XBuffer_Register ; register mouse input buffer + ] + MOV r0, #BufferFlags_GenerateInputFull :OR: BufferFlags_SendThresholdUpCalls + LDR r1, =RS423InBuff + LDR r2, =RS423InBuff + RS423InBuffSize + MOV r3, #Buff_RS423In + SWI XBuffer_Register ; register serial input buffer + + MOV r0, #BufferFlags_GenerateOutputEmpty + LDR r1, =RS423OutBuff + LDR r2, =RS423OutBuff + RS423OutBuffSize + MOV r3, #Buff_RS423Out + SWI XBuffer_Register ; register serial output buffer + + MOV r0, #0 ; used as index to PrinterBufferThing + LDR r1, [r0, #PrinterBufferAddr] ; r1 -> start of buffer + LDR r2, [r0, #PrinterBufferSize] ; r2 = size + ADD r2, r2, r1 ; r2 -> end+1 of buffer + MOV r3, #Buff_Print + MOV r0, #BufferFlags_GenerateOutputEmpty + SWI XBuffer_Register ; register the MOS's printer buffer + + Pull "r0-r3,pc" + +; service DeviceFSCloseRequest +; in: r2 = handle we are requested to close +; if r2 = PrinterActive (word) or SerialInHandle (byte) or SerialOutHandle (byte) +; then zero appropriate variable and close file, then claim service +; NB there is a disadvantage to doing it for SerialInHandle, in that it won't get +; opened again, but we assume they accidentally left it in an fx2,2 state +; + +10 + Push "r0,r1,lr" + MOV r0, #0 + LDR r1, [r0, #OsbyteVars + :INDEX: PrinterActive] + TEQ r1, r2 + STREQ r0, [r0, #OsbyteVars + :INDEX: PrinterActive] + BEQ %FT20 + LDRB r1, [r0, #OsbyteVars + :INDEX: SerialInHandle] + TEQ r1, r2 + STREQB r0, [r0, #OsbyteVars + :INDEX: SerialInHandle] + BEQ %FT20 + LDRB r1, [r0, #OsbyteVars + :INDEX: SerialOutHandle] + TEQ r1, r2 + Pull "r0,r1,pc",NE,^ ; if not any of these then exit preserving everything + STRB r0, [r0, #OsbyteVars + :INDEX: SerialOutHandle] +20 + SWI XOS_Find ; close file, ignore errors (if we get an error it's closed anyway) + MOV r1, #Service_Serviced ; indicate we closed it + Pull "r0,lr,pc",,^ ; restore r0, junk r1, and exit restoring flags + + ] + +Util_Die ROUT + CMP R10, #0 + MOVEQ PC, lr ; non-fatal : can cope + ADR R0, %FT01 + [ International + Push "lr" + BL TranslateError + Pull "pc" + | + ORRS PC, lr, #V_bit + ] + +01 + & ErrorNumber_CantKill + [ International + = "CantKill", 0 + | + = "Deleting the utility module is foolish", 0 + ] + + +UtilModTitle = "UtilityModule", 0 + +UtilHelpStr = "MOS Utilities", 9, "$VersionNo", 0 + +UtilHelpTab + Command Break, 0, 0, International_Help ; just help + Command Configure, 255, 0, Help_Is_Code_Flag :OR: International_Help + Command Commands, 0, 0, Help_Is_Code_Flag :OR: International_Help + Command Echo, 255, 0, International_Help + Command Error, 255, 1, International_Help + Command Eval, 255, 1, International_Help + Command FileCommands,0, 0, Help_Is_Code_Flag :OR: International_Help + Command GOS, 0, 0, International_Help + Command IF, 255, 2, International_Help + Command Ignore, 1, 0, International_Help + Command Modules, 0, 0, Help_Is_Code_Flag :OR: International_Help + Command PowerOn, 0, 0, International_Help ; just help + Command Reset, 0, 0, International_Help ; just help + Command RMClear, 0, 0, International_Help + Command RMEnsure, 255, 2, International_Help + Command RMFaster, 1, 1, International_Help + Command RMInsert, 2, 1, International_Help + Command RMKill, 1, 1, International_Help + Command RMLoad, 255, 1, International_Help + Command RMReInit, 255, 1, International_Help + Command RMRun, 255, 1, International_Help + Command RMTidy, 0, 0, International_Help + Command ROMModules, 0, 0, International_Help + Command Set, 255, 2, International_Help + Command SetEval, 255, 2, International_Help + Command SetMacro, 255, 2, International_Help + Command Show, 1, 0, International_Help ; *show = *show * + Command Status, 255, 0, International_Help + Command Syntax, 0, 0, International_Help + Command Time, 0, 0, International_Help + Command Unplug, 2, 0, International_Help + Command Unset, 1, 1, International_Help + = 0 + +Configure_Syntax * Module_BaseAddr +Commands_Code * Module_BaseAddr +Commands_Syntax * Module_BaseAddr +Syntax_Code * Module_BaseAddr +Syntax_Syntax * Module_BaseAddr +Echo_Syntax * Module_BaseAddr +Status_Syntax * Module_BaseAddr +FileCommands_Code * Module_BaseAddr +FileCommands_Syntax * Module_BaseAddr +Reset_Code * Module_BaseAddr +Reset_Syntax * Module_BaseAddr +Break_Code * Module_BaseAddr +Break_Syntax * Module_BaseAddr +PowerOn_Code * Module_BaseAddr +PowerOn_Syntax * Module_BaseAddr + +RMFaster_Code + Push "lr" + MOV R1, R0 + MOV R0, #ModHandReason_LookupName + SWI XOS_Module + Pull "PC", VS + CMP R3, #ROM + BLT RMFast_notinROM + MOV R1, R3 + LDR R2, [R1, #-4] + MOV R0, #ModHandReason_CopyArea + SWI XOS_Module + Pull PC + +RMFast_notinROM + ADRL R0, ErrorBlock_RMNotFoundInROM + [ International + BL TranslateError + ] + Pull lr + ORRS PC, lr, #V_bit + +RMKill_Code + MOV R6, #ModHandReason_Delete + +Rmcommon Push "lr" + MOV r1, r0 + MOV r0, r6 + SWI XOS_Module + Pull "PC" + +RMLoad_Code + MOV R6, #ModHandReason_Load + B Rmcommon + +RMRun_Code + MOV R6, #ModHandReason_Run + B Rmcommon + +RMTidy_Code + MOV R6, #ModHandReason_Tidy + B Rmcommon + +RMClear_Code + MOV R6, #ModHandReason_Clear + B Rmcommon + +RMReInit_Code + MOV R6, #ModHandReason_ReInit + B Rmcommon + +Modules_Help ROUT + Push "r2, r3, lr" + MOV r0, #0 ; Try our own message file before Global. + LDR r0, [r0, #KernelMessagesBlock] + TEQ r0, #0 + ADRNE r0, KernelMessagesBlock+4 + ADRL r1, modules_help1 + MOV r2, #0 + SWI XMessageTrans_Lookup + SWIVC XMessageTrans_Dictionary + MOVVC r1, r0 + MOVVC r0, r2 + SWIVC XOS_PrettyPrint + Pull "r2, r3, PC", VS + MOV R1, #Module_List +03 LDR R1, [R1] + CMP R1, #0 + BEQ %FT05 + LDR R0, [R1, #Module_code_pointer] + BL PrintTitle + BVC %BT03 +05 MOVVC R0, #0 + Pull "r2, r3, PC" + +PrintTitle ; of module at R0 : corrupts R0 + Push "R1, lr" + LDR R1, [R0, #Module_HelpStr] + CMP R1, #0 + ADREQ R0, NoRIT + [ International + BLEQ Write0_Translated + ADDNE R0, R1, R0 + SWINE XOS_PrettyPrint + | + ADDNE R0, R1, R0 + SWI XOS_PrettyPrint + ] + SWIVC XOS_NewLine + Pull "R1, PC" + +Modules_Code ROUT + Push "R7, lr" + + [ International + BL WriteS_Translated + = "Modules:No. Position Workspace Name", 10, 13, 0 + ALIGN + | + SWI XOS_WriteS + = "No. Position Workspace Name", 10, 13, 0 + ALIGN + ] + Pull "R7, PC", VS + + MOV R1, #0 + MOV R2, #0 + MOV R6, #0 + MOV R7, #0 +06 + SWI XOS_ReadEscapeState + Pull "R7, lr", CS + BCS AckEscape + MOV R0, #ModHandReason_GetNames + SWI XOS_Module + Pull "R7, lr", VS + BICVSS PC, lr, #V_bit ; back, clearing V + + Push "R1, R2" + CMP R6, #0 + MOVNE R1, #0 + BNE %FT02 + ADD R7, R7, #1 + MOV R0, R7 + LDR R1, =GeneralMOSBuffer + MOV R2, #256 + SWI XOS_ConvertCardinal2 + SUB R1, R1, R0 ; characters in buffer +02 CMP R1, #3 + SWILT XOS_WriteI+" " + BVS %FT03 + ADDLT R1, R1, #1 + BLT %BT02 +03 + Pull "R1, R2" + BVS %FT04 + CMP R6, #0 + SWIEQ XOS_Write0 + SWIVC XOS_WriteI+" " + MOV R0, R3 + BLVC HexR0LongWord + SWIVC XOS_WriteI+" " + MOV R0, R4 + BLVC HexR0LongWord + SWIVC XOS_WriteI+" " + SWIVC XOS_WriteI+" " + BLVC %FT01 ; title out + SWIVC XOS_NewLine + BVC %BT06 +04 + Pull "R7, PC" +01 + Push "lr" + LDR R0, [R3, #Module_Title] + CMP R0, #0 + ADDNE R0, R3, R0 + ADREQ R0, NoRIT + [ International + BLEQ Write0_Translated + SWINE XOS_Write0 + | + SWI XOS_Write0 + ] + Pull "PC", VS + CMP R6, #0 + CMPEQ R2, #0 + MOV R6, R2 + Pull "PC", EQ ; only one incarnation + SWI XOS_WriteI + Postfix_Separator + MOV R0, R5 + SWIVC XOS_Write0 + Pull "PC" + + [ International +NoRIT = "Untitled:<Untitled>", 0 + | +NoRIT = "<Untitled>", 0 + ] +starstr = "*", 13 + ALIGN + + + +Show_Code + CMP r1, #0 ; *show only? + ADREQ r0, starstr + Entry "r0",8+256 + + ADD r6, sp, #8 ; initial buffer for var expansions + MOV lr, #256+4 + STR lr, [sp, #4] ; fake heap block size + MOV lr, #&ffffffff + STR lr, [sp, #0] ; inhibit page mode off on exit + + ; Read current VDU status and save it away + MOVVC r0, #117 + SWIVC XOS_Byte + STRVC R1, [sp, #0] + SWIVC XOS_WriteI+14 ; paged mode on. + BVS ShowBang + + MOV r3, #0 ; enumeration pointer +01 + LDR r0, [sp, #Proc_LocalStack + 0*4] ; wildcard +10 + MOV r1, r6 ; 'heap' block + LDR r2, [r6, #-4] ; block size + SUB r2, r2, #4 + MOV r4, #0 ; no expansion + SWI XOS_ReadVarVal + BVS Show_ErrorReading + + ; Varname + MOV r0, r3 + SWI XOS_Write0 + BVS ShowBang + + ; (Number) or (Macro) as appropriate + CMP R4, #VarType_String + BEQ skipvalprt + [ :LNOT: International + SWI XOS_WriteS + = " (", 0 + ALIGN + BVS ShowBang + ] + CMP R4, #VarType_Number + MOVEQ R2, #256 + LDREQ R0, [R1] + SWIEQ XOS_BinaryToDecimal + ADREQ R0, %FT02 + ADRHI R0, %FT03 + [ International + BLVC Write0_Translated + | + SWIVC XOS_Write0 + SWIVC XOS_WriteI+")" + ] + BVS ShowBang +skipvalprt + ; " : " + SWI XOS_WriteS + = " : ", 0 + ALIGN + BVS ShowBang + + ; Now output the value's value + MOV R5, #-1 +05 ADD R5, R5, #1 + CMP R5, R2 + BEQ %FT06 + SWI XOS_ReadEscapeState + BLCS AckEscape + BVS ShowBang + LDRB R0, [R1, R5] + CMP R0, #&7F + MOVEQ R0, #"?"-"@" + CMP R0, #31 + ADDLE R0, R0, #"@" + SWILE XOS_WriteI+"|" + BVS ShowBang + + CMP R0, #"|" + CMPNE R0, #"""" + CMPNE R0, #"<" + SWINE XOS_WriteC + BVS ShowBang + BNE %BT05 + + CMP R4, #VarType_Macro + SWINE XOS_WriteI+"|" + SWIVC XOS_WriteC + BVC %BT05 +ShowBang + STR r0, [sp, #Proc_LocalStack + 0*4] + LDR lr, [sp, #Proc_LocalStack + 1*4] ; lr in + ORR lr, lr, #V_bit + STR lr, [sp, #Proc_LocalStack + 1*4] + +Show_Exit + ; Release buffer if necessary + ADD lr, sp, #8 ; stack buffer + TEQ r6, lr + MOVNE r0, #ModHandReason_Free + MOVNE r2, r6 + SWINE XOS_Module + + ; Switch paged mode off if necessary + LDR lr, [sp, #0] + TST lr, #5 + SWIEQ XOS_WriteI+15 ; paged mode off + + EXITS + +06 SWI XOS_NewLine + BVS ShowBang + B %BT01 + +Show_ErrorReading + ; Error from OS_ReadVarVal: + ; VarCantFind - end of *show + ; BuffOverflow - try and extend buffer + ; other - return as error + LDR r5, [r0] + LDR lr, =ErrorNumber_VarCantFind + TEQ r5, lr + BEQ Show_Exit + LDR lr, =ErrorNumber_BuffOverflow + TEQ r5, lr + BNE ShowBang + + ; try and extend the buffer + CLRV + MOV r1, r3 ; actual name so retry gets this node exactly + ADD lr, sp, #8 ; stack buffer + TEQ r6, lr + MOV r0, #ModHandReason_Free + MOV r2, r6 + MOV r6, lr ; to prevent any attempt at freeing in ShowBang + SWINE XOS_Module + BVS ShowBang + + MOV r0, r1 + MOV r1, #ARM_CC_Mask + MOV r2, #-1 ; To sence size + MOV r3, #0 ; 1st var + MOV r4, #0 ; unexpanded + SWI XOS_ReadVarVal + CLRV ; error will be buffer overflow + MOV r1, r3 ; varname again + MVN r3, r2 + ADD r3, r3, #&ff ; round up to 256 byte boundary + BIC r3, r3, #&ff + MOV r0, #ModHandReason_Claim + SWI XOS_Module + BVS ShowBang + MOV r6, r2 + MOV r0, r1 + MOV r3, #0 ; restart from that node + B %BT10 + + [ International +02 + = "Number:(Number)", 0 +03 + = "Macro:(Macro)", 0 + | +02 + = "Number", 0 +03 + = "Macro", 0 + ] + +Set_Code ROUT + MOV R4, #VarType_String +01 + Push "lr" + + ; space terminated name in R0 + + ; Skip name in R1 + MOV R1, R0 +02 LDRB R2, [R1], #1 + CMP R2, #" " + BNE %BT02 + + ; Then skip spaces +03 LDRB R2, [R1], #1 + CMP R2, #" " + BEQ %BT03 + SUB R1, R1, #1 + + ; r2 +ve to set, r3 = 0 for 1st var + MOV R2, #1 + MOV R3, #0 + SWI XOS_SetVarVal + Pull "PC" + + LTORG + +SetMacro_Code MOV R4, #VarType_Macro + B %BT01 + +SetEval_Code MOV R4, #VarType_Expanded + B %BT01 + +Unset_Code ROUT + Push "lr" + MOV R2, #-1 + MOV R3, #0 +01 SWI XOS_SetVarVal + BVC %BT01 + Pull "lr" + BICS PC, lr, #V_bit + +Echo_Code ROUT + Push "lr" + MOV R2, #GS_NoQuoteMess + SWI XOS_GSInit +01 SWI XOS_GSRead + BVS %FT02 + MOVCC R3, R0 + MOVCC R0, R1 + SWICC XOS_WriteC + BVS %FT02 + MOVCC R0, R3 + BCC %BT01 + SWI XOS_NewLine +02 + Pull "PC" + +Commands_Help ROUT + Push "R0, lr" ; keep buffer pointer + ADRL R0, commands_helpstr + MOV R1, #0 +KeyHelpCommon ; also used by *Configure + Push r1 +; R2 & R3 can be junked here? + MOV r1, r0 + MOV r0, #0 ; Try our own message file before Global. + LDR r0, [r0, #KernelMessagesBlock] + TEQ r0, #0 + ADRNE r0, KernelMessagesBlock+4 + MOV r2, #0 + SWI XMessageTrans_Lookup + SWIVC XMessageTrans_Dictionary + MOVVC r1, r0 + MOVVC r0, r2 + SWIVC XOS_PrettyPrint + Pull "r1,lr,PC", VS ; if error, pull R1, junk stacked R0 and exit + Pull "r1,r3" ; restore r1 and get buffer pointer + MOV r0, #0 + ADRL R2, SysCommsModule + BL OneModuleK + BVS %FT10 + MOV R6, #Module_List +12 LDR R6, [R6] + CMP R6, #0 + BEQ %FT10 + LDR R2, [R6, #Module_code_pointer] + BL OneModuleK + BVC %BT12 +10 MOVVC R0, #0 + Pull "PC" + +FileCommands_Help + Push "R0, lr" + ADRL R0, fscommands_helpstr + MOV R1, #FS_Command_Flag + B KeyHelpCommon + +; take module code pointer in r2 +; flags in r1 +; HelpBufferSize buffer in r3 +; string to print in r0 + +OneModuleK ROUT + Push "r2-r6, lr" + LDR R4, [R2, #Module_HC_Table] + CMP R4, #0 + Pull "r2-r6, PC", EQ ; no table + ORR R3, R3, #&80000000 ; buffer position ptr and flag + MOV R5, #0 ; buffer offset + + ADD R2, R2, R4 ; point at table start. +03 MOV R6, R2 + LDRB R4, [R2] + CMP R4, #0 + BEQ %FT06 + +04 LDRB R4, [R6], #1 + CMP R4, #0 + BNE %BT04 + ADD lr, R6, #3 + BIC lr, lr, #3 ; align but leave r6 at end of command for below (05) + LDR R4, [lr, #0] ; code offset + CMP r1, #-1 ; fudge? + BEQ %FT78 + CMP R4, #0 + ADDEQ R2, lr, #16 + BEQ %BT03 + LDRB R4, [lr, #7] + BIC R4, R4, #(Help_Is_Code_Flag:OR:International_Help) :SHR: 24 + CMP R4, R1, LSR #24 ; move flags into bottom byte +79 ADDNE R2, lr, #16 + BNE %BT03 + TST R3, #&80000000 + BEQ %FT05 + SWI XOS_NewLine + SWIVC XOS_NewLine + BVS %FT77 + MOV r4, r0 + CMP r0, #0 + BEQ OneModuleK_PrintTitle ; Don't trust MessageTrans to preserve Z + SWI XMessageTrans_Dictionary + STMDB sp!, {r1} + MOVVC r1, r0 + MOVVC r0, r4 + SWIVC XOS_PrettyPrint + LDMIA sp!, {r1} + B %FT77 +OneModuleK_PrintTitle + LDR r0, [stack] + BL PrintTitle +77 + MOVVC r0, r4 + Pull "r2-r6, PC", VS + BIC R3, R3, #&80000000 +05 + SUB lr, r6, r2 + RSB r4, r5, #HelpBufferSize + CMP r4, lr ; have we got enough space for command+tab + BCS %FT07 + MOV r4, #0 ; no, so 0 terminate what we've got and print it + SUB r5, r5, #1 ; write 0 over trailing tab + STRB r4, [r3, r5] + MOV r4, r0 + MOV r0, r3 + SWI XOS_PrettyPrint + SWIVC XOS_NewLine + Pull "r2-r6,pc",VS + MOV r0, r4 + MOV r5, #0 ; start again with empty buffer +07 + LDRB r4, [r2], #1 ; copy command + CMP r4, #0 + STRNEB r4, [r3, r5] + ADDNE r5, r5, #1 + BNE %BT07 + MOV r4, #TAB ; add tab + STRB r4, [r3, r5] + ADD r5, r5, #1 + ADD r2, r2, #3+16 ; align and move on to next command + BIC r2, r2, #3 + B %BT03 + +78 CMP r4, #0 + B %BT79 + +06 TST R3, #&80000000 + Pull "r2-r6, PC", NE + Push "R0" + MOV R0, #0 + SUB R5, R5, #1 + STRB R0, [R5, R3] + MOV R0, R3 + SWI XOS_PrettyPrint + STRVS r0, [stack] + Pull "R0, r2-r6, PC" + +; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +GOS_Code + Push lr + MOV r2, r0 + addr R1, UtilModTitle + MOV R0, #ModHandReason_Enter + SWI XOS_Module + Pull pc + + END diff --git a/s/vdu/vdu23 b/s/vdu/vdu23 new file mode 100644 index 0000000000000000000000000000000000000000..601dec2f8afe9d52a12e02eb5d03633a098e9d6f --- /dev/null +++ b/s/vdu/vdu23 @@ -0,0 +1,1677 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.Vdu23 + +; ***************************************************************************** +; +; DefineChar - define soft character +; +; in: R0 = char to be defined +; + +DefineChar + ADD R1, WsPtr, #(Font-32*8) + ADD R1, R1, R0, LSL #3 ; point to char definition + + ADD R2, WsPtr, #QQ+1 + LDMIA R2, {R2, R3} ; load 8 bytes + STMIA R1, {R2, R3} ; store 8 bytes +Nop + MOV PC, R14 + +; ***************************************************************************** +; +; VDU 23,7,m,d,z| - Scroll window directly +; +; m=0 Scroll text window +; m=1 Scroll entire screen +; +; d=0 Scroll right +; d=1 Scroll left +; d=2 Scroll down +; d=3 Scroll up +; d=4 Scroll "right" +; d=5 Scroll "left" +; d=6 Scroll "down" +; d=7 Scroll "up" +; +; z=0 Scroll by 1 character cell +; z=1 Scroll by 1 char vertically, 1 byte (whatever that is) horiz. +; + +Vdu23_7 ROUT + LDRB R0, [WsPtr, #QQ+1] ; R0 := m + LDRB R1, [WsPtr, #QQ+2] ; R1 := d + LDRB R2, [WsPtr, #QQ+3] ; R2 := z +Scroll012 + LDR R6, [WsPtr, #CursorFlags] + AND R1, R1, #7 ; ignore higher bits + CMP R1, #4 + BCC %FT10 + LDR R4, ScrollDirWord + CMP R1, #6 + MOVCS R4, R4, ROR #16 + AND R3, R6, #&0E + MOV R3, R3, LSL #1 + MOV R4, R4, LSR R3 + MOVS R1, R1, LSR #1 + AND R1, R4, #&0F + EORCS R1, R1, #1 +10 + Push R14 + TST R6, #ClipBoxEnableBit ; if calculating clip box + BLNE ClipScroll ; then add text window or whole screen + CMP R0, #1 ; C=1 => whole screen + ADC R1, R1, R1 ; put m into bit 0 + TEQ R2, #0 + ORRNE R1, R1, #&08 ; put z into bit 3 + ADR R0, ScrollTab + LDR R2, [R0, R1, LSL #2] + ADR R14, ScrollRetn + ADD PC, R0, R2 ; carry on entry is m + +ScrollRetn + Pull R14 + +; insert code here to re-address input cursor as well + + B AddressCursors ; re-address cursor positions + +ScrollDirWord + & &33221010 + +ScrollTab + & ScrollRightChar-ScrollTab ; window right char + & ScrollRightChar-ScrollTab ; screen right char + & ScrollLeftChar-ScrollTab ; window left char + & ScrollLeftChar-ScrollTab ; screen left char + & ScrollDown-ScrollTab ; window down char + & HardScrollDown-ScrollTab ; screen down char + & ScrollUp-ScrollTab ; window up char + & HardScrollUp-ScrollTab ; screen up char + & ScrollRightByte-ScrollTab ; window right byte + & ScrollRightByte-ScrollTab ; screen right byte + & ScrollLeftByte-ScrollTab ; window left byte + & ScrollLeftByte-ScrollTab ; screen left byte + & ScrollDown-ScrollTab ; window down byte + & HardScrollDown-ScrollTab ; screen down byte + & ScrollUp-ScrollTab ; window up byte + & HardScrollUp-ScrollTab ; screen up byte + + +; ***************************************************************************** +; +; VDU 23,17,c,t| - Set tint +; +; c=0 Set text foreground tint (default &FF) +; c=1 Set text background tint (default &00) +; c=2 Set graphics foreground tint (default &FF) +; c=3 Set graphics background tint (default 0) +; c=4 t=0 => BBC compatible ECFs, t=1 => native ECFs (default 0) +; c=5 Swap foreground and background text colours/tints +; c=6 VDU 23,17,6,x;y; - Set ECF origin to (x,y) +; c=7 VDU 23,17,7,flags,x;y;0,0 - Set character size(s) +; c=8-255 Reserved +; +; t=tint Only bits 6,7 relevant with this hardware + +Vdu23_17 + LDRB R0, [WsPtr, #QQ+1] ; get c + CMP R0, #7 + MOVHI R0, #17 ; if unknown (>7), reload R0 + BHI UnknownVdu23 ; and call UKVDU23 vector + BEQ SetCharSizes + + CMP R0, #6 + BEQ SetECFOrigin + + CMP R0, #4 + BHI SwapColours ; 5 => swap colours + + LDRB R1, [WsPtr, #QQ+2] ; tint or BBC parm + STREQ R1, [WsPtr, #BBCcompatibleECFs] ; VDU 23,17,4,t... + MOVEQ PC, R14 + + ADD R2, WsPtr, #TFTint + LDR R3, [R2, R0, LSL #2] ; get old tint + STR R1, [R2, R0, LSL #2] + + CMP R0, #2 ; graphics tint ? + BCS SetColour ; then update masks + + EOR R1, R1, R3 + TST R1, #&C0 ; are top two bits different ? + MOVEQ PC, R14 ; no need to redo table + + ; amg: use R1 here instead of 'bpp' which is R0. I need R0 in a moment. + LDR R1, [WsPtr, #BitsPerPix] + CMP R1, #8 ; are we in 8 bits-per-pixel or more? + MOVCC PC, R14 ; no, then exit + + Push "lr" + + ; amg: only do foreground or background as appropriate + CMP R0,#1 + BLNE CompileTextFg + BLEQ CompileTextBg ; update TextFgColour/TextBgColour + + Pull "lr" + +SetColoursDirty + LDR R6, [WsPtr, #CursorFlags] + ORR R6, R6, #TEUpdate ; yes, then set colours dirty + STR R6, [WsPtr, #CursorFlags] + MOV PC, R14 + +; ***************************************************************************** + +SwapColours ROUT + LDR R1, [WsPtr, #TForeCol] + LDR R2, [WsPtr, #TBackCol] + STR R1, [WsPtr, #TBackCol] + STR R2, [WsPtr, #TForeCol] + + LDR R1, [WsPtr, #TextFgColour] + LDR R2, [WsPtr, #TextBgColour] + STR R1, [WsPtr, #TextBgColour] + STR R2, [WsPtr, #TextFgColour] + + LDR R3, [WsPtr, #BitsPerPix] + CMP R3, #8 ; C=1 <=> 256 colour mode + BCC %FT10 ; [not 256 colour mode] + + LDR R1, [WsPtr, #TFTint] + LDR R2, [WsPtr, #TBTint] + STR R1, [WsPtr, #TBTint] + STR R2, [WsPtr, #TFTint] +10 + B SetColoursDirty ; don't bother optimising the case + ; when both colours are the same + +; ***************************************************************************** +; +; SetECFOrigin - Set the origin of the ECF pattern +; +; Called by VDU 23,17,6,x;y;0,0,0 +; +; in: QQ+2, QQ+3 = xlo, xhi +; QQ+4, QQ+5 = ylo, yhi +; + +SetECFOrigin ROUT + +; *****Change made by DJS +; Original code was: +; LDRB R0, [WsPtr, #QQ+3] ; xhi +; LDRB R1, [WsPtr, #QQ+2] ; xlo +; PackXtnd R0, R0, R1 ; pack 2 bytes and sign extend +; LDRB R1, [WsPtr, #QQ+5] ; yhi +; LDRB R2, [WsPtr, #QQ+4] ; ylo +; PackXtnd R1, R1, R2 ; pack 2 bytes and sign extend + + LoadCoordPair R0, R1, WsPtr, QQ+2 + +; *****End of change made by DJS + +SetECFOriginCommon + Push R14 + ADD R8, WsPtr, #GCsX ; save ECursor away, cos EIG changes it + LDMIA R8, {R6, R7} ; and we don't want it to! + + MOV R2, #&FF ; convert external-to-internal + BL EIG ; as absolute coordinates + +; now R0 = internal X; R1 = internal Y + + LDR R3, [WsPtr, #NPix] + LDR R4, [WsPtr, #Log2BPC] + + AND R0, R0, R3 ; X MOD (number of pixels per word) + +; *****Change made by DJS +; Original code was: +; MOVS R0, R0, LSL R4 ; number of bits to rotate ECF left by +; MOVEQ R0, #32 ; if zero then make 32 +; RSB R0, R0, #32 ; so we make it zero again! +; I don't think anything cares whether this value is 0 or 32 in this case - it +; is only used as Rm in a couple of MOV Rn, Rn, ROR Rm instructions. So change +; to: + MOV R0, R0, LSL R4 ; number of bits to rotate ECF left by + RSB R0, R0, #32 +; *****End of change made by DJS + + STR R0, [WsPtr, #ECFShift] ; number of bits to rotate right by + + LDR R3, [WsPtr, #YWindLimit] +; *****Change made by DJS +; Need to increase R3 by one to produce correct alignment of the ECF patterns, +; as YWindLimit is an inclusive bound, not an exclusive one. + ADD R3, R3, #1 +; *****End of change made by DJS + SUB R1, R3, R1 ; invert Y + AND R1, R1, #7 ; modulo 8 + STR R1, [WsPtr, #ECFYOffset] + + STMIA R8, {R6, R7} + + BL SetColour ; update colours now + + Pull PC + +; ***************************************************************************** +; +; SWISetECFOrigin - Entry point for SWI OS_SetECFOrigin +; +; in: R0 = x-coordinate (external coords) +; R1 = y-coordinate (-------""------) +; + +SWISetECFOrigin ROUT + Push "R0-R9, R14" + VDWS WsPtr + BL SetECFOriginCommon + Pull "R0-R9, R14" + ExitSWIHandler + +; ***************************************************************************** +; +; Scroll left and right +; +; in: C=0 => scroll window +; C=1 => scroll screen + +ScrollLeftChar + MOV R9, #0 + B ScrollLeft + +ScrollLeftByte + LDR R9, [WsPtr, #Log2BPP] + LDR R10, [WsPtr, #ModeFlags] + TST R10, #Flag_BBCGapMode ; if in BBC gap mode + [ True + +; TMD 23-May-89: BBC gap modes were done wrong here - it scrolled by 1/2 a +; BBC byte instead of 1 + + SUBNE R9, R9, #1 ; then 1 BBC byte = 2 ARM bytes + | + MOVNE R9, #1 ; then 1 BBC byte = 2 ARM bytes + ] + +ScrollLeft + LDR R10, [WsPtr, #Log2BPC] + SUB R9, R10, R9 + + MOV R10, #1 + MOV R9, R10, LSL R9 ; R9 = bytes to move by + + ADC R0, R0, R0 ; bit0(R0) set => whole screen + TST R6, #TeletextMode ; if teletext, then do special + BNE TTXScrollLeft + + Push "R0, R14" ; save link and carry + MOVS R0, R0, LSR #1 ; C=0/1 => window/screen + BL GetScrWindInfo + BL ScrollLeft2 + Pull R0 + MOVS R0, R0, LSR #1 + +; now clear right hand column + + ADDCC R0, WsPtr, #TWBRow ; C=0 => window + LDMCCIA R0, {R1-R3} ; R1 = TWBRow; R2 = TWRCol + MOVCC R0, R2 ; R3 = TWTRow; R0 = TWRCol + + ADDCS R0, WsPtr, #ScrRCol ; C=1 => screen + LDMCSIA R0, {R0, R1} ; R0 = ScrRCol; R1 = ScrBRow + MOVCS R2, R0 ; R2 = ScrRCol; R3 = 0 + MOVCS R3, #0 + +; R9 = width of column to clear (in bytes) + + BL GetBoxInfo ; get info for right hand char column + ; R2 -> top left of right hand char col + ; R5 := number of bytes for one char + ADD R2, R2, R5 ; R2 -> off right of top line + MOV R5, R9 ; R5 := real number of bytes to do + SUB R2, R2, R5 ; R2 -> top left of column to clear + Pull R14 + B ClearThisBox + +; ***************************************************************************** + +GetScrWindInfo + BCC GetWindowInfo +GetScreenInfo + MOV R0, #0 + LDR R1, [WsPtr, #ScrBRow] + LDR R2, [WsPtr, #ScrRCol] + MOV R3, #0 + B GetBoxInfo + +; ***************************************************************************** +; +; ScrollLeft2 - Scroll area of screen left (don't clear right column) +; +; in: R2 -> screen(left,top) +; R5 = width of box in bytes +; R6 = number of scan lines in box +; R7 = linelength +; R9 = number of bytes to scroll by +; + +ScrollLeft2 ROUT + SUBS R5, R5, R9 ; number of bytes to scroll + MOVEQ PC, R14 ; none to scroll + + MOV R10, R9, LSL #3 ; number of bits moving by + CMP R10, #32 + MOVCS R10, #32 ; only do 32 at a time + RSB R11, R10, #32 ; 32-number of bits moving by + +ScrollLineLeft + MOV R0, R2 ; to addr (left) + ADD R1, R0, R9 ; from addr (right) + ADD R3, R0, R5 ; end+1 to addr +10 + TST R0, #3 ; if not on word boundary + LDRNEB R4, [R1], #1 ; then copy a byte from R1 + STRNEB R4, [R0], #1 ; to R0 + CMPNE R0, R3 ; if not on bdy and not at end + BNE %BT10 ; then loop + +20 + ADD R1, R1, #3 ; round R1 up to next word + BIC R1, R1, #3 + + TEQ R11, #0 ; if no shifts, use fast code + BEQ %FT60 + + SUB R3, R3, #3 ; fudge factors anonymous + CMP R0, R3 ; if can't do any words + BCS %FT40 ; then skip + LDR R8, [R0] ; get word to be put into R4 +30 + MOV R4, R8, LSR R10 ; get 2nd bits of old word + LDR R8, [R1], #4 ; load new word + ORR R4, R4, R8, LSL R11 ; merge with 1st bits of new + STR R4, [R0], #4 ; and store + CMP R0, R3 ; if more words to do then loop + BCC %BT30 +40 + ADD R3, R3, #3 ; put it back again + +; finish off the odd bytes +; R0 -> next dest byte + + ADD R1, R0, R9 ; R1 -> next source byte + CMP R0, R3 ; if not at end +50 + LDRCCB R4, [R1], #1 ; then copy a byte from R1 + STRCCB R4, [R0], #1 ; to R0 + CMPCC R0, R3 ; check for end + BCC %BT50 ; and loop if not + + ADD R2, R2, R7 ; goto next line down + SUBS R6, R6, #1 ; one less line to do + BNE ScrollLineLeft + MOV PC, R14 + +; fast code for when R10=32, R11=0 + +60 + SUB R3, R3, #7 ; must be able to do 8 bytes + CMP R0, R3 +70 + LDMCCIA R1!, {R4, R8} ; if OK then copy 2 words + STMCCIA R0!, {R4, R8} + CMPCC R0, R3 ; check for end + BCC %BT70 + ADD R3, R3, #4 ; must be able to do 4 bytes + CMP R0, R3 +80 + LDRCC R4, [R1], #4 ; if OK then copy a word + STRCC R4, [R0], #4 + CMPCC R0, R3 ; check for end + BCC %BT80 + B %BT40 ; do odd bytes at end + +; ***************************************************************************** + +ScrollRightChar + MOV R9, #0 + B ScrollRight + +ScrollRightByte + LDR R9, [WsPtr, #Log2BPP] + LDR R10, [WsPtr, #ModeFlags] + TST R10, #Flag_BBCGapMode ; if in BBC gap mode + + [ True + +; TMD 23-May-89: BBC gap modes were done wrong here - it scrolled by 1/2 a +; BBC byte instead of 1 + + SUBNE R9, R9, #1 ; then 1 BBC byte = 2 ARM bytes + | + MOVNE R9, #1 ; then 1 BBC byte = 2 ARM bytes + ] + +ScrollRight + LDR R10, [WsPtr, #Log2BPC] + SUB R9, R10, R9 + + MOV R10, #1 + MOV R9, R10, LSL R9 ; R9 = bytes to move by + + ADC R0, R0, R0 ; bit0(R0) set => whole screen + TST R6, #TeletextMode ; if teletext, then do special + BNE TTXScrollRight + + Push "R0, R14" ; save link and carry + MOVS R0, R0, LSR #1 ; C=0/1 => window/screen + BL GetScrWindInfo + BL ScrollRight2 + Pull R0 + MOVS R0, R0, LSR #1 + +; now clear left column + + ADDCC R0, WsPtr, #TWLCol ; C=0 => window + LDMCCIA R0, {R0-R3} ; R0 = TWLCol; R1 = TWBRow + MOVCC R2, R0 ; R2 = TWLCol; R3 = TWTRow + + MOVCS R0, #0 + LDRCS R1, [WsPtr, #ScrBRow] + MOVCS R2, R0 + MOVCS R3, #0 + +; R9 = width of column to clear (in bytes) + + BL GetBoxInfo ; get info for right hand char column + ; R2 -> top left of left hand char col + ; R5 := number of bytes for one char + MOV R5, R9 ; R5 := real number of bytes to do + Pull R14 + B ClearThisBox + +; ***************************************************************************** +; +; ScrollRight2 - Scroll area of screen right (don't clear left column) +; +; in: R2 -> screen(left,top) +; R5 = width of box in bytes +; R6 = number of scan lines in box +; R7 = linelength +; R9 = number of bytes to scroll by +; + +ScrollRight2 ROUT + ADD R2, R2, R5 ; R2 -> off top right + SUB R2, R2, #1 ; R2 -> top right + + SUBS R5, R5, R9 ; number of bytes to scroll + MOVEQ PC, R14 ; none to scroll + + MOV R10, R9, LSL #3 ; number of bits moving by + CMP R10, #32 + MOVCS R10, #32 ; only do 32 at a time + RSB R11, R10, #32 ; 32-number of bits moving by + +ScrollLineRight + MOV R0, R2 ; to addr (right) + SUB R1, R0, R9 ; from addr (left) + SUB R3, R0, R5 ; end-1 to addr + + MOV R8, #(3 :SHL: 30) +10 + CMP R8, R0, LSL #30 ; EQ if (R0 AND 3)=3 + LDRNEB R4, [R1], #-1 ; if not then copy a byte + STRNEB R4, [R0], #-1 + CMPNE R0, R3 ; if not aligned and not end + BNE %BT10 ; then loop + + SUB R1, R1, #3 ; round R1 down to next word + BIC R1, R1, #3 + + SUB R0, R0, #3 ; make R0 -> word boundary + TEQ R11, #0 ; if no shifts, use fast code + BEQ %FT60 + + CMP R0, R3 ; if no words + BLS %FT40 ; then skip + LDR R8, [R0] ; get word to be put into R4 +30 + MOV R4, R8, LSL R10 + LDR R8, [R1], #-4 + ORR R4, R4, R8, LSR R11 + STR R4, [R0], #-4 + CMP R0, R3 ; if R3 < R1 then no more words + BHI %BT30 +40 + ADD R0, R0, #3 ; put it back again + +; finish off the odd bytes +; R0 -> next dest byte + + SUB R1, R0, R9 ; R1 -> next source byte + CMP R0, R3 ; check for end +50 + LDRHIB R4, [R1], #-1 ; if not end then copy byte + STRHIB R4, [R0], #-1 + CMPHI R0, R3 ; check for end + BHI %BT50 + + ADD R2, R2, R7 ; move to next row + SUBS R6, R6, #1 ; one less row to do + BNE ScrollLineRight + MOV PC, R14 + +; fast code for when R10=32, R11=0 + +60 + ADD R3, R3, #4 ; need to do at least 8 bytes + CMP R0, R3 +70 + LDMHIDA R1!, {R4, R8} ; if OK then copy 2 words + STMHIDA R0!, {R4, R8} + CMPHI R0, R3 ; check for end + BHI %BT70 + + SUB R3, R3, #4 ; put it back + CMP R0, R3 +80 + LDRHI R4, [R1], #-4 ; if OK then copy 1 word + STRHI R4, [R0], #-4 + CMPHI R0, R3 ; check for end + BHI %BT80 + B %BT40 + +; ***************************************************************************** +; +; VDU 23,16,x,y| - Change cursor flags +; +; new := (old AND y) EOR x + +Vdu23_16 + LDRB R0, [WsPtr, #CursorFlags] ; just affect bottom byte + LDRB R1, [WsPtr, #QQ+1] ; x + LDRB R2, [WsPtr, #QQ+2] ; y + AND R0, R0, R2 + EOR R0, R0, R1 + STRB R0, [WsPtr, #CursorFlags] + + TST R0, #1 + BEQ RCRLF ; leaving 81 column mode + ; so release CRLF + MOV PC, R14 + +; ***************************************************************************** +; +; Move cursor to R0 chars from boundary +; and check for being legal +; +; out: C=1 => was within window +; C=0 => outside window + + ASSERT CursorY = CursorX +4 + +CursorBdyCheck + Push R14 + BL CursorBdy + ADD R9, WsPtr, #CursorX + LDMIA R9, {R9, R10} + CMP R4, R9 + CMPCS R3, R10 + Pull PC + +; ***************************************************************************** +; +; Move cursor to boundary indicated by value of R6 in bits 1-3 +; (0 or 4 = left, 2 or 6 = right, 8 or 10 = up, 12 or 14 = down) +; + R0 character positions in +; +; out: R7, R8, R11 undefined +; R0, R1, R6, R9, R10, R12, R13 preserved +; R2-R5 are window coords (left,down,right,up) +; + ASSERT TWBRow = TWLCol + 4 + ASSERT TWRCol = TWLCol + 8 + ASSERT TWTRow = TWLCol + 12 + +InputCursorB0 + MOV R0, #0 +InputCursorBdy + ADD R11, WsPtr, #InputCursorX + B CBDY05 + +CursorB0 + MOV R0, #0 +CursorBdy + ADD R11, WsPtr, #CursorX +CBDY05 + ADD R7, WsPtr, #TWLCol ; point to window coords + LDMIA R7, {R2-R5} + + ADR R7, CBDYTab +DoJumpTable + AND R8, R6, #&0E + LDR R8, [R7, R8, LSL #1] + ADD PC, R7, R8 + +CBDYTab + & CursorLBdy-CBDYTab + & CursorRBdy-CBDYTab + & CursorLBdy-CBDYTab + & CursorRBdy-CBDYTab + & CursorUBdy-CBDYTab + & CursorUBdy-CBDYTab + & CursorDBdy-CBDYTab + & CursorDBdy-CBDYTab + +; Move cursor to left boundary + R0 characters in + +CursorLBdy + ADD R7, R0, R2 +CBDY10 + STR R7, [R11, #CursorX-CursorX] + MOV PC, R14 + +; Move cursor to right boundary + R0 characters in + +CursorRBdy + SUB R7, R4, R0 + B CBDY10 + +; Move cursor to up boundary + R0 characters in + +CursorUBdy + ADD R7, R0, R5 +CBDY20 + STR R7, [R11, #CursorY-CursorX] + MOV PC, R14 + +; Move cursor to down boundary + R0 characters in + +CursorDBdy + SUB R7, R3, R0 + B CBDY20 + +; ***************************************************************************** +; +; CursorMove - Move cursor in direction corresponding to R6 bits 1-3 +; (0,4 = right; 2,6 = left; 8,10 = down; 12,14 = up) +; R6 is preserved + + ASSERT InputCursorY-InputCursorX = CursorY-CursorX + ASSERT InputCursorAddr-InputCursorX = CursorAddr-CursorX + +InputCursorMove + ADD R11, WsPtr, #InputCursorX + B CurM10 + +CursorMove + ADD R11, WsPtr, #CursorX +CurM10 + ADR R7, CMVTab + B DoJumpTable + +CMVTab + & MoveRight-CMVTab + & MoveLeft-CMVTab + & MoveRight-CMVTab + & MoveLeft-CMVTab + & MoveDown-CMVTab + & MoveDown-CMVTab + & MoveUp-CMVTab + & MoveUp-CMVTab + +; Move cursor right if possible - on exit C=1 iff at RHS + +MoveRight + LDR R0, [R11, #CursorX-CursorX] + LDR R4, [WsPtr, #TWRCol] + CMP R0, R4 + MOVCS PC, R14 + LDR R2, [R11, #CursorAddr-CursorX] + LDR R3, [WsPtr, #BytesPerChar] + ADD R0, R0, #1 + ADD R2, R2, R3 + STR R0, [R11, #CursorX-CursorX] + STR R2, [R11, #CursorAddr-CursorX] + MOV PC, R14 + +; Move cursor left if possible - on exit C=1 iff at LHS + +MoveLeft + LDR R0, [R11, #CursorX-CursorX] + LDR R4, [WsPtr, #TWLCol] + CMP R4, R0 + MOVCS PC, R14 + LDR R2, [R11, #CursorAddr-CursorX] + LDR R3, [WsPtr, #BytesPerChar] + SUB R0, R0, #1 + SUB R2, R2, R3 + STR R0, [R11, #CursorX-CursorX] + STR R2, [R11, #CursorAddr-CursorX] + MOV PC, R14 + +; Move cursor down if possible - on exit C=1 iff at bottom + +MoveDown + LDR R1, [R11, #CursorY-CursorX] + LDR R4, [WsPtr, #TWBRow] + CMP R1, R4 + MOVCS PC, R14 + LDR R2, [R11, #CursorAddr-CursorX] + LDR R3, [WsPtr, #RowLength] + ADD R1, R1, #1 + ADD R2, R2, R3 + STR R1, [R11, #CursorY-CursorX] + STR R2, [R11, #CursorAddr-CursorX] + MOV PC, R14 + +; Move cursor up if possible - on exit C=1 iff at top + +MoveUp + LDR R1, [R11, #CursorY-CursorX] + LDR R4, [WsPtr, #TWTRow] + CMP R4, R1 + MOVCS PC, R14 + LDR R2, [R11, #CursorAddr-CursorX] + LDR R3, [WsPtr, #RowLength] + SUB R1, R1, #1 + SUB R2, R2, R3 + STR R1, [R11, #CursorY-CursorX] + STR R2, [R11, #CursorAddr-CursorX] + MOV PC, R14 + +; ***************************************************************************** +; +; Special HT - used when abnormal cursor direction selected +; or if C81Bit set +; +; in: R6 = CursorFlags +; + +SpecialHT + TST R6, #Vdu5Bit + BNE Vdu5HT + Push "R6,R14" + BL RCRLFR6 + Pull R6 + BL CursorMove ; try to move in appropriate direction + Pull PC, CC ; if successful, finish + BL CursorB0 ; else move cursor to -ve X boundary + BL AddressCursor ; re-address cursor + Pull R14 + B VduLF ; and do a line-feed + +; ***************************************************************************** +; +; CHT - version of HT used after printing character +; will set pending CRLF if necessary +; +; in: R6 = CursorFlags + +CHT + TST R6, R6, ROR #10 ; test for Vdu5 or &1E or C81Bit, latter not + ; possible as we just printed a char + BNE SpecialCHT + + LDR R0, [WsPtr, #CursorX] + LDR R2, [WsPtr, #CursorAddr] + LDR R3, [WsPtr, #BytesPerChar] + LDR R4, [WsPtr, #TWRCol] + + ADD R0, R0, #1 + ADD R2, R2, R3 + CMP R0, R4 + STRLS R0, [WsPtr, #CursorX] + STRLS R2, [WsPtr, #CursorAddr] + MOVLS PC, R14 + + TST R6, #1 ; are we in "81-column" mode + BNE CHT10 ; yes, then just set C81Bit + + BSR PageTest + + LDR R0, [WsPtr, #TWLCol] + LDR R1, [WsPtr, #CursorY] + LDR R4, [WsPtr, #TWBRow] + + ADD R1, R1, #1 + CMP R1, R4 + BLS CursorR0R1 ; not on bottom line + + STR R0, [WsPtr, #CursorX] + BSR ScrollUp + B AddressCursor ; re-address cursor position + +CHT10 + ORR R6, R6, #C81Bit + STR R6, [WsPtr, #CursorFlags] + MOV PC, R14 + +SpecialCHT + TST R6, #Vdu5Bit + BNE Vdu5HT + BSR CursorMove ; try to move in appropriate direction + MOVCC PC, R14 ; if successful, finish + + TST R6, #1 + BNE CHT10 + + Push R14 + BL CursorB0 ; else move cursor to -ve X boundary + BL AddressCursor ; re-address cursor + Pull R14 + B VduLF ; and do a line-feed + +; ***************************************************************************** +; +; Special BS - used when abnormal cursor direction selected +; or Vdu5 mode +; or if C81Bit was set +; +; in : R6 = CursorFlags +; + +SpecialBS + TST R6, #Vdu5Bit ; VDU 5 mode ? + BNE Vdu5BS ; then branch + + TST R6, #C81Bit ; did we come here cos of C81Bit + BICNE R6, R6, #C81Bit ; if so then clear the bit + STRNE R6, [WsPtr, #CursorFlags] ; store it back + MOVNE PC, R14 ; and leave cursor where it is + + EOR R6, R6, #6 ; move "left" + Push R14 + BL CursorMove + Pull PC, CC ; if successful + BL CursorB0 ; move to +ve X boundary + BL AddressCursor ; re-address cursor + Pull R14 + B VT ; and do reverse line-feed + +; ***************************************************************************** +; +; Special LF - used when abnormal cursor direction selected +; +; in : R6 = CursorFlags +; + +SpecialLF + EOR R6, R6, #8 ; move "down" + Push R14 + BL CursorMove + Pull PC, CC ; if successful + BL CanScroll ; see if we can scroll + Pull PC, CS ; if failed, exit with all done + Pull R14 + MOV R0, #0 ; scroll window + MOV R1, #7 ; "up" + MOV R2, #0 ; by 1 char + B Scroll012 + +; ***************************************************************************** +; +; Special VT - used when abnormal cursor direction selected +; +; in : R6 = CursorFlags +; + +SpecialVT + EOR R6, R6, #14 ; move "up" + Push R14 + BL CursorMove + Pull PC, CC ; if successful + BL CanScroll ; see if we can scroll + Pull PC, CS ; if failed, exit with all done + Pull R14 + MOV R0, #0 ; scroll window + MOV R1, #6 ; "down" + MOV R2, #0 ; by 1 char + B Scroll012 + +; ***************************************************************************** +; +; CanScroll - check whether we can scroll in direction R6 +; +; in: R6 = CursorFlags + +CanScroll ROUT + Push R14 + TST R6, #&10 ; do we scroll or move to other edge + BNE CantScroll + + TST R6, #CursorsSplit + BEQ %FT10 ; cursors not split, so input cursor + ; not relevant + EOR R6, R6, #6 + BL InputCursorMove ; if cursor fails to move, it's OK + ; where it is + BL AddressInputCursor ; readdress it anyway, just in case + EOR R6, R6, #6 ; put R6 back +10 + CLC + Pull PC + +CantScroll + BL CursorB0 ; move to opposite edge + BL AddressCursor + SEC + Pull PC + +; ***************************************************************************** +; +; Release any pending CRLF +; + +RCRLF + LDR R6, [WsPtr, #CursorFlags] + +; Extra entry point when R6 already loaded + +RCRLFR6 + TST R6, #C81Bit + MOVEQ PC, R14 ; no pending CRLF + BSR CR10 ; (clears C81Bit) + B VduLF + +; ***************************************************************************** +; +; VDU 23,8,t1,t2,x1,y1,x2,y2| - Clear block of text +; +; t=0 Top left of window +; t=1 Top of cursor column +; t=2 Off top right of window +; +; t=4 Left end of cursor line +; t=5 Cursor position +; t=6 Off right of cursor line +; +; t=8 Bottom left of window +; t=9 Bottom of cursor column +; t=10 Off bottom right of window +; + +Vdu23_8 + MOV R0, #0 ; top left of window + STRB R0, [WsPtr, #CBWS+0] + STRB R0, [WsPtr, #CBWS+1] + BSR CP81 ; cursor position + STRB R0, [WsPtr, #CBWS+2] + STRB R1, [WsPtr, #CBWS+3] + BSR WBotRig ; bottom right of window + ADD R0, R0, #1 ; off bottom right of window + STRB R0, [WsPtr, #CBWS+4] + STRB R1, [WsPtr, #CBWS+5] + + ADD R3, WsPtr, #CBWS + ADD R2, R3, #QQ+2-CBWS + LDRB R0, [WsPtr, #QQ+1] ; t1 + BSR CLBL50 + LDRB R0, [WsPtr, #QQ+2] ; t2 + BSR CLBL50 + +; Check end is after start + + LDRB R2, [WsPtr, #CBStart] ; start X + LDRB R3, [WsPtr, #CBStart+1] ; start Y + LDRB R4, [WsPtr, #CBEnd] ; end X + LDRB R5, [WsPtr, #CBEnd+1] ; end Y + + CMP R5, R3 + CMPEQ R4, R2 + MOVLS PC, R14 ; end <= start so do nothing + + LDR R0, [WsPtr, #CursorX] ; save cursor position + LDR R1, [WsPtr, #CursorY] + Push "R0,R1" + + MOV R0, R3 ; First row to clear + MOV R1, R2 ; Start position for first row + LDRB R7, [WsPtr, #CBWS+4] ; End position for all but last row + + ADD R6, WsPtr, #TWLCol + LDMIA R6, {R8-R11} + + LDR R6, [WsPtr, #CursorFlags] +CLBL20 + TEQ R0, R5 + BEQ CLBL40 + BSR RowClear + ADD R0, R0, #1 + MOV R1, #0 ; start position for subsequent rows + B CLBL20 + +CLBL40 + MOV R7, R4 ; end position for last row + BSR RowClear + + Pull "R0,R1" + STR R0, [WsPtr, #CursorX] + STR R1, [WsPtr, #CursorY] + B AddressCursor + +CLBL50 + AND R1, R0, #3 + MOV R1, R1, LSL #1 + LDRB R6, [WsPtr, #CBWS+4] + BSR CLBL60 + MOV R1, R0, LSR #1 + ORR R1, R1, #1 + LDRB R6, [WsPtr, #CBWS+5] +CLBL60 + LDRB R4, [R3, R1] ; get base coordinate to use + LDRB R5, [R2, #1]! ; get x or y offset + + MOV R5, R5, LSL #24 + ADDS R4, R4, R5, ASR #24 ; add sign extended offset to base + MOVMI R4, #0 ; if <0 then make =0 + CMP R4, R6 + MOVHI R4, R6 ; is this stringent enough ? + + STRB R4, [R2, #CBStart-(QQ+3)] + MOV PC, R14 + +; ***************************************************************************** +; +; RowClear - Clear a "row" {R1 <= X < R7, Y = R0} + +RowClear + Push "R0-R11,R14" + SUB R7, R7, #1 + CMP R1, R7 + BHI RowCL10 ; left > right, so ignore + + TST R6, #8 + + MOVEQ R2, R1 ; left + MOVEQ R3, R0 ; bottom + MOVEQ R4, R7 ; right + MOVEQ R5, R0 ; top + + MOVNE R2, R0 ; left + MOVNE R3, R7 ; bottom + MOVNE R4, R0 ; right + MOVNE R5, R1 ; top + + TST R6, #2 + + ADDEQ R0, R8, R2 + ADDEQ R2, R8, R4 + + SUBNE R0, R10, R4 + SUBNE R2, R10, R2 + + TST R6, #4 + + ADDEQ R1, R11, R3 + ADDEQ R3, R11, R5 + + SUBNE R1, R9, R5 + SUBNE R3, R9, R3 + + BL ClearBox + +RowCL10 + Pull "R0-R11,PC" + + [ :LNOT: AssemblingArthur + +; ***************************************************************************** +; +; DoVduExternal - External entry point for +; a) reading input cursor position +; b) reading output cursor position +; c) reading character at cursor position and screen mode +; d) resetting all or part of font +; e) reading font definitions +; f) reading VDU status +; g) reading VDU variables +; h) reading palette (OSWORD &0B) +; i) setting palette (OSWORD &0C) +; j) various mouse/pointer stuff +; k) set top of screen address +; l) set VDU driver bank +; m) set display bank +; +; in: R0 = 0 => read input cursor position +; R0 = 1 => read output cursor position +; R0 = 2 => OSBYTE &87 - R1 := char at cursor, R2 := screen mode +; R0 = 3 => reset font (R1*32 = start char, R2 = number of pages) +; R0 = 4 => OSWORD 10 (R1 -> control block) +; R0 = 5 => read VDU status +; R0 = 6 => read VDU variables number R1, R1+1 +; R0 = 7 => read palette +; R0 = 8 => set palette +; R0 = 9 => mouse/pointer control +; R0 = 10 => set top of screen address +; R0 = 11 => set VDU driver bank +; R0 = 12 => set display bank +; +; out: a,b; R1 = X, R2 = Y +; c; R1=char, R2=screen mode +; f; R1=VDU status +; g; R1=variable(n), R2=variable(n+1) +; R0, R3 destroyed +; R4-R11 preserved +; + +DoVduExternal ROUT + CMP R0, #ExtEntries + MOVCS PC, R14 + LDR R3, [PC, R0, LSL #2] + ADD PC, PC, R3 + +ExtTable OutputExternals + + ] + +; ***************************************************************************** + +DoReadPOSVPOSI ROUT + MOV R0, #0 + B %FT05 +DoReadPOSVPOSO + MOV R0, #1 +05 + Push "R4-R11, R14" + LDR R6, [WsPtr, #CursorFlags] + TST R6, #CursorsSplit ; if cursors are split + TEQNE R0, #1 ; and reading input cursor + BNE %FT10 ; then use input cursor + BL CP81 ; else read output cursor + B %FT20 +10 + BL CP79 +20 + MOV R2, R1 + MOV R1, R0 + Pull "R4-R11, PC" + +; ***************************************************************************** +; +; DoSetScreenStart - Set top of screen address (display + drivers) +; +; in: R1 -> control block +; [R1, #0] = bit mask; bit 0 set => change drivers address +; bit 1 set => change display address +; +; [R1, #1..4] = byte offset from lowest screen address +; +; out: - +; + +DoSetScreenStart ROUT + Push R14 + LDRB R3, [R1, #0] ; R3 = bitmask + LDRB R0, [R1, #1] + LDRB R2, [R1, #2] + ORR R0, R0, R2, LSL #8 + LDRB R2, [R1, #3] + ORR R0, R0, R2, LSL #16 + LDRB R2, [R1, #4] + ORR R0, R0, R2, LSL #24 ; R0 is now the offset + LDR R2, [WsPtr, #TotalScreenSize] + CMP R0, R2 + BCS %FT10 ; offset too large + Push "R0,R2,R3,R5-R10" + + MOV R0, #1 + STRB R0, [WsPtr, #ScreenMemoryClaimed] + ; indicate memory not available + BL PreWrchCursor + Pull "R0,R2,R3,R5-R10" + ADD R0, R0, #ScreenEndAdr + SUB R0, R0, R2 ; make into a LOGRAM address + + TST R3, #1 + BEQ %FT05 + Push R0 + BL NewScreenStart + Pull R0 +05 + TST R3, #2 + BLNE SetVinit ; program vinit and set DisplayStart + + Push "R5-R10" ; save registers + BL PostWrchCursor + Pull "R5-R10" +10 + Pull PC + +; ***************************************************************************** +; +; NewScreenStart - Update ScreenStart and readdress cursors +; +; in: R0 = new screen start +; +; out: R0, R2 corrupted; all others preserved +; + +NewScreenStart ROUT + LDR R2, [WsPtr, #VduSprite] ; test if outputting to sprite + TEQ R2, #0 ; Z => outputting to screen + + LDR R2, [WsPtr, #DisplayScreenStart] + STR R0, [WsPtr, #DisplayScreenStart] + MOVNE PC, R14 ; if outputting to sprite, don't update + ; Screenstart or cursor addresses + + STR R0, [WsPtr, #ScreenStart] + SUB R0, R0, R2 ; R0 := new-old + Push R14 +AdjustCursorVars + LDR R14, [WsPtr, #CursorAddr] + ADD R14, R14, R0 + STR R14, [WsPtr, #CursorAddr] + LDR R14, [WsPtr, #InputCursorAddr] + ADD R14, R14, R0 + STR R14, [WsPtr, #InputCursorAddr] + Pull PC + +; ***************************************************************************** +; +; DoSetDriverBank - Set VDU driver's screen bank (OSBYTE &70) +; +; in: R1 = bank number (1..n) (NOTE: starts at 1) +; + +DoSetDriverBank ROUT + Push R14 + MOVS R2, R1 + BNE %FT10 + LDR R1, [WsPtr, #VduStatus] + TST R1, #Shadowing + MOVEQ R2, #1 + MOVNE R2, #2 +10 + MOV R0, #0 + LDRB R1, [R0, #OsbyteVars + :INDEX: MemDriver] ; old value + + Push "R1,R4-R10" ; save registers + BL ConvertBankToAddress ; R3 := start address of NEXT bank + CMP R3, #ScreenEndAdr ; if after end, can't do it + Pull "R1,R4-R10,PC", HI ; so exit + + STRB R2, [WsPtr, #ScreenMemoryClaimed] + ; indicate memory not available (R2<>0) + STRB R2, [R0, #OsbyteVars + :INDEX: MemDriver] ; store new value + + LDR R0, [WsPtr, #DriverBankAddr] ; R0:=old default bank start + LDR R2, [WsPtr, #DisplayScreenStart] ; R2:=old current screen start + SUB R0, R2, R0 ; R0 := (current-default) + ; in range 1-TotalSize..TotalSize-1 + + LDR R2, [WsPtr, #ScreenSize] + SUB R3, R3, R2 ; default start of THIS bank + STR R3, [WsPtr, #DriverBankAddr] ; R3 := new default bank start + + ADD R0, R0, R3 ; new current start (not bound checked) + + LDR R2, [WsPtr, #TotalScreenSize] + + RSBS R0, R0, #ScreenEndAdr + ADDLS R0, R0, R2 + CMP R0, R2 + SUBHI R0, R0, R2 ; now in bounds (but inverted) + RSB R0, R0, #ScreenEndAdr + + Push R0 + BL PreWrchCursor + Pull R0 + + BL NewScreenStart + + BL PostWrchCursor + Pull "R1,R4-R10,PC" + +; ***************************************************************************** +; +; DoSetDisplayBank - Set displayed screen bank (OSBYTE &71) +; +; in: R1 = bank number (1..n) (NOTE: starts at 1) +; + +DoSetDisplayBank ROUT + Push R14 + MOVS R2, R1 + BNE %FT10 + LDR R1, [WsPtr, #VduStatus] + TST R1, #Shadowing + MOVEQ R2, #1 + MOVNE R2, #2 +10 + MOV R0, #0 + LDRB R1, [R0, #OsbyteVars + :INDEX: MemDisplay] ; old value + Push "R1,R4-R5" ; save registers + BL ConvertBankToAddress ; R3 := start address of NEXT bank + CMP R3, #ScreenEndAdr ; if after end, can't do it + Pull "R1,R4-R5,PC", HI ; so exit + + STRB R2, [WsPtr, #ScreenMemoryClaimed] + ; indicate memory not available (R2<>0) + STRB R2, [R0, #OsbyteVars + :INDEX: MemDisplay] ; store new value + + LDR R0, [WsPtr, #DisplayBankAddr] ; R0 := old default bank start + LDR R2, [WsPtr, #DisplayStart] ; R2 := old current display start + SUB R0, R2, R0 ; R0 := (current-default) + ; in range 1-TotalSize..TotalSize-1 + + LDR R2, [WsPtr, #ScreenSize] + SUB R3, R3, R2 ; default start of THIS bank + STR R3, [WsPtr, #DisplayBankAddr] ; R3 := new default bank start + + ADD R0, R0, R3 ; new current start (not bound checked) + + LDR R2, [WsPtr, #TotalScreenSize] + + RSBS R0, R0, #ScreenEndAdr + ADDLS R0, R0, R2 + CMP R0, R2 + SUBHI R0, R0, R2 ; now in bounds (but inverted) + RSB R0, R0, #ScreenEndAdr + + BL SetVinit ; program vinit and set DisplayStart + Pull "R1,R4-R5,PC" + +; ***************************************************************************** +; +; CP81 - Read output cursor position, +; taking C81Bit and CursorFlags into account +; +; out: R0=X, R1=Y + +CP81 + Push R14 + BL CP80 + LDR R6, [WsPtr, #CursorFlags] + TST R6, #C81Bit + ADDNE R0, R0, #1 ; in hidden column, so inc X + Pull PC + +; ***************************************************************************** +; +; CP79 - Read input cursor position, +; taking CursorFlags into account +; +; out: R0=X, R1=Y + +CP79 + MOV R1, #InputCursorX-TWLCol + B CP80R1 + +; ***************************************************************************** +; +; WBotRig - Read coordinates of "bottom right" in user coords +; +; out: R0=X, R1=Y + +WBotRig + ADD R5, WsPtr, #TWLCol + LDR R6, [WsPtr, #CursorFlags] + LDR R0, [R5, #TWLCol-TWLCol] ; get TWLCol + LDR R1, [R5, #TWRCol-TWLCol] ; get TWRCol + SUB R4, R1, R0 + MOV R2, #0 + MOV R1, #0 + B CP8010 + +; ***************************************************************************** +; +; CP80 - Read cursor position, taking CursorFlags into account + +CP80 + MOV R1, #CursorX-TWLCol +CP80R1 + ADD R5, WsPtr, #TWLCol + LDR R6, [WsPtr, #CursorFlags] + MOV R2, #2 + MOV R0, #0 + BSR CP8020 + MOV R4, R2 + MOV R2, #4 +CP8010 + ADD R1, R1, #4 + MOV R0, #TWTRow-TWLCol + BSR CP8020 + MOV R0, R2 + MOV R1, R2 + TST R6, #8 + MOVEQ R0, R4 + MOVNE R1, R4 + + MOV PC, R14 + +CP8020 + TST R2, R6 + EORNE R0, R0, #8 + LDR R2, [R5, R0] + LDR R3, [R5, R1] + SUBNE R2, R2, R3 + SUBEQ R2, R3, R2 + MOV PC, R14 + +; ***************************************************************************** +; +; Vdu23_0 - Program "6845" +; + +Vdu23_0 + LDRB R1, [WsPtr, #QQ+1] ; get register number + AND R2, R1, #31 ; address register is 5 bits + CMP R2, #8 + MOVCC PC, R14 + BEQ Vdu23_0_8 + CMP R2, #10 + BEQ Vdu23_0_10 + CMP R2, #12 + BCC Vdu23_0_11 + + [ DoVdu23_0_12 + BEQ Vdu23_0_12 + CMP R2, #13 + BEQ Vdu23_0_13 + ] + B UnknownVdu23 + + +; ***************************************************************************** +; +; Vdu23_0_8 - Program interlace +; +; in: R1 = unmasked register number (bits 5-7 may be set) + +Vdu23_0_8 ROUT + LDRB R0, [WsPtr, #QQ+2] ; value to program into interlace + TST R0, #&80 ; if negative, don't EOR with *TV + TSTEQ R1, #&E0 ; if not register 8, don't EOR + BNE %FT10 ; don't EOR + + LDROSB R1, TVInterlace + TST R1, #1 + EORNE R0, R0, #1 ; toggle if *TV n,1 and number +ve +10 + LDR R1, [WsPtr, #VIDCControlCopy] + BIC R1, R1, #CR_Interlace + TST R0, #1 + ORRNE R1, R1, #CR_Interlace ; zero => no interlace + + MOV R0, #VIDC + STR R1, [R0] ; program VIDC + MOV PC, R14 + + [ DoVdu23_0_12 + +; ***************************************************************************** +; +; Vdu23_0_12 - Program "hi" byte of start of screen +; + +Vdu23_0_12 + MOV R2, #11 ; starting bit number +V23012_10 + LDRB R0, [WsPtr, #QQ+2] ; get parameter + LDR R1, [WsPtr, #VinitCopy] + MOV R1, R1, ROR R2 ; move changing bits to bottom + BIC R1, R1, #&FF ; clear old bits out + ORR R1, R1, R0 ; put in new bits + RSB R2, R2, #32 ; fudge cos we ain't got ROL + MOV R0, R1, ROR R2 ; put back to correct position + B SetVinitPhys + +; ***************************************************************************** +; +; Vdu23_0_13 - Program "lo" byte of start of screen +; + +Vdu23_0_13 + MOV R2, #3 ; starting bit number + B V23012_10 + + ] + +; ***************************************************************************** +; +; Vdu23_9 - Equivalent of FX 9 +; Vdu23_10 - Equivalent of FX 10 +; +; in: R0 = 9 or 10 +; + +Vdu23_9 +Vdu23_10 + Push R14 ; for the SWI + LDRB R1, [WsPtr, #QQ+1] ; get X parameter + SWI XOS_Byte + Pull PC, VC ; no error, then return + + Pull R14 ; get stack back + B VduBadExit ; and tell the world + +; ***************************************************************************** +; +; DoReadVDUStatus - Read VDU status +; +; out: R1 = status +; bit 0 set => printer enabled by VDU 2 +; bit 1 set => N/A +; bit 2 set => in page mode +; bit 3 set => text window in force +; bit 4 set => in a shadow mode +; bit 5 set => in VDU 5 mode +; bit 6 set => cursor editing in progress +; bit 7 set => VDU disabled (by VDU 21) +; +; R2 corrupted +; + +DoReadVDUStatus + LDR R1, [WsPtr, #VduStatus] ; Vdu2, Window, Shadow bits + + LDR R2, [WsPtr, #CursorFlags] + + TST R2, #PageMode + ORRNE R1, R1, #&04 + + TST R2, #Vdu5Bit + ORRNE R1, R1, #&20 + + TST R2, #CursorsSplit + ORRNE R1, R1, #&40 + + TST R2, #VduDisabled + ORRNE R1, R1, #&80 + + MOV PC, R14 + +; ***************************************************************************** +; +; DoReadVDUVariable - Read BBC-style VDU variables +; +; in: R1 = variable to read (only &00..&0F are supported) +; +; out: R1 = value of that variable +; R2 = value of next variable +; + +DoReadVDUVariable + CMP R1, #(BBCVduVarsEnd-BBCVduVars) + MOVCS PC, R14 ; don't support this variable + ADR R3, BBCVduVars ; point to lookup table + LDRB R0, [R3, R1]! ; get index for first variable + LDRB R1, [WsPtr, R0] ; get first variable + LDRB R0, [R3, #1] ; get index for second variable + LDRB R2, [WsPtr, R0] ; get second variable + MOV PC, R14 + +BBCVduVars + EQUB GWLCol + EQUB GWLCol+1 + EQUB GWBRow + EQUB GWBRow+1 + EQUB GWRCol + EQUB GWRCol+1 + EQUB GWTRow + EQUB GWTRow+1 + EQUB TWLCol + EQUB TWBRow + EQUB TWRCol + EQUB TWTRow + EQUB OrgX + EQUB OrgX+1 + EQUB OrgY + EQUB OrgY+1 +BBCVduVarsEnd + +; ***************************************************************************** +; +; SetCharSizes - Set char sizes for VDU 4 or VDU 5 text +; +; in: QQ+2 = flags: bit 0 set => set VDU 4 size +; bit 1 set => set VDU 5 size +; bit 2 set => set VDU 5 spacing +; QQ+3,4 x size in pixels +; QQ+5,6 y size in pixels +; + + ASSERT YEigFactor = XEigFactor +4 + +SetCharSizes ROUT + LDRB R0, [WsPtr, #QQ+3] + LDRB R2, [WsPtr, #QQ+4] + ORR R0, R0, R2, LSL #8 ; R0 = x size + + LDRB R1, [WsPtr, #QQ+5] + LDRB R2, [WsPtr, #QQ+6] + ORR R1, R1, R2, LSL #8 ; R1 = y size + + LDRB R2, [WsPtr, #QQ+2] + + ADD R3, WsPtr, #GCharSizes + TST R2, #2 ; if modifying VDU 5 size + STMNEIA R3, {R0, R1} + + ADD R3, R3, #8 + TST R2, #4 ; if modifying VDU 5 spacing + STMNEIA R3, {R0, R1} + + MOV PC, R14 + + END diff --git a/s/vdu/vdu5 b/s/vdu/vdu5 new file mode 100644 index 0000000000000000000000000000000000000000..4fda4da0bfc8a910202f06fda5c7e0e968353f54 --- /dev/null +++ b/s/vdu/vdu5 @@ -0,0 +1,662 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.Vdu5 + +; ***************************************************************************** +; +; Print a character in VDU 5 mode +; + +; *****This file has been extensively modified by DJS + +; Alter these at your peril ! + +cxl RN 0 +scr RN 0 + +ecfptr RN 1 +cword0 RN 1 + +cyb RN 2 +cyt2 RN 2 +scrend RN 2 +cword1 RN 2 + +cxr RN 3 +cyb2 RN 3 +ormask RN 3 + +cxl2 RN 4 +eormask RN 4 + +cyb3 RN 5 +charmsk RN 5 +cword2 RN 5 + +cyt RN 6 +llength RN 6 +chartmp RN 6 + +sizex RN 7 +charptr RN 7 + +sizey RN 8 +invcharshf RN 8 + +charbyte RN 9 + +cxr2 RN 10 +charshf RN 10 + +lgBPC RN 11 + +Vdu5Wrch + Push R14 + BL Vdu5DoChar + Pull R14 + B PostCharMove + +; Vdu23_18 +; LDR R0, [WsPtr, #QQ+1] +Vdu5DoChar + ADD ecfptr, WsPtr, #FgEcfOraEor ;Base address of OR/EOR pairs +Vdu5DoChar10 + Push "R14" + MOV charbyte, R0 ;Put character out of harm's + ; way + ASSERT cxl < cyt + ASSERT GCsIY = GCsIX +4 + ADD cxl, WsPtr, #GCsIX + LDMIA cxl, {cxl, cyt} ; cxl=where left pixel would be + ; cyt=where top pixel would be + + ASSERT sizex < sizey + ADD sizex, WsPtr, #GCharSizes + LDMIA sizex, {sizex, sizey} + CMP sizey, #16 ; if SizeY=8 or SizeY=16 + TEQNE sizey, #8 ; (leaving CS <=> SizeY=16) + TEQEQ sizex, #8 ; and SizeX=8, then do it fast + BNE SlowVdu5 ; else do by scaled char + + TEQ charbyte, #127 ; Which font do we use? + ADDNE charptr, WsPtr, #(Font-32*8) ; Soft if character not DELETE + ADREQL charptr, HardFont-32*8 ; Hard if character is DELETE + ADD charptr, charptr, charbyte, LSL #3 ;Point at char def + + MOVCS charptr, charptr, LSL #1 ; Double address if SizeY = 16 + ; (tricky code, originally + ; designed by TMD) + + SUB cyb, cyt, sizey + ADD cyb, cyb, #1 ; where bottom pixel would be + ADD cxr, cxl, #7 ; where right pixel would be + + ASSERT GWBRow = GWLCol+4 + ASSERT GWRCol = GWLCol+8 + ASSERT GWTRow = GWLCol+12 + ASSERT cyb3 > cxl2 + ASSERT cxr2 > cyb3 + ASSERT R14 > cxr2 + ADD cxl2, WsPtr, #GWLCol + LDMIA cxl2, {cxl2, cyb3, cxr2, R14} + + Greatest cxl2, cxl2, cxl ; cxl2 := windowed left + ; (2 instructions) + Least cxr2, cxr2, cxr ; cxr2 := windowed right + ; (2 instructions) + Greatest cyb2, cyb3, cyb ; cyb2 := windowed bottom + ; (3 instructions) + Least cyt2, R14, cyt ; cyt2 := windowed top + ; (3 instructions) + + SUBS cyb2, cyt2, cyb2 ; top >= bottom ? + CMPGE cxr2, cxl2 ; and right >= left ? + Pull "PC", LT ; Exit if not. Otherwise cyb2 + ; has become clipped height + + LDR R14, [WsPtr, #CursorFlags] ; update changed box, if wanted + TST R14, #ClipBoxEnableBit + BLNE ClipVdu5 + + ADD charptr, charptr, cyt ; adjust charptr to point at + SUB charptr, charptr, cyt2 ; first used row of character + + TEQ sizey, #16 ; If double height, signal this + RSBEQ charptr, charptr, #0 ; by making fontptr negative + + MOV charmsk, #&FF ; Produce mask to do left/right + SUB R14, cxl2, cxl ; clipping + MOV charmsk, charmsk, LSR R14 + SUB R14, cxr2, cxl2 + ADD R14, R14, #1 + BIC charmsk, charmsk, charmsk, LSR R14 + + ASSERT llength > scr + ASSERT LineLength = YWindLimit+4 + LDR lgBPC, [WsPtr, #Log2BPC] ; Address point at (cxl, cyt2), + MOV charshf, cxl, LSL lgBPC ; putting address in scr, bit + ADD scr, WsPtr, #YWindLimit ; offset in charshf and + LDMIA scr, {scr, llength} ; adjusting ecfptr + SUB scr, scr, cyt2 + AND R14, scr, #7 + ADD ecfptr, ecfptr, R14, LSL #3 + LDR R14, [WsPtr, #ScreenStart] + MLA scr, llength, scr, R14 + MOV R14, charshf, ASR #5 + ADD scr, scr, R14, LSL #2 + AND charshf, charshf, #31 + + MLA scrend, llength, cyb2, scr ;Calculate terminating address + + RSB invcharshf, charshf, #32 ;And inverse shift + +Vdu5NextLine + ASSERT eormask > ormask + LDMIA ecfptr!, {ormask, eormask} ;Pick up ecf info and advance + TST ecfptr, #63 ; ecf pointer, wrapping if + SUBEQ ecfptr, ecfptr, #64 ; necessary + + MVNS charbyte, charptr ;Pick up character definition + LDRPLB charbyte, [charbyte, -charbyte, LSR #1] ; byte, using tricky + SUBPL charptr, charptr, #1 ; code for double height (and + LDRMIB charbyte, [charptr], #1 ; simple code for single!) + + ANDS charbyte, charbyte, charmsk ;Clip left & right; skip loop + BEQ Vdu5TryNextLine ; body if nothing to plot + + Push "ecfptr,scrend,charmsk,llength,charptr" + + [ VIDC_Type = "VIDC20" + LDR R14, [WsPtr, #TextExpandArea] ;Address correct expansion + | + ADD R14, WsPtr, #TextExpand ;Address correct expansion + ] + ADD charptr, charbyte, #&100 ; table entry, assuming that + ADD charptr, R14, charptr, LSL lgBPC ; this is not mode 10 or greater + + CMP lgBPC, #1 ;Pick up this entry: + LDRLSB cword0, [charptr, #0] ; 1 byte if lgBPC = 0 + LDREQB R14, [charptr, #1] ; 2 bytes if lgBPC = 1 + ORREQ cword0, cword0, R14, LSL #8 + MOV cword1, #0 + BLS Vdu5DoOneWord + CMP lgBPC, #3 + LDRLO cword0, [charptr, #0] ; 1 word if lgBPC = 2 + BLO Vdu5DoOneWord + BHI Vdu5Mode10 ; 4 words if lgBPC = 4 + LDMIA charptr, {cword0, cword1} ; 2 words if lgBPC = 3 + MOVS cword2, cword1, LSR invcharshf +Vdu5DoTwoWords + LDRNE chartmp, [scr, #8] + ANDNE R14, ormask, cword2 + ORRNE chartmp, chartmp, R14 + ANDNE R14, eormask, cword2 + EORNE chartmp, chartmp, R14 + STRNE chartmp, [scr, #8] + MOV cword1, cword1, LSL charshf +Vdu5DoOneWord + ORRS cword1, cword1, cword0, LSR invcharshf + LDRNE chartmp, [scr, #4] + ANDNE R14, ormask, cword1 + ORRNE chartmp, chartmp, R14 + ANDNE R14, eormask, cword1 + EORNE chartmp, chartmp, R14 + STRNE chartmp, [scr, #4] + MOVS cword0, cword0, LSL charshf + LDRNE chartmp, [scr] + ANDNE R14, ormask, cword0 + ORRNE chartmp, chartmp, R14 + ANDNE R14, eormask, cword0 + EORNE chartmp, chartmp, R14 + STRNE chartmp, [scr] + +Vdu5LinePainted + Pull "ecfptr,scrend,charmsk,llength,charptr" + +Vdu5TryNextLine + TEQ scr, scrend + ADDNE scr, scr, llength + BNE Vdu5NextLine + + Pull "PC" + +; This is mode 10 (or similar) - we must do bit expansion on the fly + +Vdu5Mode10 + [ VIDC_Type = "VIDC20" + CMP lgBPC, #5 ; is this a 32 bit per pixel mode, if so then ignore the + BEQ Vdu5Mode32 ; existing code and use a newer function + ] + + ADRL charptr, C16BTab + AND R14, charbyte, #&0F + ADD R14, charptr, R14, LSL #3 + LDMIA R14, {cword0, cword1} + + MOVS cword2, cword1, LSR invcharshf + LDRNE chartmp, [scr, #16] + ANDNE R14, ormask, cword2 + ORRNE chartmp, chartmp, R14 + ANDNE R14, eormask, cword2 + EORNE chartmp, chartmp, R14 + STRNE chartmp, [scr, #16] + MOV cword1, cword1, LSL charshf + ORRS cword1, cword1, cword0, LSR invcharshf + LDRNE chartmp, [scr, #12] + ANDNE R14, ormask, cword1 + ORRNE chartmp, chartmp, R14 + ANDNE R14, eormask, cword1 + EORNE chartmp, chartmp, R14 + STRNE chartmp, [scr, #12] + MOVS cword2, cword0, LSL charshf + + AND R14, charbyte, #&F0 + ADD R14, charptr, R14, LSR #1 + LDMIA R14, {cword0, cword1} + ORRS cword2, cword2, cword1, LSR invcharshf + B Vdu5DoTwoWords + +; Expand the character data out to 32 bit per pixel (mode 48 or similar) + + [ VIDC_Type = "VIDC20" + + MACRO +$l PixMunge32 $reg, $mask, $offset +$l + TST $reg, #$mask + LDRNE chartmp, [scr, #$offset] + ORRNE chartmp, chartmp, ormask + EORNE chartmp, chartmp, eormask + STRNE chartmp, [scr, #$offset] + MEND + +; Perform bit expansion on the fly, this is a word based operation, no need to +; extract sub-pixels from the ORR / EOR masks, simply perform the bit test and +; then write the character data to the screen! + +Vdu5Mode32 + + PixMunge32 charbyte, 1<<7, 0 + PixMunge32 charbyte, 1<<6, 4 + PixMunge32 charbyte, 1<<5, 8 + PixMunge32 charbyte, 1<<4, 12 + PixMunge32 charbyte, 1<<3, 16 + PixMunge32 charbyte, 1<<2, 20 + PixMunge32 charbyte, 1<<1, 24 + PixMunge32 charbyte, 1<<0, 28 + + B Vdu5LinePainted ; flow down and try the next line + + ] + +; ***************************************************************************** +; +; Slow VDU 5 - Print char by scaled method (in SprExtend) +; +; in: R1 (ecfptr) = pointer to ecf pattern +; R7 (sizex) = SizeX +; R8 (sizey) = SizeY +; R9 (charbyte) = character to plot +; +; Stack: Return address +; + + ASSERT ecfptr = R1 + ASSERT sizex = R7 + ASSERT sizey = R8 + ASSERT charbyte = R9 + +SlowVdu5 ROUT + + MOV R10, R1 ; R10 := ecfptr + +; now save current GCOL on stack if necessary + + ADD R11, WsPtr, #FgEcfOraEor + TEQ R10, R11 ; if going to use this one + BEQ %FT20 ; then skip + + MOV R0, #64 ; 64 bytes +10 + LDMIA R11, {R3-R6} ; copy old GCOL into stack + Push "R3-R6" ; frame, reversing order of + ; 16 byte chunks + LDMIA R10!, {R3-R6} ; copy new colour + STMIA R11!, {R3-R6} ; into GCOL + SUBS R0, R0, #16 + BNE %BT10 + +20 + MOV R4, #8 + MOV R5, #8 + Push "R4,R5" + Push "R7,R8" + MOV R6, R13 ; R6 -> scaling block + + SUB R1, R8, #1 ; SizeY-1 + LDR R5, [WsPtr, #YEigFactor] + ADD R3, WsPtr, #GCsX + LDMIA R3, {R3, R4} ; R3 = ext X; R4 = ext Y (top) + SUB R4, R4, R1, LSL R5 ; R4 = ext Y (bottom) + MOV R1, R9 ; R1 = char + MOV R0, #SpriteReason_PaintCharScaled + SWI XOS_SpriteOp + + ADD R13, R13, #4*4 ; junk scaling block + + TEQ R10, R11 ; if we didn't copy GCOLs + Pull "PC", EQ ; then return, else copy back + + MOV R0, #64 +30 + Pull "R3-R6" ; Reverse order of 16 byte + STMDB R11!, {R3-R6} ; chunks during copy again + SUBS R0, R0, #16 + BNE %BT30 + Pull PC + + +; ***************************************************************************** +; +; VDU 5 - Start printing text at graphics cursor + +ENQ + [ {TRUE} + GraphicsMode R0 + MOVNE PC, R14 + | + LDR R0, [WsPtr, #NPix] ; Graphics mode ? + TEQ R0, #0 + MOVEQ PC, R14 ; no, then return + ] + + MOV R1, #0 + BSR CursorOnOff ; turn cursor off without + ; saving to copy + + LDR R6, [WsPtr, #CursorFlags] + ORR R6, R6, #Vdu5Bit + B R6toCursorFlags + +; ***************************************************************************** +; +; VDU 4 - Return to printing text at text cursor + +EOT + [ {TRUE} + GraphicsMode R0 + MOVNE PC,LR + | + LDR R0, [WsPtr, #NPix] ; Graphics mode ? + TEQ R0, #0 + MOVEQ PC, R14 ; no, then return + ] + + MOV R1, #1 + BSR CursorOnOff ; restore cursor from copy + + LDR R6, [WsPtr, #CursorFlags] + BIC R6, R6, #Vdu5Bit + B R6toCursorFlags + +; ***************************************************************************** +; +; Vdu5HT - Move cursor "right" when in VDU 5 mode +; +; in: R6 = CursorFlags + +Vdu5HT + Push R14 + BL GCursorMove ; try to move in +ve X direction + BCC EndVdu5HT ; if successful, finish + BL GCursorB0 ; else move cursor to -ve X boundary +Vdu5HT10 + EOR R6, R6, #8 ; change to +ve Y direction + BL GCursorMove ; try to move in that direction + BLCS GCursorB0 ; if unsuccessful, move to -ve Y bdy +EndVdu5HT + Pull R14 + B IEG + +; ***************************************************************************** +; +; Vdu5BS - Move cursor "left" when in VDU 5 mode +; +; in: R6 = CursorFlags + +Vdu5BS + EOR R6, R6, #6 ; go to -ve X direction + B Vdu5HT ; dead easy, huh ? + +; ***************************************************************************** +; +; Vdu5LF - Move cursor "down" when in VDU 5 mode +; +; in: R6 = CursorFlags + +Vdu5LF + Push R14 + B Vdu5HT10 + +; ***************************************************************************** +; +; Vdu5VT - Move cursor "up" when in VDU 5 mode +; +; in: R6 = CursorFlags + +Vdu5VT + EOR R6, R6, #6 ; go to -ve Y direction (eventually) + B Vdu5LF + +; ***************************************************************************** +; +; Vdu5CR - Carriage return in VDU 5 mode +; +; in: R6 = CursorFlags + +Vdu5CR + BSR GCursorB0 + B IEG + +; ***************************************************************************** +; +; Vdu5FF - Clear screen in VDU 5 mode +; +; in: R6 = CursorFlags + +Vdu5FF + BSR Home + B CLG + +; ***************************************************************************** +; +; Vdu5TAB - TAB(X,Y) in VDU 5 mode +; +; in: R0 = X, R1 = Y, R6 = CursorFlags + +Vdu5TAB + BSR GCursorBdy + EOR R6, R6, #8 + MOV R0, R1 + BSR GCursorBdy + B IEG + +; ***************************************************************************** +; +; Vdu5Delete - Delete in VDU 5 mode (already done backspace) +; +; in: R6 = CursorFlags + +Vdu5Delete + ADD ecfptr, WsPtr, #BgEcfStore ; STORE background colour/ecf + MOV R0, #127 ; uses hard font for this char + B Vdu5DoChar10 + +; ***************************************************************************** +; +; GCursorMove - Move graphics cursor in direction specified by R6 +; (0,4 = right; 2,6 = left; 8,10 = down; 12,14 = up) +; R6 is preserved + +GCursorMove + ADD R0, WsPtr, #GCsIX + LDMIA R0, {R0, R1} ; R0 = GCsIX; R1 = GCsIY + ADD R2, WsPtr, #GCharSpacing+8 ; +8 needed to address it + LDMDB R2, {R2, R3} ; R2=GCharSpaceX;R3=GCharSpaceY + WINDow R0, R1, R8,R9,R10,R11 ; return LT if outside window + ADR R7, GCMVTab + B DoJumpTable + +GCMVTab + & GMoveRight-GCMVTab + & GMoveLeft-GCMVTab + & GMoveRight-GCMVTab + & GMoveLeft-GCMVTab + & GMoveDown-GCMVTab + & GMoveDown-GCMVTab + & GMoveUp-GCMVTab + & GMoveUp-GCMVTab + +; Move graphics cursor right if possible - on exit C=0 iff OK to move + +GMoveRight + ADD R0, R0, R2 ; add on GCharSpaceX +GMove10 + STR R0, [WsPtr, #GCsIX] +GMove15 + BLT GMoveOK ; if we were outside already + TST R6, #&40 ; or we are in nowrap mode + BNE GMoveOK ; then we were OK to move + WINDow R0, R1, R8,R9,R10,R11 + BGE GMoveOK ; if inside now, then OK + SEC + MOV PC, R14 + +GMoveOK + CLC + MOV PC, R14 + +; Move graphics cursor left if possible - on exit C=0 iff OK to move + +GMoveLeft + SUB R0, R0, R2 ; subtract off GCharSpaceX + B GMove10 + +; Move graphics cursor down if possible - on exit C=0 iff OK to move + +GMoveDown + SUB R1, R1, R3 ; subtract off GCharSpaceY +GMove20 + STR R1, [WsPtr, #GCsIY] + B GMove15 + +; Move graphics cursor up if possible - on exit C=0 iff OK to move + +GMoveUp + ADD R1, R1, R3 ; add on GCharSpaceY + B GMove20 + +; ***************************************************************************** +; +; Move graphics cursor to boundary indicated by value of R6 in bits 1-3 +; (0 or 4 = left, 2 or 6 = right, 8 or 10 = up, 12 or 14 = down) +; + R0 character positions in +; + +GCursorB0 + MOV R0, #0 +GCursorBdy + ADR R7, GCBDYTab + B DoJumpTable + +GCBDYTab + & GCursorLBdy-GCBDYTab + & GCursorRBdy-GCBDYTab + & GCursorLBdy-GCBDYTab + & GCursorRBdy-GCBDYTab + & GCursorUBdy-GCBDYTab + & GCursorUBdy-GCBDYTab + & GCursorDBdy-GCBDYTab + & GCursorDBdy-GCBDYTab + +; Move graphics cursor to left boundary + R0 characters in + +GCursorLBdy + LDR R7, [WsPtr, #GWLCol] + LDR R2, [WsPtr, #GCharSpaceX] + MLA R0, R2, R0, R7 ; GCsIX := GWLCol + (X*SpaceX) + STR R0, [WsPtr, #GCsIX] + MOV PC, R14 + +; Move graphics cursor to right boundary + R0 characters in +; (adjust for character size) + +GCursorRBdy + LDR R7, [WsPtr, #GWRCol] + LDR R2, [WsPtr, #GCharSizeX] + SUB R7, R2, R7 ; R7 = SizeX-GWRCol + LDR R2, [WsPtr, #GCharSpaceX] + MLA R0, R2, R0, R7 ; R0 = SizeX-GWRCol+X*SpaceX + RSB R0, R0, #1 ; GWRCol-X*SpaceX-(SizeX-1) + STR R0, [WsPtr, #GCsIX] + MOV PC, R14 + +; Move graphics cursor to up boundary + R0 characters in + +GCursorUBdy + LDR R7, [WsPtr, #GWTRow] + LDR R2, [WsPtr, #GCharSpaceY] + RSB R2, R2, #0 ; -SizeY + MLA R0, R2, R0, R7 ; GWTRow-Y*SizeY + STR R0, [WsPtr, #GCsIY] + MOV PC, R14 + +; Move graphics cursor to down boundary + R0 characters in +; (adjust for character size) + +GCursorDBdy + LDR R7, [WsPtr, #GWBRow] + LDR R2, [WsPtr, #GCharSpaceY] + MLA R0, R2, R0, R7 ; GWBRow+Y*SpaceY + LDR R2, [WsPtr, #GCharSizeY] + ADD R0, R0, R2 + SUB R0, R0, #1 ; GWBRow+Y*SpaceY+(SizeY-1) + STR R0, [WsPtr, #GCsIY] + MOV PC, R14 + +; ***************************************************************************** +; +; ClipVdu5 - Add a VDU 5 char to clip box +; +; in: cxl2 = left +; cyb2 = top-bottom +; cxr2 = right +; cyt2 = top +; +; out: All registers preserved +; + + ASSERT (cxl2=R4) :LAND: (cyb2=R3) :LAND: (cxr2=R10) :LAND: (cyt2=R2) + +ClipVdu5 ROUT + Push "R0-R3, R4, R10, R14" + MOV R0, cxl2 + SUB R1, cyt2, cyb2 ; top-(top-bottom) = bottom + MOV R3, cyt2 + MOV R2, cxr2 + BL MergeClipBox + Pull "R0-R3, R4, R10, PC" + + END diff --git a/s/vdu/vducursoft b/s/vdu/vducursoft new file mode 100644 index 0000000000000000000000000000000000000000..4876557f9a6fe8df7670825a4307ce967b1c6bb0 --- /dev/null +++ b/s/vdu/vducursoft @@ -0,0 +1,665 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.VduCurSoft + +SlowCursorSpeed * 16 +FastCursorSpeed * 8 +OnFlashTime * 48 +OffFlashTime * 16 + +; InitCursor - initialise cursor shape and address + +InitCursor ROUT + Push R14 + LDR R6, [WsPtr, #CursorFlags] + TST R6, #TeletextMode ; if teletext mode + MOVNE R0, #&72 ; then start at 9 (slow flash) + MOVEQ R0, #&67 ; else start at 7 (slow flash) + BL ProgReg10AndCopy + + MOV R0, #1 ; set to flash immediately + STR R0, [WsPtr, #CursorCounter] ; AFTER setting CursorSpeed + ; in case VSYNC happens + LDR R1, [WsPtr, #VduSprite] + TEQ R1, #0 ; if outputting to sprite + MOVNE R0, #&20 ; then turn cursor off + BLNE ProgReg10AndCopy + + LDR R0, [WsPtr, #RowMult] ; 8 or 10 or 16 or 20 + Pull R14 + +; and drop thru to ... + +SetCursorBottom + LDR R1, [WsPtr, #LineLength] + MUL R2, R1, R0 + STR R2, [WsPtr, #CursorEndOffset] + MOV PC, R14 + +SetCursorTop + LDR R1, [WsPtr, #LineLength] + MUL R2, R1, R0 + STR R2, [WsPtr, #CursorStartOffset] + MOV PC, R14 + +; ***************************************************************************** + +; Cursors are split, so remove output cursor + +DoOutputCursor ROUT + Push R14 + LDR R1, [WsPtr, #LineLength] + MOV R1, R1, LSL #3 ; and end after 8 rows + LDR R0, [WsPtr, #ModeFlags] + TST R0, #Flag_DoubleVertical ; if double vertical + ADDNE R1, R1, R1 ; end after 16 rows + MOV R0, #0 ; start on top line + BL EORCursor + LDR R2, [WsPtr, #InputCursorAddr] ; flashing cursor is at input + Pull R14 + B PreWC10 + +; ***************************************************************************** +; +; PreWrchCursor - Remove cursors prior to Wrch +; +; out: R6 = new CursorFlags; R5,R7 preserved; others corrupted +; + +PreWrchCursor + +; Need to disable IRQs here to stop Vsync modifying CursorFlags in between +; us reading it and writing it + + SETPSR I_bit, R1 + LDR R6, [WsPtr, #CursorFlags] + MOVS R0, R6, LSL #(32-InWrchBitPosn) ; CS => was already off + ORRCC R6, R6, #InWrchBit ; protect against vsyncs + STRCC R6, [WsPtr, #CursorFlags] + + LDR R0, [WsPtr, #CursorStack] + MOV R0, R0, RRX ; shift down + put current + ; state in top bit + STR R0, [WsPtr, #CursorStack] + + MOVCSS PC, R14 ; already off, so exit + ; (restoring I_bit) + TEQP R14, #0 ; restore old I_bit + + LDR R2, [WsPtr, #CursorAddr] ; point to output + TST R6, #CursorsSplit + BNE DoOutputCursor +PreWC10 + TST R6, #ActualState + MOVEQ PC, R14 ; flash cursor is off anyway + BIC R6, R6, #ActualState + STR R6, [WsPtr, #CursorFlags] + +; and drop thru to EORFlashCursor + +; ***************************************************************************** +; +; EORCursor - Exclusive-OR cursor with screen +; +; in: R0 = Start offset from top of cursor +; R1 = End+1 offset +; R2 = Screen address of appropriate cursor +; R6 = CursorFlags +; +; out: R5-R7 preserved; R0-R4, R8-R11 corrupted +; + +EORFlashCursor + ASSERT CursorEndOffset-CursorStartOffset=4 + ADD R0, WsPtr, #CursorStartOffset + LDMIA R0, {R0,R1} +EORCursor + CMP R0, R1 + MOVCS PC, R14 ; top >= bottom, so nowt + + ADD R1, R1, R2 + + LDR R3, [WsPtr, #LineLength] + + ASSERT CursorNbit = CursorFill +4 + ADD R4, WsPtr, #CursorFill + LDMIA R4, {R4, PC} ; load CursorFill and CursorNbit + +Cursor1bit + LDRB R8, [R0, R2]! + EOR R8, R8, R4 + STRB R8, [R0], R3 + TEQ R0, R1 + MOVEQ PC, R14 +Cursor1loop + LDRB R8, [R0] + EOR R8, R8, R4 + STRB R8, [R0], R3 + TEQ R0, R1 + BNE Cursor1loop + MOV PC, R14 + +Cursor2bit + ADD R0, R0, R2 +Cursor2loop + LDRB R8, [R0, #1] + EOR R8, R8, R4 + STRB R8, [R0, #1] + LDRB R8, [R0] + EOR R8, R8, R4 + STRB R8, [R0], R3 + TEQ R0, R1 + BNE Cursor2loop + MOV PC, R14 + +CursorTeletext + Push "R0, R1, R14" + ADD R0, R0, #40*1024 ; go to other screen + ADD R1, R1, #40*1024 + BL Cursor4bit + Pull "R0, R1, R14" + +; and drop thru to ... + +Cursor4bit + LDR R8, [R0, R2]! + EOR R8, R8, R4 + STR R8, [R0], R3 + TEQ R0, R1 + MOVEQ PC, R14 +Cursor4loop + LDR R8, [R0] + EOR R8, R8, R4 + STR R8, [R0], R3 + TEQ R0, R1 + BNE Cursor4loop + MOV PC, R14 + +Cursor8bit + ADD R0, R0, R2 +Cursor8loop + LDMIA R0, {R8,R9} + EOR R8, R8, R4 + EOR R9, R9, R4 + STMIA R0, {R8,R9} + ADD R0, R0, R3 + TEQ R0, R1 + BNE Cursor8loop + MOV PC, R14 + +Cursor16bit + ADD R0, R0, R2 +Cursor16loop + LDMIA R0, {R8-R11} + EOR R8, R8, R4 + EOR R9, R9, R4 + EOR R10, R10, R4 + EOR R11, R11, R4 + STMIA R0, {R8-R11} + ADD R0, R0, R3 + TEQ R0, R1 + BNE Cursor16loop + MOV PC, R14 + +Cursor32bit + ADD R0, R0, R2 + SUB R3, R3, #32 +Cursor32loop + LDMIA R0, {R8-R11} + EOR R8, R8, R4 + EOR R9, R9, R4 + EOR R10, R10, R4 + EOR R11, R11, R4 + STMIA R0!, {R8-R11} + LDMIA R0, {R8-R11} + EOR R8, R8, R4 + EOR R9, R9, R4 + EOR R10, R10, R4 + EOR R11, R11, R4 + STMIA R0!, {R8-R11} + ADD R0, R0, R3 + TEQ R0, R1 + BNE Cursor32loop + MOV PC, R14 + +; ***************************************************************************** +; +; PostWrchCursor - Put back cursors after Wrch +; +; out: R6 = new CursorFlags, R5,R7 preserved, all others undefined +; + +PostWrchCursor + LDR R6, [WsPtr, #CursorFlags] + LDR R0, [WsPtr, #CursorStack] + MOVS R0, R0, LSL #1 + STR R0, [WsPtr, #CursorStack] + MOVCS PC, R14 ; we're still off, so do nowt + + Push R14 + [ ForceMark + LDR R0, [WsPtr, #CursorCounter] + TEQ R0, #0 ; are we flashing + LDRNE R0, [WsPtr, #CursorSpeed] ; force to start of mark state + STRNE R0, [WsPtr, #CursorCounter] + MOVNE R0, #ActualState + STRNE R0, [WsPtr, #CursorDesiredState] + ] + + [ RePlot + LDR R1, [WsPtr, #CursorDesiredState] + EOR R1, R1, R6 ; EOR of desired and actual + ANDS R1, R1, #ActualState ; just get that bit + BEQ PWC10 ; same, then go home + + EOR R6, R1, R6 ; EOR actual bit + + TST R6, #CursorsSplit + LDRNE R2, [WsPtr, #InputCursorAddr] + LDREQ R2, [WsPtr, #CursorAddr] + BL EORFlashCursor +PWC10 + ] + + BIC R6, R6, #InWrchBit ; coming out of wrch now + TST R6, #CursorsSplit + STREQ R6, [WsPtr, #CursorFlags] + Pull PC, EQ ; return if no output cursor + + LDR R2, [WsPtr, #CursorAddr] + LDR R1, [WsPtr, #LineLength] + MOV R1, R1, LSL #3 ; and end after 8 rows + LDR R0, [WsPtr, #ModeFlags] + TST R0, #Flag_DoubleVertical ; if double vertical + ADDNE R1, R1, R1 ; end after 16 rows + MOV R0, #0 ; start on top line + BL EORCursor + STR R6, [WsPtr, #CursorFlags] ; only clear it now ? + Pull PC + + +; ***************************************************************************** + +VsyncCall ROUT + Push "R0-R11,R14" + + [ AssemblePointerV + BL PollPointer + ] + BL UpdatePointer + + LDR R6, [WsPtr, #CursorFlags] + TST R6, #TeletextMode + BLNE TeletextFlashTest ; if TTX, do other stuff +VsyncReturn + LDR R1, [WsPtr, #CursorDesiredState] + LDR R0, [WsPtr, #CursorCounter] + SUBS R0, R0, #1 + LDREQ R0, [WsPtr, #CursorSpeed] ; if is zero, reload + EOREQ R1, R1, #ActualState ; and toggle desired state + STREQ R1, [WsPtr, #CursorDesiredState] + + STRCS R0, [WsPtr, #CursorCounter] ; store back unless was frozen + + TST R6, #InWrchBit + Pull "R0-R11,PC", NE ; in wrch, so don't touch screen + ; or modify CursorFlags + + EOR R1, R1, R6 ; EOR of desired and actual + ANDS R1, R1, #ActualState ; just get that bit + Pull "R0-R11,PC", EQ ; same, then go home + + EOR R6, R1, R6 ; EOR actual bit + STR R6, [WsPtr, #CursorFlags] + + TST R6, #CursorsSplit + LDRNE R2, [WsPtr, #InputCursorAddr] + LDREQ R2, [WsPtr, #CursorAddr] + BL EORFlashCursor + + Pull "R0-R11,PC" + +; ***************************************************************************** + +TeletextFlashTest ROUT + LDR R3, [WsPtr, #TeletextCount] + SUBS R3, R3, #1 + BNE %FT20 ; count not expired + + LDR R1, [WsPtr, #TeletextOffset] + EORS R1, R1, #40*1024 ; switch to other flash bank + STR R1, [WsPtr, #TeletextOffset] + MOVEQ R3, #OnFlashTime + MOVNE R3, #OffFlashTime + LDR R0, [WsPtr, #DisplayStart] + BL SetVinit ; preserves R3 +20 + STR R3, [WsPtr, #TeletextCount] + B VsyncReturn + +; ***************************************************************************** +; +; Vdu23_0_10 - Program cursor start, flash/steady, on/off +; + +Vdu23_0_10 + LDRB R0, [WsPtr, #QQ+2] ; get parameter +ProgReg10AndCopy + STR R0, [WsPtr, #Reg10Copy] + +; and drop thru to ... + +ProgReg10 + AND R1, R0, #&60 + CMP R1, #&40 + BCS IsFlashing + MOV R2, #0 + STR R2, [WsPtr, #CursorCounter] ; freeze the flashing + TST R1, #&20 + MOVEQ R2, #ActualState ; steady cursor + STR R2, [WsPtr, #CursorDesiredState] + B PR1010 + +IsFlashing + TST R1, #&20 + MOVEQ R2, #FastCursorSpeed + MOVNE R2, #SlowCursorSpeed + STR R2, [WsPtr, #CursorSpeed] + LDR R2, [WsPtr, #CursorCounter] + TEQ R2, #0 ; was flashing frozen ? + ; if not, don't perturb flash + MOVEQ R2, #1 ; set to flash immediately + STREQ R2, [WsPtr, #CursorCounter] + +PR1010 + AND R0, R0, #&1F ; get start position bits + TST R6, #TeletextMode ; if teletext mode + MOVNE R0, R0, LSR #1 ; then divide by 2 + LDR R1, [WsPtr, #ModeFlags] + TST R1, #Flag_DoubleVertical ; if double vertical + MOVNE R0, R0, LSL #1 ; then double cursor value + + LDR R1, [WsPtr, #RowMult] + CMP R0, R1 ; is it > rowmult ? + MOVHI R0, R1 ; set to rowmult if so + B SetCursorTop + + +; ***************************************************************************** +; +; Vdu23_0_11 - Program cursor end +; + +Vdu23_0_11 + LDRB R0, [WsPtr, #QQ+2] ; get parameter + TST R6, #TeletextMode ; if teletext + MOVNE R0, R0, LSR #1 ; then divide by 2 + + ADD R0, R0, #1 ; get end line +1 + + LDR R1, [WsPtr, #ModeFlags] + TST R1, #Flag_DoubleVertical ; if double vertical + MOVNE R0, R0, LSL #1 ; then double cursor value + + LDR R1, [WsPtr, #RowMult] + CMP R0, R1 + MOVHI R0, R1 ; if > rowmult, set to rowmult + B SetCursorBottom + +; ***************************************************************************** +; +; Vdu23_1 - Program cursor +; + +Vdu23_1 + LDR R0, [WsPtr, #CursorFlags] + TST R0, #Vdu5Bit + MOVNE PC, R14 ; none of this nonsense in VDU5 mode + + LDRB R1, [WsPtr, #QQ+1] ; get parameter + +CursorOnOff + CMP R1, #1 + MOVCC R0, #&20 ; 0 -> just turn off + LDRCS R0, [WsPtr, #Reg10Copy] ; 1,2,3 -> read old state + BLS ProgReg10 ; 0,1 -> program hardware + TEQ R1, #2 + BICEQ R0, R0, #&60 ; 2 -> steady + ORRNE R0, R0, #&60 ; 3 -> slow flashing + STR R0, [WsPtr, #Reg10Copy] ; save in copy + B ProgReg10 + +; ***************************************************************************** +; +; DoCursorEdit +; +; in: R0 = &87 => COPY +; &88 => cursor left +; &89 => cursor right +; &8A => cursor down +; &8B => cursor up +; +; out: C=0 => doing COPY and valid character +; C=1 otherwise +; + + +DoCursorEdit + LDR R6, [WsPtr, #CursorFlags] + TEQ R0, #&87 + BNE IsCursorMove + +; COPY character under cursor + + Push R14 + TST R6, #CursorsSplit + BEQ BadCopyExit ; cursors not split so don't copy + + TST R6, #Vdu5Bit + BNE BadCopyExit ; can't copy in VDU5 mode + + BL ReadCharacter + + TEQ R0, #0 + BEQ BadCopyExit + + BL VDUBE ; is a cursor movement valid ? + BNE DoCE10 + + Push R0 + BL PreWrchCursor + BL InputCursorHT + BL PostWrchCursor + Pull R0 + +DoCE10 + CLC + Pull PC + +BadCopyExit + BL BEL ; make bell sound + SEC + Pull PC + +; ***************************************************************************** +; +; VDUBE - Check if valid to move cursor +; +; out: R0 preserved +; R1 = 0 => OK, R1<>0 => OK +; R6 = CursorFlags +; Z => OK, NZ => not OK +; C = 1 + +VDUBE + LDR R6, [WsPtr, #CursorFlags] + LDROSB R1, VDUqueueItems ; zero if not buffering + TEQ R1, #0 + + ANDEQS R1, R6, #Vdu5Bit ; zero if not in VDU 5 mode + +; insert check for vdu disabled here + + CMP R1, #0 ; set Z on R1, C:=1 + MOV PC, R14 + +; ***************************************************************************** + +IsCursorMove + Push R14 + BL VDUBE + Pull PC, NE + + Push R0 + BL PreWrchCursor ; remove both cursors + Pull R0 + BL ICM10 + BL PostWrchCursor + + SEC + Pull PC + +ICM10 + TST R6, #CursorsSplit + BNE AlreadySplit + + Push R0 + LDR R0, [WsPtr, #Reg10Copy] + AND R0, R0, #&DF ; use double flash rate + BSR ProgReg10 + + LDR R0, [WsPtr, #CursorX] ; copy parameters + STR R0, [WsPtr, #InputCursorX] + LDR R0, [WsPtr, #CursorY] + STR R0, [WsPtr, #InputCursorY] + LDR R0, [WsPtr, #CursorAddr] + STR R0, [WsPtr, #InputCursorAddr] + + ORR R6, R6, #CursorsSplit + STR R6, [WsPtr, #CursorFlags] + + Pull R0 + +AlreadySplit + CMP R0, #&89 + BCC InputCursorLeft ; &88 + BEQ InputCursorRight ; &89 + CMP R0, #&8B + BCC InputCursorDown ; &8A + +; and drop thru to ... + +InputCursorUp + LDR R1, [WsPtr, #InputCursorY] + LDR R2, [WsPtr, #InputCursorAddr] + LDR R3, [WsPtr, #RowLength] + LDR R4, [WsPtr, #TWTRow] + + SUB R1, R1, #1 + SUB R2, R2, R3 + CMP R1, R4 + LDRLT R1, [WsPtr, #TWBRow] + STR R1, [WsPtr, #InputCursorY] ; need signed comparison + STRGE R2, [WsPtr, #InputCursorAddr] ; in case Y went -ve + MOVGE PC, R14 + B AddressInputCursor + +InputCursorDown + LDR R1, [WsPtr, #InputCursorY] + LDR R2, [WsPtr, #InputCursorAddr] + LDR R3, [WsPtr, #RowLength] + LDR R4, [WsPtr, #TWBRow] + + ADD R1, R1, #1 + ADD R2, R2, R3 + CMP R1, R4 + LDRHI R1, [WsPtr, #TWTRow] + STR R1, [WsPtr, #InputCursorY] + STRLS R2, [WsPtr, #InputCursorAddr] + MOVLS PC, R14 + +; and drop thru to ... + +AddressInputCursor + Push R14 + LDR R0, [WsPtr, #InputCursorX] + LDR R1, [WsPtr, #InputCursorY] + BL AddressR0R1 + STR R2, [WsPtr, #InputCursorAddr] + Pull PC + +AddressCursors + LDR R6, [WsPtr, #CursorFlags] + TST R6, #CursorsSplit + BEQ AddressCursor + BSR AddressInputCursor + B AddressCursor + + +InputCursorLeft + LDR R0, [WsPtr, #InputCursorX] + LDR R2, [WsPtr, #InputCursorAddr] + LDR R3, [WsPtr, #BytesPerChar] + LDR R4, [WsPtr, #TWLCol] + + SUB R0, R0, #1 + SUB R2, R2, R3 + CMP R0, R4 + LDRLT R0, [WsPtr, #TWRCol] + STR R0, [WsPtr, #InputCursorX] + STRGE R2, [WsPtr, #InputCursorAddr] ; I do mean GE ! + MOVGE PC, R14 + + BSR AddressInputCursor + B InputCursorUp + +InputCursorRight + LDR R0, [WsPtr, #InputCursorX] + LDR R2, [WsPtr, #InputCursorAddr] + LDR R3, [WsPtr, #BytesPerChar] + LDR R4, [WsPtr, #TWRCol] + + ADD R0, R0, #1 + ADD R2, R2, R3 + CMP R0, R4 + LDRHI R0, [WsPtr, #TWLCol] + STR R0, [WsPtr, #InputCursorX] + STRLS R2, [WsPtr, #InputCursorAddr] + MOVLS PC, R14 + + BSR AddressInputCursor + B InputCursorDown + +; ***************************************************************************** +; +; InputCursorHT - move input cursor "right" after copying +; + +InputCursorHT + Push R14 + LDR R6, [WsPtr, #CursorFlags] + BL InputCursorMove + BCC ICHTExit + + BL InputCursorB0 + BL AddressInputCursor + EOR R6, R6, #8 + BL InputCursorMove + BLCS InputCursorB0 +ICHTExit + Pull R14 + B AddressInputCursor + + END diff --git a/s/vdu/vdudecl b/s/vdu/vdudecl new file mode 100644 index 0000000000000000000000000000000000000000..bd604275739e1f8feb9d35e0eb949a0100b9d5d2 --- /dev/null +++ b/s/vdu/vdudecl @@ -0,0 +1,556 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.VduDecl + +; ARTHUR OPERATING SYSTEM - Vdu Drivers +; ======================= +; +; Vdu driver workspace and macro declarations +; +; Author R C Manby +; Date 5.9.86 +; + + GBLL ForceMark ; whether we force start of mark state +ForceMark SETL {FALSE} ; of cursor on exit from WRCH + + GBLL RePlot ; Re-plot cursor after wrch +RePlot SETL {TRUE} + + GBLL UseVLineOnSolidLines ; When TRUE VLine is assembled and used +UseVLineOnSolidLines SETL {TRUE} ; to plot vertical solid lines + +; +; Register usage +; ============== +; +StkPtr RN 13 ;Restore on exit to keep BASIC happy!! +Link RN 14 + +; +; Manifest constants +; ================== +; + [ VIDC_Type = "VIDC20" + +; Registers + +VIDCPalAddress * &10000000 ; used in palette programming + +LCDOffsetRegister0 * &30000000 +LCDOffsetRegister1 * &31000000 + +HorizCycle * &80000000 +HorizSyncWidth * &81000000 +HorizBorderStart * &82000000 +HorizDisplayStart * &83000000 +HorizDisplayEnd * &84000000 +HorizBorderEnd * &85000000 +HorizCursorStart * &86000000 ; used in pointer programming +HorizInterlace * &87000000 + +VertiCycle * &90000000 +VertiSyncWidth * &91000000 ; Needed to set up FSIZE register in IOMD +VertiBorderStart * &92000000 ; First register affected by *TV +VertiDisplayStart * &93000000 +VertiDisplayEnd * &94000000 +VertiBorderEnd * &95000000 +VertiCursorStart * &96000000 +VertiCursorEnd * &97000000 ; Last register affected by *TV + +VIDCExternal * &C0000000 +VIDCFSyn * &D0000000 +VIDCControl * &E0000000 +VIDCDataControl * &F0000000 + +; Pseudo-registers used to return additional information to kernel + +PseudoRegister_ClockSpeed * &FC000000 ; used to indicate real VIDC rclock speed +PseudoRegister_DPMSState * &FD000000 ; used to return desired DPMS state + + +; Bits in external register + +Ext_HSYNCbits * 3 :SHL: 16 +Ext_InvertHSYNC * 1 :SHL: 16 +Ext_CompHSYNC * 2 :SHL: 16 +Ext_InvertCompHSYNC * 3 :SHL: 16 +Ext_VSYNCbits * 3 :SHL: 18 +Ext_InvertVSYNC * 1 :SHL: 18 +Ext_CompVSYNC * 2 :SHL: 18 +Ext_InvertCompVSYNC * 3 :SHL: 18 +Ext_HiResMono * 1 :SHL: 14 +Ext_LCDGrey * 1 :SHL: 13 +Ext_DACsOn * 1 :SHL: 12 +Ext_PedsOn * 7 :SHL: 8 +Ext_PedsShift * 8 +Ext_ERegShift * 4 +Ext_ECKOn * 1 :SHL: 2 +Ext_ERegBits * 3 :SHL: 0 +Ext_ERegRed * 0 :SHL: 0 +Ext_ERegGreen * 1 :SHL: 0 +Ext_ERegBlue * 2 :SHL: 0 +Ext_ERegExt * 3 :SHL: 0 ; use this for lowest power + +; Bits in Frequency Synthesizer Register + +FSyn_VShift * 8 +FSyn_RShift * 0 +FSyn_ClearV * 1 :SHL: 15 +FSyn_ForceLow * 1 :SHL: 14 +FSyn_ClearR * 1 :SHL: 7 +FSyn_ForceHigh * 1 :SHL: 6 + +FSyn_ResetValue * FSyn_ClearV :OR: FSyn_ClearR :OR: FSyn_ForceLow :OR: (63 :SHL: FSyn_RShift) :OR: (0 :SHL: FSyn_VShift) ; value to get PLL working properly + +; Bits in Control Register + +CR_DualPanel * 1 :SHL: 13 +CR_Interlace * 1 :SHL: 12 +CR_FIFOLoadShift * 8 +CR_LBPP0 * 0 :SHL: 5 +CR_LBPP1 * 1 :SHL: 5 +CR_LBPP2 * 2 :SHL: 5 +CR_LBPP3 * 3 :SHL: 5 +CR_LBPP4 * 4 :SHL: 5 +CR_LBPP5 * 6 :SHL: 5 ; spot the gap! +CR_PixelDivShift * 2 +CR_VCLK * 0 :SHL: 0 +CR_HCLK * 1 :SHL: 0 +CR_RCLK * 2 :SHL: 0 + +; Bits in Data Control Register + +DCR_VRAMOff * 0 :SHL: 18 +DCR_VRAMDiv1 * 1 :SHL: 18 +DCR_VRAMDiv2 * 2 :SHL: 18 +DCR_VRAMDiv4 * 3 :SHL: 18 +DCR_BusBits * 3 :SHL: 16 +DCR_Bus31_0 * 1 :SHL: 16 +DCR_Bus63_32 * 2 :SHL: 16 +DCR_Bus63_0 * 3 :SHL: 16 +DCR_HDis * 1 :SHL: 13 +DCR_Sync * 1 :SHL: 12 +DCR_HDWRShift * 0 + + | + +; Registers + +HorizDisplayStart * &8C000000 ; used in mode change code +HorizCursorStart * &98000000 ; used in pointer programming + +VertiBorderStart * &A8000000 ; First register affected by *TV +VertiDisplayStart * &AC000000 +VertiCursorStart * &B8000000 +VertiCursorEnd * &BC000000 ; Last register affected by *TV + +SoundFrequency * &C0000000 +VIDCControl * &E0000000 + +; Bits in control register + +CR_Interlace * &40 ; 0 - no interlace, 64 - interlace +CompSync * &80 ; Controls sync signal on CS/VS pin + ; 0 - output vertical sync, 128 - composite sync. +; Other bits + +SupBit * &1000 ; Supremacy bit in palette + ] + +PhysCursorStartAdr * CursorSoundPhysRAM + +; Reason codes for generalised DAG interface - independent of MEMC type + +MEMCDAG_VInit * 0 +MEMCDAG_VStart * 1 +MEMCDAG_VEnd * 2 +MEMCDAG_CInit * 3 + +MEMCDAG_MaxReason * 3 + + [ ModeSelectors + +; OS_ScreenMode reason codes + +ScreenModeReason_SelectMode * 0 +ScreenModeReason_ReturnMode * 1 +ScreenModeReason_EnumerateModes * 2 +ScreenModeReason_SelectMonitorType * 3 +ScreenModeReason_Limit * 4 + +; Mode selector format + + ^ 0 +ModeSelector_Flags # 4 ; flags word +ModeSelector_XRes # 4 ; x-resolution in pixels +ModeSelector_YRes # 4 ; y-resolution in pixels +ModeSelector_PixelDepth # 4 ; pixel depth (=Log2BPP) +ModeSelector_FrameRate # 4 ; nominal frame rate (in Hz) +ModeSelector_ModeVars # 0 ; start of pairs of (mode var index, value) + +ModeSelectorFlags_FormatMask * &FF +ModeSelectorFlags_ValidFormat * 1 + +ModeSelector_MaxSize * ModeSelector_ModeVars+(NumModeVars * 8)+4 + ; maximum size of a mode selector, with each mode variable overridden + ; plus terminator on end + + ] + + + +; +; Macro Definitions +; ================= +; + +; +; Macro Sort - Sort two values into increasing order +; + MACRO + Sort $lo, $hi + CMP $hi, $lo + EORLT $lo, $lo, $hi + EORLT $hi, $lo, $hi + EORLT $lo, $lo, $hi + MEND + +; +; Macro SortT - Sort two values into increasing order using a temporary reg +; + MACRO + SortT $lo, $hi, $temp + SUBS $temp, $hi, $lo + MOVLT $hi, $lo + ADDLT $lo, $lo, $temp + MEND + +; +; Macro CompSwap - Compare and sort a pair of coordinates into +; order of increasing Y +; If Y values equal, sort in order of decreasing X +; + MACRO + CompSwap $xl,$yl, $xh,$yh + CMP $yh, $yl + EORLT $yl, $yl, $yh + EORLT $yh, $yl, $yh + EORLT $yl, $yl, $yh + CMPEQ $xl, $xh + EORLT $xl, $xl, $xh + EORLT $xh, $xl, $xh + EORLT $xl, $xl, $xh + MEND + +; +; Macro CompSwapT - Compare and sort a pair of coordinates into +; order of increasing Y +; If Y values equal, sort in order of decreasing X +; Uses a temporary register +; + MACRO + CompSwapT $xl,$yl, $xh,$yh, $temp + SortT $yl, $yh, $temp + CMPEQ $xl, $xh + EORLT $xl, $xl, $xh + EORLT $xh, $xl, $xh + EORLT $xl, $xl, $xh + MEND + +; +; Macro Difference - rc := ABS(ra-rb) +; +; Test GE/LT for ra>=rb / ra<rb +; + MACRO + Difference $rc,$ra,$rb + SUBS $rc,$ra,$rb + RSBLT $rc,$rc,#0 + MEND + +; +; Macro Least - Select the smallest value (signed) +; + MACRO + Least $rc,$ra,$rb + CMP $ra,$rb + [ $rc = $ra + | + MOVLE $rc,$ra + ] + [ $rc = $rb + | + MOVGT $rc,$rb + ] + MEND + +; +; Macro Greatest - Select the largest (signed) value +; + MACRO + Greatest $rc,$ra,$rb + CMP $ra,$rb + [ $rc = $ra + | + MOVGE $rc,$ra + ] + [ $rc = $rb + | + MOVLT $rc,$rb + ] + MEND + +; +; Macro PackXtnd - pack 2 bytes into 1 word and sign extend +; + + MACRO + PackXtnd $result,$hi,$lo + [ $lo = $result + ADD $result,$lo,$hi,LSL #8 + MOV $result,$result,LSL #16 + MOV $result,$result,ASR #16 + | + MOV $result,$hi,LSL #24 + ORR $result,$lo,$result,ASR #16 + ] + MEND + + MACRO + LoadCoordPair $x, $y, $basereg, $offset + ASSERT $x < $y + [ ($offset) :AND: 3 = 2 + ADD $x, $basereg, #($offset)-2 + LDMIA $x, {$x, $y} ; (Xh,Xl,??,??) (??,??,Yh,Yl) + MOV $x, $x, ASR #16 ; (Xs,Xs,Xh,Xl) + MOV $y, $y, LSL #16 ; (Yh,Yl, 0, 0) + MOV $y, $y, ASR #16 ; (Ys,Ys,Yh,Yl) + | + [ ($offset) :AND: 3 = 0 + LDR $x, [$basereg, #$offset] ; (Yh,Yl,Xh,Xl) + | + [ ($offset) :AND: 3 = 1 + ADD $x, $basereg, #($offset)-1 + LDMIA $x, {$x, $y} ; (Yl,Xh,Xl,??) (??,??,??,Yh) + MOV $x, $x, LSR #8 ; ( 0,Yl,Xh,Xl) + ORR $x, $x, $y, LSL #24 ; (Yh,Yl,Xh,Xl) + | + ADD $x, $basereg, #($offset)-3 + LDMIA $x, {$x, $y} ; (Xl,??,??,??) (??,Yh,Yl,Xh) + MOV $x, $x, LSR #24 ; ( 0, 0, 0,Xl) + ORR $x, $x, $y, LSL #8 ; (Yh,Yl,Xh,Xl) + ] + ] + MOV $y, $x, ASR #16 ; (Ys,Ys,Yh,Yl) + MOV $x, $x, LSL #16 ; (Xh,Xl, 0, 0) + MOV $x, $x, ASR #16 ; (Xs,Xs,Xh,Xl) + ] + MEND + +; +; Macro SaveRetAdr - Push R14 to our pseudo stack +; + MACRO + SaveRetAdr + Push R14 + MEND + +; +; Macro Return - Pull from stack into PC +; + MACRO + Return $cond + LDM$cond.FD StkPtr!, {PC} + MEND + +; +; Macro SuperMode - Set supervisor mode +; + MACRO + SuperMode + SWI &16 + MEND + +; +; Macro UserMode - Return to user mode +; + MACRO + UserMode + TEQP PC,#0 ; Return to user mode + MOV R0,R0 ; Force a NOP so it works + MEND + +; +; Macro WINDow - Compare coordinate against graphics window +; +; Test GE/LT for within/outside window +; + MACRO + WINDow $rx,$ry, $rl,$rb,$rr,$rt +; ASSERT ($rl < $rb) AND ($rb < $rr) AND ($rr < $rt) + ADD $rt,WsPtr,#GWLCol + LDMIA $rt,{$rl,$rb,$rr,$rt} + CMP $rx,$rl + CMPGE $rr,$rx + CMPGE $ry,$rb + CMPGE $rt,$ry + MEND + +; +; Macro WindowRes - Window a coordinate, giving status word +; +; Result word is as follows: +; +; | | +; 1001 | 1000 | 1010 +; | | +; -----+------+----- GWTRow +; | | +; 0001 | 0000 | 0010 +; | | +; -----+------+----- GWBRow +; | | +; 0101 | 0100 | 0110 +; | | +; +; GWLCol GWRCol +; +; + MACRO + WindowRes $result, $rx,$ry, $rl,$rb,$rr,$rt +; ASSERT ($rl < $rb) AND ($rb < $rr) AND ($rr < $rt) + MOV $result,#0 + ADD $rt,WsPtr,#GWLCol + LDMIA $rt,{$rl,$rb,$rr,$rt} + CMP $rx,$rl + ORRLT $result,$result,#1 ;Set bit 0 if X < window + CMP $rr,$rx + ORRLT $result,$result,#2 ;Set bit 1 if X > window + CMP $ry,$rb + ORRLT $result,$result,#4 ;Set bit 2 if Y < window + CMP $rt,$ry + ORRLT $result,$result,#8 ;Set bit 3 if Y > window + MEND + + MACRO +$lab EQUB $var + ASSERT $var >= &00 + ASSERT $var <= &FF +$lab = $var + MEND + + MACRO + OrrEor $d,$s, $or,$eor + ORR $d,$s,$or + EOR $d,$d,$eor + MEND + + + MACRO ;Scr:=ScrOR(oraANDmsk)EOR(eorANDmsk) + OrrEorMASK $scr,$msk, $ora,$eor, $tmp + AND $tmp,$msk,$ora + ORR $scr,$scr,$tmp + AND $tmp,$msk,$eor + EOR $scr,$scr,$tmp + MEND + + + MACRO + ORoreorEORoreor $d,$s, $oo,$eo,$oe,$ee, $tmp + OrrEor $tmp,$s, $oo,$eo + ORR $d,$d,$tmp + OrrEor $tmp,$s, $oe,$ee + EOR $d,$d,$tmp + MEND + + + MACRO + ORoreorEORoreorMASK $d,$s,$m, $oo,$eo,$oe,$ee, $tmp + OrrEor $tmp,$s, $oo,$eo + AND $tmp,$tmp,$m + ORR $d,$d,$tmp + OrrEor $tmp,$s, $oe,$ee + AND $tmp,$tmp,$m + EOR $d,$d,$tmp + MEND + + + MACRO + ShiftR $d,$e, $r,$rcomp + MOV $d,$d,LSR $r + ORR $d,$d,$e,LSL $rcomp + MEND + + MACRO + ShiftL $d,$e, $r,$rcomp + MOV $e,$e,LSL $rcomp + ORR $e,$e,$d,LSR $r + MEND + + + MACRO + BitLOffset $b,$x, $xshftfactor,$npix,$log2bpc + AND $b,$x,$npix + MOV $b,$b,LSL $log2bpc + MEND + + + MACRO + BitROffset $b,$x, $xshftfactor,$npix,$log2bpc + AND $b,$x,$npix + ADD $b,$b,#1 + MOV $b,$b,LSL $log2bpc + SUB $b,$b,#1 + MEND + + + MACRO + WordOffset $w,$x, $xshftfactor,$npix,$log2bpc + MOV $w,$x,ASR $xshftfactor + MEND + + + MACRO + OffsetWordAndBit $o,$b,$x,$tmp + LDR $tmp,[WsPtr,#XShftFactor] + MOV $o,$x,ASR $tmp ;Word offset into scanline + LDR $tmp,[WsPtr,#NPix] + AND $b,$x,$tmp ;Pixel offset into word + LDR $tmp,[WsPtr,#Log2BPC] + MOV $b,$b,LSL $tmp ;Bit offset into word + MEND + + + MACRO +$label ErrorMsg $num,$string +$label DCD $num + DCB "$string", 0 + ALIGN + MEND + +; +; Macro when given a register will return the state to indicate +; if we are in a graphics mode. Originally lots of code used to simply +; load NPix and look for a null parameter (fair enough in 1-8 bit per pixel) +; but now we look at the mode flags, the choice of a new generation! +; + MACRO +$label GraphicsMode $scrap +$label LDR $scrap, [WsPtr, #ModeFlags] + TST $scrap, #Flag_NonGraphic ;NE then non-graphic mode! + MEND + + END diff --git a/s/vdu/vdudriver b/s/vdu/vdudriver new file mode 100644 index 0000000000000000000000000000000000000000..c5a31f057ef467da44c80855bf831026044f7ba6 --- /dev/null +++ b/s/vdu/vdudriver @@ -0,0 +1,3092 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.VduDriver +; +; ARTHUR OPERATING SYSTEM - Vdu Drivers +; ======================= +; +; Vdu driver code - Vdu queue, mode, default windows etc. +; +; Author R C Manby +; Date 5.9.86 +; + GBLL NewStyleEcfs +NewStyleEcfs SETL 1=1 + + GBLL DoVdu23_0_12 +DoVdu23_0_12 SETL {FALSE} + + GBLL BleedinDaveBell +BleedinDaveBell SETL {TRUE} + + GET s.vdu.VduDecl + GET s.vdu.VduGrafDec + + MACRO + HostVdu + Push "R0,R14" + LDR R0, [R0, -R0] + TEQ R0, #0 + ADREQ R0, %FT01 + SWIEQ OS_CLI + Pull "R0,R14" + B %FT02 +01 + = "HOSTVDU", 0 + ALIGN +02 + MEND + + MACRO + Print $string + Push "R0,R14" + LDR R0, [R0, -R0] + TEQ R0, #0 + BNE %FT01 + SWI OS_WriteS + = "$string", 0 + ALIGN + SWI OS_ReadC + Pull "R0,R14",CS + SWICS OS_BreakPt + SWI OS_NewLine +01 + Pull "R0,R14" + MEND + + MACRO + RMVT $var, $BW + [ "$BW"="B" + = (wk$var-wkstart)*2 + | + [ "$BW"="W" + = (wk$var-wkstart)*2 +1 + | + .... Invalid option on RMVT .... + ] + ] + MEND + + MACRO + RVVT $var + ASSERT ($var >= 0) :LAND: ($var < &400) :LAND: (($var :AND: 3)=0) + = $var :SHR: 2 + MEND + + MACRO + IssueService + BL Issue_Service + MEND + + MACRO + MALIGN $length, $phase + LCLA temp + LCLS string +temp SETA .-ArthurVduDriver + [ "$phase"="" +string SETS "ALIGN $length" + | +string SETS "ALIGN $length, $phase" + ] + $string +temp SETA .-ArthurVduDriver-temp + [ temp=0 + ! 0, string :CC: " fitted exactly" + | + ! 0, string :CC: " wasted " :CC: :STR: temp + ] + MEND + + [ ModeSelectors + +; Macro to load up video bandwidth and video memory size + + MACRO + GetBandwidthAndSize $bw, $size + [ MEMC_Type = "IOMD" + MOV $size, #0 + LDR $bw, [$size, #VideoBandwidth] ; load bandwidth + LDR $size, [$size, #VideoSize] ; and total amount of video RAM + | + LDR $bw, =38400000 ; if no ARM600 then must be MEMC based + LDR $size, =480*1024 + ] + MEND + ] + +; ***************************************************************************** + +; Vdu status bits + +Vdu2ModeBitPosn * 0 +Vdu2Mode * 1 :SHL: Vdu2ModeBitPosn +Windowing * 1 :SHL: 3 +Shadowing * 1 :SHL: 4 + +; ***************************************************************************** + +ArthurVduDriver + +; ***************************************************************************** +; +; VduInit - Once only initialisation of Vdu drivers eg after Break +; ======= +; +VduInit ROUT + Push R14 + MOV R0, #0 + STRB R0, [R0, #OsbyteVars + :INDEX: VDUqueueItems] ;purge queue + STRB R0, [WsPtr, #ScreenBlankFlag] ; not blanked + STR R0, [WsPtr, #CursorCounter] + STR R0, [WsPtr, #CursorDesiredState] + STR R0, [WsPtr, #VduStatus] + STR R0, [WsPtr, #PointerHeights] ; zero all 4 heights + STRB R0, [WsPtr, #PointerShapeNumber] ; make sure pointer off + STR R0, [WsPtr, #CursorStack] ; 0 bits => on + STR R0, [WsPtr, #VduSaveAreaPtr] ; indicate no save area yet + STR R0, [WsPtr, #ClipBoxEnable] ; no clip box calculating + + LDR R0, =RangeC+SpriteReason_SwitchOutputToSprite + STR R0, [WsPtr, #SpriteMaskSelect] + + MOV R0, #InitialCursorFlags ; TMD 25/9/86 + STR R0, [WsPtr, #CursorFlags] + + ADRL R0, NUL ; point to MOV PC,R14 + STR R0, [WsPtr, #WrchNbit] ; just in case ... + + ADRL R0, ExportedHLine + STR R0, [WsPtr, #HLineAddr] + ADD R0, WsPtr, #FgEcfOraEor + STR R0, [WsPtr, #GcolOraEorAddr] + + MOV R0, #maxmode + STR R0, [WsPtr, #MaxMode] ; constant now + + + LDROSB R0, LastBREAK ; is it a hard reset ? + TEQ R0, #0 + BEQ %FT10 ; [no, don't reset font] + + [ VIDC_Type = "VIDC20" + +; allocate buffer for Tim's whizzy text expansion. This now lives +; in the system heap, unless the claim request fails. If the request +; fails then the pointer points at the original buffer in the Vdu +; driver workspace. + +; This allows the user to access depths upto 16 bit per pixel before +; strings things things become afoot at the Circle K. + + LDR R3, =TextExpandArea_Size + BL ClaimSysHeapNode ; allocate buffer for heap data + ADDVS R2, WsPtr, #TextExpand + STR R2, [WsPtr, #TextExpandArea] + + [ ModeSelectors + LDR R3, =ModeSelector_MaxSize+4 ; get block for two overlapping copies + BL ClaimSysHeapNode ; of mode selector, 1 word apart + STR R2, [WsPtr, #KernelModeSelector] + ] + + ] + +; now reset soft font from hard font + + MOV R1, #1 ; start at character 1*32 + STRB R1, [WsPtr, #ScreenMemoryClaimed] + ; can't claim memory till a mode change + MOV R2, #7 ; copy 7 pages + BL DoResetFont + + [ VIDC_Type = "VIDC20" + [ GammaCorrection + MOV r3, #(256+1+3)*4*4+3*256 ; logical and physical copies of both flash states + ; plus 3 lookup tables for r,g,b + | + MOV r3, #(256+1+3)*4*2 ; soft copy of palette (2 flash states) + ] + BL ClaimSysHeapNode ; this had better succeed! + STR r2, [WsPtr, #FirPalAddr] + + ADD r3, r2, #260*4 + STR r3, [WsPtr, #SecPalAddr] + +; now initialise entries for pointer palette so they will actually program pointer palettte +; because VDU20 doesn't change pointer palette + + MOV r3, #&50000000 + MOV r4, #&60000000 + MOV r5, #&70000000 + + ADD r2, r2, #260*4 ; store in 1st copy of logical + STMDB r2, {r3-r5} ; (last 3 entries) + + ADD r2, r2, #260*4 + STMDB r2, {r3-r5} ; store in 2nd copy of logical + + [ GammaCorrection + ADD r2, r2, #260*4 + STMDB r2, {r3-r5} ; store in 1st copy of physical + + ADD r2, r2, #260*4 + STMDB r2, {r3-r5} ; store in 2nd copy of physical + +; r2 now points off end of all 4 copies, ie start of rgb tables +; initialise red, green and blue transfer function tables to 1-1 mapping + + MOV r0, #0 +05 + STRB r0, [r2, #&200] ; store in blue table + STRB r0, [r2, #&100] ; store in green table + STRB r0, [r2], #1 ; store in red table, and advance + ADD r0, r0, #1 + CMP r0, #256 + BCC %BT05 + ] + ] +10 + BL SpriteInit + + LDR R0, [WsPtr, #TotalScreenSize] + RSB R0, R0, #ScreenEndAdr + STR R0, [WsPtr, #DisplayStart] + STR R0, [WsPtr, #DisplayScreenStart] + STR R0, [WsPtr, #ScreenStart] + STR R0, [WsPtr, #CursorAddr] + STR R0, [WsPtr, #InputCursorAddr] + + Pull PC + + LTORG + +; ***************************************************************************** +; +; InitialiseMode - Select mode number given by ModeNo variable +; +; Called by MOS once before initialisation, and then afterwards +; before printing "RISC OS ..." +; +; in: - +; out: All registers may be corrupted (except R13_svc !) +; + +InitialiseMode ENTRY + [ SoftResets + MOV r0, #&FD ; read last reset type + MOV r1, #0 + MOV r2, #&FF + SWI XOS_Byte + CMP r1, #SoftReset + LDREQ r0, =VduDriverWorkSpace+ModeNo + LDREQ r0, [r0] ; use previous mode if a soft reset + MOVNE r0, #1 ; otherwise read configured mode + SWINE XOS_ReadSysInfo + | + MOV r0, #1 ; no need to check for soft reset, + SWI XOS_ReadSysInfo ; always use configured value + ] + [ ModeSelectors + MOV r1, r0 + MOV r0, #ScreenModeReason_SelectMode + SWI XOS_ScreenMode + EXIT VC + | + SWI XOS_WriteI+22 + SWIVC XOS_WriteC + EXIT VC + ] + + MOV r0, #114 ; failed, so get rid of any shadow + MOV r1, #1 + SWI XOS_Byte + SWI XOS_WriteI+22 + SWIVC XOS_WriteI+0 ; and if we can't get mode 0, we're really fooked!!! + EXIT + +; +;------------------------------------------------------------------------------ +; +; Vdu - Main VDU driver entry point +; === Queue up bytes and dispatch via JVec +; +; in: R0 = character to be printed +; +; out: C=1 <=> send character to printer if enabled +; + +Vdu ROUT + MOV R11, #0 ; NB used later in Vdu07 as well + LDRB R10, [R11, #OsbyteVars + :INDEX: VDUqueueItems] + MOVS R9, R10, LSL #24 ; move up to top byte (for sign extend) + BEQ Vdu07 ; not queueing, then start Vdu sequence + +; *****Comment made by DJS: Changing this to fall through if not queueing +; and branch if queueing might be a good idea - it would speed up all +; printable characters and simple cursor movements. + + LDR R8, [WsPtr, #QOffset] + STRB R0, [R8, R9, ASR #24] ; add byte to queue + + ADD R10, R10, #1 ; move on pointer + STRB R10, [R11, #OsbyteVars + :INDEX: VDUqueueItems] + + CMP R10, #&100 ; finished sequence ? + MOVCC PC, R14 ; no, then return (no printing) + + Push "R0, R14" + BL PreWrchCursor ; exits with R6 = CursorFlags + Pull "R0" +05 + MOV R14, PC + ADD R14, R14, #(VduPrintExit-%BT05-8) ; push address of SEC exit + ; (with flags) + Push R14 + BL Vdu05 + BL PostWrchCursor + CLC ; also clears V + Pull "R14,PC" + +VduPrintExit ; exit used if print required + BL PostWrchCursor + SEC ; also clears V + Pull PC + +; ***************************************************************************** + +Vdu05 ROUT + TST R6, #VduDisabled ; VDU enabled ? + LDREQ PC, [WsPtr, #JVec] ; yes, then do it (no printing) + +; Queue sequence has just completed, but VDU is disabled +; Only interesting case is VDU 1 (SOH), which must still print +; the character if the printer is enabled + + LDR R10, [WsPtr, #JVec] + ADR R11, SOH + TEQ R10, R11 ; JVec -> SOH ? + MOVNE PC, R14 ; no, then return (no printing) +SOH + LDR R1, [WsPtr, #VduStatus] ; in VDU 2 mode ? + TST R1, #Vdu2Mode + MOVEQ PC, R14 ; no, then return + + Push R14 + BL MOSDoPrint + Pull PC, VC ; good exit, so return + + Pull R14 ; bad exit, return with error + B VduBadExit + +; ***************************************************************************** + +Vdu07 ROUT + AND R0, R0, #&FF ; Only look at bottom byte! + + CMP R0,#127 ;If DELETE, change R0 to 32 and + MOVEQ R0,#32 ; drop through to control char code + CMPNE R0,#31 ;Otherwise, branch to printable char + BHI Vdu20 ; code if not a control char + +; *****Further desirable change: Make printable characters fall through, +; control characters take the branch - speeding up printable characters is +; important! + + ADR R10, VduJTb ; Address of beginning of jump table + LDR R9, [R10, R0, LSL #2] ; Get routine address from VduJTB + STR R9, [WsPtr, #JVec] ; save address + + ADD R10, R10, #(VduQTb-VduJTb) + + LDRB R9, [R10, R0] ; Pick up QQ + length of queue + RSBS R10, R9, #QQ ; -(length of queue) & test if none + + STRNEB R10, [R11, #OsbyteVars + :INDEX: VDUqueueItems] + ; yes, then set up Osbyte variable + ADDNE R9, R9, WsPtr + STRNE R9, [WsPtr, #QOffset] ; and QOffset + MOVNE PC, R14 + + Push "R0,R14" + BL PreWrchCursor ; exits with R6 = CursorFlags + Pull "R0" +10 + MOV R14, PC + ADD R14, R14, #(VduPrintExit-%BT10-8) ; push address of SEC exit + ; (with flags) + Push R14 + BL Vdu10 + BL PostWrchCursor + CLC ; also clears V + Pull "R14,PC" + +; +; This is the only byte of a single byte Vdu sequence +; +; R6 = CursorFlags +; R11 = 0 (used to index VDUqueueItems) +; + +Vdu10 ROUT + TST R6, #CursorsSplit ; are we cursor editing ? + BNE Vdu15 +Vdu10Continue + +; TMD 31/7/87; bug fixed here - chars 8 to 13 should still go to printer if +; enabled, even if VDU is disabled + + CMP R0, #8 ; is char in range 8-13 ? + RSBCSS R1, R0, #13 ; if so then we want to print it + LDRCS R1, [WsPtr, #VduStatus] + MOVCSS R1, R1, LSR #(Vdu2ModeBitPosn +1) ; providing printer enabled + Pull R14, CS ; so pull old R14 + + TST R6, #VduDisabled ; are we disabled + LDREQ PC, [WsPtr, #JVec] ; enabled, so go get em floyd ! + + TEQ R0, #6 ; disabled, so is it ACK (enable VDU) + BICEQ R6, R6, #VduDisabled + STREQ R6, [WsPtr, #CursorFlags] + +NUL ;Does nothing +ESC ;Does nothing + MOV PC, R14 ; return anyway + +; ***************************************************************************** + +Vdu15 + TEQ R0, #13 ; and is it a carriage return ? + BNE Vdu10Continue + + Push "R0, R14" + BIC R6, R6, #CursorsSplit ; then stop cursor editing + STR R6, [WsPtr, #CursorFlags] + MOV R1, #1 ; restore old Reg10Copy + BL CursorOnOff + Pull "R0, R14" + B Vdu10Continue + +; ***************************************************************************** + +Vdu20 ROUT + Push "R0,R14" + BL PreWrchCursor ; exits with R6 = CursorFlags + Pull "R0" +05 + MOV R14, PC + ADD R14, R14, #(VduPrintExit-%BT05-8) ; push address of SEC exit + ; (with flags) + Push R14 + BL TimWrch + BL PostWrchCursor + CLC ; also clears V + Pull "R14,PC" + +; ***************************************************************************** + +VduJTb ; Table of addresses + & NUL ; Does nothing + & SOH ; Next char to printer only + & STX ; Enable printer + & ETX ; Disable printer + & EOT ; Write text at text cursor + & ENQ ; Write text at graphics cursor + & NUL ; Enable VDU drivers + & BEL ; Beep + & BS ; Cursor left + & HT ; Cursor right + & VduLF ; Cursor down + & VT ; Cursor up + & FF ; Clear text area (CLS) + & VduCR ; Carriage return + & SO ; Page mode on + & SI ; Page mode off + & DLE ; Clear graphics area (CLG) + & DC1 ; Define text colour (COLOUR) + & DC2 ; Define graphics colour and action (GCOL) + & DC3 ; Define logical colour + & VDU20 ; Restore default logical colours + & NAK ; Disable VDU drivers + & SYN ; Select screen mode (MODE) + & ETB ; Reprogram display character (VDU23,...) + & CAN ; Define graphics window + & EM ; (PLOT k,x,x,y,y) + & DefaultWindows ; Restore default windows + & ESC ; Does nothing + & FS ; Define text window + & GS ; Define graphics origin + & RS ; Home cursor to "top left" + & US ; Move text cursor (TAB x,y) + & Delete ; Delete character (127) + + ASSERT QQ+9 < 256 + +VduQTb ; QQ + length of queue for each of the above + DCB QQ+0, QQ+1, QQ+0, QQ+0, QQ+0, QQ+0, QQ+0, QQ+0 + DCB QQ+0, QQ+0, QQ+0, QQ+0, QQ+0, QQ+0, QQ+0, QQ+0 + DCB QQ+0, QQ+1, QQ+2, QQ+5, QQ+0, QQ+0, QQ+1, QQ+9 + DCB QQ+8, QQ+5, QQ+0, QQ+0, QQ+4, QQ+4, QQ+0, QQ+2 + DCB QQ+0 ; (delete) + ALIGN + +; ***************************************************************************** + +WrchNbitTab + & Wrch1bit-WrchNbitTab + & Wrch2bit-WrchNbitTab + & Wrch4bit-WrchNbitTab + & Wrch8bit-WrchNbitTab + & Wrch16bit-WrchNbitTab + & Wrch32bit-WrchNbitTab +WrchNbitDoubleTab + & Wrch1bitDouble-WrchNbitDoubleTab + +CursorNbitTab + & Cursor1bit-CursorNbitTab + & Cursor2bit-CursorNbitTab + & Cursor4bit-CursorNbitTab + & Cursor8bit-CursorNbitTab + & Cursor16bit-CursorNbitTab + & Cursor32bit-CursorNbitTab + +; ***************************************************************************** +; +; SYN - Perform MODE change +; +; External routine +; +; in: Vdu queue contains mode number +; + +SYN ROUT ; Select screen mode (MODE) + Push lr + LDRB R2, [WsPtr, #QQ] ; Read mode number from queue + BL ModeChangeSub + Pull lr + MOVVC pc, lr ; if no error, exit to Vdu + ; (which calls PostWrchCursor) +; else drop thru into ... + +VduBadExit ; jumped to if an error in VDU code + Push R0 ; save error pointer + BL PostWrchCursor + SETV + Pull "R0, R14,PC" + +ModeChangeSub ROUT + Push lr + MOV R1, #Service_PreModeChange + IssueService + TEQ R1, #0 ; was service claimed ? + BNE %FT03 ; no, so continue + + CMP R0, #0 ; service claimed; generate error ? + Pull PC, EQ ; no, just exit (V=0 from CMP) + B %FT07 ; yes, then generate error +03 + MOV R0, R2 ; put mode (possibly changed) in R0 + MOV R2, R0, LSR #7 ; R2 = 0/1 if bit 7 of mode clear/set + [ ModeSelectors + CMP r2, #2 ; if mode number >= 256 then mode selector + MOVCS r2, #0 ; so no shadow + ] + LDROSB R1, Shadow + TEQ R1, #0 ; if shadow 0 then force shadow mode + MOVEQ R2, #1 + + BL FindOKMode ; out: R1 = mode we are going to use + BVS %FT07 + + TEQ R0, R1 ; if substitute mode + MOVNE R2, #0 ; then don't use shadow + + [ ModeSelectors + CMP r1, #&100 + BICCC r10, r1, #&80 + MOVCS r10, r1 + | + BIC R10, R1, #&80 + ] + MOV R11, R10 + BL PushModeInfo + BVS %FT07 ; [probably duff mode selector] + + LDR R11, [R13, #wkScreenSize] ; get screen size for this mode + LDR R9, [WsPtr, #TotalScreenSize] ; maximum allowed amount + + Push R1 ; save proper mode + RSBS R1, R9, R11, LSL R2 ; extra amount we need + BLS %FT08 ; enough memory, so skip + +; try to extend the amount of screen memory + + MOV R0, #2 ; expand screen memory + SWI XOS_ChangeDynamicArea + BVC %FT08 + + ADD R13, R13, #PushedInfoSize + 1*4 ; junk stacked info + mode no. + ADR R0, ErrorBlock_BadMODE + [ International + BL TranslateError + ] +07 + SETV ; indicate error + Pull PC + +; valid mode and enough memory + +08 + Pull R0 ; restore mode we are using + [ ModeSelectors + CMP r0, #&100 ; if not mode selector + BICCC r0, r0, #&80 ; then knock off shadow bit + BCC %FT12 + +; it's a mode selector, so copy it to our static mode selector block + + LDR r1, [WsPtr, #KernelModeSelector] ; point at block + + SUBS r3, r0, r1 ; if r0 -> 1st mode block position + TEQNE r3, #4 ; or r0 -> 2nd mode block position + MOVEQ r1, r0 ; then use it in place + BEQ %FT09 + + LDR r3, [WsPtr, #DisplayModeNo] ; else check if current mode is a mode selector + SUB r3, r3, r1 ; r3 = offset from start of block + CMP r3, #8 ; if 0 or 4 + EORCC r3, r3, #4 ; then make 4 or 0 (ie toggle between them) + ADDCC r1, r1, r3 ; and add on base + + ASSERT (ModeSelector_ModeVars+4) :AND: 7 = 0 +09 + MOV r3, #0 +10 + LDR r6, [r0, r3] ; copy 1st word - after fixed bit this will be previous var value + STR r6, [r1, r3] + ADD r3, r3, #4 + LDR r6, [r0, r3] ; copy 2nd word - after fixed bit this will be next var index + STR r6, [r1, r3] + ADD r3, r3, #4 + CMP r3, #ModeSelector_ModeVars + 4 ; only exit if we've done the essential bit + CMPCS r6, #-1 ; AND we've had a -1 as the var index (NOT as the value) + CMPCC r3, #ModeSelector_MaxSize ; OR we've gone off the end of our block + BCC %BT10 ; [we haven't, so loop] + + CMP r3, #ModeSelector_MaxSize ; if we did go off the end + MOVCS r6, #-1 + STRCS r6, [r1, #ModeSelector_MaxSize-4] ; then terminate it properly + + MOV r0, r1 ; point at static block +12 + | + BIC R0, R0, #&80 ; knock out shadow bit + ] + STR R0, [WsPtr, #DisplayModeNo] ; store the new display mode + +; now issue Service_ModeChanging + + MOV R1, #Service_ModeChanging + BL IssueModeService + +; R13 -> mode variables + + LDR R3, [R13, #wkScreenSize] + STR R3, [WsPtr, #ScreenSize] ; store screensize BEFORE calling + ; ConvertBankToAddress (was a bug!) + + TEQ R2, #0 ; Shadowing or not ? + LDR R3, [WsPtr, #VduStatus] + BICEQ R3, R3, #Shadowing + ORRNE R3, R3, #Shadowing + STR R3, [WsPtr, #VduStatus] + + STRB R2, [WsPtr, #ScreenMemoryClaimed] ; only allow ADFS to claim + ; if non-shadow (simplifies things!) + + BL ConvertBankToAddress ; R3 := default start for this bank + STR R3, [WsPtr, #DriverBankAddr] + STR R3, [WsPtr, #DisplayBankAddr] + + MOV R6, #0 + STRB R6, [R6, #OsbyteVars + :INDEX:MemDriver] ; indicate default + STRB R6, [R6, #OsbyteVars + :INDEX:MemDisplay] ; for both of these + + LDR R6, [R13, #wkModeFlags] + STR R6, [WsPtr, #DisplayModeFlags] + + MOV R2, #wkend-wkdispstart ; number of bytes to do + ADD R1, R13, #wkdispstart + + ADD R4, WsPtr, #PalIndex ; first display mode variable +15 + LDR R3, [R1], #4 ; copy variables + STR R3, [R4], #4 + SUBS R2, R2, #4 ; loop until all done + BNE %BT15 + +; now set up other mode variables by calling SwitchOutput + + ADD R3, WsPtr, #VduSaveArea+InitFlag + STR R2, [R3] ; indicate uninitialised (R2=0) + TST R6, #Flag_Teletext + MOVNE R3, #0 ; if teletext, then no save area + MOVEQ R3, #1 ; else MOS's save area + MOV R1, #0 ; just in case + MOV R0, #SpriteReason_SwitchOutputToSprite + SWI XOS_SpriteOp + +; now create other variables from simple ones + + LDR R3, [WsPtr, #NColour] + STR R3, [WsPtr, #DisplayNColour] + + ASSERT YWindLimit = XWindLimit +4 + ASSERT DisplayYWindLimit = DisplayXWindLimit +4 + ADD R0, WsPtr, #XWindLimit + LDMIA R0, {R3, R4} + ADD R0, WsPtr, #DisplayXWindLimit + STMIA R0, {R3, R4} + + ASSERT YEigFactor = XEigFactor +4 + ASSERT DisplayYEigFactor = DisplayXEigFactor +4 + ADD R0, WsPtr, #XEigFactor + LDMIA R0, {R3, R4} + ADD R0, WsPtr, #DisplayXEigFactor + STMIA R0, {R3, R4} + + ASSERT Log2BPP = Log2BPC +4 + ADD R0, WsPtr, #Log2BPC + LDMIA R0, {R0, R1} ; R0 = Log2BPC; R1 = Log2BPP + SUB R3, R3, R0 ; adjust XEig for double pixels + ADD R3, R3, R1 + STR R3, [WsPtr, #PointerXEigFactor] + +; finished doing other variables + + [ VIDC_Type = "VIDC20" + LDROSB R2, TVInterlace + TST R2, #1 + MOVNE R4, #0 + MOVEQ R4, #CR_Interlace + | + BL ReadSyncType ; out: r4 = configured sync (0 or 1) and NE if 1 + MOVNE R4, #CompSync + + LDROSB R2, TVInterlace + TST R2, #1 + ORREQ R4, R4, #CR_Interlace ; 0 or &40 + ] + + LDROSB R5, TVVertical + MOV R5, R5, LSL #24 ; sign extend to 32 bits + [ VIDC_Type = "VIDC20" + MOV R5, R5, ASR #24-3 ; and multiply by 8 + | + MOV R5, R5, ASR #24-3-14 ; and multiply by 8*(2^14) + ] + LDR R1, [WsPtr, #ModeFlags] + TST R1, #Flag_GapMode ; gap mode ? + ADDNE R5, R5, R5, ASR #2 ; add on 2 rows if so + TST R1, #Flag_DoubleVertical ; if double vertical + ADDNE R5, R5, R5 ; then double it + + ADD R0, R13, #wkwordsize ; R0 -> table of VIDC parms + MOV R7, R0 ; keep copy for if we go wrong + + [ VIDC_Type = "VIDC20" + LDR R1, [R0, #(PseudoRegister_DPMSState:SHR:22)-&80*4] ; get DPMS state if specified + CMP R1, #-1 ; if not specified + MOVEQ R1, #0 ; then use zero + ANDNE R1, R1, #3 ; else only use bits 0 and 1 + STRB R1, [WsPtr, #ScreenBlankDPMSState] + + MOV R1, #0 ; always select 24MHz clock to feed into VIDC, and normal syncs + | +; now set up the VIDC clock latch, before we program any VIDC registers +; and also set up the sync polarity while we're at it + + LDR R1, [R0, #(&E0-&80)] ; get CR with clock+sync bits + EOR R1, R1, R4 ; adjust vertical/composite flag + TST R1, #CompSync ; if doing composite sync + BICNE R1, R1, #SyncControlMask ; then ensure normal syncs + + AND R1, R1, #ClockControlMask :OR: SyncControlMask + + ASSERT SyncControlShift = ClockControlShift+2 + + MOV R1, R1, LSR #ClockControlShift + ] + [ IO_Type <> "IOMD" + LDR R3, =VIDCClockSelect + STRB R1, [R3] + ] + + [ {FALSE} ; TMD 02-Sep-92: This bit removed - no production h/w has this latch + BL ReadMonitorType ; now mute sound pin if not monitortype 0 (sound pin = VGA test pin) + TEQ R3, #0 ; if monitortype 0 then program 0 + MOVNE R3, #1 ; else program 1 + LDR R1, =IOEB_SoundSuppress + STRB R3, [R1] ; OK to do this on old machines + ] + + MOV R3, #VIDC ; point to VidC +18 + [ VIDC_Type = "VIDC20" + MOV R1, #124*4 ; number of bytes to do (register &FC is the pseudo one to tell + ; the OS the real VIDC clock rate) + | + MOV R1, #31*4 ; number of bytes to do (register &FC is the pseudo one to tell + ; the OS the real VIDC clock rate) + ] +20 + LDR R2, [R0], #4 ; Get data from table + + CMP R2, #-1 ; unprogrammed register ? + BEQ %FT80 ; then skip + + AND R6, R2, #&FF000000 + + TEQ R6, #HorizDisplayStart + STREQ R2, [WsPtr, #CursorFudgeFactor] ; save for later ! + +25 + CMP R6, #VertiBorderStart + RSBCSS R14, R6, #VertiCursorEnd + BCC %FT40 ; not a vertical register + +; programming one of the registers affected by *TV + + SUB R8, R2, R5 ; subtract offset + TEQ R6, #VertiDisplayStart ; test for display start + BICEQ R14, R8, #&FF000000 ; get rid of register bits + STREQ R14, [WsPtr, #VertAdjust] ; save for pointer programming + + EOR R14, R8, R2 ; see if now programming different reg + MOVS R14, R14, LSR #24 ; zero if OK + + MOVNE R5, #0 ; we've gone wrong, so set 0 adjust + MOVNE R0, R7 ; and go back to the beginning + BNE %BT18 + + MOV R2, R8 ; otherwise update register +40 + [ VIDC_Type = "VIDC20" + TEQ R6, #HorizSyncWidth ; if h.sync width register + STREQ R2, [WsPtr, #HSWRSoftCopy] ; then save for DPMS stuff + TEQ R6, #VertiSyncWidth ; likewise v.sync width + STREQ R2, [WsPtr, #VSWRSoftCopy] + + TEQ R6, #VIDCExternal ; check for external register (which contains syncs) + BNE %FT50 + + Push "r4" + BL ReadSyncType + Pull "r4" + BICNE R2, R2, #(Ext_HSYNCbits :OR: Ext_VSYNCbits) ; if composite sync then don't invert syncs + ORRNE R2, R2, #Ext_InvertCompVSYNC :OR: Ext_InvertCompHSYNC ; and force both syncs to be composite (because of lack of + ; swap in A540 VIDC card) + B %FT75 +50 + TEQ R6, #VIDCFSyn + BNE %FT60 + + LDR R8, =FSyn_ResetValue ; set test bits on, and r > v + STR R8, [R3] + +; we may need some delay in here... + + LDR R8, =FSyn_ClearR :OR: FSyn_ClearV :OR: FSyn_ForceLow :OR: FSyn_ForceHigh + ORR R2, R2, R8 + BIC R2, R2, #FSyn_ForceHigh ; force test bits on, except this one + STR R2, [R3] + +; we may also need some delay in here... + + BIC R2, R2, R8 ; remove test bits + B %FT75 + +60 + [ MEMC_Type = "IOMD" + TEQ r6, #VIDCDataControl + BNE %FT65 + + BIC r2, r2, #DCR_BusBits + MOV r14, #0 + LDR r14, [r14, #VRAMWidth] + CMP r14, #2 ; if using 64-bit wide VRAM + ORRCS r2, r2, #DCR_Bus63_0 ; then data on all 64 bits + ORRCC r2, r2, #DCR_Bus31_0 ; else for 32-bit wide VRAM or DRAM-only, + ; data is on low 32 bits + BCC %FT65 + +; dual-bank VRAM, so HDWR value needs to be halved + + MOV r14, r2, LSL #(31-10) ; get HDWR bits at top - NB allow bit 10 to be used here! + BIC r2, r2, r14, LSR #(31-10) ; knock off bits + TST r14, #1 :SHL: (31-10) ; see if bottom bit would get knocked off + ORRNE r2, r2, #DCR_HDis ; if so, then disable HDis mechanism (for eg mode 29) + ORREQ r2, r2, r14, LSR #(31-9) ; otherwise, put bits back one bit further down + +65 + ] + ] + TEQ R6, #VIDCControl ; if control register + BNE %FT75 + +; programming control register, so EOR sync/interlace bits, save in soft copy +; then work out CursorFudgeFactor from HorizDisplayStart (in CursorFudgeFactor) +; and bits-per-pixel in control register + + EOR R2, R2, R4 ; then EOR sync/interlace bits + + [ VIDC_Type = "VIDC20" + [ MorrisSupport + ; MOV R10, #IOMD_Base + ; LDRB R9, [R10, #IOMD_ID0] + ; CMP R9, #&98 + ; LDRB R9, [R10, #IOMD_ID1] + ; CMPEQ R9, #&5B + ; MOVEQ R9, #32000 ;Morris clocks VIDC20L at 32Mhz + ; LDRNE R9, =24000 ;RISC PC clocks VIDC20 at 24MHz + MOV R9, #0 + LDRB R9, [R9, #IOSystemType] + TST R9, #IOST_7500 + LDREQ R9, =24000 ;RISC PC clocks VIDC20 at 24MHz + MOVNE R9, #32000 ;Morris clocks VIDC20L at 32Mhz ; + | + LDR R9, =24000 + ] + STR R9, [WsPtr, #VIDCClockSpeed] + [ {FALSE} + +; The following code computes the actual pixel rate used, but we don't actually +; need to know this! + + AND R8, R2, #3 + CMP R8, #1 + MOVEQ R9, #0 ; dunno what HCLK is, so assume 0 + MOVCS R8, #1 ; r-modulus not used, so 1 + BCS %FT71 ; PLL not used + + LDR R10, [R7, #(&D0-&80)*4] ; get FreqSyn register + MOV R8, R10, LSR #8 + AND R8, R8, #63 + ADD R8, R8, #1 ; r8 = v-modulus + MUL R9, R8, R9 + + AND R8, R10, #63 + ADD R8, R8, #1 ; r8 = r-modulus +71 + MOV R10, R2, LSR #2 + AND R10, R10, #7 + ADD R10, R10, #1 ; r10 = clock divider + MUL R8, R10, R8 ; r8 = global divider + DivRem R10, R9, R8, R11 ; r10 = pixel rate in kHz + ] + STR R2, [WsPtr, #VIDCControlCopy] ; and save in copy + + [ MEMC_Type = "IOMD" +; now compute FSIZE properly + LDR R10, [R7, #(&94-&80)*4] ; get vertidisplayend + BIC R10, R10, #&FF000000 + LDR R8, [R7, #(&93-&80)*4] ; get vertidisplaystart + BIC R8, R8, #&FF000000 + SUB R10, R10, R8 ; verti displayed + LDR R8, [R7, #(&90-&80)*4] ; verti total + BIC R8, R8, #&FF000000 + SUB R10, R8, R10 + ADD R10, R10, #1 ; vidc parms are n-2, we want n-1 + MOV R8, #IOMD_Base + STRB R10, [R8, #IOMD_FSIZE] + ] + + LDR R14, [WsPtr, #CursorFudgeFactor] ; R14 = horiz display start (-18) + BIC R14, R14, #&FF000000 + ADD R14, R14, #(18-17) ; horiz cursor start is programmed with n-17 + STR R14, [WsPtr, #CursorFudgeFactor] + | + +; new algorithm for working out DMA request values from MemorySpeed, +; bits/pixel, pixel rate, and VIDC clock rate +; value n to program is >= (25-11v/m)/8 +; therefore n = 3-INT((11v/m-1)/8), forced into range 0..3, +; where m=memory rate (in kHz) +; v=screen memory rate (in kbytes/second (NOT Kbytes/second)) +; = <vc=VIDC clock>*<vs=value out of MemorySpeedTab>/48 +; +; ie n = 3-INT((vc*vs*11/(48*m)-1)/8) + + LDR R9, [R7, #&FC-&80] ; see if the module has told us the real VIDC clock + CMP R9, #-1 + BNE %FT71 + AND R8, R2, #ClockControlMask ; extract VIDC clock bits + ADR R9, VIDCClockSpeeds + LDR R9, [R9, R8, LSR #ClockControlShift-2] ; R9 = vc (in kHz) +71 + STR R9, [WsPtr, #VIDCClockSpeed] ; store away for reading by RVV + AND R8, R2, #15 ; pixel rate in 0,1, bits/pixel in 2,3 + ADR R10, MemorySpeedTab ; now load memory rate relative to 24M + LDRB R8, [R10, R8] ; R8 = vs + MUL R8, R9, R8 ; R8 = vc*vs + ADD R9, R8, R8, LSL #2 ; R9 = vc*vs*5 + ADD R8, R8, R9, LSL #1 ; R8 = vc*vs*11 + MOV R9, #0 + LDR R9, [R9, #MemorySpeed] ; memory speed in kHz in bottom 16 bits + BIC R9, R9, #&FF000000 + BIC R9, R9, #&00FF0000 ; R9 = m + ADD R9, R9, R9, LSL #1 ; R9 = m*3 + MOV R9, R9, LSL #4 ; R9 = m*48 + DivRem R10, R8, R9, R11 ; R10 = vc*vs*11/(48*m) + SUB R10, R10, #1 ; R10 = vc*vs*11/(48*m)-1 + MOVS R10, R10, ASR #3 ; R10 = (vc*vs*11/(48*m)-1)/8 + MOVMI R10, #0 ; if going to be > 3 then make 3 + RSBS R10, R10, #3 ; R10 = 3-(vc*vs*11/(48*m)-1)/8 + MOVMI R10, #0 ; if -ve then make 0 + BIC R2, R2, #(3:SHL:4) :OR: ClockControlMask + ; knock out FIFO + clock bits + ORR R2, R2, R10, LSL #4 ; put result in bits 4,5 + STR R2, [WsPtr, #VIDCControlCopy] ; and save in copy + + LDR R14, [WsPtr, #CursorFudgeFactor] ; R14 = horiz display start + BIC R14, R14, #&FF000000 ; lbpp = 0, 1, 2, 3 + MOV R14, R14, LSR #14 ; R14 = (m-19, m-11, m-7, m-5)/2 + + MOV R8, R2, LSR #2 ; put bits 2,3 (lbpp) into bits 0,1 + AND R8, R8, #3 ; just look at these bits + RSB R8, R8, #3 ; R8 = 3, 2, 1, 0 + MOV R9, #1 + ADD R14, R14, R9, LSL R8 ; R14 = (m-3, m-3, m-3, m-3)/2 + MOV R14, R14, LSL #1 ; R14 = m-3 + SUB R14, R14, #3 ; R14 = m-6 + STR R14, [WsPtr, #CursorFudgeFactor] + ] +75 + + [ {FALSE} ; *** debugging + Push "r0" + MOV r0, r2 + BL TubeDumpR0 + Pull "r0" + TubeString r8, r9, r10, " ",cc ; pad out to 10 chars + ] + + STR R2, [R3] ; stuff it into VidC +80 + SUBS R1, R1, #4 + BNE %BT20 + + ADD R13, R13, #PushedInfoSize ; junk stacked data + + MOV R0, #(1 :SHL: 10) ; enable video DMA + ORR R1, R0, #(1 :SHL: 9) ; refresh only in vflyback + SWI XOS_UpdateMEMC + + MOV R0, #VertiCursorStart + 0 ; program cursor start and end + STR R0, [R3] + MOV R0, #VertiCursorEnd + 0 ; to zero + STR R0, [R3] + + BL SetVendDefault ; set to ScreenEndAdr-16 + + MOV R1, #ScreenEndAdr ; need to reload cos corrupt + LDR R2, [WsPtr, #TotalScreenSize] + SUB R0, R1, R2 ; R0 = Vstart + BL SetVstart + MOV R0, #0 + STRB R0, [WsPtr, #PointerShapeNumber] + STR R0, [WsPtr, #TeletextOffset] + STR R0, [WsPtr, #CursorStack] ; restore cursor on a mode + + BL PalInit ; set default palette + BL UnblankScreen + BL SetMouseRectangle + BL FF + + MOV R1, #Service_ModeChange + BL IssueModeService + + CLRV ; indicate no error + Pull PC ; return to caller + + MakeErrorBlock BadMODE + + LTORG + + [ :LNOT: (VIDC_Type = "VIDC20") +MemorySpeedTab + = 2, 3, 4, 6, 4, 6, 8, 12, 8, 12, 16, 24, 16, 24, 32, 48 + ALIGN + +VIDCClockSpeeds + & 24000 + & 25175 + & 36000 + & 00000 + ] + +; The following symbols, apart from being used in NColourTable, +; are also used in constructing mode selectors for mode numbers in VduModes + +NColour_0 * 1 +NColour_1 * 3 +NColour_2 * 15 +NColour_3 * 63 +NColour_4 * &FFFF +NColour_5 * &FFFFFFFF + + GET s.vdu.VduModes + +; ***************************************************************************** +; +; IssueModeService - Issue service (either ModeChanging or ModeChange) +; +; in: R1 = service code +; +; out: R1 corrupted +; + +IssueModeService ENTRY "r2,r3" + BL ReadMonitorType + LDR r2, [WsPtr, #DisplayModeNo] + IssueService + EXITS + +; ***************************************************************************** +; +; PushModeInfo - Push appropriate mode table and VIDC parms +; onto stack, having generated it by possibly issuing service +; +; in: R10 = mode to try for (issue service if not in range 0..20,22..23) +; R11 = mode to use if service not claimed +; R10 and R11 should have bit 7 CLEAR +; +; out: If r10 is an invalid mode selector or invalid new format sprite word then +; V=1 +; r0 -> error +; stack flat +; else +; V=1 +; Stack holds a mode table (size wkwordsize) and VIDC parms (size 32*4) +; (total size PushedInfoSize) +; endif +; All other registers preserved +; + +PushModeInfoAnyMonitor ROUT + SUB sp, sp, #PushedInfoSize + Push "r2-r4,r7-r11, lr" + MOV r3, #-1 + MOV r7, #-1 ; indicate no VIDC stuff necessary + [ ModeSelectors + CMP r10, #&100 ; is it a mode selector + BCS PushModeInfoCommonNoService + ] + BranchIfKnownMode r10, PushModeInfoCommonNoService + B PushModeInfoCommon + +PushModeInfo ROUT + SUB sp, sp, #PushedInfoSize + Push "r2-r4,r7-r11, lr" + MOV r7, #0 ; indicate VIDC stuff IS necessary + BL ReadMonitorType +PushModeInfoCommon + MOV r2, r10 ; r2 = original mode + BL OfferModeExtension + [ ModeSelectors + BEQ %FT30 ; [service claimed] + + CMP r2, #&100 ; service not claimed - check if mode selector + MOVCC r10, r11 ; unrecognised mode number, so use substitute + BCC PushModeInfoCommonNoService + +; service not claimed and it's a mode selector - return error "Screen mode not available" + + ADR r0, ErrorBlock_ModeNotAvailable + [ International + BL TranslateError + ] + B %FT40 + + MakeErrorBlock ModeNotAvailable + +30 + TEQ r4, #0 ; if r4 returned zero, then a mode selector was used + ; either initially or after translation from mode number + BEQ %FT35 ; so no ws list + LDR r2, [r4, #4]! ; else if claimed, then find ws base mode + CMP r2, #&100 ; if ws base mode is a mode selector, it's invalid + ANDCC r2, r2, #&7F ; else knock off shadow bit + BCC %FT35 + MOV r10, r11 ; invalid ws base mode, so pretend service not responded to + +; and drop thru to PushModeInfoCommonNoService + + | + MOVNE r10, r11 ; not claimed, so use substitute + BNE PushModeInfoCommonNoService + LDR r2, [r4, #4]! ; if claimed, then find ws base mode + AND r2, r2, #&7F ; no funny business + B %FT35 + ] +PushModeInfoCommonNoService + MOV r2, r10 ; else use provided mode + MOV r3, #0 + MOV r4, #0 +35 + ADD r9, sp, #9*4 ; adjust for pushed registers + [ ModeSelectors :LOR: {TRUE} ; mode selectors or sprite mode words + CMP r2, #&100 + BCC %FT45 + BL GenerateModeSelectorVars ; also copes with new sprite mode word + BVC %FT55 + +; we got an error + +40 + SETV + Pull "r2-r4,r7-r11,lr" ; restore registers + ADD sp, sp, #PushedInfoSize ; junk stack frame + MOV pc, lr ; exit VS, r0 -> error + +45 + ] +47 + ADRL r14, Vwstab + LDR r10, [r14, r2, LSL #2] + ADD r14, r14, r10 ; r14 -> mode table + MOV r10, #wkwordsize-4 +50 + LDR r2, [r14, r10] + STR r2, [r9, r10] + SUBS r10, r10, #4 + BCS %BT50 + +; now change any variables specified in workspace block or mode selector overrides + +55 + TEQ r4, #0 ; if service was claimed + ADDNE r4, r4, #4 ; then skip ws base mode + BLNE ProcessModeVarPairs + +; hopefully, R7 is still set from up there to be NZ if no VIDC stuff necessary + + CMP r7, #0 + Pull "r2-r4,r7-r11, pc", NE ; if no VIDC stuff required, exit (NB V=0 from CMP) + +; now set up VIDC table, first from MOS table, then changes from module + +; first clear out all 32 (or 128) VIDC entries with -1 + + ADD R14, R9, #wkwordsize + MOV R10, #VIDCParmsSize + MOV R8, #-1 +60 + STR R8, [R14], #4 + SUBS R10, R10, #4 + BNE %BT60 + +; now copy over MOS's table + + ADD R9, R9, #wkwordsize-VIDCParmsSize + + TEQ R3, #0 ; if no module claimed service + MOVEQ R2, R11 ; then use provided mode + BEQ %FT62 + [ VIDCListType3 + LDR r2, [r3, #0] + TEQ r2, #3 ; if VIDC list type 3 + BEQ ProcessVIDCListType3 ; then don't copy any MOS data into table, just process list + ] + LDR r2, [r3, #4] ; else just load VIDC list base mode, and copy MOS's table for that + +62 + Push R3 + BL ReadMonitorType ; get monitor type in R3 + CMP R3, #NumMonitorTypes ; monitor type must be in range + CMPCC R2, #NumModes ; and mode must be in range + MOVCC R11, #NumModes + MLACC R11, R3, R11, R2 ; then form monitortype*numberofmodes + modenumber + MOVCS R11, #0 ; if illegal then use mode 0 monitortype 0 + ADRL R14, BigVIDCTable ; point to big table + LDR R11, [R14, R11, LSL #2] ; and load offset + CMP R11, #-1 ; if table offset is valid + ADDCC R11, R14, R11 ; then add to table address + BLCC UpdateVIDCTable ; and fetch data + Pull R3 + + [ VIDC_Type = "VIDC20" + TEQ R3, #0 + LDRNE R2, [R3, #0] ; get VIDC table type + TSTNE R2, #2 ; test for VIDC20 compatible table + ADDNE R11, R3, #8 ; if exists + BLNE UpdateVIDCTable ; then modify parameters + + CLRV + Pull "R2-R4,R7-R11, PC" ; ignore any second list for the time being (it's all coded in main list) + | + +; now copy modules changes + + TEQ R3, #0 + ADDNE R11, R3, #8 ; if module list exists, then + BLNE UpdateVIDCTable ; modify the table + + LDRNE R2, [R3, #0] ; get VIDC table type + TSTNE R2, #1 ; bit 0 set if has second list + BNE %FT70 ; has 2nd list +65 + CLRV + Pull "R2-R4,R7-R11, PC" ; if no module table, or no second list + ; then exit +70 + LDR R2, [R11], #4 + CMP R2, #-1 + BEQ %BT65 ; exit VC if found end of list + + MOV R7, R2, LSR #24 ; R7=type of data (0=pixel rate,1=sync, 2=real VIDC clock) + BIC R2, R2, R7, LSL #24 ; knock out data type + +; now the change to allow the real VIDC clock rate to be declared by the module + + CMP R7, #2 + STREQ R2, [R13, #9*4+wkwordsize+&FC-&80] ; store in pseudo-register &FC + BEQ %BT70 + CMP R7, #1 + BHI %BT70 ; if > 1 then unknown, so skip + BEQ %FT90 ; if 1 then sync polarity specification + +; R2 is requested pixel rate in kHz - scan through available pixel rates to +; find match + + MOV R3, #-1 ; least error so far + MOV R4, #(0 :SHL: ClockControlShift) :OR: 3 + ; clock and internal pixel rates merged + ; bits 9 and 10 are clock rate + ; bits 0 and 1 are internal pixel rate + ; 0 => n/3, 1 => n/2, 2 => 2n/3, 3 => n +75 + ADRL R9, VIDCClockSpeeds ; point at table of available rates + LDR R9, [R9, R4, LSR #ClockControlShift-2] ; get clock rate + TST R4, #2 + MOVNE R9, R9, LSL #1 ; if bit 1 set then multiply by 2 + TST R4, #1 + MOVNE R10, R9, LSR #1 ; if bit 0 set then divide by 2 + BNE %FT80 ; and skip + MOV R7, #3 + DivRem R10, R9, R7, R14 ; if bit 0 clear then divide by 3 +80 + SUBS R14, R10, R2 ; difference between desired and actual + MOVEQ R8, R4 + BEQ %FT85 ; found exact match, so use it + RSBMI R14, R14, #0 ; get absolute error + CMP R14, R3 ; if less than least error + MOVCC R3, R14 ; then R3 = new least error + MOVCC R8, R4 ; and R8 = best fit + TST R4, #3 ; if not just tried pixel rate 0 + SUBNE R4, R4, #1 ; then try next pixel rate + BNE %BT75 + ADD R4, R4, #1 :SHL: ClockControlShift ; move to next clock rate + TEQ R4, #4 :SHL: ClockControlShift ; if not finished + ORRNE R4, R4, #3 ; then set internal pixel rate to 3 + BNE %BT75 ; and loop + +; R8 is best fit, so store it in the VIDC list + +85 + ADD R9, R13, #9*4+wkwordsize+&E0-&80 ; point at control register + LDR R10, [R9] ; get previously specified CR + BIC R10, R10, #ClockControlMask ; knock out clock select + BIC R10, R10, #3 ; and pixel rate select + ORR R10, R10, R8 + STR R10, [R9] + B %BT70 ; go back and see if any more + +; R2 = sync polarity specification +; bit 0 set => -ve Hsync +; bit 1 set => -ve Vsync + +90 + ADD R9, R13, #9*4+wkwordsize+&E0-&80 ; point at control register + LDR R10, [R9] ; get previously specified CR + BIC R10, R10, #SyncControlMask ; knock out sync selects + ORR R10, R10, R2, LSL #SyncControlShift ; and insert new ones + STR R10, [R9] + B %BT70 ; go back and see if any more + + ] + +; ***************************************************************************** +; +; GenerateModeSelectorVars - Work out mode variables from mode selector +; or new format sprite mode word +; +; Note: the algorithms used to generate these variables are duplicated in +; s.vdu.vduswis in the OS_ReadModeVariable code. + +; in: r2 = new format sprite word or pointer to mode selector +; r9 -> stack frame to store vars in +; +; out: If valid then +; V=0 +; r0 preserved +; else +; V=1 +; r0 -> error +; endif +; All other registers preserved +; + +GenerateModeSelectorVars ENTRY "r0,r1,r3-r8,r10-r12" + [ ModeSelectors + ASSERT ModeSelector_Flags = 0 + ASSERT ModeSelector_XRes = 4 + ASSERT ModeSelector_YRes = 8 + ASSERT ModeSelector_PixelDepth = 12 + ] + TST r2, #1 ; is it a new format sprite mode word? + BNE %FT50 ; [yes, so skip] + [ ModeSelectors + MOV r0, r2 + BL ValidateModeSelector + BVS %FT95 ; invalid - return error + LDMIB r2, {r4-r6} ; r4 = xres; r5 = yres; r6 = pixdepth + + STR r6, [r9, #wkLog2BPC] ; log2bpc = log2bpp = pixdepth + STR r6, [r9, #wkLog2BPP] + ADR lr, NColourTable + LDR lr, [lr, r6, LSL #2] ; load NColour value + STR lr, [r9, #wkNColour] + ADR lr, PalIndexTable + LDRB lr, [lr, r6] + STR lr, [r9, #wkPalIndex] + ADR lr, ECFIndexTable + LDRB lr, [lr, r6] + STR lr, [r9, #wkECFIndex] + + MOV lr, #0 + STR lr, [r9, #wkYShftFactor] ; yshftfactor = 0 (obsolete) + STR lr, [r9, #wkModeFlags] ; modeflags = 0 + + [ RogerEXEY +; TMD 09-Dec-93 +; New algorithms for xeig, yeig from Roger: +; xeig = 1: yeig = 1 +; if yres<xres/2 OR yres<400 then yeig = 2 +; if (xres<<xeig)<(yres<<yeig) then xeig = 2 + + CMP r5, r4, LSR #1 ; if yres < xres/2 + CMPCS r5, #400 ; or yres < 400 + MOVCC r7, #2 ; then yeig = 2 + MOVCS r7, #1 ; else yeig = 1 + STR r7, [r9, #wkYEigFactor] + + MOV r7, r5, LSL r7 ; r7 = yres << yeig + CMP r7, r4, LSL #1 ; if (xres<<1) < (yres<<yeig) + MOVHI r7, #2 ; then xeig = 2 + MOVLS r7, #1 ; else xeig = 1 + STR r7, [r9, #wkXEigFactor] + + MOV lr, #1 + | + MOV lr, #1 + STR lr, [r9, #wkXEigFactor] ; xeig = 1 + CMP r5, r4, LSR #1 ; if yres < xres/2 + MOVCC r7, #2 ; then yeig = 2 + MOVCS r7, #1 ; else yeig = 1 + STR r7, [r9, #wkYEigFactor] + ] + RSB r7, lr, r4, LSR #3 ; scrrcol = (xres >> 3) -1 + STR r7, [r9, #wkScrRCol] + RSB r7, lr, r5, LSR #3 ; scrbrow = (yres >> 3) -1 + STR r7, [r9, #wkScrBRow] + + SUB r7, r4, #1 + STR r7, [r9, #wkXWindLimit] ; xwindlimit = xres-1 + SUB r7, r5, #1 + STR r7, [r9, #wkYWindLimit] ; ywindlimit = yres-1 + + MOV r7, r4, LSL r6 ; r7 = xres << pixdepth + MOV lr, r7, LSR #3 + STR lr, [r9, #wkLineLength] ; linelen = (xres << pixdepth) >> 3 + + MUL r7, r5, r7 ; r7 = (xres * yres) << pixdepth + MOV lr, r7, LSR #3 + STR lr, [r9, #wkScreenSize] ; screensize = ((xres * yres) << pixdepth) >> 3 + + ADD r4, r2, #ModeSelector_ModeVars ; now do pairs of mode variables + BL ProcessModeVarPairs + + CLRV + EXIT + + | + B %FT90 ; it's not a new format sprite word, and mode selectors not enabled + ; so return error + ] + +; store info for new format sprite word in stack frame + +50 + MOV r0, #0 + STR r0, [r9, #wkYShftFactor] ; yshftfactor = 0 + STR r0, [r9, #wkModeFlags] ; modeflags = 0 + + MOV r0, r2, LSR #27 ; get type + CMP r0, #SpriteType_MAX ; check for legality - NB type 0 is illegal because r2>=&100 + MOVCS r0, #SpriteType_Substitute ; substitute if unknown + ADRL lr, NSM_bpptable-4 + LDR r0, [lr, r0, LSL #2] ; get the bpp from table + + STR r0, [r9, #wkLog2BPC] + STR r0, [r9, #wkLog2BPP] + + ADR r1, NColourTable + LDR r1, [r1, r0, LSL #2] + STR r1, [r9, #wkNColour] + + ADR r1, PalIndexTable + LDRB r1, [r1, r0] + STR r1, [r9, #wkPalIndex] + + ADR r1, ECFIndexTable + LDRB r1, [r1, r0] + STR r1, [r9, #wkECFIndex] + + MOV r1, r2, LSL #(31-13) + MOV r1, r1, LSR #(31-13)+1 ; extract xdpi (bits 1..13) + + TEQ r1, #180 ; 180 => xeig=0 + MOVEQ r1, #0 + BEQ %FT70 + + TEQ r1, #22 ; 22/23 => xeig=3 + TEQNE r1, #23 + MOVEQ r1, #3 + BEQ %FT70 + + TEQ r1, #(45 :SHL: 2), 2 ; check if 45 (EQ,CC if so) + CMPNE r1, #90 ; or 90 (EQ,CS if so) + BNE %FT80 + MOVCC r1, #2 ; 45 => xeig=2 + MOVCS r1, #1 ; 90 => xeig=1 +70 + STR r1, [r9, #wkXEigFactor] + + MOV r1, r2, LSL #(31-26) + MOV r1, r1, LSR #(31-26)+14 ; extract ydpi (bits 14..26) + + TEQ r1, #180 ; 180 => yeig=0 + MOVEQ r1, #0 + BEQ %FT71 + + TEQ r1, #22 ; 22/23 => yeig=3 + TEQNE r1, #23 + MOVEQ r1, #3 + BEQ %FT71 + + TEQ r1, #(45 :SHL: 2), 2 ; check if 45 (EQ,CC if so) + CMPNE r1, #90 ; or 90 (EQ,CS if so) + BNE %FT80 + MOVCC r1, #2 ; 45 => yeig=2 + MOVCS r1, #1 ; 90 => yeig=1 +71 + STR r1, [r9, #wkYEigFactor] + + CLRV + EXIT + +80 + ADR r0, ErrorBlock_Sprite_BadDPI +90 + [ International + BL TranslateError + ] +95 + STR r0, [sp] ; update saved r0 + SETV ; indicate error + EXIT + +NColourTable & NColour_0, NColour_1, NColour_2 + & NColour_3, NColour_4, NColour_5 +PalIndexTable = 0, 1, 2, 3, 6, 7 + ALIGN ; makes ECFIndexTable more accessible +ECFIndexTable = 4, 2, 3, 5, 5, 5 + ALIGN + + MakeErrorBlock BadPixelDepth + MakeErrorBlock Sprite_BadDPI + + [ ModeSelectors +; ***************************************************************************** +; +; ValidateModeSelector - Check a mode selector is valid +; +; in: r0 -> mode selector +; +; out: If OK, then +; V=0 +; All registers preserved +; else +; V=1 +; r0 -> error +; All other registers preserved +; endif +; + +ValidateModeSelector ENTRY + LDR lr, [r0, #ModeSelector_Flags] + AND lr, lr, #ModeSelectorFlags_FormatMask + TEQ lr, #ModeSelectorFlags_ValidFormat + ADRNE r0, ErrorBlock_BadMSFlags + BNE %FT90 + LDR lr, [r0, #ModeSelector_PixelDepth] + CMP lr, #6 + ADRCS r0, ErrorBlock_BadPixelDepth + BCS %FT90 + CLRV + EXIT + +90 + [ International + BL TranslateError + ] + SETV + EXIT + + MakeErrorBlock BadMSFlags + + ] + +; ***************************************************************************** +; +; ProcessModeVarPairs - Modify stacked variable info from +; mode variable (index, value) pairs +; +; Internal routine used to do Service_ModeExtension workspace lists and +; mode selectors +; +; in: r4 -> first pair (may be none) +; r9 -> stack frame +; +; out: All registers preserved + +ProcessModeVarPairs ENTRY "r4, r8, r10" + ADRL r14, RMVTab +10 + LDR r10, [r4], #4 ; get next entry in ws table + CMP r10, #-1 + EXIT EQ ; no more to do + CMP r10, #(SWIRVVTabModeEnd-SWIRVVTab) ; is it a mode variable ? + BCS %BT10 ; no, then ignore + LDRB r10, [r14, r10] ; load index out of RMVTab + MOVS r10, r10, LSR #1 ; shift byte/word flag into carry + LDR r8, [r4], #4 ; load value + STRCCB r8, [r9, r10] ; either store byte + STRCS r8, [r9, r10] ; or store word + B %BT10 + + [ VIDCListType3 + + ^ 4 +VIDCList3_PixelDepth # 4 +VIDCList3_HorizSyncWidth # 4 +VIDCList3_HorizBackPorch # 4 +VIDCList3_HorizLeftBorder # 4 +VIDCList3_HorizDisplaySize # 4 +VIDCList3_HorizRightBorder # 4 +VIDCList3_HorizFrontPorch # 4 +VIDCList3_VertiSyncWidth # 4 +VIDCList3_VertiBackPorch # 4 +VIDCList3_VertiTopBorder # 4 +VIDCList3_VertiDisplaySize # 4 +VIDCList3_VertiBottomBorder # 4 +VIDCList3_VertiFrontPorch # 4 +VIDCList3_PixelRate # 4 +VIDCList3_SyncPol # 4 +VIDCList3_ControlList # 0 + +; Indices in control list + + ^ 1 +ControlList_LCDMode # 1 +ControlList_LCDDualPanelMode # 1 +ControlList_LCDOffset0 # 1 +ControlList_LCDOffset1 # 1 +ControlList_HiResMode # 1 +ControlList_DACControl # 1 +ControlList_RGBPedestals # 1 +ControlList_ExternalRegister # 1 +ControlList_HClockSelect # 1 +ControlList_RClockFrequency # 1 +ControlList_DPMSState # 1 +ControlList_InvalidReason # 0 + +; +; ProcessVIDCListType3 - Convert type3 VIDC list into VIDC20 parameters +; +; in: r3 -> VIDC list (type 3) +; r9 -> VIDC table (where R9!(nn << 2) holds parameter for register nnxxxxxx +; for nn=80 to FF +; stacked r2-r4, r7-r11, lr + +ProcessVIDCListType3 ROUT + LDR r2, [r3, #VIDCList3_HorizSyncWidth] + BIC r2, r2, #1 ; must be even + SUB r2, r2, #8 ; horiz parameters start off at n-8 + ORR r14, r2, #HorizSyncWidth + STR r14, [r9, #HorizSyncWidth :SHR: 22] + + LDR r4, [r3, #VIDCList3_HorizBackPorch] + ADD r2, r2, r4 + BIC r2, r2, #1 + SUB r2, r2, #4 ; HBSR is N-12 + ORR r14, r2, #HorizBorderStart + STR r14, [r9, #HorizBorderStart :SHR: 22] + + LDR r4, [r3, #VIDCList3_HorizLeftBorder] + ADD r2, r2, r4 + BIC r2, r2, #1 + SUB r2, r2, #6 ; HDSR is N-18 + ORR r14, r2, #HorizDisplayStart + STR r14, [r9, #HorizDisplayStart :SHR: 22] + + LDR r4, [r3, #VIDCList3_HorizDisplaySize] + BIC r4, r4, #1 + LDR r7, [r3, #VIDCList3_PixelDepth] + MOV r10, r4, LSL r7 ; number of bits in one displayed raster (not needed later any more) + + ANDS r8, r10, #31 ; if line length not multiple of 32 + MOVNE r8, #DCR_HDis ; then set HDis bit + ORR r8, r8, r10, LSR #5 ; OR in number of words per line + +; Note - the DCR_Bus bits get overridden and the HDWR bits modified further down the line by the mode change code +; on the basis of how much VRAM we've got + + [ MEMC_Type = "IOMD" + ORR r8, r8, #DCR_VRAMOff :OR: DCR_Bus31_0 :OR: DCR_Sync + | + ORR r8, r8, #DCR_VRAMOff :OR: DCR_Bus31_0 + ] + ORR r8, r8, #VIDCDataControl + STR r8, [r9, #VIDCDataControl :SHR: 22] + + ADD r2, r2, r4 ; HDER is also N-18 + ORR r14, r2, #HorizDisplayEnd + STR r14, [r9, #HorizDisplayEnd :SHR: 22] + + LDR r4, [r3, #VIDCList3_HorizRightBorder] + ADD r2, r2, r4 + ADD r2, r2, #6 ; HBER is N-12 + BIC r2, r2, #1 + ORR r14, r2, #HorizBorderEnd + STR r14, [r9, #HorizBorderEnd :SHR: 22] + + LDR r4, [r3, #VIDCList3_HorizFrontPorch] + ADD r2, r2, r4 + ADD r2, r2, #4 ; HCR is N-8 + BIC r2, r2, #3 ; must be mult of 4 + ORR r14, r2, #HorizCycle + STR r14, [r9, #HorizCycle :SHR: 22] + + ADD r2, r2, #8 ; HIR is N/2 + MOV r2, r2, LSR #1 + ORR r14, r2, #HorizInterlace + STR r14, [r9, #HorizInterlace :SHR: 22] + + LDR r2, [r3, #VIDCList3_VertiSyncWidth] + SUB r2, r2, #2 ; vertical registers are N-2 + ORR r14, r2, #VertiSyncWidth + STR r14, [r9, #VertiSyncWidth :SHR: 22] + + LDR r4, [r3, #VIDCList3_VertiBackPorch] + ADD r2, r2, r4 + ORR r14, r2, #VertiBorderStart + STR r14, [r9, #VertiBorderStart :SHR: 22] + + LDR r4, [r3, #VIDCList3_VertiTopBorder] + ADD r2, r2, r4 + ORR r14, r2, #VertiDisplayStart + STR r14, [r9, #VertiDisplayStart :SHR: 22] + + LDR r4, [r3, #VIDCList3_VertiDisplaySize] + ADD r2, r2, r4 + ORR r14, r2, #VertiDisplayEnd + STR r14, [r9, #VertiDisplayEnd :SHR: 22] + + LDR r4, [r3, #VIDCList3_VertiBottomBorder] + ADD r2, r2, r4 + ORR r14, r2, #VertiBorderEnd + STR r14, [r9, #VertiBorderEnd :SHR: 22] + + LDR r4, [r3, #VIDCList3_VertiFrontPorch] + ADD r2, r2, r4 + ORR r14, r2, #VertiCycle + STR r14, [r9, #VertiCycle :SHR: 22] + + LDR r4, [r3, #VIDCList3_SyncPol] + MOV r14, #VIDCExternal + TST r4, #1 + ORRNE r14, r14, #Ext_InvertHSYNC + TST r4, #2 + ORRNE r14, r14, #Ext_InvertVSYNC + ORR r14, r14, #Ext_DACsOn + ORR r14, r14, #Ext_ERegExt + STR r14, [r9, #VIDCExternal :SHR: 22] + + Push "r0, r1" + LDR r0, [r3, #VIDCList3_PixelRate] ; get pixel rate + MOV r10, r0, LSL r7 ; peak mem b/w (x 1E3 bits/sec) - save for FIFO calculation + + [ MorrisSupport + ; MOV R14, #IOMD_Base + ; LDRB R1, [R14, #IOMD_ID0] + ; CMP R1, #&98 + ; LDRB R1, [R14, #IOMD_ID1] + ; CMPEQ R1, #&5B + ; MOVEQ R1, #32000 ;Morris clocks VIDC20L at 32Mhz + ; LDRNE R1, =24000 ;RISC PC clocks VIDC20 at 24MHz + MOV R1, #0 + LDRB R1, [R1, #IOSystemType] + TST R1, #IOST_7500 + LDREQ R1, =24000 ;RISC PC clocks VIDC20 at 24MHz + MOVNE R1, #32000 ;Morris clocks VIDC20L at 32Mhz +;>>>RCM says can we replace the above by +;>>> LDR R1, [WsPtr, #VIDCClockSpeed] + | + LDR r1, =rclk ; eventually will need to replace this if specified in control list + ] + BL ComputeModuli ; out: r0 = FSync bits, r1 = CR bits + ORR r0, r0, #VIDCFSyn + STR r0, [r9, #VIDCFSyn :SHR: 22] + + TEQ r7, #5 ; if 32 bpp, then stick in 6 not 5 + MOVEQ r7, #6 + ORR r0, r1, r7, LSL #5 + +; now work out FIFO load position - r10 is b/w in thousands of bytes/sec + + [ {TRUE} + +; do it by means of a binary chop on 3 bits + + ADR r4, FIFOLoadTable + LDR r2, [r4, #4*4] ; load 0-3/4-7 split + CMP r10, r2 + MOVLS r7, #0 ; if <=, then bottom half + MOVHI r7, #4 ; else top half + ADDHI r4, r4, #4*4 ; and advance table pointer + + LDR r2, [r4, #2*4] + CMP r10, r2 + ORRHI r7, r7, #2 + ADDHI r4, r4, #2*4 + + LDR r2, [r4, #1*4] + CMP r10, r2 + ORRHI r7, r7, #1 + | + CMP r10, #&10000 :SHL: 3 ; this value (65.536 Mbytes/sec) lies above the point at which 7 works + ; and below the point at which 7 is needed + MOVCC r7, #6 + MOVCS r7, #7 + ] + + ORR r0, r0, r7, LSL #CR_FIFOLoadShift + ORR r0, r0, #VIDCControl + STR r0, [r9, #VIDCControl :SHR: 22] + +; Now go through VIDC control parameters list (not all indices can be handled yet) + + ADD r3, r3, #VIDCList3_ControlList-8 ; point at 1st entry -8 +50 + LDR r4, [r3, #8]! ; load next index + CMP r4, #-1 ; if -1 then end of list + BEQ %FT60 ; so skip + + CMP r4, #0 ; if non-zero (CS if zero) + CMPNE r4, #ControlList_InvalidReason ; and if known reason + LDRCC r2, [r3, #4] ; then load value + BLCC ProcessControlListItem ; and process this item + B %BT50 ; go onto next item in list + + [ {TRUE} +FIFOLoadTable + [ {TRUE} ; put a minimum of 4, cos 800 x 600 x 1bpp don't work otherwise + & 0 ; dummy entry (not used) + & 0 ; never use 0 + & 0 ; use 1 up to (and including) here + & 0 ; use 2 up to (and including) here + & 0 ; use 3 up to (and including) here + & 60000 :SHL: 3 ; use 4 up to (and including) here + & 75000 :SHL: 3 ; use 5 up to (and including) here + & 90000 :SHL: 3 ; use 6 up to (and including) here + ; else use 7 + | + & 0 ; dummy entry (not used) + & 0 ; never use 0 + & 12000 :SHL: 3 ; use 1 up to (and including) here + & 24000 :SHL: 3 ; use 2 up to (and including) here + & 36000 :SHL: 3 ; use 3 up to (and including) here + & 60000 :SHL: 3 ; use 4 up to (and including) here + & 75000 :SHL: 3 ; use 5 up to (and including) here + & 90000 :SHL: 3 ; use 6 up to (and including) here + ; else use 7 + ] + ] + + +60 + +; Now, for debugging purposes, output data to a file + + [ {FALSE} + + ! 0, "**** WARNING: Mode change debugging assembled in ****" + + MOV r0, #&80 + ADR r1, ModeFilename + SWI XOS_Find + + Pull "r0, r1, r2-r4, r7-r11, pc", VS + + MOV r1, r0 + MOV r0, #2 + ADD r2, r9, #VIDCParmsSize ; r2 -> data + MOV r3, #VIDCParmsSize + SWI XOS_GBPB + + MOV r0, #0 + SWI XOS_Find + + Pull "r0, r1, r2-r4, r7-r11, pc" + +ModeFilename + = "SCSI::HD4.$.ModeData", 0 + ALIGN + | + Pull "r0, r1, r2-r4, r7-r11, pc" + ] + +; ***************************************************************************** +; +; ProcessControlListItem +; +; in: r2 = value for item +; r4 = index for item (guaranteed in range) +; r9 -> VIDC register array +; +; out: r0-r2, r4, r7, r8, r10, r11 may be corrupted +; r3, r9, r12 must be preserved + +ProcessControlListItem ENTRY + LDR pc, [pc, r4, LSL #2] + NOP + & ProcessControlListNOP ; 0 - NOP + & ProcessControlListLCDMode ; 1 - LCD mode + & ProcessControlListLCDDualPanelMode ; 2 - LCD dual-panel mode + & ProcessControlListLCDOffsetRegister0 ; 3 - LCD offset register 0 + & ProcessControlListLCDOffsetRegister1 ; 4 - LCD offset register 1 + & ProcessControlListHiResMode ; 5 - Hi-res mode + & ProcessControlListDACControl ; 6 - DAC control + & ProcessControlListRGBPedestals ; 7 - RGB pedestal enables + & ProcessControlListExternalRegister ; 8 - External register + & ProcessControlListNOP ; 9 - HClk select/specify + & ProcessControlListNOP ; 10 - RClk frequency + & ProcessControlListDPMSState ; 11 - DPMS state + +ProcessControlListLCDMode + MOV r1, #Ext_LCDGrey +05 + MOV r0, #VIDCExternal +10 + MOV r7, r1 + TEQ r2, #0 ; if value non-zero + MOVNE r2, r1 ; then use value in r1 +15 + AND r2, r2, r7 ; ensure only relevant bits set + LDR lr, [r9, r0, LSR #22] ; load word from register bank + BIC lr, lr, r7 ; knock out bits in mask + ORR lr, lr, r2 ; OR in new bits + STR lr, [r9, r0, LSR #22] ; and store in array +ProcessControlListNOP + EXIT + +ProcessControlListHiResMode + MOV r1, #Ext_HiResMono ; bit of a misnomer, it's not nec. mono + B %BT05 + +ProcessControlListDACControl + MOV r1, #Ext_DACsOn + B %BT05 + +ProcessControlListRGBPedestals + MOV r0, #VIDCExternal + MOV r2, r2, LSL #Ext_PedsShift + MOV r7, #Ext_PedsOn + B %BT15 + +ProcessControlListExternalRegister + MOV r0, #VIDCExternal + MOV r7, #&FF + B %BT15 + +ProcessControlListLCDDualPanelMode + MOV r0, #VIDCControl + MOV r1, #CR_DualPanel + B %BT10 + +ProcessControlListLCDOffsetRegister0 + MOV r0, #LCDOffsetRegister0 +20 + ORR r2, r2, r0 ; put high bits of register at top + STR r2, [r9, r0, LSR #22] ; and store in array + EXIT + +ProcessControlListLCDOffsetRegister1 + MOV r1, #LCDOffsetRegister1 + B %BT20 + +ProcessControlListDPMSState + MOV r0, #PseudoRegister_DPMSState ; pseudo-register holding DPMS state + ORR r2, r2, r0 ; form combined value + STR r2, [r9, r0, LSR #22] ; store in register + EXIT + + +; ***************************************************************************** +; +; ComputeModuli - Work out VCO moduli for a given frequency +; +; in: r0 = desired frequency (kHz) +; r1 = rclk frequency (kHz) (normally 24000) +; +; out: r0 = bits to put in bits 0..15 of Frequency Synthesizer Register +; r1 = bits to put in bits 0..4 of Control Register + +rclk * 24000 ; Reference clock into VIDC20 (in kHz) +VCO_Min * 55000 ; minimum VCO frequency (in kHz) +VCO_Max * 110000 ; maximum VCO frequency (in kHz) + +fpshf * 11 ; Shift value for fixed point arithmetic + + ^ 0, sp + +BestDInOrOutOfRange # 4 +BestRInOrOutOfRange # 4 +BestVInOrOutOfRange # 4 +BestDInRange # 4 +BestRInRange # 4 +BestVInRange # 4 +BestRangeError # 4 +ComputeModuliStack * :INDEX: @ + +ComputeModuli ENTRY "r2-r12", ComputeModuliStack + MOV r12, #-1 ; smallest error for values in or out of VCO range + MOV r11, #-1 ; smallest error for values in VCO range + STR r11, BestDInRange + STR r11, BestVInRange + STR r11, BestRInRange + STR r11, BestDInOrOutOfRange + STR r11, BestVInOrOutOfRange + STR r11, BestRInOrOutOfRange + STR r11, BestRangeError + MOV r5, r1 ; r5 = rclk frequency, normally 24000 (32000 on Morris) + LDR r1, =VCO_Min ; r1 = minimum VCO frequency (in kHz) + LDR r2, =VCO_Max ; r2 = maximum VCO frequency (in kHz) + MOV r3, #1 ; r3 = D +10 + MOV r4, #1 ; r4 = R +15 + MUL r6, r0, r3 ; r6 = xD + MUL r7, r6, r4 ; r7 = xRD + ADD r7, r7, r5, LSR #1 ; r7 = xRD + vref/2 + DivRem r8, r7, r5, r9 ; r8 = (xRD + vref/2) DIV vref = V value + + TEQ r4, #1 ; if R=1 then V must be 1, else it's no good + BNE %FT20 + TEQ r8, #1 + BNE %FT50 + BEQ %FT25 +20 + CMP r8, #2 ; if R<>1 then V must be in range 2..64 + RSBCSS r7, r8, #64 + BCC %FT50 ; V out of range, so skip +25 + MUL r7, r5, r8 ; r7 = V * vref + MOV r7, r7, LSL #fpshf ; r7 = (V * vref) << fixedpointshift + DivRem r9, r7, r4, r14 ; r9 = ((V * vref) << fixedpointshift)/R = VCO frequency << fixedpointshift + MOV r6, r9 + DivRem r7, r9, r3, r14 ; r7 = output frequency << fixedpointshift + SUBS r7, r7, r0, LSL #fpshf + RSBCC r7, r7, #0 ; r7 = absolute error << fixedpointshift + + TEQ r4, #1 ; if R=1 then no need to check VCO range + BEQ %FT27 ; because VCO won't be used, so it's a 1st class citizen + + CMP r6, r1, LSL #fpshf ; test if VCO freq >= min + RSBCSS r14, r6, r2, LSL #fpshf ; and <= max + BCC %FT40 ; not in range, so not a first class citizen +27 + CMP r7, r11 + BHI %FT40 ; worse than the best case for in VCO range, so ignore + BCC %FT30 ; is definitely better than the best case for in or out + + LDR r14, BestRInRange ; is equal best for in, so check R value + CMP r4, r14 ; is newR < bestR + BCS %FT40 ; is greater or equal R value (ie not higher comp. freq., so not best) +30 + MOV r11, r7 + STR r3, BestDInRange + STR r4, BestRInRange + STR r8, BestVInRange + MOV r14, #0 + B %FT45 + +40 + RSBS r14, r6, r1, LSL #fpshf ; r14 = min-this, if this<min + SUBCC r14, r6, r2, LSL #fpshf ; else r14 = this-max, ie r14 = how much this is outside range + + CMP r7, r12 + BHI %FT50 ; worse than the best case for in or out of VCO range, so ignore + BCC %FT45 ; is definitely better than the best case for in or out + + LDR r9, BestRangeError ; is equal best for in or out, so check error + CMP r14, r9 + BCS %FT50 ; not lower error, so skip +45 + MOV r12, r7 + STR r3, BestDInOrOutOfRange + STR r4, BestRInOrOutOfRange + STR r8, BestVInOrOutOfRange + STR r14, BestRangeError +50 + ADD r4, r4, #1 + CMP r4, #16 ; R goes from 2 to 16 (was 2 to 64) + BLS %BT15 + + ADD r3, r3, #1 + CMP r3, #8 ; D goes from 1 to 8 + BLS %BT10 + + ADR r2, BestDInRange + LDR r3, [r2] + CMP r3, #-1 + ADDEQ r2, r2, #BestDInOrOutOfRange - BestDInRange + LDREQ r3, [r2] ; r3 = Best D + LDR r4, [r2, #BestRInRange - BestDInRange] ; r4 = Best R + LDR r5, [r2, #BestVInRange - BestDInRange] ; r5 = Best V + + SUBS r4, r4, #1 ; values in FSyn are n-1 + MOVEQ r4, #63 ; if R=V=1 then use max R + MOVEQ r5, #2 ; and min V to make VCO go really slow + + SUB r5, r5, #1 ; for both v and r + ASSERT FSyn_RShift = 0 + ORR r0, r4, r5, LSL #FSyn_VShift + + SUB r3, r3, #1 ; D is also stored as n-1 + MOV r1, r3, LSL #CR_PixelDivShift + ASSERT CR_VCLK = 0 + ORREQ r1, r1, #CR_RCLK ; if using VCO then set for VCLK, else RCLK + + EXIT + + ] + +; ***************************************************************************** +; +; UpdateVIDCTable - Add changes to a pushed VIDC table +; +; in: R9 + nn -> entry on stack for register nn000000 +; or R9 + (nn << 2) -> ditto, for VIDC20 +; R11 -> change table, terminated with -1 +; +; out: R11 -> word after -1 terminator +; All other registers preserved (including PSR) +; + [ MorrisSupport +UpdateVIDCTable ROUT + Push "R0,R14" + MOV R0, #0 + LDRB R0, [R0, #IOSystemType] + TST R0, #IOST_7500 + MOVEQ R0, #1 ;if rclk is 24MHz, stop at first -1 + MOVNE R0, #2 ;if rclk is 32MHz, overwrite clock dividers with different data +10 + LDR R14, [R11], #4 + CMP R14, #-1 + LDREQ R14, [R11], #4 ;EQ, on terminator, so skip it + SUBEQS R0, R0, #1 + Pull "R0,PC",EQ,^ ;EQ, quit on first (iff rclk=24MHz) or second terminator (iff rclk=32MHz) + + CMP R14, #&80000000 ; must be in range &80..&FF + STRCS R14, [R9, R14, LSR #22] ; NB bits 23 and 22 are assumed to be zero + B %BT10 + | +UpdateVIDCTable ROUT + Push "R14" +10 + LDR R14, [R11], #4 + CMP R14, #-1 + Pull "PC",EQ,^ + CMP R14, #&80000000 ; must be in range &80..&FF + [ VIDC_Type = "VIDC20" + STRCS R14, [R9, R14, LSR #22] ; NB bits 23 and 22 are assumed to be zero + | + STRCS R14, [R9, R14, LSR #24] + ] + B %BT10 + ] + +; ***************************************************************************** +; +; OfferModeExtension - Issue mode extension service +; +; in: R2 = mode specifier +; +; out: EQ => service claimed, R3 -> VIDC list, R4 -> workspace list +; NE => service not claimed, R3,R4 preserved +; All other registers preserved +; + +OfferModeExtensionAnyMonitor ROUT + MOV r3, #-1 +OfferModeExtension ROUT + [ ModeSelectors + Push "r1,r2,r4,r5,r14" + +; TMD 10-Jan-94 - added code here to check for erroneous passing in of a sprite mode word. +; This prevents data aborts when modules try to index off a bad address. +; +; We could have done OS_ValidateAddress, but that would be rather slow, and mode selectors +; are of indeterminate length. +; +; If we detect one of these, we pretend the service wasn't claimed. Hopefully this should +; ensure that the mode change returns an error. + +; Fixes bug MED-00483. + + BICS r14, r2, #&FF ; NE if not a mode number + TSTNE r2, #3 ; NE if not a mode number, but invalid mode selector + Pull "r1,r2,r4,r5,pc", NE ; so exit NE, pretending that service not claimed + + GetBandwidthAndSize r4, r5 + MOV r1, #Service_ModeExtension + IssueService + TEQ r1, #0 ; if service claimed + CMPNE r3, #-1 ; or if "don't care" monitortype + BEQ %FT90 ; then we can't do any more + + CMP r2, #&100 ; if it's a mode selector + BCS %FT90 ; then we can't help them either + BranchIfNotKnownMode r2, %FA90 ; if we don't recognise screen mode number we can't either + +; it is a known numbered mode, so create a mode selector on the stack that we can pass to service + + Push "r6,r7" + SUB sp, sp, #ModeSelector_ModeVars+4 ; make room for block including terminator + MOV r6, #ModeSelectorFlags_ValidFormat + STR r6, [sp, #ModeSelector_Flags] + ADRL r6, FrameRateTable + LDRB r6, [r6, r2] + STR r6, [sp, #ModeSelector_FrameRate] + + ADRL r6, Vwstab + LDR r14, [r6, r2, LSL #2] + ADD r6, r6, r14 + LDR r14, [r6, #wkLog2BPP] + STR r14, [sp, #ModeSelector_PixelDepth] ; pixdepth = log2bpp + + LDR r7, [r6, #wkLog2BPC] + SUB r14, r7, r14 ; r14 = log2bpc-log2bpp + + LDR r7, [r6, #wkXWindLimit] + ADD r7, r7, #1 + MOV r7, r7, LSL r14 + STR r7, [sp, #ModeSelector_XRes] + + LDR r7, [r6, #wkYWindLimit] + ADD r7, r7, #1 + STR r7, [sp, #ModeSelector_YRes] + + MOV r7, #-1 + STR r7, [sp, #ModeSelector_ModeVars] + + MOV r2, sp + IssueService + TEQ r1, #0 + BEQ %FT10 ; service was claimed + +; not claimed, so try again with -1 as frame rate + + MOV r7, #-1 + STR r7, [sp, #ModeSelector_FrameRate] + IssueService + TEQ r1, #0 +10 + ADD sp, sp, #ModeSelector_ModeVars+4 ; junk mode selector + Pull "r6, r7" +90 + CMP r2, #&100 ; if we started or ended up with a mode selector + MOVCS r4, #0 ; then return r4 = 0 (if claimed) + + TEQ r1, #0 + STREQ r4, [sp, #2*4] ; if service claimed, then return r4 from service, else preserve it + Pull "r1,r2,r4,r5,pc" + | + Push "r1, lr" + MOV r1, #Service_ModeExtension + IssueService + TEQ r1, #0 + Pull "r1, pc" + ] + +; ***************************************************************************** +; +; ETB - Redefine character +; === & other stuff +; +; VDU 23,0,r,v,0| Talk to 6845 ! +; VDU 23,1,n,m,r,g,b| Program cursor +; VDU 23,2,n1..n8 Ecf pattern 1 +; VDU 23,3,n1..n8 Ecf pattern 2 +; VDU 23,4,n1..n8 Ecf pattern 3 +; VDU 23,5,n1..n8 Ecf pattern 4 +; VDU 23,6,n1..n8 Dot dash line style +; VDU 23,7,m,d,z| Scroll window directly +; VDU 23,8,t1,t2,x1,y1,x2,y2| Clear block +; VDU 23,9,n| Set 1st flash time +; VDU 23,10,n| Set 2nd flash time +; VDU 23,11| Default Ecf patterns +; VDU 23,12,n1..n8 Ecf pattern 1 (simple setting) +; VDU 23,13,n1..n8 Ecf pattern 2 (simple setting) +; VDU 23,14,n1..n8 Ecf pattern 3 (simple setting) +; VDU 23,15,n1..n8 Ecf pattern 4 (simple setting) +; VDU 23,16,x,y| Cursor movement control +; VDU 23,17,c,t| Set colour tints, ECF info, char sizes +; +; +ETB + LDRB R0, [WsPtr, #QQ+0] + CMP R0, #32 ; defining a normal character ? + BCS DefineChar + LDR R2, [PC, R0, LSL #2] + ADD PC, PC, R2 ; enters routine with R0 => byte after 23 + + +ETBtab + & Vdu23_0-ETBtab-4 + & Vdu23_1-ETBtab-4 + & ComplexEcfPattern-ETBtab-4 + & ComplexEcfPattern-ETBtab-4 + & ComplexEcfPattern-ETBtab-4 + & ComplexEcfPattern-ETBtab-4 + & LineStyle-ETBtab-4 + & Vdu23_7-ETBtab-4 + & Vdu23_8-ETBtab-4 + & Vdu23_9-ETBtab-4 + & Vdu23_10-ETBtab-4 + & DefaultEcfPattern-ETBtab-4 + & SimpleEcfPattern-ETBtab-4 + & SimpleEcfPattern-ETBtab-4 + & SimpleEcfPattern-ETBtab-4 + & SimpleEcfPattern-ETBtab-4 + & Vdu23_16-ETBtab-4 + & Vdu23_17-ETBtab-4 + & Vdu23_18-ETBtab-4 + & Vdu23_19-ETBtab-4 + & Vdu23_20-ETBtab-4 + & Vdu23_21-ETBtab-4 + & Vdu23_22-ETBtab-4 + & Vdu23_23-ETBtab-4 + & Vdu23_24-ETBtab-4 + & Vdu23_25-ETBtab-4 + & Vdu23_26-ETBtab-4 + & Vdu23_27-ETBtab-4 + & Vdu23_28-ETBtab-4 + & Vdu23_29-ETBtab-4 + & Vdu23_30-ETBtab-4 + & Vdu23_31-ETBtab-4 + +; NB All other labels for Vdu23 are in TMD files so I don't have to pester RCM + +Vdu23_18 +Vdu23_19 +Vdu23_20 +Vdu23_21 +Vdu23_22 +Vdu23_23 +Vdu23_24 +Vdu23_25 +Vdu23_26 +; Vdu23_27 ; Assigned to Richard (well some of it, anyway) +Vdu23_28 +Vdu23_29 +Vdu23_30 +Vdu23_31 +UnknownVdu23 + +; R0 already contains first parameter to VDU23 + + MOV R10, #UKVDU23V + Push "WsPtr, R14" ; calling a vector corrupts R12 + BL VduQQVec ; so we have to preserve it + Pull "WsPtr, PC", VC ; before we return to PostWrchCursor + +; error in UKVDU23 vector, so go to vdu error exit + + Pull "WsPtr, R14" + B VduBadExit + +; ***************************************************************************** +; +; DLE +; CLG - Clear graphics window +; === +; +; On exit, R0..R11 corrupt +; +DLE +CLG ROUT + GraphicsMode R0 + MOVNE PC,LR ; check for graphics mode (changed by DDV 15/9/92) + + ADD R0, WsPtr, #BgEcfOraEor ; point at background colour + STR R0, [WsPtr, #GColAdr] + ADD R11, WsPtr, #GWLCol ; load window coordinates into + LDMIA R11, {R0-R3} ; RectFill's parameter space + + LDR R6, [WsPtr, #CursorFlags] ; if clip box is not enabled + TST R6, #ClipBoxEnableBit ; then goto code directly + BEQ RectFillA + + Push R14 ; else merge graphics window (in R0-R3) + BL MergeClipBox ; with clip box + Pull R14 + B RectFillA + +; ***************************************************************************** +; +; DC2 +; GCol - Set Graphics action and colour +; ==== +; +; On entry, R0 holds GCol action +; R1 holds GCol colour, 0..127 means program fg +; 128..255 means program bg +; +; In 256-colour modes, the extra colours are accessed via TINT +; +DC2 +GCol ROUT + LDRB R0, [WsPtr, #QQ+0] ; GCol action, eg store, eor etc. + LDRB R1, [WsPtr, #QQ+1] ; GCol colour + LDR R2, [WsPtr, #NColour] ; number of colours-1 + TST R1, #&80 + AND R1, R1, R2 ; limit colour to range available + + STREQ R0, [WsPtr, #GPLFMD] ; GCOL(a,0..127) is foreground + STREQ R1, [WsPtr, #GFCOL] + + STRNE R0, [WsPtr, #GPLBMD] ; GCOL(a,128..255) is background + STRNE R1, [WsPtr, #GBCOL] + ; drop into SetColour to.... + +; SetColour - Setup FgEcf & BgEcf, used after GCOL or setting of Ecfs +; ========= or default palette (does a gcol). + +SetColour + Push R14 + LDR R1, [WsPtr, #GPLFMD] ; setup FgEcf, maybe solid or Ecf + LDR R0, [WsPtr, #GFCOL] + ADD R2, WsPtr, #FgEcf + LDR R3, [WsPtr, #GFTint] ; tint only used in 256 colour modes + ADD R4, WsPtr, #FgPattern ; used if OS_SetColour call + BL SetCol10 + + LDR R1, [WsPtr, #GPLBMD] ; and BgEcf + LDR R0, [WsPtr, #GBCOL] + ADD R2, WsPtr, #BgEcf + LDR R3, [WsPtr, #GBTint] + ADD R4, WsPtr, #BgPattern ; used if OS_SetColour call + BL SetCol10 + + ADD R0, WsPtr, #FgEcf ; setup FgEcfOraEor + ADD R1, WsPtr, #BgEcf + ADD R2, WsPtr, #FgEcfOraEor + LDR R3, [WsPtr, #GPLFMD] + BL SetCol60 + + ADD R0, WsPtr, #BgEcf ; and BgEcfOraEor + ADD R1, WsPtr, #FgEcf + ADD R2, WsPtr, #BgEcfOraEor + LDR R3, [WsPtr, #GPLBMD] + BL SetCol60 + + ADD R0, WsPtr, #BgEcf ; and BgEcfStore + ADD R1, WsPtr, #FgEcf + ADD R2, WsPtr, #BgEcfStore + MOV R3, #0 + BL SetCol60 + + Pull PC + +; SetCol10 - Internal to SetColour +; Build up an Ecf, given action and colour numbers +; +; On entry, R0 holds colour (0..255, where 127..255 means 0..127) +; R1 holds action (may indicate ecf) +; R2 holds address to write data (FgEcf or BgEcf) +; R3 holds tint information (only used in 256 colour modes) +; R4 holds pointer to suitable pattern table for OS_SetColour call + +SetCol10 ROUT + ANDS R1, R1, #&F0 ; actions >=16 mean Ecf + BNE SetCol30 + + Push R14 + LDR R4, [WsPtr, #NColour] ; else use given colour number + AND R0, R0, R4 + AND R0, R0, #63 ; another bodge in the house of bodges + TST R4, #&F0 ; if 256 colour (ie 8bpp) + BLNE AddTintToColour ; then combine tint with colour + +; R0 contains colour number for current mode + + LDR LR, [WsPtr, #BitsPerPix] +10 + TEQ LR, #32 + ORRNE R0, R0, R0, LSL LR ; replicate again + MOVNE LR, LR, LSL #1 ; doubling the shift for each pass + BNE %BT10 + + STR R0, [R2] + STR R0, [R2, #4] + STR R0, [R2, #8] + STR R0, [R2, #12] + STR R0, [R2, #16] + STR R0, [R2, #20] + STR R0, [R2, #24] + STR R0, [R2, #28] + + Pull "PC" + +; R1 = ecf number as 16,32,48,64,80,96 +; R2 -> destination +; R4 -> pattern block (if R1 =96!) + +SetCol30 + CMP R1, #96 ; special internal plot? + MOVCS R0, R4 ; yes, so point at pattern to be copied + MOVCS R3, #1 ; col step =1 + MOVCS R4, #0 ; row step =0 (already there!) + BCS SetCol35 + + CMP R1, #80 ; 80 => giant ecf (>80 does same) + ADDCS R0, WsPtr, #Ecf1 ; then point at ecf0 + MOVCS R3, #8 ; col step=8 + MOVCS R4, #(1-8*4) ; row step, back to 1st ecf on 1 byte + BCS SetCol35 + + ADD R0, WsPtr, #(Ecf1-8) + ADD R0, R0, R1, LSR #1 ; else point R0 at Ecf1,2,3 or 4 + + LDR R4, [WsPtr, #BitsPerPix] ; if BitsPerPix <> 'fudged' BitsPerPix + LDR R5, [WsPtr, #BytesPerChar] + TEQ R4, R5 + BNE SetCol52 ; then double up the pixels + ; else its a normal Ecf + MOV R3, #0 ; col step=0, same byte each coloum + MOV R4, #1 ; row step=1 +SetCol35 + MOV R5, #8 ; do 8 rows +SetCol40 + MOV R6, #4 ; of 4 columns +SetCol50 + LDRB R7, [R0], R3 ; read from source & move by col step + STRB R7, [R2], #1 ; write to dest, update dest pointer + SUBS R6, R6, #1 + BNE SetCol50 + ADD R0, R0, R4 ; step source pointer to next row + SUBS R5, R5, #1 + BNE SetCol40 + MOV PC, R14 + +; Double up the pixels for Mode2 etc +; +; R0 points to Ecf(n) +; R2 points to destination +; +; Uses +; +; R3 - NColour used as PixMsk +; R4 - BitsPerPix +; R5 - BytesPerChar (unused) +; R6 - byte cntr 7..0 +; R7 - source byte +; R8 - ExtrtShftFact +; R9 - InsrtShftFact +; R10 - result word +; R11 - temp + +SetCol52 + LDR R3, [WsPtr, #NColour] ; mask for extracting pixels from ecf + TST R3, #&F0 ; ** if 256 colour mode + MOVNE R3, #&FF ; ** then use &FF (TMD 25-Mar-87) + LDR R4, [WsPtr, #BitsPerPix] + MOV R6, #7 ; 8 bytes/rows to do +SetCol54 + LDRB R7, [R0, R6] ; get byte of Ecf(n) + RSB R8, R4, #8 + RSB R9, R4, #32 + MOV R10, #0 ; clear result word +SetCol57 + AND R11, R3, R7, ROR R8 ; extract 1 pixel from Ecf + ORR R10, R10, R11, LSL R9 ; double it into result word + SUB R9, R9, R4 + ORR R10, R10, R11, LSL R9 + + SUB R8, R8, R4 + AND R8, R8, #7 + + SUBS R9, R9, R4 + BGE SetCol57 ; process next pixel in result word + + STR R10, [R2, R6, LSL #2] ; write expanded word to (Fg/Bg)Ecf + + SUBS R6, R6, #1 + BGE SetCol54 ; process next row/byte + MOV PC, R14 + +; Tables of full colours for 2,4 & 16 colour modes (256 colour modes +; use colour number directly). +; +; N.B. these are tables of bytes + +TBFullCol + = &FF ; not used - remove sometime + ; (DJS comment: don't bother!) + = &00, &FF ; 2 colour mode + = &00, &55, &AA, &FF ; 4 colour mode + + = &FF, &FF, &FF, &FF ; not used but cannot be removed + = &FF, &FF, &FF, &FF ; (8 colour mode!) + + = &00, &11, &22, &33 ; 16 colour mode + = &44, &55, &66, &77 + = &88, &99, &AA, &BB + = &CC, &DD, &EE, &FF + + ALIGN + +; ***************************************************************************** +; +; SetCol60 - Build up an ecf, ORed and EORed appropriate to GCOL action +; +; Internal to SetColour +; +; in: R0 -> ecf colour (FgEcf/BgEcf) +; R1 -> transparent colour (BgEcf/FgEcf) +; R2 -> destination FgEcfOraEor/BgEcfOraEor/BgEcfStore +; R3 = gcol action number (may indicate ecf) +; +; uses: R4 = index into ecf (7..0) +; R5 = ecf colour word +; R6 = transparency mask, set to &FFFFFFFF for NO transparency +; R7 -> zgoo..zgee for gcol action +; R8 = mask for pixel under examination +; R9 = shift factor to move mask to next pixel (BytesPerChar) +; R10, R11 temporary +; + +SetCol60 ROUT + MOV R4, #7 ; 7..0 words to process + AND R3, R3, #&F ; extract action bits + AND R11, R3, #7 ; 0-7 Store etc + ; 8-15 ditto with transparency + MOV R11, R11, LSL #2 ; 4 bits for each + LDR R7, =TBscrmasks + MOV R7, R7, ROR R11 ; relevant bits are in top 4 + AND R7, R7, #&F0000000 ; isolate these bits (N,Z,C,V) +SetCol70 + LDR R5, [R0, R4, LSL #2] ; get ecf word + TST R3, #8 ; if action < 8 + MOVEQ R6, #&FFFFFFFF + BEQ SetCol90 ; then not transparent + ; else build transparency mask + LDR R8, [WsPtr, #RAMMaskTb] ; fetch mask for leftmost pixel + LDR R9, [WsPtr, #BytesPerChar] ; shift factor for next pixel + LDR R6, [R1, R4, LSL #2] ; get 'transparent' colour + EOR R6, R6, R5 +SetCol80 + TST R6, R8 ; if pixels the same, + ; then it's transparent + ORRNE R6, R6, R8 ; else set mask to plot it + MOVS R8, R8, LSL R9 + BNE SetCol80 + +SetCol90 + TEQP R7, #SVC_mode ; put bits into N, Z, C, V + ; OO,EO,OE,EE + + MOVCC R10, R5 ; if ORing with &00000000 + MOVCS R10, #&FFFFFFFF ; if ORing with &FFFFFFFF + MVNVS R10, R10 ; if EORing with &FFFFFFFF + +; MOVPL R5, R5 ; if ORing with &00000000 + MOVMI R5, #&FFFFFFFF ; if ORing with &FFFFFFFF + MVNEQ R5, R5 ; if EORing with &FFFFFFFF + +; now R5 = OR mask, R10 = EOR mask + + AND R5, R5, R6 ; then clear 'transparent' + AND R10, R10, R6 ; pixels + + LDR R11, [WsPtr, #ECFShift] + MOV R5, R5, ROR R11 ; rotate OR and EOR masks + MOV R10, R10, ROR R11 ; to correct for ECF X origin + + LDR R11, [WsPtr, #ECFYOffset] + ADD R11, R11, R4 ; add on ECF Y offset + AND R11, R11, #7 ; and wrap + + ADD R11, R2, R11, LSL #3 + STMIA R11, {R5, R10} ; write to (Fg/Bg)EcfOraEor + + SUBS R4, R4, #1 + BCS SetCol70 + + MOV PC, R14 + +; ***************************************************************************** +; +; AddTintToColour - in 256 colour modes +; +; Internal to SetColour (derived from TMD's FudgeColour) +; +; in: R0 = colour (0..255), where 6 LSBits are used +; R3 = tint +; +; out: R0 holds colour byte with tint added +; R1-R3 preserved +; R4 undefined +; PSR preserved +; + + ! 0,"WARNING: AddTintToColour returns > 8 bit values now, check ECF handling!" + +AddTintToColour + Push "R3,LR" + AND R0, R0, #63 ; extract suitable set of bits + AND R3, R3, #192 ; and another set + ORR R0, R0, R3 + BL ConvertGCOLToColourNumber + Pull "R3,PC" + +; ***************************************************************************** +; +; CAN - Define graphics window +; +; External routine +; +; in: The window is given by bytes in the vdu queue, as follows :- +; QQ+0 = leftLo +; QQ+1 = leftHi +; QQ+2 = bottomLo +; QQ+3 = bottomHi +; QQ+4 = rightLo +; QQ+5 = rightHi +; QQ+6 = topLo +; QQ+7 = topHi +; +; These are relative to the current graphics origin. +; The resultant window must obey the following rules :- +; RCol >= LCol +; TRow >= BRow +; LCol >= 0 +; BRow >= 0 +; YWindLimit >= TRow +; XWindLimit >= RCol +; + +CAN ROUT + Push R14 + ADD R8, WsPtr, #GCsX ; save ECursor away, cos EIG changes it + LDMIA R8, {R6, R7} ; and we don't want it to! + +; *****Change made by DJS +; Original code was: +; LDRB R0, [WsPtr, #QQ+5] ; rightHi +; LDRB R1, [WsPtr, #QQ+4] ; rightLo +; PackXtnd R0,R0,R1 ; pack 2 bytes and sign extend +; +; LDRB R1, [WsPtr, #QQ+7] ; topHi +; LDRB R2, [WsPtr, #QQ+6] ; topLo +; PackXtnd R1,R1,R2 ; pack 2 bytes and sign extend + + LoadCoordPair R0, R1, WsPtr, QQ+4 ;Get top right point + +; *****End of change made by DJS + + MOV R2, #&FF ; convert external-to-internal + BL EIG ; as absolute coordinates + + MOV R4, R0 ; move internal version of top right + MOV R5, R1 ; out of harm's way + +; *****Change made by DJS +; Original code was: +; LDRB R0, [WsPtr, #QQ+1] ; leftHi +; LDRB R1, [WsPtr, #QQ+0] ; leftLo +; PackXtnd R0,R0,R1 ; pack 2 bytes and sign extend +; +; LDRB R1, [WsPtr, #QQ+3] ; bottomHi +; LDRB R2, [WsPtr, #QQ+2] ; bottomLo +; PackXtnd R1,R1,R2 ; pack 2 bytes and sign extend + + LoadCoordPair R0, R1, WsPtr, QQ+0 ;Get bottom left point + +; *****End of change made by DJS + + MOV R2, #&FF ; convert external-to-internal + BL EIG ; as absolute coordinates + +; For a valid window, the following must be true + + CMP R4, R0 ; RCol >= LCol + CMPGE R5, R1 ; TRow >= BRow + CMPGE R0, #0 ; LCol >= 0 + CMPGE R1, #0 ; BRow >= 0 + LDRGE R2, [WsPtr, #YWindLimit] ; YWindLimit >= TRow + CMPGE R2, R5 + LDRGE R2, [WsPtr, #XWindLimit] ; XWindLimit >= RCol + CMPGE R2, R4 + + ADD R2, WsPtr, #GWLCol + STMGEIA R2, {R0,R1, R4,R5} ; if the new window is OK, update it + + STMIA R8, {R6, R7} ; restore ECursor (EIG corrupted it) + Pull PC + +; ***************************************************************************** +; +; DefaultWindows - Restore default windows +; +; External routine, and called by mode change + switch output to sprite +; +; Set default text and graphics windows, +; Clear graphics origin and both cursors +; + +DefaultWindows ROUT + Push R14 + MOV R0, #0 + MOV R1, #0 + ADD R4, WsPtr, #GWLCol + + ASSERT YWindLimit = XWindLimit +4 + + ADD R2, WsPtr, #XWindLimit + LDMIA R2, {R2,R3} ; R2 := XWindLimit; R3 := YWindLimit + STMIA R4, {R0-R3} ; zero GWLCol, GWBRow + ; GWRCol:=XWindLimit; GWTRow:=YWindLimit + MOV R3, #0 + LDR R1, [WsPtr, #ScrBRow] + LDR R2, [WsPtr, #ScrRCol] + ADD R4, WsPtr, #TWLCol ; zero TWLCol, TWTRow + STMIA R4!, {R0-R3} ; TWRCol := ScrRCol; TWBRow := ScrBRow + + MOV R1, #0 + MOV R2, #0 + STMIA R4!, {R0-R3} ; zero OrgX, OrgY, GCsX, GCsY + STMIA R4!, {R0-R3} ; zero OlderCsX, OlderCsY, OldCsX, OldCsY + STMIA R4!, {R0-R3} ; zero GCsIX, GCsIY, NewPtX, NewPtY + + LDR R0, [WsPtr, #ModeFlags] + TST R0, #Flag_HardScrollDisabled + + LDR R0, [WsPtr, #VduStatus] ; if not outputting to sprite + BICEQ R0, R0, #Windowing ; then indicate no text window + ORRNE R0, R0, #Windowing ; else indicate is text window + STR R0, [WsPtr, #VduStatus] + + BL HomeVdu4 ; home TEXT cursor + ; (even in VDU 5 mode) + Pull PC + +; ***************************************************************************** +; +; GS - Define graphics origin +; +; External routine +; +; in: The origin is given by bytes in the vdu queue, as follows :- +; QQ+0 = xLo +; QQ+1 = xHi +; QQ+2 = yLo +; QQ+3 = yHi +; +; The coordinates are in external 16 bit form. +; This does not move the windows, but does move the graphics cursor +; + +GS ROUT + Push R14 + +; *****Change made by DJS +; Original code was: +; LDRB R0, [WsPtr, #QQ+1] ; xHi +; LDRB R1, [WsPtr, #QQ+0] ; xLo +; PackXtnd R0,R0,R1 ; pack 2 bytes and sign extend +; LDRB R1, [WsPtr, #QQ+3] ; yHi +; LDRB R2, [WsPtr, #QQ+2] ; yLo +; PackXtnd R1,R1,R2 ; pack 2 bytes and sign extend + + LoadCoordPair R0, R1, WsPtr, QQ+0 + +; *****End of change made by DJS + + ADD R2, WsPtr, #OrgX + STMIA R2, {R0,R1} ; write the new origin + BL IEG ; update external cursor + Pull PC + + LTORG + +;------------------------------------------------------------------------------ +; +; OS_SetColour implementation +; ------------ +; +; This call can be used to change the current GCOL/pattern table used for +; plotting with the VDU primitives. +; +; in R0 = flags / logical operation +; bit 0-3 = logical operation +; bit 4 = set => bg, else fg flag +; bit 5 = set => pattern block supplied +; bit 6 = set => set text colour +; bit 7 = set => read colour +; R1 = colour number / -> pattern block to use +; out - +; +;------------------------------------------------------------------------------ + +setcol_LogicOpMask * &0F +setcol_FgBgFlag * &10 +setcol_PatternFlag * &20 +setcol_TextColour * &40 +setcol_ReadFlag * &80 + + ASSERT WsPtr > 9 + +SWISetColour ROUT + + Push "R0-R9,WsPtr,R14" + + VDWS WsPtr ; Obtain base of the VDU driver workspace + + TST R0, #setcol_ReadFlag ; Are we reading? + BNE %FT75 + + TST R0, #setcol_TextColour ; Are we changing the text colour? + BNE %FT70 + + AND R2, R0, #setcol_LogicOpMask ; Get the logical operation + ORR R2, R2, #&60 ; Mark as being a special kind of pattern + + TST R0, #setcol_FgBgFlag + STREQ R2, [WsPtr, #GPLFMD] ; Store the relevant logical operation away for fg/bg + STRNE R2, [WsPtr, #GPLBMD] + ADDEQ R3, WsPtr, #FgPattern + ADDNE R3, WsPtr, #BgPattern ; Setup the pointer to a store for the pattern + + TST R0, #setcol_PatternFlag ; Did the caller specify a pattern block? + BNE %FT50 ; Yes so don't try to expand colour value to pattern + + MOV R2, #1 + LDR R4, [WsPtr, #Log2BPP] ; Get the Log2 depth of the mode + MOV R4, R2, ASL R4 ; R4 = bits per pixel + RSB R2, R2, R2, LSL R4 ; Get a mask to extract only meaningful bits from word + AND R1, R1, R2 ; Extract bits suitable for this depth of mode +10 + TEQ R4, #32 ; Do we need to do any more replication + ORRNE R1, R1, R1, LSL R4 ; Yes so or word with itself shifted + MOVNE R4, R4, LSL #1 ; and double amount to shift next time + BNE %BT10 + + MOV R2, #8 +20 + STR R1, [R3], #4 ; now copy word 8 times into block + SUBS R2, R2, #1 + BNE %BT20 + B %FT60 + +50 + LDMIA R1,{R0,R2,R4-R9} + STMIA R3,{R0,R2,R4-R9} ; Copy the pattern into the buffer (assumes word aligned) +60 + BL SetColour ; And then setup the internal GCOL tables +65 + Pull "R0-R9,WsPtr,R14" + ExitSWIHandler +70 + TST R0, #setcol_FgBgFlag ; Store the foreground or background colour? + STREQ R1, [WsPtr, #TextFgColour] + STRNE R1, [WsPtr, #TextBgColour] + + LDR R0, [WsPtr, #CursorFlags] ; Indicate the text colour needs re-computing! + ORR R0, R0, #TEUpdate + STR R0, [WsPtr, #CursorFlags] + + B %BT65 ; Leave gracefully .... + +75 + ; Reading the colour... + TST R0, #setcol_TextColour + BEQ %FT80 + + ; Reading text colour + TST R0, #setcol_FgBgFlag + LDREQ R1, [WsPtr, #TextFgColour] + LDRNE R1, [WsPtr, #TextBgColour] + BIC R0, R0, #setcol_PatternFlag :OR: setcol_ReadFlag + +77 + ; Standard exit for reading the colour + STMIA SP, {R0,R1} + B %BT65 + +80 + ; Reading graphics colour + TST R0, #setcol_FgBgFlag + LDREQ R2, [WsPtr, #GPLFMD] ; Get the relevant logical operation for fg/bg + LDRNE R2, [WsPtr, #GPLBMD] + + ; SetColour setting - copy block + ADDEQ R3, WsPtr, #FgEcf + ADDNE R3, WsPtr, #BgEcf + + ; Copy the pattern to the user's buffer + LDMIA R3,{R0,R3,R4-R9} + STMIA R1,{R0,R3,R4-R9} + + ; Construct a suitable reason code + AND R0, R2, #setcol_LogicOpMask + ORRNE R0, R0, #setcol_FgBgFlag + ORR R0, R0, #setcol_PatternFlag + B %BT77 + + END diff --git a/s/vdu/vdufont b/s/vdu/vdufont new file mode 100644 index 0000000000000000000000000000000000000000..5d14964a7be3ec1b86309c3778d5069b7e67686a --- /dev/null +++ b/s/vdu/vdufont @@ -0,0 +1,243 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.VduFont + +HardFont + = &00, &00, &00, &00, &00, &00, &00, &00 + = &18, &18, &18, &18, &18, &00, &18, &00 + = &6C, &6C, &6C, &00, &00, &00, &00, &00 + = &36, &36, &7F, &36, &7F, &36, &36, &00 + = &0C, &3F, &68, &3E, &0B, &7E, &18, &00 + = &60, &66, &0C, &18, &30, &66, &06, &00 + = &38, &6C, &6C, &38, &6D, &66, &3B, &00 + = &0C, &18, &30, &00, &00, &00, &00, &00 + = &0C, &18, &30, &30, &30, &18, &0C, &00 + = &30, &18, &0C, &0C, &0C, &18, &30, &00 + = &00, &18, &7E, &3C, &7E, &18, &00, &00 + = &00, &18, &18, &7E, &18, &18, &00, &00 + = &00, &00, &00, &00, &00, &18, &18, &30 + = &00, &00, &00, &7E, &00, &00, &00, &00 + = &00, &00, &00, &00, &00, &18, &18, &00 + = &00, &06, &0C, &18, &30, &60, &00, &00 + = &3C, &66, &6E, &7E, &76, &66, &3C, &00 + = &18, &38, &18, &18, &18, &18, &7E, &00 + = &3C, &66, &06, &0C, &18, &30, &7E, &00 + = &3C, &66, &06, &1C, &06, &66, &3C, &00 + = &0C, &1C, &3C, &6C, &7E, &0C, &0C, &00 + = &7E, &60, &7C, &06, &06, &66, &3C, &00 + = &1C, &30, &60, &7C, &66, &66, &3C, &00 + = &7E, &06, &0C, &18, &30, &30, &30, &00 + = &3C, &66, &66, &3C, &66, &66, &3C, &00 + = &3C, &66, &66, &3E, &06, &0C, &38, &00 + = &00, &00, &18, &18, &00, &18, &18, &00 + = &00, &00, &18, &18, &00, &18, &18, &30 + = &0C, &18, &30, &60, &30, &18, &0C, &00 + = &00, &00, &7E, &00, &7E, &00, &00, &00 + = &30, &18, &0C, &06, &0C, &18, &30, &00 + = &3C, &66, &0C, &18, &18, &00, &18, &00 + = &3C, &66, &6E, &6A, &6E, &60, &3C, &00 + = &3C, &66, &66, &7E, &66, &66, &66, &00 + = &7C, &66, &66, &7C, &66, &66, &7C, &00 + = &3C, &66, &60, &60, &60, &66, &3C, &00 + = &78, &6C, &66, &66, &66, &6C, &78, &00 + = &7E, &60, &60, &7C, &60, &60, &7E, &00 + = &7E, &60, &60, &7C, &60, &60, &60, &00 + = &3C, &66, &60, &6E, &66, &66, &3C, &00 + = &66, &66, &66, &7E, &66, &66, &66, &00 + = &7E, &18, &18, &18, &18, &18, &7E, &00 + = &3E, &0C, &0C, &0C, &0C, &6C, &38, &00 + = &66, &6C, &78, &70, &78, &6C, &66, &00 + = &60, &60, &60, &60, &60, &60, &7E, &00 + = &63, &77, &7F, &6B, &6B, &63, &63, &00 + = &66, &66, &76, &7E, &6E, &66, &66, &00 + = &3C, &66, &66, &66, &66, &66, &3C, &00 + = &7C, &66, &66, &7C, &60, &60, &60, &00 + = &3C, &66, &66, &66, &6A, &6C, &36, &00 + = &7C, &66, &66, &7C, &6C, &66, &66, &00 + = &3C, &66, &60, &3C, &06, &66, &3C, &00 + = &7E, &18, &18, &18, &18, &18, &18, &00 + = &66, &66, &66, &66, &66, &66, &3C, &00 + = &66, &66, &66, &66, &66, &3C, &18, &00 + = &63, &63, &6B, &6B, &7F, &77, &63, &00 + = &66, &66, &3C, &18, &3C, &66, &66, &00 + = &66, &66, &66, &3C, &18, &18, &18, &00 + = &7E, &06, &0C, &18, &30, &60, &7E, &00 + = &7C, &60, &60, &60, &60, &60, &7C, &00 + = &00, &60, &30, &18, &0C, &06, &00, &00 + = &3E, &06, &06, &06, &06, &06, &3E, &00 + = &18, &3C, &66, &42, &00, &00, &00, &00 + = &00, &00, &00, &00, &00, &00, &00, &FF + = &1C, &36, &30, &7C, &30, &30, &7E, &00 + = &00, &00, &3C, &06, &3E, &66, &3E, &00 + = &60, &60, &7C, &66, &66, &66, &7C, &00 + = &00, &00, &3C, &66, &60, &66, &3C, &00 + = &06, &06, &3E, &66, &66, &66, &3E, &00 + = &00, &00, &3C, &66, &7E, &60, &3C, &00 + = &1C, &30, &30, &7C, &30, &30, &30, &00 + = &00, &00, &3E, &66, &66, &3E, &06, &3C + = &60, &60, &7C, &66, &66, &66, &66, &00 + = &18, &00, &38, &18, &18, &18, &3C, &00 + = &18, &00, &38, &18, &18, &18, &18, &70 + = &60, &60, &66, &6C, &78, &6C, &66, &00 + = &38, &18, &18, &18, &18, &18, &3C, &00 + = &00, &00, &36, &7F, &6B, &6B, &63, &00 + = &00, &00, &7C, &66, &66, &66, &66, &00 + = &00, &00, &3C, &66, &66, &66, &3C, &00 + = &00, &00, &7C, &66, &66, &7C, &60, &60 + = &00, &00, &3E, &66, &66, &3E, &06, &07 + = &00, &00, &6C, &76, &60, &60, &60, &00 + = &00, &00, &3E, &60, &3C, &06, &7C, &00 + = &30, &30, &7C, &30, &30, &30, &1C, &00 + = &00, &00, &66, &66, &66, &66, &3E, &00 + = &00, &00, &66, &66, &66, &3C, &18, &00 + = &00, &00, &63, &6B, &6B, &7F, &36, &00 + = &00, &00, &66, &3C, &18, &3C, &66, &00 + = &00, &00, &66, &66, &66, &3E, &06, &3C + = &00, &00, &7E, &0C, &18, &30, &7E, &00 + = &0C, &18, &18, &70, &18, &18, &0C, &00 + = &18, &18, &18, &00, &18, &18, &18, &00 + = &30, &18, &18, &0E, &18, &18, &30, &00 + = &31, &6B, &46, &00, &00, &00, &00, &00 + = &FF, &FF, &FF, &FF, &FF, &FF, &FF, &FF + = &66, &00, &3C, &66, &7E, &66, &66, &00 + = &3C, &66, &3C, &66, &7E, &66, &66, &00 + = &3F, &66, &66, &7F, &66, &66, &67, &00 + = &3C, &66, &60, &60, &60, &66, &3C, &60 + = &0C, &18, &7E, &60, &7C, &60, &7E, &00 + = &66, &3C, &66, &66, &66, &66, &3C, &00 + = &66, &00, &66, &66, &66, &66, &3C, &00 + = &7E, &C3, &9D, &B1, &9D, &C3, &7E, &00 + = &00, &18, &38, &7F, &38, &18, &00, &00 + = &00, &18, &1C, &FE, &1C, &18, &00, &00 + = &18, &18, &18, &18, &7E, &3C, &18, &00 + = &00, &18, &3C, &7E, &18, &18, &18, &18 + = &30, &18, &3C, &06, &3E, &66, &3E, &00 + = &30, &18, &3C, &66, &7E, &60, &3C, &00 + = &66, &00, &3C, &66, &7E, &60, &3C, &00 + = &3C, &66, &3C, &66, &7E, &60, &3C, &00 + = &66, &00, &3C, &06, &3E, &66, &3E, &00 + = &3C, &66, &3C, &06, &3E, &66, &3E, &00 + = &00, &00, &3F, &0D, &3F, &6C, &3F, &00 + = &00, &00, &3C, &66, &60, &66, &3C, &60 + = &0C, &18, &3C, &66, &7E, &60, &3C, &00 + = &66, &00, &3C, &66, &66, &66, &3C, &00 + = &66, &00, &66, &66, &66, &66, &3E, &00 + = &30, &18, &00, &38, &18, &18, &3C, &00 + = &3C, &66, &00, &38, &18, &18, &3C, &00 + = &30, &18, &00, &3C, &66, &66, &3C, &00 + = &3C, &66, &00, &3C, &66, &66, &3C, &00 + = &30, &18, &00, &66, &66, &66, &3E, &00 + = &3C, &66, &00, &66, &66, &66, &3E, &00 + = &66, &00, &66, &66, &66, &3E, &06, &3C + = &00, &66, &3C, &66, &66, &3C, &66, &00 + = &3C, &60, &3C, &66, &3C, &06, &3C, &00 + = &3C, &66, &3C, &00, &00, &00, &00, &00 + = &00, &00, &00, &18, &18, &18, &18, &18 + = &00, &00, &00, &1F, &00, &00, &00, &00 + = &00, &00, &00, &1F, &18, &18, &18, &18 + = &00, &00, &00, &F8, &00, &00, &00, &00 + = &00, &00, &00, &F8, &18, &18, &18, &18 + = &00, &00, &00, &FF, &00, &00, &00, &00 + = &00, &00, &00, &FF, &18, &18, &18, &18 + = &18, &18, &18, &18, &00, &00, &00, &00 + = &18, &18, &18, &18, &18, &18, &18, &18 + = &18, &18, &18, &1F, &00, &00, &00, &00 + = &18, &18, &18, &1F, &18, &18, &18, &18 + = &18, &18, &18, &F8, &00, &00, &00, &00 + = &18, &18, &18, &F8, &18, &18, &18, &18 + = &18, &18, &18, &FF, &00, &00, &00, &00 + = &18, &18, &18, &FF, &18, &18, &18, &18 + = &00, &00, &00, &07, &0C, &18, &18, &18 + = &00, &00, &00, &E0, &30, &18, &18, &18 + = &18, &18, &0C, &07, &00, &00, &00, &00 + = &18, &18, &30, &E0, &00, &00, &00, &00 + = &18, &00, &18, &18, &30, &66, &3C, &00 + = &18, &00, &18, &18, &18, &18, &18, &00 + = &36, &6C, &00, &66, &76, &6E, &66, &00 + = &36, &6C, &00, &7C, &66, &66, &66, &00 + = &18, &7E, &18, &18, &18, &18, &18, &00 + = &18, &7E, &18, &18, &18, &7E, &18, &00 + = &18, &18, &18, &00, &00, &00, &00, &00 + = &30, &18, &0C, &00, &00, &00, &00, &00 + = &3F, &7B, &7B, &3B, &1B, &1B, &1F, &00 + = &00, &00, &00, &18, &18, &00, &00, &00 + = &03, &03, &06, &06, &76, &1C, &0C, &00 + = &AA, &55, &AA, &55, &AA, &55, &AA, &55 + = &3E, &63, &67, &6B, &73, &63, &3E, &00 + = &1C, &36, &63, &63, &7F, &63, &63, &00 + = &7E, &33, &33, &3E, &33, &33, &7E, &00 + = &7F, &63, &60, &60, &60, &60, &60, &00 + = &1C, &1C, &36, &36, &63, &63, &7F, &00 + = &7F, &33, &30, &3E, &30, &33, &7F, &00 + = &7E, &66, &0C, &18, &30, &66, &7E, &00 + = &77, &33, &33, &3F, &33, &33, &77, &00 + = &3E, &63, &63, &7F, &63, &63, &3E, &00 + = &3C, &18, &18, &18, &18, &18, &3C, &00 + = &63, &66, &6C, &78, &6C, &66, &63, &00 + = &1C, &1C, &36, &36, &63, &63, &63, &00 + = &63, &77, &7F, &6B, &63, &63, &63, &00 + = &63, &73, &7B, &6F, &67, &63, &63, &00 + = &7E, &00, &00, &3C, &00, &00, &7E, &00 + = &3E, &63, &63, &63, &63, &63, &3E, &00 + = &7F, &36, &36, &36, &36, &36, &36, &00 + = &7E, &33, &33, &3E, &30, &30, &78, &00 + = &7F, &63, &30, &18, &30, &63, &7F, &00 + = &7E, &5A, &18, &18, &18, &18, &18, &00 + = &66, &66, &66, &3C, &18, &18, &3C, &00 + = &3E, &08, &3E, &6B, &3E, &08, &3E, &00 + = &63, &63, &36, &1C, &36, &63, &63, &00 + = &3E, &08, &6B, &6B, &3E, &08, &3E, &00 + = &3E, &63, &63, &63, &36, &36, &63, &00 + = &7F, &63, &63, &36, &36, &1C, &1C, &00 + = &18, &18, &7E, &18, &18, &00, &7E, &00 + = &00, &7E, &00, &18, &18, &7E, &18, &18 + = &18, &18, &18, &18, &18, &18, &18, &00 + = &36, &36, &36, &36, &36, &36, &36, &00 + = &00, &66, &66, &66, &66, &66, &3C, &00 + = &00, &3C, &66, &66, &66, &66, &66, &00 + = &00, &03, &3E, &67, &6B, &73, &3E, &60 + = &00, &00, &3B, &6E, &66, &6E, &3B, &00 + = &1E, &33, &33, &3E, &33, &33, &3E, &60 + = &00, &00, &66, &36, &1C, &18, &30, &30 + = &3C, &60, &30, &3C, &66, &66, &3C, &00 + = &00, &00, &1E, &30, &1C, &30, &1E, &00 + = &3E, &0C, &18, &30, &60, &60, &3E, &06 + = &00, &00, &7C, &66, &66, &66, &06, &06 + = &3C, &66, &66, &7E, &66, &66, &3C, &00 + = &00, &00, &18, &18, &18, &18, &0C, &00 + = &00, &00, &66, &6C, &78, &6C, &66, &00 + = &60, &30, &18, &1C, &36, &63, &63, &00 + = &00, &00, &33, &33, &33, &33, &3E, &60 + = &00, &00, &63, &33, &1B, &1E, &1C, &00 + = &3C, &60, &60, &3C, &60, &60, &3E, &06 + = &00, &00, &3E, &63, &63, &63, &3E, &00 + = &00, &00, &7F, &36, &36, &36, &36, &00 + = &00, &00, &3C, &66, &66, &7C, &60, &60 + = &00, &00, &3F, &66, &66, &66, &3C, &00 + = &00, &00, &7E, &18, &18, &18, &0C, &00 + = &00, &00, &73, &33, &33, &33, &1E, &00 + = &00, &00, &3E, &6B, &6B, &3E, &18, &18 + = &00, &00, &66, &36, &1C, &1C, &36, &33 + = &00, &00, &63, &6B, &6B, &3E, &18, &18 + = &00, &00, &36, &63, &6B, &7F, &36, &00 + = &38, &0C, &06, &3E, &66, &66, &3C, &00 + = &00, &31, &6B, &46, &00, &7F, &00, &00 + = &00, &7E, &00, &7E, &00, &7E, &00, &00 + = &07, &1C, &70, &1C, &07, &00, &7F, &00 + = &06, &0C, &7E, &18, &7E, &30, &60, &00 + = &70, &1C, &07, &1C, &70, &00, &7F, &00 + = &FF, &FF, &FF, &FF, &FF, &FF, &FF, &FF + + END diff --git a/s/vdu/vdufontl1 b/s/vdu/vdufontl1 new file mode 100644 index 0000000000000000000000000000000000000000..3abae2186b0a4ff35ea218bb699dac53425f45c3 --- /dev/null +++ b/s/vdu/vdufontl1 @@ -0,0 +1,258 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.VduFontL1 + +HardFont + = &00,&00,&00,&00,&00,&00,&00,&00 ;ISO "space" + = &18,&18,&18,&18,&18,&00,&18,&00 ;ISO "exclamation mark" + = &6C,&6C,&6C,&00,&00,&00,&00,&00 ;ISO "quotation mark" + = &36,&36,&7F,&36,&7F,&36,&36,&00 ;ISO "number sign (hash)" + = &0C,&3F,&68,&3E,&0B,&7E,&18,&00 ;ISO "dollar sign" + = &60,&66,&0C,&18,&30,&66,&06,&00 ;ISO "percent sign" + = &38,&6C,&6C,&38,&6D,&66,&3B,&00 ;ISO "ampersand" + = &18,&18,&18,&00,&00,&00,&00,&00 ;ISO "apostrophe" changed 09-Sep-88 + = &0C,&18,&30,&30,&30,&18,&0C,&00 ;ISO "left parenthesis" + = &30,&18,&0C,&0C,&0C,&18,&30,&00 ;ISO "right parenthesis" + = &00,&18,&7E,&3C,&7E,&18,&00,&00 ;ISO "asterisk" + = &00,&18,&18,&7E,&18,&18,&00,&00 ;ISO "plus sign" + = &00,&00,&00,&00,&00,&18,&18,&30 ;ISO "comma" + = &00,&00,&00,&7E,&00,&00,&00,&00 ;ISO "hyphen or minus sign" + = &00,&00,&00,&00,&00,&18,&18,&00 ;ISO "full stop, period" + = &00,&06,&0C,&18,&30,&60,&00,&00 ;ISO "solidus" + = &3C,&66,&6E,&7E,&76,&66,&3C,&00 ;ISO "digit zero" + = &18,&38,&18,&18,&18,&18,&7E,&00 ;ISO "digit one" + = &3C,&66,&06,&0C,&18,&30,&7E,&00 ;ISO "digit two" + = &3C,&66,&06,&1C,&06,&66,&3C,&00 ;ISO "digit three" + = &0C,&1C,&3C,&6C,&7E,&0C,&0C,&00 ;ISO "digit four" + = &7E,&60,&7C,&06,&06,&66,&3C,&00 ;ISO "digit five" + = &1C,&30,&60,&7C,&66,&66,&3C,&00 ;ISO "digit six" + = &7E,&06,&0C,&18,&30,&30,&30,&00 ;ISO "digit seven" + = &3C,&66,&66,&3C,&66,&66,&3C,&00 ;ISO "digit eight" + = &3C,&66,&66,&3E,&06,&0C,&38,&00 ;ISO "digit nine" + = &00,&00,&18,&18,&00,&18,&18,&00 ;ISO "colon" + = &00,&00,&18,&18,&00,&18,&18,&30 ;ISO "semi-colon" + = &0C,&18,&30,&60,&30,&18,&0C,&00 ;ISO "less-than sign" + = &00,&00,&7E,&00,&7E,&00,&00,&00 ;ISO "equals sign" + = &30,&18,&0C,&06,&0C,&18,&30,&00 ;ISO "greater-than sign" + = &3C,&66,&0C,&18,&18,&00,&18,&00 ;ISO "question mark" + = &3C,&66,&6E,&6A,&6E,&60,&3C,&00 ;ISO "commercial at" + = &3C,&66,&66,&7E,&66,&66,&66,&00 ;ISO "capital A" + = &7C,&66,&66,&7C,&66,&66,&7C,&00 ;ISO "capital B" + = &3C,&66,&60,&60,&60,&66,&3C,&00 ;ISO "capital C" + = &78,&6C,&66,&66,&66,&6C,&78,&00 ;ISO "capital D" + = &7E,&60,&60,&7C,&60,&60,&7E,&00 ;ISO "capital E" + = &7E,&60,&60,&7C,&60,&60,&60,&00 ;ISO "capital F" + = &3C,&66,&60,&6E,&66,&66,&3C,&00 ;ISO "capital G" + = &66,&66,&66,&7E,&66,&66,&66,&00 ;ISO "capital H" + = &7E,&18,&18,&18,&18,&18,&7E,&00 ;ISO "capital I" + = &3E,&0C,&0C,&0C,&0C,&6C,&38,&00 ;ISO "capital J" + = &66,&6C,&78,&70,&78,&6C,&66,&00 ;ISO "capital K" + = &60,&60,&60,&60,&60,&60,&7E,&00 ;ISO "capital L" + = &63,&77,&7F,&6B,&6B,&63,&63,&00 ;ISO "capital M" + = &66,&66,&76,&7E,&6E,&66,&66,&00 ;ISO "capital N" + = &3C,&66,&66,&66,&66,&66,&3C,&00 ;ISO "capital O" + = &7C,&66,&66,&7C,&60,&60,&60,&00 ;ISO "capital P" + = &3C,&66,&66,&66,&6A,&6C,&36,&00 ;ISO "capital Q" + = &7C,&66,&66,&7C,&6C,&66,&66,&00 ;ISO "capital R" + = &3C,&66,&60,&3C,&06,&66,&3C,&00 ;ISO "capital S" + = &7E,&18,&18,&18,&18,&18,&18,&00 ;ISO "capital T" + = &66,&66,&66,&66,&66,&66,&3C,&00 ;ISO "capital U" + = &66,&66,&66,&66,&66,&3C,&18,&00 ;ISO "capital V" + = &63,&63,&6B,&6B,&7F,&77,&63,&00 ;ISO "capital W" + = &66,&66,&3C,&18,&3C,&66,&66,&00 ;ISO "capital X" + = &66,&66,&66,&3C,&18,&18,&18,&00 ;ISO "capital Y" + = &7E,&06,&0C,&18,&30,&60,&7E,&00 ;ISO "capital Z" + = &7C,&60,&60,&60,&60,&60,&7C,&00 ;ISO "left square bracket" + = &00,&60,&30,&18,&0C,&06,&00,&00 ;ISO "reverse solidus" + = &3E,&06,&06,&06,&06,&06,&3E,&00 ;ISO "right square bracket" + = &3C,&66,&00,&00,&00,&00,&00,&00 ;ISO "circumflex accent" + = &00,&00,&00,&00,&00,&00,&00,&FF ;ISO "low line" + = &30,&18,&00,&00,&00,&00,&00,&00 ;ISO "grave accent" + = &00,&00,&3C,&06,&3E,&66,&3E,&00 ;ISO "small a" + = &60,&60,&7C,&66,&66,&66,&7C,&00 ;ISO "small b" + = &00,&00,&3C,&66,&60,&66,&3C,&00 ;ISO "small c" + = &06,&06,&3E,&66,&66,&66,&3E,&00 ;ISO "small d" + = &00,&00,&3C,&66,&7E,&60,&3C,&00 ;ISO "small e" + = &1C,&30,&30,&7C,&30,&30,&30,&00 ;ISO "small f" + = &00,&00,&3E,&66,&66,&3E,&06,&3C ;ISO "small g" + = &60,&60,&7C,&66,&66,&66,&66,&00 ;ISO "small h" + = &18,&00,&38,&18,&18,&18,&3C,&00 ;ISO "small i" + = &18,&00,&38,&18,&18,&18,&18,&70 ;ISO "small j" + = &60,&60,&66,&6C,&78,&6C,&66,&00 ;ISO "small k" + = &38,&18,&18,&18,&18,&18,&3C,&00 ;ISO "small l" + = &00,&00,&36,&7F,&6B,&6B,&63,&00 ;ISO "small m" + = &00,&00,&7C,&66,&66,&66,&66,&00 ;ISO "small n" + = &00,&00,&3C,&66,&66,&66,&3C,&00 ;ISO "small o" + = &00,&00,&7C,&66,&66,&7C,&60,&60 ;ISO "small P" + = &00,&00,&3E,&66,&66,&3E,&06,&07 ;ISO "small q" + = &00,&00,&6C,&76,&60,&60,&60,&00 ;ISO "small r" + = &00,&00,&3E,&60,&3C,&06,&7C,&00 ;ISO "small s" + = &30,&30,&7C,&30,&30,&30,&1C,&00 ;ISO "small t" + = &00,&00,&66,&66,&66,&66,&3E,&00 ;ISO "small u" + = &00,&00,&66,&66,&66,&3C,&18,&00 ;ISO "small v" + = &00,&00,&63,&6B,&6B,&7F,&36,&00 ;ISO "small w" + = &00,&00,&66,&3C,&18,&3C,&66,&00 ;ISO "small x" + = &00,&00,&66,&66,&66,&3E,&06,&3C ;ISO "small y" + = &00,&00,&7E,&0C,&18,&30,&7E,&00 ;ISO "small z" + = &0C,&18,&18,&70,&18,&18,&0C,&00 ;ISO "left curly bracket" + = &18,&18,&18,&18,&18,&18,&18,&00 ;ISO "vertical line" + = &30,&18,&18,&0E,&18,&18,&30,&00 ;ISO "right curly bracket" + = &31,&6B,&46,&00,&00,&00,&00,&00 ;ISO "tilde" + = &FF,&FF,&FF,&FF,&FF,&FF,&FF,&FF ;BFNT "Solid block" + + ; + ; This block of character definitions consists characters displayed as pairs of + ; hex digits, followed by a number of definitions + ; added in RISC OS 2.14 onwards that give greater continuity between system font + ; and outline fonts. These definitions appear in the kernel Latin1, and in + ; Latin1-4 in the International module. + + ; From 3.06 onwards four Welsh characters were added, and the hex characters were + ; changed to slope from bottom-left to top-right + + = &06,&09,&09,&69,&96,&60,&90,&60 ; "80" + = &1C,&63,&6B,&6B,&7F,&77,&63,&00 ; "W circumflex" (81) + = &1C,&36,&00,&6B,&6B,&7F,&36,&00 ; "w circumflex" (82) + = &06,&01,&06,&61,&96,&60,&90,&60 ; "83" + = &05,&05,&07,&61,&91,&60,&90,&60 ; "84" + = &18,&66,&42,&66,&3C,&18,&18,&00 ; "Y circumflex" (85) + = &18,&66,&00,&66,&66,&3E,&06,&3C ; "y circumflex" (86) + = &07,&01,&02,&64,&94,&60,&90,&60 ; "87" + = &06,&09,&06,&69,&96,&60,&90,&60 ; "88" + = &06,&09,&07,&61,&96,&60,&90,&60 ; "89" + = &06,&09,&0F,&69,&99,&60,&90,&60 ; "8A" + = &0E,&09,&0E,&69,&9E,&60,&90,&60 ; "8B" + = &00,&00,&00,&00,&00,&DB,&DB,&00 ; "ellipsis" (8C) + = &F1,&5B,&55,&51,&00,&00,&00,&00 ; "trademark" (8D) + = &C0,&CC,&18,&30,&60,&DB,&1B,&00 ; "perthousand" (8E) + = &00,&00,&3C,&7E,&7E,&3C,&00,&00 ; "bullet" (8F) + = &0C,&18,&18,&00,&00,&00,&00,&00 ; "quoteleft" (90) + = &0C,&0C,&18,&00,&00,&00,&00,&00 ; "quoteright" (91) + = &00,&0C,&18,&30,&30,&18,&0C,&00 ; "guilsinglleft" (92) + = &00,&30,&18,&0C,&0C,&18,&30,&00 ; "guilsinglright" (93) + = &1B,&36,&36,&00,&00,&00,&00,&00 ; "quotedblleft" (94) + = &36,&36,&6C,&00,&00,&00,&00,&00 ; "quotedblright" (95) + = &00,&00,&00,&00,&00,&36,&36,&6C ; "quotedblbase" (96) + = &00,&00,&00,&3C,&00,&00,&00,&00 ; "endash" (97) + = &00,&00,&00,&FF,&00,&00,&00,&00 ; "emdash" (98) + = &00,&00,&00,&7E,&00,&00,&00,&00 ; "minus" (99) + = &77,&CC,&CC,&CF,&CC,&CC,&77,&00 ; "OE" (9A) + = &00,&00,&6E,&DB,&DF,&D8,&6E,&00 ; "oe" (9B) + = &18,&18,&7E,&18,&18,&18,&18,&18 ; "dagger" (9C) + = &18,&18,&7E,&18,&7E,&18,&18,&18 ; "daggerdbl" (9D) + = &3C,&66,&60,&F6,&66,&66,&66,&00 ; "fi" (9E) + = &3E,&66,&66,&F6,&66,&66,&66,&00 ; "fl" (9F) + + = &00,&00,&00,&00,&00,&00,&00,&00 ;ISO "space" + = &18,&00,&18,&18,&18,&18,&18,&00 ;ISO "inverted exclamation mark" + = &08,&3E,&6B,&68,&6B,&3E,&08,&00 ;ISO "cent sign" + = &1C,&36,&30,&7C,&30,&30,&7E,&00 ;ISO "pound sign" + = &00,&66,&3C,&66,&66,&3C,&66,&00 ;ISO "general currency sign" + ; changed 09-Sep-88 + = &66,&3C,&18,&18,&7E,&18,&18,&00 ;ISO "yen sign" + = &18,&18,&18,&00,&18,&18,&18,&00 ;ISO "Broken vertical bar" + = &3C,&60,&3C,&66,&3C,&06,&3C,&00 ;ISO "section sign, paragraph" + = &66,&00,&00,&00,&00,&00,&00,&00 ;ISO "diaeresis or umlaut mark" + = &3C,&42,&99,&A1,&A1,&99,&42,&3C ;ISO "copyright sign" + = &1C,&06,&1E,&36,&1E,&00,&3E,&00 ;ISO "ordinal indicator, feminine" + = &00,&33,&66,&CC,&CC,&66,&33,&00 ;ISO "angle quotation left" + = &7E,&06,&00,&00,&00,&00,&00,&00 ;ISO "NOT symbol" changed 21/7/87 + = &00,&00,&00,&7E,&00,&00,&00,&00 ;ISO "hyphen or minus sign" + = &3C,&42,&B9,&A5,&B9,&A5,&42,&3C ;ISO "registered sign" + = &7E,&00,&00,&00,&00,&00,&00,&00 ;ISO "macron" + = &3C,&66,&3C,&00,&00,&00,&00,&00 ;ISO "ring" + = &18,&18,&7E,&18,&18,&00,&7E,&00 ;ISO "plus or minus sign" + = &38,&04,&18,&20,&3C,&00,&00,&00 ;ISO "superscript two" + = &38,&04,&18,&04,&38,&00,&00,&00 ;ISO "superscript three" + = &0C,&18,&00,&00,&00,&00,&00,&00 ;ISO "acute accent" + = &00,&00,&33,&33,&33,&33,&3E,&60 ;ISO "micro sign" + = &03,&3E,&76,&76,&36,&36,&3E,&00 ;ISO "pilcrow" + = &00,&00,&00,&18,&18,&00,&00,&00 ;ISO "middle dot" + = &00,&00,&00,&00,&00,&00,&18,&30 ;ISO "cedilla" changed 21/7/87 + = &10,&30,&10,&10,&38,&00,&00,&00 ;ISO "superscript one" 12/8/87 + = &1C,&36,&36,&36,&1C,&00,&3E,&00 ;ISO "ordinal indicator, masculine" + = &00,&CC,&66,&33,&33,&66,&CC,&00 ;ISO "angle quotation right" + = &40,&C0,&40,&48,&48,&0A,&0F,&02 ;ISO "fraction one-quarter" + = &40,&C0,&40,&4F,&41,&0F,&08,&0F ;ISO "fraction one-half" + = &E0,&20,&E0,&28,&E8,&0A,&0F,&02 ;ISO "fraction three-quarters" + = &18,&00,&18,&18,&30,&66,&3C,&00 ;ISO "inverted question mark" + = &30,&18,&00,&3C,&66,&7E,&66,&00 ;ISO "capital A with grave accent" + = &0C,&18,&00,&3C,&66,&7E,&66,&00 ;ISO "capital A with acute accent" + = &18,&66,&00,&3C,&66,&7E,&66,&00 ;ISO "capital A with circumflex" + = &36,&6C,&00,&3C,&66,&7E,&66,&00 ;ISO "capital A with tilde" + = &66,&66,&00,&3C,&66,&7E,&66,&00 ;ISO "capital A with umlaut mark" + = &3C,&66,&3C,&3C,&66,&7E,&66,&00 ;ISO "capital A with ring" + = &3F,&66,&66,&7F,&66,&66,&67,&00 ;ISO "capital AE dipthong" + = &3C,&66,&60,&60,&66,&3C,&30,&60 ;ISO "capital C with cedilla" + = &30,&18,&7E,&60,&7C,&60,&7E,&00 ;ISO "capital E with grave accent" + = &0C,&18,&7E,&60,&7C,&60,&7E,&00 ;ISO "capital E with acute accent" + = &3C,&66,&7E,&60,&7C,&60,&7E,&00 ;ISO "capital E with circumflex" + = &66,&00,&7E,&60,&7C,&60,&7E,&00 ;ISO "capital E with umlaut" + = &30,&18,&00,&7E,&18,&18,&7E,&00 ;ISO "capital I with grave accent" + = &0C,&18,&00,&7E,&18,&18,&7E,&00 ;ISO "capital I with acute accent" + = &3C,&66,&00,&7E,&18,&18,&7E,&00 ;ISO "capital I with circumflex" + = &66,&66,&00,&7E,&18,&18,&7E,&00 ;ISO "capital I with umlaut" + = &78,&6C,&66,&F6,&66,&6C,&78,&00 ;ISO "capital D with stroke" + = &36,&6C,&00,&66,&76,&6E,&66,&00 ;ISO "capital N with tilde" + = &30,&18,&3C,&66,&66,&66,&3C,&00 ;ISO "capital O with grave accent" + = &0C,&18,&3C,&66,&66,&66,&3C,&00 ;ISO "capital O with acute accent" + = &3C,&66,&3C,&66,&66,&66,&3C,&00 ;ISO "capital O with circumflex" + = &36,&6C,&3C,&66,&66,&66,&3C,&00 ;ISO "capital O with tilde" + = &66,&00,&3C,&66,&66,&66,&3C,&00 ;ISO "capital O with umlaut" + = &00,&63,&36,&1C,&1C,&36,&63,&00 ;ISO "multiply sign" + = &3D,&66,&6E,&7E,&76,&66,&BC,&00 ;ISO "capital O with slash" + = &30,&18,&66,&66,&66,&66,&3C,&00 ;ISO "capital U with grave accent" + = &0C,&18,&66,&66,&66,&66,&3C,&00 ;ISO "capital U with acute accent" + = &3C,&66,&00,&66,&66,&66,&3C,&00 ;ISO "capital U with circumflex" + = &66,&00,&66,&66,&66,&66,&3C,&00 ;ISO "capital U with umlaut" + = &0C,&18,&66,&66,&3C,&18,&18,&00 ;ISO "capital Y with acute accent" + = &F0,&60,&7C,&66,&7C,&60,&F0,&00 ;ISO "capital thorn, Icelandic" + = &3C,&66,&66,&6C,&66,&66,&6C,&C0 ;ISO "small sharp s, German" + = &30,&18,&3C,&06,&3E,&66,&3E,&00 ;ISO "small a with grave accent" + = &0C,&18,&3C,&06,&3E,&66,&3E,&00 ;ISO "small a with acute accent" + = &18,&66,&3C,&06,&3E,&66,&3E,&00 ;ISO "small a with circumflex" + = &36,&6C,&3C,&06,&3E,&66,&3E,&00 ;ISO "small a with tilde" + = &66,&00,&3C,&06,&3E,&66,&3E,&00 ;ISO "small a with umlaut mark" + = &3C,&66,&3C,&06,&3E,&66,&3E,&00 ;ISO "small a with ring" + = &00,&00,&3F,&0D,&3F,&6C,&3F,&00 ;ISO "small ae dipthong" + = &00,&00,&3C,&66,&60,&66,&3C,&60 ;ISO "small c with cedilla" + = &30,&18,&3C,&66,&7E,&60,&3C,&00 ;ISO "small e with grave accent" + = &0C,&18,&3C,&66,&7E,&60,&3C,&00 ;ISO "small e with acute accent" + = &3C,&66,&3C,&66,&7E,&60,&3C,&00 ;ISO "small e with cirumflex" + = &66,&00,&3C,&66,&7E,&60,&3C,&00 ;ISO "small e with umlaut" + = &30,&18,&00,&38,&18,&18,&3C,&00 ;ISO "small i with grave accent" + = &0C,&18,&00,&38,&18,&18,&3C,&00 ;ISO "small i with acute accent" + = &3C,&66,&00,&38,&18,&18,&3C,&00 ;ISO "small i with circumflex" + = &66,&00,&00,&38,&18,&18,&3C,&00 ;ISO "small i with umlaut" + = &18,&3E,&0C,&06,&3E,&66,&3E,&00 ;ISO "small eth, Icelandic" + = &36,&6C,&00,&7C,&66,&66,&66,&00 ;ISO "small n with tilde" + = &30,&18,&00,&3C,&66,&66,&3C,&00 ;ISO "small o with grave accent" + = &0C,&18,&00,&3C,&66,&66,&3C,&00 ;ISO "small o with acute accent" + = &3C,&66,&00,&3C,&66,&66,&3C,&00 ;ISO "small o with circumflex" + = &36,&6C,&00,&3C,&66,&66,&3C,&00 ;ISO "small o with tilde" + = &66,&00,&00,&3C,&66,&66,&3C,&00 ;ISO "small o with umlaut" + = &00,&18,&00,&FF,&00,&18,&00,&00 ;ISO "divide sign" + = &00,&02,&3C,&6E,&76,&66,&BC,&00 ;ISO "small o with slash" + = &30,&18,&00,&66,&66,&66,&3E,&00 ;ISO "small u with grave accent" + = &0C,&18,&00,&66,&66,&66,&3E,&00 ;ISO "small u with acute accent" + = &3C,&66,&00,&66,&66,&66,&3E,&00 ;ISO "small u with circumflex" + = &66,&00,&00,&66,&66,&66,&3E,&00 ;ISO "small u with umlaut" + = &0C,&18,&66,&66,&66,&3E,&06,&3C ;ISO "small y with acute accent" + = &60,&60,&7C,&66,&7C,&60,&60,&00 ;ISO "small thorn, Icelandic" + = &66,&00,&66,&66,&66,&3E,&06,&3C ;ISO "small y with umlaut" + + ASSERT (.-HardFont)=(256-32)*8 + + END diff --git a/s/vdu/vdugrafa b/s/vdu/vdugrafa new file mode 100644 index 0000000000000000000000000000000000000000..a8faef18368d641dfdcc79b2409b64f9c4306ed2 --- /dev/null +++ b/s/vdu/vdugrafa @@ -0,0 +1,359 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.VduGrafA +; +; ARTHUR OPERATING SYSTEM - Vdu Drivers +; ======================= +; +; Vdu driver code - Graphics rectangle, triangle +; +; Author R C Manby +; Date 5.9.86 +; + +; ***************************************************************************** +; +; GenLineParm - Generate a control block for a line +; +; Internal routine, called by TriangleFill, LowerTri, ParallelogramFill, +; SegmentLineO5, GenArcParmBlk, GenSegParmBlk, LineDraw +; +; in: R0 (X), R1(Y) hold start of line +; R2 (X), R3(Y) hold end of line +; +; out: R0..R6 hold the following control block +; R0 - StartX +; R1 - StartY +; R2 - Bres +; R3 - DeltaX +; R4 - DeltaY +; R5 - StepX (+1/-1) (Equv bit6 of Sign in 6502 version) +; R6 - StepY (+1/-1) (Equv bit7 of Sign in 6502 version) +; R7 - EndX +; R8 - EndY +; + +GenLineParm ROUT + MOV R7, R2 ; EndX,EndY - might be worth passing them + MOV R8, R3 ; in R7,R8 not R2,R3 + + SUB R3, R7, R0 ; Crude deltaX + SUB R4, R8, R1 ; Crude deltaY + + CMP R4, R3 + MOVLT R2, #0 ; if deltaY >= deltaX R2 := -1 + MOVGE R2, #-1 ; else R2 := 0 + ; this is used to fudge the bres + ; variable so lines of grad -1 are + ; the same as lines of grad 1 + + MOVS R5, R3, ASR #31 ; R5 := SGN(DeltaX) + MOVPL R5, #1 + RSBMI R3, R3, #0 ; DeltaX := ABS(DeltaX) + + MOVS R6, R4, ASR #31 ; R6 := SGN(DeltaY) + MOVPL R6, #1 + RSBMI R4, R4, #0 ; DeltaY := ABS(DeltaY) + + CMP R4, R3 ; Bres = MAX(DeltaX,DeltaY) + fudge factor + ADDPL R2, R4, R2 + ADDMI R2, R3, R2 + + RSB R2, R4, R2, ASR #1 ; Bres = Bres/2 - DeltaY + MOVS PC, R14 ; Return + +; ***************************************************************************** +; +; AdvLineParm - Advance a set of line parameters +; +; Internal routine, called by TrapFill, SegLineStep, ArcLineStep, +; LineDraw, InYWind, InXWind +; +; in: R0..R6, (R7,R8) hold a line parameter block +; +; out: R0 (X), R1 (Y) R2 (Bres) updated +; +; Format of a control block +; R0 - StartX (CurrentX) +; R1 - StartY (CurrentY) +; R2 - Bres +; R3 - DeltaX +; R4 - DeltaY +; R5 - StepX (+1/-1) (Equv bit6 of Sign in 6502 version) +; R6 - StepY (+1/-1) (Equv bit7 of Sign in 6502 version) +; R7 - EndX (Not used in this routine, so) +; R8 - EndY (doesnt need to be passed in) +; + +AdvLineParm ROUT + CMP R2, #0 ; If Bres +ve, advance in X dirn only + ADDLT R1, R1, R6 ; Advance in Y dirn + ADDLTS R2, R2, R3 ; Add DeltaX to Bres + ; If new Bres +ve advance X as well + ; Advance X + SUBGE R2, R2, R4 ; Sub DeltaY from Bres to advance in X dirn + ADDGE R0, R0, R5 ; Add or subtract 1 dependent on sign DeltaX + MOVS PC, R14 + +; ***************************************************************************** +; +; AdvLineParm_GE - Macro to advance line in XDirn if flags are GE +; +; Used by Triangles,Parallelograms,Arcs etc +; +; Use: CMP R2,#0 +; AdvLineParm_GE +; +; Instead of: CMP R2,#0 +; BLGE AdvLineParm +; + + MACRO + AdvLineParm_GE + SUBGE R2, R2, R4 + ADDGE R0, R0, R5 + MEND + +; ***************************************************************************** +; +; RectangleFill - Fill a rectangle +; +; External routine, and RectFillA entry point used by BlockCopyMove, CLG +; and RectFillB entry point used by PlotMask +; +; in: ICursor & NewPt mark a diagonal of the rectangle +; +; out: R0-R11 corrupt +; +; + +RectangleFill ROUT + ADD R11,WsPtr,#GCsIX ; load ICursor & NewPt + LDMIA R11, {R0-R3} +RectFillA + Push R14 +RectFillB + SortT R0, R2, R11 ; ensure R0 holds the lesser X value + SortT R3, R1, R11 ; ensure R1 holds the higher Y value + MOV R11, R3 ; place end Y out of harm's way +10 + BL NewHLine + SUB R1, R1, #1 ; step Y down a line + CMP R1, R11 + BGE %BT10 + Pull PC + +; ***************************************************************************** +; +; TriangleFill - Triangular area fill +; +; External routine +; +; in: OldCs, ICursor & NewPt are verticies of the triangle +; +; out: R0-R11 corrupt +; + +TriangleFill ROUT + Push R14 + ADD R11, WsPtr, #OldCsX ; vertices are OldCs,ICursor + LDMIA R11, {R0-R5} ; and NewPt + BL LowerTri ; sort vertices and fill the + ; lower triangle + ADD R11, WsPtr, #Vertex2X ; restart TLine1 to run from + LDMIA R11, {R0-R3} ; Vertex2 to Vertex3 + ADD R11, WsPtr, #TLine1 +TriangleFil5 ; entry point from par fill + BL GenLineParm + STMIA R11, {R0-R8} ; initialise parameter block + STR R8, [WsPtr, #TEndY] ; end Y point for both lines + BL TrapFill ; fill the upper trapezoid + MOV R0, R9 ; fill top line LeftX,RightX + MOV R2, R10 ; leftY already in R1 + BL NewHLine + Pull PC + +; ***************************************************************************** +; +; LowerTri - Sort 3 vertices and fill the lower triangle between the +; points up to but excluding the horizontal through the middle point +; +; Internal routine, called by TriangleFill and ParallelogramFill +; + +LowerTri ROUT + Push R14 + CompSwapT R0,R1, R2,R3, R14 ; bubble highest vertex into R4,R5 + CompSwapT R2,R3 ,R4,R5, R14 + + CompSwapT R0,R1, R2,R3, R14 ; place lowest in R0,R1 and middle in R2,R3 + + ADD R11, WsPtr, #Vertex1X + STMIA R11, {R0-R7} ; save all our vertices + + MOV R9, R0 ; initalise TLeftX,TRightX + MOV R10, R0 ; to lowest point + BL GenLineParm ; Run TLine1 from lowest to + ADD R11, WsPtr, #TLine1 ; middle point + STMIA R11, {R0-R8} + STR R8, [WsPtr, #TEndY] ; this line ends first + + ADD R2, WsPtr, #Vertex3X ; run TLine2 from lowest to + LDMIA R2, {R2, R3} ; highest point + BL GenLineParm + ADD R11, WsPtr, #TLine2 + STMIA R11, {R0-R8} + BL TrapFill ; fill the lower trapezoid + + Pull PC + +; ***************************************************************************** +; +; ParallelogramFill - Fill a parallelogram +; +; External routine +; +; in: OldCs, ICursor & NewPt are 3 vertices of the parallelogram +; +; out: R0-R11 corrupt +; + +ParallelogramFill ROUT + Push R14 + ADD R11, WsPtr, #OldCsX ; vertices are OldCs,ICursor + LDMIA R11, {R0-R5} ; and NewPt + +; now calculate Vertex4 from other three + + ADD R6, R0, R4 ; Vertex4X := Vertex1X + Vertex3X - Vertex2X + SUB R6, R6, R2 + + ADD R7, R1, R5 ; Vertex4Y := Vertex1Y + Vertex3Y - Vertex2Y + SUB R7, R7, R3 + + CompSwapT R0,R1, R2,R3, R14 ; Bubble the highest point into R6,R7 + CompSwapT R2,R3 ,R4,R5, R14 + CompSwapT R4,R5 ,R6,R7, R14 + + BL LowerTri ; sort other vertices and draw lower triangle + + ADD R11, WsPtr, #Vertex2X ; restart TLine1 to run from + LDMIA R11!, {R0-R3} ; Vertex2 to Vertex4 + STR R3, [WsPtr, #TEndY] ; and indicate line Vertex1 to + LDMIA R11, {R2,R3} ; Vertex3 as the next to finish + + BL GenLineParm + ADD R11, WsPtr, #TLine1 + STMIA R11, {R0-R8} ; TLine1 parameter block + + BL TrapFill ; fill the middle trapezoid + + ADD R11, WsPtr, #Vertex3X ; restart TLine2 to run from + LDMIA R11, {R0-R3} ; Vertex3 to Vertex4 + ADD R11, WsPtr, #TLine2 + B TriangleFil5 ; Use common code with + ; triangles to initialise and + ; fill upper trapezoid + +; ***************************************************************************** +; +; TrapFill - Fill a trapezoid +; +; Internal routine, called by TriangleFill, LowerTri, ParallelogramFill +; +; in: R9 = TLeftX } the line limits for this scanline +; R10 = TRightX } +; +; out: R9,R10 updated +; + +TrapFill ROUT + Push R14 +10 + ADD R11, WsPtr, #TLine1 ; Advance TLine1 until currentY about + BL TrapLineStep ; to change, or end of line reached + + ADD R11, WsPtr, #TLine2 ; ditto TLine2 + BL TrapLineStep + + LDR R11, [WsPtr, #TEndY] + CMP R11, R1 ; if CurrentY = EndY + Pull PC, EQ ; then quit + + MOV R0, R9 ; LeftX + MOV R2, R10 ; RightX + ; LeftY already in R1 + BL NewHLine ; Plot current scanline + + ADD R11, WsPtr, #TLine1 ; advance TLine1 to next scanline + LDMIA R11, {R0-R6} + BL AdvLineParm + STMIA R11, {R0-R2} ; save the changes + + MOV R9, R0 ; assume currentX will be LeftX + + ADD R11, WsPtr, #TLine2 ; advance TLine2 to next scanline + LDMIA R11, {R0-R6} + BL AdvLineParm + STMIA R11, {R0-R2} ; save the changes + + CMP R0, R9 ; LeftX=Min(CurrentX,CurrentY) + MOVGE R10, R0 ; RightX=Max(CurrentX,CurrentY) + MOVLT R10, R9 + MOVLT R9, R0 + B %BT10 ; continue with next scanline + + +; ***************************************************************************** +; +; TrapLineStep - Step line parameters until CurrentY about to change +; or end of line reached - compares CurrentX with line limits +; (LeftX,RightX) and widens them if needed +; +; Internal routine, called by TrapFill +; +; in: R9 = LeftX +; R10 = RightX +; R11 = address of parameter block +; +; out: R0-R8 parameter block for this line +; R9, R10 updated +; R11 preserved +; + +TrapLineStep ROUT + Push R14 + LDMIA R11, {R0-R8} ; get line parameter block + CMP R8, R1 ; if on last scanline + MOVEQ R0, R7 ; then set currentX to EndX + BEQ TrapLin20 ; (bres unchanged, but who cares) + + CMP R2, #0 ; else While bres >= 0 do AdvLineParm +TrapLin10 ; {step until Y about to change} + ADDGE R0, R0, R5 + SUBGES R2, R2, R4 + BGE TrapLin10 + +TrapLin20 + STMIA R11, {R0-R2} ; update the changes to parameter block + CMP R0, R9 ; LeftX=Min(LeftX,CurrentX) + MOVLT R9, R0 + CMP R0, R10 + MOVGT R10, R0 ; RightX=Max(RightX,CurrentX) + Pull PC + + + + END diff --git a/s/vdu/vdugrafb b/s/vdu/vdugrafb new file mode 100644 index 0000000000000000000000000000000000000000..acf1d3cf0a38afe8c31caecc3c4d68162353c2b9 --- /dev/null +++ b/s/vdu/vdugrafb @@ -0,0 +1,1116 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.VduGrafB +; +; ARTHUR OPERATING SYSTEM - Vdu Drivers +; ======================= +; +; Vdu driver code - Graphics circle outline, fill, arc, sector & segment +; +; Author R C Manby +; Date 5.9.86 +; + +; ***************************************************************************** +; +; CircleOutline - Circle outline +; +; External routine +; +; in: ICursor is the centre of the circle +; NewPt is a point on the circumference +; +; out: R0-R11 corrupt +; + +CircleOutline ROUT + Push R14 + ADD R11, WsPtr, #GCsIX ; R0 := CentreX; R1 := CentreY + LDMIA R11, {R0-R3} ; R2 := NewPtX; R3 := NewPtY + BL GenCircleParm ; set up parm. block in R0-R7 + ADD R9, WsPtr, #CircleBlk ; R9 -> saved R0 + ADD R11, R9, #5*4 ; R11 -> saved R5 + STMIA R11, {R5-R7} ; save R5-R7 once and for all +10 + STMIA R9, {R0-R4} ; save R0-R4 before plotting pt + + SUB R10, R5, R0 ; upper left point + ADD R0, R5, R0 ; upper right point + ADD R1, R6, R1 + BL PlotPoint ; do upper right point + + CMP R10, R0 + MOVNE R0, R10 ; do upper left point + BLNE PlotPoint ; unless same as upper right + + LDMIA R9, {R0,R1} ; reload X, Y + CMP R1, #0 ; if yPnt=0, skip lower + BEQ %FT20 ; pixel pair + + LDMIA R11, {R5,R6} ; reload CentreX, CentreY + + SUB R10, R5, R0 ; lower left point + ADD R0, R5, R0 ; lower right point + SUB R1, R6, R1 + BL PlotPoint + + CMP R10, R0 + MOVNE R0, R10 ; do lower left point + BLNE PlotPoint ; unless same as lower right + +20 + LDMIA R9, {R0-R7} ; reload the parameter block + TEQ R0, #0 ; if xPnt<>0 + BLNE AdvCircleParm ; then step to next point + BNE %BT10 ; and go round again + + Pull PC ; else finish + +; ***************************************************************************** +; +; CircleFill - Circular area fill +; +; External routine +; +; in: ICursor is the centre of the circle +; NewPt is a point on the circumference +; +; out: R0-R11 corrupt +; + +CircleFill ROUT + Push R14 + ADD R11, WsPtr, #GCsIX ; centre is ICursor + LDMIA R11, {R0-R3} ; point is NewPt + BL GenCircleParm ; set up parameter block + ADD R11, WsPtr, #CircleBlk ; in R0-R6 +10 + STMIA R11, {R0-R7} ; save prior to line drawing + ADD R2, R5, R0 ; RightX = CentreX+xPnt + SUB R11, R6, R1 ; LowerY = CentreY-yPnt + + SUB R0, R5, R0 ; LeftX = CentreX-xPnt + ADD R1, R6, R1 ; UpperY = CentreY+yPnt + BL NewHLine ; draw upper slice + + CMP R11, R1 ; unless UpperY=LowerY + MOV R1, R11 + BLNE NewHLine ; do draw lower slice + + ADDS R11, WsPtr, #CircleBlk ; (C := 0) + LDMIA R11, {R0-R7} ; reload the parameter block +20 + TEQ R0, #0 + Pull PC, EQ ; finish if xPnt=0 + BL AdvCircleParm ; else step to next point + BCC %BT20 ; step until yPnt changes + B %BT10 ; do next slice + +; ***************************************************************************** +; +; CircleArc - Circular arc outline +; +; External routine +; +; in: OldCs is the centre of the circle +; ICursor is the start of the arc +; NewPt is the finishing point of the arc +; +; out: R0-R11 corrupt +; + +CircleArc ROUT + Push R14 + BL GenArcParmBlk + ADD R11, WsPtr, #CircleBlk + LDMIA R11, {R0-R7} ; reload the parameter block +10 + STMIA R11, {R0-R7} ; save prior to line drawing + BL Reflect + BL UpdateQuadrants + + LDRB R8, [WsPtr, #Quad0Draw] ; if LSBit set, plot this point + TST R8, #1 + LDRNE R0, [WsPtr, #ArcPoint0X] + LDRNE R1, [WsPtr, #ArcPoint0Y] + BLNE PlotPoint + + LDR R0, [WsPtr, #CircleBlk] ; if xPnt=0, ignore left pixel + CMP R0, #0 + BEQ %FT20 + + LDRB R8, [WsPtr, #Quad1Draw] ; if LSBit set, plot this point + TST R8, #1 + LDRNE R0, [WsPtr, #ArcPoint1X] + LDRNE R1, [WsPtr, #ArcPoint1Y] + BLNE PlotPoint +20 + LDR R0, [WsPtr, #(CircleBlk+4)] ; if yPnt=0, skip lower + CMP R0, #0 ; pixel pair + BEQ %FT30 + + LDRB R8, [WsPtr, #Quad3Draw] ; if LSBit set, plot this point + TST R8, #1 + LDRNE R0, [WsPtr, #ArcPoint3X] + LDRNE R1, [WsPtr, #ArcPoint3Y] + BLNE PlotPoint + + LDR R0, [WsPtr, #CircleBlk] ; if xPnt=0, ignore left pixel + CMP R0, #0 + BEQ %FT30 + + LDRB R8, [WsPtr, #Quad2Draw] ; if LSBit set, plot this point + TST R8,#1 + LDRNE R0, [WsPtr, #ArcPoint2X] + LDRNE R1, [WsPtr, #ArcPoint2Y] + BLNE PlotPoint +30 + ADD R11, WsPtr, #CircleBlk + LDMIA R11, {R0-R7} ; reload the parameter block + TEQ R0, #0 + Pull PC, EQ ; finish if xPnt=0 + + BL AdvCircleParm ; else step to next point + B %BT10 ; and go round again + +; ***************************************************************************** +; +; SegmentFill - Circular segment fill +; +; External routine +; +; in: OldCs is the centre of the circle +; ICursor is the start of the segment +; NewPt is the finishing point of the segment +; +; out: R0-R11 corrupt +; + +SegmentFill ROUT + Push R14 + BL GenArcParmBlk + BL GenSegParmBlk + ADD R11, WsPtr,#CircleBlk + LDMIA R11, {R0-R7} ; reload the parameter block +10 + STMIA R11, {R0-R7} ; save prior to line drawing + BL Reflect + BL UpdateQuadrants + LDR R0, [WsPtr, #Quad0StateChange] ; if any quadrant changes state + CMP R0, #0 + BLNE SegmentLineOn ; try starting segment line + + LDR R7, [WsPtr, #ArcPoint1X] ; limits of segment line + LDR R8, [WsPtr, #ArcPoint0X] + LDR R9, [WsPtr, #ArcPoint1Y] ; current scanline + LDR R11, [WsPtr, #UpperSegLinePtr] ; holds 0 or points at CLine2 + CMP R11, #0 + BLNE SegLineStep ; and advance if active + + LDR R0, [WsPtr, #ArcPoint1X] + LDR R1, [WsPtr, #ArcPoint1Y] + LDR R2, [WsPtr, #ArcPoint0X] + LDRB R3, [WsPtr, #Quad1Draw] + LDRB R4, [WsPtr, #Quad0Draw] + BL SegmentSlice + + LDR R0, [WsPtr, #(CircleBlk+4)] ; if yPnt=0, skip lower line + CMP R0, #0 + BEQ %FT15 + + LDR R7, [WsPtr, #ArcPoint2X] ; limits of segment line + LDR R8, [WsPtr, #ArcPoint3X] + LDR R9, [WsPtr, #ArcPoint3Y] ; current scanline + LDR R11, [WsPtr, #LowerSegLinePtr] ; holds 0 or points at CLine3 + CMP R11, #0 + BLNE SegLineStep ; and advance if active + + Swap R7,R8 + + LDR R0, [WsPtr, #ArcPoint3X] + LDR R1, [WsPtr, #ArcPoint3Y] + LDR R2, [WsPtr, #ArcPoint2X] + LDRB R3, [WsPtr, #Quad3Draw] + LDRB R4, [WsPtr, #Quad2Draw] + BL SegmentSlice +15 + LDR R0, [WsPtr, #Quad0StateChange] ; if any quadrant state changes + CMP R0, #0 ; left, kill segment line + BLNE SegmentLineOff + + ADD R11, WsPtr, #CircleBlk + LDMIA R11, {R0-R7} ; reload the parameter block +20 + TEQ R0, #0 + Pull PC, EQ ; finish if xPnt=0 + + BL AdvCircleParm ; else step to next point + BCS %BT10 ; do next slice + BCC %BT20 ; step until yPnt changes + +; ***************************************************************************** +; +; SegLineStep - Advance the segment line, limited to be within the circle +; +; Internal routine, called by SegmentFill +; +; in: R7 = left circleX +; R8 = right circleX +; R9 = current scanline +; R11 = pointer to Line (CLine2 or CLine3) (can't hold zero any more) +; + +SegLineStep ROUT + Push R14 + LDMIA R11, {R0-R6,R10} ; N.B. EndX is in R10 + CMP R4, #0 ; if line is horizontal + MOVEQ R9, R10 ; then line limits are in R0 & R10, + BEQ %FT50 ; R9 := R10 and branch + ; else find limits + + CMP R9, R1 ; advance line until currentY = circleY +20 + BLNE AdvLineParm ; (this usually takes one step) + CMP R9, R1 + BNE %BT20 + + MOV R9, R0 ; assume CurrentX is the left most point + + CMP R10, R0 ; if currentX=EndX + BEQ %FT40 ; then no need to advance line + + CMP R2, #0 ; else While bres >= 0 do AdvLineParm +30 + AdvLineParm_GE ; this leaves us furthest point on segment + CMP R10, R0 + BEQ %FT40 + CMP R2, #0 ; line for this scanline in R0 + BGE %BT30 +40 + STMIA R11, {R0-R4} ; update the line parameter block +50 + CMP R9, R0 ; R9 := LeftX + MOVGT R10, R9 + MOVGT R9, R0 + MOVLE R10, R0 ; R10 := RightX + + CMP R8, R10 ; force R10 into range R7..R8 + MOVLT R10, R8 + CMP R7, R10 + MOVGT R10, R7 + + CMP R7, R9 ; force R9 into range R7..R8 + MOVGT R9, R7 + CMP R8, R9 + MOVLT R9, R8 + + MOV R8, R10 + MOV R7, R9 + Pull PC + +; ***************************************************************************** +; +; SegmentSlice - Draw a slice of a circular segment +; +; Internal routine, called by SegmentFill +; +; in: R0 = circleX left +; R1 = circleY +; R2 = circleX right +; R3 = left quadrant control word (TopL or BotR) +; R4 = right quadrant control word (TopR or BotL) +; R7 = left most point of segment line for this slice +; R8 = right most point of segment line for this slice +; +; out: R0-R11 corrupt +; + +SegmentSlice ROUT + TST R3, #1 ; if both quadrants empty + TSTEQ R4, #1 ; or not at start of segment + MOVEQ PC, R14 ; then return + + TST R3, #1 ; if both quadrants to be filled + TSTNE R4, #1 ; or filling below segment line + BNE HLine ; then draw a slice of circle + +; 0 0 ; ...... +; 1 1 ; (----) + +; 0 1 ; \) ; /) ; \---) ; /---) +; 1 0 ; (/ ; (\ ; (---/ ; (---\ + +; From here on, all plotting decisions can be made from +; the LSBit of one quadrant field + + TST R3, #1 + MOVEQ R0, R7 ; Draw ---) + BEQ HLine + + MOV R2, R8 ; Draw (--- + B HLine + +; ***************************************************************************** +; +; SegmentLineOn - Try to start segment line +; +; Internal routine, called by SegmentFill +; + +SegmentLineOn ROUT + Push R14 + ; quadrant 0 + LDRB R10, [WsPtr, #Quad0StateChange] ; state change 0..2 + ADD R9, WsPtr, #ArcPoint0X ; address of point on circle + ADD R8, WsPtr, #CLine2 ; line block to use if starting + LDR R11, [WsPtr, #UpperSegLinePtr] ; 0 or ptr to active line + BL SegmentLineO5 + STRB R10, [WsPtr, #Quad0StateChange] ; new state change flag + + LDRB R10, [WsPtr, #Quad1StateChange] ; quadrant 1 + ADD R9, WsPtr, #ArcPoint1X + ADD R8, WsPtr, #CLine2 + BL SegmentLineO5 + STRB R10, [WsPtr, #Quad1StateChange] + STR R11, [WsPtr, #UpperSegLinePtr] ; unchanged/updated lineptr + + ; lower hemisphere + LDRB R10, [WsPtr, #Quad2StateChange] ; quadrant 2 + ADD R9, WsPtr, #ArcPoint2X + ADD R8, WsPtr, #CLine3 + LDR R11, [WsPtr, #LowerSegLinePtr] + BL SegmentLineO5 + STRB R10, [WsPtr, #Quad2StateChange] + + LDRB R10, [WsPtr, #Quad3StateChange] ; quadrant 3 + ADD R9, WsPtr, #ArcPoint3X + ADD R8, WsPtr, #CLine3 + BL SegmentLineO5 + STRB R10, [WsPtr, #Quad3StateChange] + STR R11, [WsPtr, #LowerSegLinePtr] + + Pull PC + +; ***************************************************************************** +; +; SegmentLineO5 - On state change, start segment line and update +; statechange - if line already active, do nothing +; +; Internal routine, called by SegmentLineOn +; +; in: R8 -> CLine(2..3) +; R9 -> ArcPoint(0..3)X +; R10 = Quad(0..3)StateChange +; 0 means no change +; 1 means one line hit +; 2 means both lines hit +; R11 = 0 or pointer to segment line +; +; out: R10 = updated Quad(0..3)StateChange +; R11 = 0 or points at newly created line +; + +SegmentLineO5 ROUT + CMP R10, #0 ; if state unchanged + MOVEQ PC, R14 ; then go home + + CMP R11, #0 ; else if segment line active + MOVNE PC, R14 ; then go home + + Push R14 ; else start the segment line + MOV R11, R8 + LDMIA R9, {R0,R1} ; run from point on circle + LDMIA R11, {R2,R3} ; to other end + BL GenLineParm + STMIA R11, {R0-R8} + MOV R10, R10, LSR #1 ; state1->state0, state2->state1 + Pull PC + +; ***************************************************************************** +; +; SegmentLineOff - Try to kill segment line +; +; Internal routine, called by SegmentFill +; +; in: R0 = stateflags for each quadrant +; +; out: R0 preserved +; R1 corrupted +; + +SegmentLineOff ROUT + MOV R1, #0 + TST R0, #&3 ; if statechange occurred in + TSTEQ R0, #&300 ; Quad0 or Quad1 + STRNE R1, [WsPtr, #UpperSegLinePtr] ; then kill upper segment line + + TST R0, #&30000 ; if statechange occured in + TSTEQ R0, #&3000000 ; Quad2 or Quad3 + STRNE R1, [WsPtr, #LowerSegLinePtr] ; then kill lower segment line + + MOVS PC, R14 + +; ***************************************************************************** +; +; SectorFill - Circular sector (pie) fill +; +; External routine +; +; in: OldCs is the centre of the circle +; ICursor is the start of the sector +; NewPt is the finishing point of the sector +; +; out: R0-R11 corrupt +; + +SectorFill ROUT + Push R14 + BL GenArcParmBlk + ADD R11, WsPtr, #CircleBlk + LDMIA R11, {R0-R7} ; reload the parameter block +SectorFi10 + STMIA R11, {R0-R7} ; save prior to line drawing + BL Reflect + BL UpdateQuadrants + + LDR R0, [WsPtr, #(CircleBlk+4)] ; if yPnt=0, panic + CMP R0, #0 + BEQ SectorFi40 + + LDR R0, [WsPtr, #ArcPoint1X] + LDR R1, [WsPtr, #ArcPoint1Y] + LDR R2, [WsPtr, #ArcPoint0X] + LDRB R3, [WsPtr, #Quad1Draw] + LDRB R4, [WsPtr, #Quad0Draw] + BL SectorSlice + + LDR R0, [WsPtr, #ArcPoint3X] + LDR R1, [WsPtr, #ArcPoint3Y] + LDR R2, [WsPtr, #ArcPoint2X] + LDRB R3, [WsPtr, #Quad3Draw] + LDRB R4, [WsPtr, #Quad2Draw] + BL SectorSlice + +SectorFi20 + ADD R11, WsPtr, #CircleBlk + LDMIA R11, {R0-R7} ; reload the parameter block +SectorFi30 + TEQ R0, #0 + Pull PC, EQ ; finish if xPnt=0 + BL AdvCircleParm ; else step to next point + BCS SectorFi10 ; do next slice + BCC SectorFi30 ; step until yPnt changes + +SectorFi40 + LDR R0, [WsPtr, #CLine0Near] ; equal to CLine1NearX & + LDR R1, [WsPtr, #ArcPoint0Y] ; centre of circle + LDR R3, [WsPtr, #CLine0Far] + LDR R4, [WsPtr, #CLine1Far] + + Greatest R2, R0,R3 ; draw from rightmost of CLine0, Cline1 + Greatest R2, R2,R4 + + Least R0, R0,R3 ; to left most of CLine0, Cline1 + Least R0, R0,R4 + + LDR R3, [WsPtr, #Quad0Draw] ; all 4 drawing control bytes + + TST R3, #&00000001 ; if Quad0 or + TSTEQ R3, #&01000000 ; Quad3 fills against circle + LDRNE R2, [WsPtr, #ArcPoint0X] ; then override R2 + + TST R3, #&00000100 ; If Quad1 or + TSTEQ R3, #&00010000 ; Quad2 fills against circle + LDRNE R0, [WsPtr, #ArcPoint1X] ; then override R0 + + BL NewHLine ; draw the line (sorted coords) + B SectorFi20 + + +; +; Internal subroutine for sector (pie) fills +; +; On entry, R0 - circleX left +; R1 - circleY +; R2 - circleX right +; R3 - left quadrant control word (TopL or BotR) +; R4 - right quadrant control word (TopR or BotL) +; +; On exit, R0-R11 corrupt +; +SectorSlice + CMP R4,#&57 ; (--//) + LDREQ R3,[WsPtr,#CLine0Far] + LDREQ R4,[WsPtr,#CLine1Near] + BEQ DoubleHLine + + CMP R3,#&73 ; (\\--) + LDREQ R3,[WsPtr,#CLine0Near] + LDREQ R4,[WsPtr,#CLine1Far] + BEQ DoubleHLine + + CMP R4,#&07 ; (-\/-) + CMPEQ R3,#&03 + LDREQ R3,[WsPtr,#CLine0Near] + LDREQ R4,[WsPtr,#CLine1Near] + BEQ DoubleHLine + + CMP R4,#&07 ; /-) + LDREQ R0,[WsPtr,#CLine1Near] + BEQ HLine + CMP R3,#&03 ; (-\ + LDREQ R2,[WsPtr,#CLine0Near] + BEQ HLine + + CMP R4,#&3A ; /-/ + LDREQ R0,[WsPtr,#CLine1Near] + LDREQ R2,[WsPtr,#CLine0Far] + BEQ HLine + + CMP R3,#&1E ; \-\ + LDREQ R0,[WsPtr,#CLine1Far] + LDREQ R2,[WsPtr,#CLine0Near] + BEQ HLine + + CMP R4,#1 ; ...--) + MOVLT PC,Link ;Nothing in either quadrant + LDRGT R2,[WsPtr,#CLine0Far] ; ...--/ + CMP R3,#1 ; (--... + LDRGT R0,[WsPtr,#CLine1Far] ; \--... + B HLine +; +; +; +;------------------------------------------------------------------------------ +; +; Reflect - Generate four point on a circle by +; ======= reflection about its centre +; +; On entry, R0..R7 hold a circle parameter block +; On exit, R0 (X), R1 (Y) point in Quadrant0 +; R2 (X), R3 (Y) point in Quadrant1 +; R7 (X), R8 (Y) point in Quadrant2 +; R9 (X), R10 (Y) point in Quadrant3 +; R11 points at ArcPoint0X +; +; ArcPoint(0..3) updated +; +; Format of a circle control block +; R0 - xPnt (CurrentX - relative to centre) +; R1 - yPnt (CurrentY - relative to centre) +; R2 - sum (Bres) +; R3 - upcnt +; R4 - downcnt +; R5 - CentreX +; R6 - CentreY +; R7 - Aspect (pixel shape : 0 square, 1 horz rect, 2 vert rect) +; +Reflect + ADD R9,R5,R0 ;Quad 3 CentreX+xPnt ;Calculate all 4 points + SUB R10,R6,R1 ; CentreY-yPnt ; by reflection about centre + + SUB R7,R5,R0 ;Quad 2 CentreX-xPnt + SUB R8,R6,R1 ; CentreY-yPnt + + SUB R2,R5,R0 ;Quad 1 CentreX-xPnt + ADD R3,R6,R1 ; CentreY+yPnt + + ADD R0,R5,R0 ;Quad 0 CentreX+xPnt + ADD R1,R6,R1 ; CentreY+yPnt + + ADD R11,WsPtr,#ArcPoint0X + STMIA R11,{R0,R1, R2,R3, R7,R8, R9,R10} ;And store the lot for later on + + MOVS PC,Link +; +; +; +; update lines & quadrant data +; +; use R9 as offset from WsPtr to ArcPoint(0..3)X +; use R10 as offset from WsPtr to QuadControl(0..3) +; use R11 as address of line parameter block(0..1) +; +; +UpdateQuadrants + SaveRetAdr + + MOV R0,#0 + STR R0,[WsPtr,#Quad0StateChange] ;Clear flags for each quadrant + + LDR R0,[WsPtr,#Quad0Control] ;Update the 4 'drawing' + STR R0,[WsPtr,#Quad0Draw] ; control bytes + + ;Start by looking at quadrant 0 + ADD R10,WsPtr,#Quad0Control ;Address of control byte + ADD R9,WsPtr,#ArcPoint0X ;Address of point on circle + BL UpdateQuadr10 + + ADD R10,R10,#(Quad1Control-Quad0Control) ;Quadrant 1 + ADD R9,R9,#(ArcPoint1X-ArcPoint0X) + BL UpdateQuadr10 + + ADD R10,R10,#(Quad1Control-Quad0Control) ;Quadrant 2 + ADD R9,R9,#(ArcPoint1X-ArcPoint0X) + BL UpdateQuadr10 + + ADD R10,R10,#(Quad1Control-Quad0Control) ;Quadrant 3 + ADD R9,R9,#(ArcPoint1X-ArcPoint0X) + BL UpdateQuadr10 + + Return + + +UpdateQuadr10 + LDRB R0,[R10] ;Get control block for quadrant + TST R0,#&2 ;If 0 or 1 + MOVEQ PC,Link ; then nothing to do + + SaveRetAdr ; else update the line + + LDMIA R9,{R7,R8} ;Point on circle in this quad + + TST R0,#4 + ADDEQ R11,WsPtr,#CLine0 ;Load parm blk for line(0/1) + ADDNE R11,WsPtr,#CLine1 + + LDMIA R11,{R0,R1,R2,R3,R4,R5,R6} ;EndX,EndY (R7,R8) not needed + BL ArcLineStep + STMIA R11,{R0,R1,R2,R3,R4,R5,R6,R8} ;Update the changes, EndX + ; used for NearX + + CMP R7,#1 ; 'change state' flag + MOV R7,#1 ;Convert to one line hit + STRGEB R7,[R10,#(Quad0StateChange-Quad0Control)] + + LDRB R0,[R10] ;Get control block for quadrant and look at + MOV R0,R0,LSR #3 ; next control field + STRGEB R0,[R10] ;If 'change state' write back next field + + ;If outside circle + TSTEQ R0,#1 ; or changing into a + STRGTB R0,[R10,#(Quad0Draw-Quad0Control)] ; plotting state update + ; drawing control byte + + TST R0,#2 ;If new field doesnt advance a + Return EQ ; line then quit + ; else update second line + Push R0 + + LDMIA R9,{R7,R8} ;Point on circle in this quad + + TST R0,#4 + ADDEQ R11,WsPtr,#CLine0 ;Load parm blk for line(0/1) + ADDNE R11,WsPtr,#CLine1 + + LDMIA R11,{R0,R1,R2,R3,R4,R5,R6} ;EndX,EndY (R7,R8) not needed + BL ArcLineStep + STMIA R11,{R0,R1,R2,R3,R4,R5,R6,R8} ;Update the changes, EndX + ; used for NearX + + CMP R7,#1 ; 'change state' flag + MOV R7,#2 ;Convert to both lines hit + STRGEB R7,[R10,#(Quad0StateChange-Quad0Control)] + + Pull R0 ;Use earlier value instead of reloading control block, + ; as whally lines (dy/dx = 0/0) blewup when 2nd line + ; terminated before 1st line. This case should not + ; now get through, but you never now. + + MOV R0,R0,LSR #3 ;Next field in control field + STRGEB R0,[R10] ;If 'changing state' write this back + + STRGTB R0,[R10,#(Quad0Draw-Quad0Control)] ; and update drawing + ; control byte + Return +; +; +; +; ArcLineStep - Step line parameter block checking for interception +; =========== with circle. +; +; Return first ('near') and last ('far') points of line +; that fall on this scanline, limiting 'far' to the point on +; the circle if interception occurs. +; +; On entry, R0..R6 hold a line parameter block (EndX,EndY are not loaded) +; +; Format of a line control block +; R0 - StartX (CurrentX) +; R1 - StartY (CurrentY) +; R2 - Bres +; R3 - DeltaX +; R4 - DeltaY +; R5 - StepX (+1/-1) (Equv bit6 of Sign in 6502 version) +; R6 - StepY (+1/-1) (Equv bit7 of Sign in 6502 version) +; (R7 - EndX Not used in this routine,) +; (R8 - EndY so not passed in) +; +; R7,R8 CircleX,CircleY +; +; On exit, R0 (X), R1 (Y), R2 (bres) updated +; R7 0/1/2 for within/on/outside circle +; R8 nearX +; +; +; R9,R10,R11 unused +; +ArcLineStep + SaveRetAdr + + CMP R8,R1 ;Advance line until CurrentY = CircleY +ArcLineSt10 + BLNE AdvLineParm + CMP R8,R1 ; {this usually takes one step} + BNE ArcLineSt10 + + MOV R8,R0 ;This point is nearX + ; ie the first point on this scanline + + CMP R0,R7 ;If (CurrentX=CircleX) then farX is on circle + TEQNE R5,PC ;If ((CurrentX-CircleX) EOR StepX is +ve) + ;then farX is outside circle + MOVPL R0,R7 ; limit farX to circleX + MOVPL R7,#2 ; set change flag =2 for outside + MOVEQ R7,#1 ; =1 for on circle + Return PL ; and return + + + CMP R2,#0 ;While bres >= 0 and within circle AdvLineParm +ArcLineSt20 ; this leaves us with farX,farY in R0,R1 + AdvLineParm_GE + + CMP R0,R7 ;If (CurrentX=CircleX) then farX is on circle + MOVEQ R7,#1 ; set change flag + Return EQ ; and return + ; else within circle + + CMP R2,#0 ;If y about to change, return farX,farY + BGE ArcLineSt20 ; else loop back to step the line + MOV R7,#0 + Return +; +; +; +; Assumes R9, R10 & R11 are not corrupted over calls to GenLineParm +; +; +GenArcParmBlk + SaveRetAdr + + ADD R11,WsPtr,#OldCsX ;Build parm block for a circle + LDMIA R11,{R0,R1,R2,R3} ; centre OldCs, point on + BL GenCircleParm ; circumference in ICursor + + ADD R11,WsPtr,#CircleBlk + STMIA R11,{R0,R1,R2,R3,R4,R5,R6,R7} + + ADD R10,WsPtr,#CLine0 + ADD R11,WsPtr,#OldCsX + + LDMIA R11!,{R0,R1,R2,R3} ;CLine0 gives start of arc + BL GenLineParm ; (OldCs->ICursor) + STMIA R10!,{R0,R1,R2,R3,R4,R5,R6,R7,R8} +; +; Use StepX and StepY for 'start of arc' line to form the beginnings of +; an index into the arc control block table +; StepX & StepY each hold +1 or -1 and the value left in R9 is +; +; R9 | Quad +; ------+------ +; 0000 | 0 +; 0100 | 1 +; 1100 | 2 +; 1000 | 3 +; +; + AND R5,R5,#&4 ; + AND R6,R6,#&8 ; See above for details + ORR R9,R6,R5 ; + + LDMIA R11,{R2,R3} ;CLine1 gives end line of arc + ; (OldCs->NewPt) + + CMP R0,R2 ;If OldCs=NewPt + CMPEQ R1,R3 ; use OldCs->(NewPtX+1,NewPtY) + ADDEQ R2,R2,#1 ; for compatability with Master + + BL GenLineParm + STMIA R10,{R0,R1,R2,R3,R4,R5,R6,R7,R8} + + AND R5,R5,#&4 + AND R6,R6,#&8 + ORR R6,R6,R5 ; 'end of arc' + + CMP R9,R6 ;If start and end quadrants different + ORRNE R9,R9,R6,LSL #2 ; then index = start OR (end <<2) + BNE GenArcPar10 ; and branch + + ;else special case code for index, based + ; on gradients of line + + LDR R7,[WsPtr,#(CLine0+12)] ; DeltaX0.DeltaY1 + LDR R8,[WsPtr,#(CLine1+16)] + MUL R0, R7, R8 + + LDR R7,[WsPtr,#(CLine0+16)] ; DeltaX1.DeltaY0 + LDR R8,[WsPtr,#(CLine1+12)] + MUL R9, R7, R8 + + CMP R0,R9 ;For gradients <,>,= + ORRLT R9,R6,#&40 ; generate index into table + ORRGT R9,R6,#&50 + ORREQ R9,R6,R6,LSL #2 + +GenArcPar10 + ADR R0,GenArcTb ; GenArcTb + + LDR R0,[R0,R9] + STR R0,[WsPtr,#Quad0Control] ;Setup all FOUR control BYTEs + + Return + + + +; +; +; 00 000 000 &00 no points to be plotted +; 00 000 001 &01 all points to be plotted +; 00 001 x10 &0A,0E plot nothing until line x hits circle then start plotting +; 00 000 x11 &03,07 plot points until line x hits circle then stop +; 00 y11 x10 &3A,1E plot points only between line x and line y +; 01 y10 x11 &73,57 plot points from x axis to line x, then line y to y axis +; +; +GenArcTb + & &0000003A ; 0->0 (short arc) + & &01010307 ; 1->0 + & &03000007 ; 3->0 + & &010A0007 ; 2->0 + + & &00000E0A ; 0->1 + & &00001E00 ; 1->1 (short arc) + & &03000E01 ; 3->1 + & &010A0E01 ; 2->1 + + & &0E01010A ; 0->3 + & &0E010300 ; 1->3 + & &1E000000 ; 3->3 (short arc) + & &0E0A0000 ; 2->3 + + & &0007010A ; 0->2 + & &00070300 ; 1->2 + & &03070101 ; 3->2 + & &003A0000 ; 2->2 (short arc) + + + & &01010157 ; 0->0 (long arc) grad line0 > grad line1 + & &00001E00 ; 1->1 (short arc) + & &1E000000 ; 3->3 (short arc) + & &01570101 ; 2->2 (long arc) + + & &0000003A ; 0->0 (short arc) grad line0 < grad line 1 + & &01017301 ; 1->1 (long arc) + & &73010101 ; 3->3 (long arc) + & &003A0000 ; 2->2 (short arc) +; +; +; + + +GenSegParmBlk + SaveRetAdr + + ADD R11,WsPtr,#CLine1 ;Get all line data except EndX,EndY + LDMIA R11,{R0,R1,R2,R3,R4,R5,R6} + + LDR R11,[WsPtr,#AspectRatio] ;Frigging non square frigging pixels + ; 0=Sq, 1=horz, 2=vert + CMP R11,#1 + MOVEQ R3,R3,LSL #1 ;If horz, scale up deltaX + MOVGT R4,R4,LSL #1 ;If vert, scale up deltaY + + [ {TRUE} + LDR R8, [WsPtr, #CircleRadSquare] ; R8 = r2 + MUL R9, R3, R3 ; R9 = DX2 + MUL R10, R4, R4 ; R10 = DY2 + ADD R11, R9, R10 ; R11 = R2 + + MOV R3, R10 + BL DoubleMulDivSquareRoot + MOV R4, R3 ; R4 = dy + + MOV R3, R9 + BL DoubleMulDivSquareRoot ; R3 = dx + | + MUL R9,R3,R3 ;R9 := Square(deltaX) + MOV R2,R9 ;R2 := Square(deltaX) + + LDR R8,[WsPtr,#CircleRadSquare] + MUL R3,R9,R8 ;R3 := Square(radius) * Square(deltaX) + + MUL R9,R4,R4 ;R9 := Square(deltaY) + ADD R2,R2,R9 ;R2 := Square(deltaX) + Square(deltaY) + + MUL R10,R9,R8 ;R10 := Square(radius) * Square(deltaY) + + MOV R9,R2 +; *****Change made by DJS +; Use new DivRem macro, not old DIVREM +; Original code was: +; DIVREM R7,R10,R9, R8 ;R7 := (rad^2 * deltaY^2)/R2 + DivRem R7,R10,R9, R8 ;R7 := (rad^2 * deltaY^2)/R2 +; *****End of change made by DJS + BL SquareRoot ;Iy left in R8 + MOV R4,R8 + +; *****Change made by DJS +; Use new DivRem macro, not old DIVREM +; Original code was: +; DIVREM R7,R3,R2, R8 ;R7 := (rad^2 * deltaX^2)/R2 + DivRem R7,R3,R2, R8 ;R7 := (rad^2 * deltaX^2)/R2 +; *****End of change made by DJS + BL SquareRoot ;Ix left in R8 + MOV R3,R8 + ] + + LDR R11,[WsPtr,#AspectRatio] ; 0=Sq, 1=horz, 2=vert + CMP R11,#1 + MOVEQ R3,R3,LSR #1 ;If horz, scale down deltaX + MOVGT R4,R4,LSR #1 ;If vert, scale down deltaY + + CMP R5,#0 ;If StepX >= 0 + ADDGE R0,R0,R3 ; then R0 := StartX+R3 + SUBLT R0,R0,R3 ; else R0 := StartX-R3 + + CMP R6,#0 ;If StepY >= 0 + ADDGE R1,R1,R4 ; then R1 := StartY+R4 + SUBLT R1,R1,R4 ; else R1 := StartY-R4 + +; +; R0,R1 is the intercept of CLine1 and the circle +; so, segment line runs from here to endpoint of CLine0 +; + + LDR R2,[WsPtr,#CLine0EndX] + LDR R3,[WsPtr,#CLine0EndY] + + CompSwapT R0,R1, R2,R3, R4 ; Order coords + +; +; If segment line crosses X axis +; then initialise both upper & lower segment lines +; else leave endpoints for later use +; + + LDR R4,[WsPtr,#Quad0Control] ;All 4 control bytes + ORR R4,R4,R4,LSR #8 ;If bit1 =0, not in upper hemisphere + ;If bit9 =0, not in lower hemisphere + AND R4,R4,R4,LSR #16 + TST R4,#2 ;If bit1 =0 + BEQ GenSegParmB10 ; then line does not cross X axis + + ; else start both CLine2 & CLine3 + ; running, so.. + + BL GenLineParm ;Initialise CLine2 as the + ADD R11,WsPtr,#CLine2 ; upper hemisphere segment line + STMIA R11,{R0,R1,R2,R3,R4,R5,R6,R7,R8} + STR R11,[WsPtr,#UpperSegLinePtr] + + MOV R2,R0 ;Run CLine3, in the opposite + MOV R3,R1 ; direction for use as the + MOV R0,R7 ; lower hemisphere segment line + MOV R1,R8 + BL GenLineParm + ADD R11,WsPtr,#CLine3 + STMIA R11,{R0,R1,R2,R3,R4,R5,R6,R7,R8} + STR R11,[WsPtr,#LowerSegLinePtr] + + Return + +GenSegParmB10 ;Line does not cross X axis, so.. + ADD R11,WsPtr,#CLine2 ;Upper hemisphere segment line, runs + STMIA R11,{R2,R3} ; to R2,R3 (if it runs at all) + + ADD R11,WsPtr,#CLine3 ;Lower hemisphere segment line, runs + STMIA R11,{R0,R1} ; to R0,R1 (if it runs at all) + + MOV R11,#0 ;Both lines inactive + STR R11,[WsPtr,#UpperSegLinePtr] + STR R11,[WsPtr,#LowerSegLinePtr] + + Return + +; ***************************************************************************** +; +; DoubleMulDivSquareRoot - Compute SQR(a*b/c) in double precision +; +; in: R3 = a +; R8 = b +; R11 = c +; +; out: R3 = result +; R2, R7 corrupted +; + +DoubleMulDivSquareRoot ROUT + Push "R8-R11,R14" + MOV R2, R3, LSR #16 ; R2 = ah + EOR R7, R3, R2, LSL #16 ; R7 = al + MOV R9, R8, LSR #16 ; R9 = bh + EOR R10, R8, R9, LSL #16 ; R10 = bl + + MUL R3, R7, R10 ; R3 = al.bl + MUL R14, R7, R9 ; R14 = al.bh + MLA R14, R10, R2, R14 ; R14 = al.bh + ah.bl + MUL R8, R2, R9 ; R8 = ah.bh + + ADDS R3, R3, R14, LSL #16 ; R3 = lower 32 bits of a.b + ADC R8, R8, R14, LSR #16 ; R8 = upper 32 bits of a.b + +; now do divide of a.b by c +; we know that a.b < 2^61, so no problem with top bit of a.b + + MOV R9, R11 ; R9 = low 32 bits of shifted c + MOV R10, #0 ; R10 = hi 32 bits of shifted c +10 + ADDS R9, R9, R9 ; shift R9,R10 left one place + ADC R10, R10, R10 + CMP R9, R3 ; compare R9,R10 with a.b + SBCS R14, R10, R8 + BCC %BT10 ; if lower then loop + + MOV R7, #0 ; zero result +20 + CMP R3, R9 ; if a.b >= R9,R10 + SBCS R14, R8, R10 + SUBCS R3, R3, R9 ; then a.b -:= R9,R10 + MOVCS R8, R14 + ADC R7, R7, R7 ; shift result up with new bit + MOVS R10, R10, LSR #1 ; shift R9,R10 right one bit + MOV R9, R9, RRX + BNE %BT20 ; for termination, R10 = 0 + CMP R9, R11 ; and R9 < R11 + BCS %BT20 + + BL SquareRoot ; in: R7 = arg + ; out: R8 = result, R9-R11 corrupt + MOV R3, R8 + Pull "R8-R11,PC" + + + + END diff --git a/s/vdu/vdugrafc b/s/vdu/vdugrafc new file mode 100644 index 0000000000000000000000000000000000000000..a088b7839bab07d57e1cc3b53248453c667583e2 --- /dev/null +++ b/s/vdu/vdugrafc @@ -0,0 +1,441 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.VduGrafC +; +; ARTHUR OPERATING SYSTEM - Vdu Drivers +; ======================= +; +; Vdu driver code - Ellipse outline & fill +; +; Author R C Manby +; Date 29.9.86 +; + + + + +; +; +; +;------------------------------------------------------------------------------ +; +; EllipseOutline +; ============== +; +; On entry, OldCs is centre of the ellipse +; ICursor is a point giving the width of the ellipse +; NewPt is the highest/lowest point on the ellipse +; +; On exit, R0..R11 corrupt +; +EllipseOutline + SaveRetAdr + + BL GenEllParm + B EllipseOut20 +EllipseOut10 + BL AdvEllParm +EllipseOut20 + ; Registers hold + ; R4 , R5 , R6 , R7 , R8 , R9 , R10 + ; ellY,prevL,prevR,thisL,thisR,nextL,nextR + + MOV R0,R7 ;Left line runs from thisL rightwards + MOV R1,R4 + Greatest R3,R5,R9 + SUB R3,R3,#1 + Greatest R3,R3,R7 ; to max(thisL, max(prevL-1,nextL-1)) + + MOV R2,R8 ;Right line runs from thisR leftwards + Least R4,R6,R10 + ADD R4,R4,#1 + Least R4,R4,R8 ; to min(thisR, min(prevR+1,nextR+1)) + + BL EllDoubleHLine ;Any overlap handled by EllDoubleHLine + + LDR R0,[WsPtr,#EllBlkSliceCnt] + CMP R0,#0 + BGE EllipseOut10 + B EllipseFi30 ;Use common code with ellipse fill for + ; last scanline +; +; +; +; +;------------------------------------------------------------------------------ +; +; EllipseFill +; =========== +; +; On entry, OldCs is centre of the ellipse +; ICursor is a point giving the width of the ellipse +; NewPt is the highest/lowest point on the ellipse +; +; On exit, R0..R11 corrupt +; +EllipseFill + SaveRetAdr + + BL GenEllParm + B EllipseFi20 +EllipseFi10 + BL AdvEllParm +EllipseFi20 + ; Registers hold + ; R4 , R5 , R6 , R7 , R8 , R9 , R10 + ; ellY,prevL,prevR,thisL,thisR,nextL,nextR + + MOV R0,R7 ;Draw slice thisL -> thisR + MOV R1,R4 + MOV R2,R8 + + BL EllHLine + + LDR R0,[WsPtr,#EllBlkSliceCnt] + CMP R0,#0 + BGE EllipseFi10 +EllipseFi30 + LDR R0,[WsPtr,#EllNextL] ;Last slice nextL -> nextR + LDR R1,[WsPtr,#EllBlkEllY] + ADD R1,R1,#1 + LDR R2,[WsPtr,#EllNextR] + + BL EllHLine + + Return +; +; +; +; EllHLine - Draw a slice then reflect around ellipse origin +; ======== +; +; On entry, R0 (X) - Left point of line +; R1 (Y) - Y ordinate of line +; R2 (X) - Right point of line +; +; On exit, R0..R11 corrupt +; +EllHLine + SaveRetAdr + + LDR R3,[WsPtr,#OldCsX] ;All points relative to OldCs + LDR R4,[WsPtr,#OldCsY] + + ADD R11,WsPtr,#EllHLineWs ;Save points given plus centre of + STMIA R11,{R0-R4} ; ellipse for later use + + ADD R0,R3,R0 ;OldCsX + LeftX + ADD R1,R4,R1 ;OldCsY + Y + ADD R2,R3,R2 ;OldCsX + RightX + + BL NewHLine ;Draw top slice + + ADD R11,WsPtr,#EllHLineWs + LDMIA R11,{R3-R7} + + CMP R4,#0 ;If EllY = 0 + Return EQ ; then quit to prevent double plotting + ; else reflect around ellipse origin + + SUB R0,R6,R5 ;OldCsX - RightY + SUB R1,R7,R4 ;OldCsY - Y + SUB R2,R6,R3 ;OldCsX - LeftY + + BL NewHLine + + Return +; +; +; +; EllDoubleHLine +; ============== +; +; On entry, R0 (X) - Left most point +; R1 (Y) - y ordinate of line +; R2 (X) - Right most point +; R3 (X) - end of left most line +; R4 (X) - start of right most line +; +EllDoubleHLine + CMP R3,R4 ;If end of left line overlaps + ; start of right + BGE EllHLine ;then draw and reflect R0->R2 + ;else + SaveRetAdr + + ADD R11,WsPtr,#EllDoubleHLineWs + STMIA R11,{R0-R4} + + MOV R2,R3 ;Draw and reflect R0->R3 + BL EllHLine + + ADD R11,WsPtr,#EllDoubleHLineWs + LDMIA R11,{R0-R4} + MOV R0,R4 + BL EllHLine ;Draw and reflect R4->R2 + + Return +; +; +; +;------------------------------------------------------------------------------ +; +; GenEllParm - Generate a control block for an ellipse +; ========== +; +; On entry, OldCs is centre of the ellipse +; ICursor is a point giving the width of the ellipse +; NewPt is the highest/lowest point on the ellipse +; +; On exit, EllBlk holds the ellipse parameter block +; +; EllThisL..EllNextR setup +; +; R4 - EllY +; R5, R6 - prevL,prevR +; R7, R8 - thisL,thisR +; R9, R10 - nextL,nextR +; +; +; Format of ellipse parameter block +; +; Var R0 - SliceCnt count of slices remaining +; R1 - EllYSqr square of current slice height +; R2 - OddNo used to give next EllYSqr value +; R3 - XOffset [bb.bb] offset in X dirn along shear line +; R4 - EllY +; Const R5 - ShearX [bb.bb] shear factor per scanline +; R6 - SliceX [0bb.b] axis ratio +; R7 - MaxYSqr [bbbb] +; +; +; +GenEllParm + SaveRetAdr + + ADD R11,WsPtr,#OldCsX + LDMIA R11,{R0,R1, R2,R3, R4,R5} ;OldCs, ICursor, NewPt + + SUBS R6,R2,R0 + RSBLT R6,R6,#0 ;R6 := ABS(width of slice) + ;R6 is sliceX (ie maxwidth) + SUBS R7,R5,R1 + MOV R8,R7 + RSBLT R7,R7,#0 ;R7 := ABS(height of ellipse) + +; +; Leave R0,R1,R2 intact upto here +; R6 is ABS(width of slice) + + BEQ EllipseZeroHeight ;If NewPtY=OldCsY draw a single line + + SUBS R5,R4,R0 + EOR R8,R8,R5 + RSBLT R5,R5,#0 ;R5 := ABS(shear at top of ellipse) + +; +; R5 holds shear in x dirn +; R6 holds width +; R7 holds height (also shearY) +; R8 sign bit is slope of shearline +; + + MOV R0,R7 ;Setup SliceCnt + + ;MOV R7,R0 ;Div R5,R5,R0 using R7,R9,R10 + MOV R9,R5,LSL #16 +; *****Change made by DJS +; Use new DivRem macro, not old DIVREM +; Original code was: +; DIVREM R5,R9,R7,R10 ;R5 := totalshear/ellipseheight + DivRem R5,R9,R7,R10 ;R5 := totalshear/ellipseheight +; *****End of change made by DJS + + ;BIC R5,R5,#&FF ;Slugg accuracy for compatability? + + CMP R8,#0 + RSBLT R5,R5,#0 ;Correct for negative slope + + MOV R7,R0 ;Div R6,R6,R0 using R7,R9,R10 + MOV R9,R6,LSL #8 +; *****Change made by DJS +; Use new DivRem macro, not old DIVREM +; Original code was: +; DIVREM R6,R9,R7,R10 ;R6 := slicewidth/ellipseheight + DivRem R6,R9,R7,R10 ;R6 := slicewidth/ellipseheight +; *****End of change made by DJS + + +; R5 holds shear per scanline +; R6 ratio of ellipse axis + + MUL R7,R0,R0 ;MaxYSqr + + MOV R1,#0 ;EllYSqr + MOV R2,#1 ;Oddno + MOV R3,#0 ;XOffset + MOV R4,#-2 ;EllY + + ADD R11,WsPtr,#EllBlk + STMIA R11,{R0-R7} + + BL AdvEllP20 ;Start by calculating first two slices + STR R9,[WsPtr,#EllThisL] ;Limits passed back in R9,R10 + STR R10,[WsPtr,#EllThisR] + + BL AdvEllP20 + + ADD R11,WsPtr,#EllThisL + LDMIA R11,{R7,R8} + + RSB R5,R10,#0 ;prevL := -nextR + RSB R6,R9,#0 ;prevR := -nextL + + ; Stretch slice if disconnected + + Least R7,R7,R6 ; thisL := min(thisL,prevR) + Least R7,R7,R10 ; thisL := min(thisL,nextR) + + Greatest R8,R8,R5 ; thisR := max(thisR,prevL) + Greatest R8,R8,R9 ; thisR := max(thisR,nextL) + + STMIA R11,{R7,R8,R9,R10} + + Return ; On return, registers hold + ; R4 , R5 , R6 , R7 , R8 , R9 , R10 + ; ellY,prevL,prevR,thisL,thisR,nextL,nextR +; +; +; +; EllipseZeroHeight - Draw a single line, no pips +; ================= +; +; On entry, R0 (X), R1 (Y) holds centre of ellipse +; R6 is ABS(width of slice/2) +; +EllipseZeroHeight + + ADD R2,R0,R6 + SUB R0,R0,R6 + + Pull Link ;Return address into ellipse code + Pull Link ;Return address to whoever called + ; ellipses + + B NewHLine ;Sorted coords + ;This will return to whoever called + ; the ellipse code +; +; +; +;------------------------------------------------------------------------------ +; +; AdvEllParm +; ========== +; +; On entry, R11 points to ellipse parameter block +; +; On exit, EllBlk, EllThisL..EllNextR updated +; +; R4 - EllY +; R5, R6 - prevL,prevR +; R7, R8 - thisL,thisR +; R9, R10 - nextL,nextR +; +; +; Format of ellipse parameter block +; +; Var R0 - SliceCnt count of slices remaining +; R1 - EllYSqr square of current slice height +; R2 - OddNo used to give next EllYSqr value +; R3 - XOffset [bb.bb] offset in X dirn along shear line +; R4 - EllY +; Const R5 - ShearX [bb.bb] shear factor per scanline +; R6 - SliceX [0bb.b] axis ratio +; R7 - MaxYSqr [bbbb] +; +; +; +AdvEllParm + SaveRetAdr + + BL AdvEllP20 ;Advance scanline + ; On return, registers hold + ; R4 , R9 , R10 + ; ellY, nextL,nextR + + ;Shuffle points + ;R9/R10 -> nextLR + ;nextLR -> thisLR - stretch if disconnected + ;thisLR -> prevLR + + ADD R11,WsPtr,#EllThisL + LDMIA R11,{R5,R6, R7,R8} + ; Stretch slice if disconnected + Greatest R8,R8,R9 ; thisR := max(thisR,nextL) + Least R7,R7,R10 ; thisL := min(thisL,nextR) + + STMIA R11,{R7,R8, R9,R10} + Return ; R4 , R5 , R6 , R7 , R8 , R9 , R10 + ; ellY,prevL,prevR,thisL,thisR,nextL,nextR +; +; +; +; +; +; +; +AdvEllP20 + SaveRetAdr + + ADD R11,WsPtr,#EllBlk + LDMIA R11,{R0-R7} ;Load ellipse parm block + + SUB R7,R7,R1 ;Sqroot(MaxYSqr-EllYSqr) + MOV R11,#24 ;Use 24 instead of 16 iterations in the + BL SquareRootAlt ; SquareRoot routine, gives result [0bb.b] + + ;Mult by axis ratio + MOV R7,R6 ; [0bb.b] * [0bb.b] + MUL R9,R7,R8 ; Result in R9 is [bb.bb] + + ADD R10,R3,R9 ;NextR [bb.bb] + ADD R10,R10,#&8000 + MOV R10,R10,ASR #16 ; [00bb] + + SUB R9,R3,R9 ;NextL [bb.bb] + ADD R9,R9,#&8000 + MOV R9,R9,ASR #16 ; [00bb] + + ADD R1,R1,R2 ;New value of EllYSqr by adding oddno + ADD R2,R2,#2 ;Next oddno in sequence + + ADD R3,R3,R5 ;XOffSet for next scanline + SUB R0,R0,#1 ;Decrement count of slices left + ADD R4,R4,#1 ;Increment EllY + + ADD R11,WsPtr,#EllBlk + STMIA R11,{R0,R1,R2,R3,R4} ;Save updated section + + Return ; R4 , R9 , R10 + ; ellY, nextL,nextR + +; +; +; +;------------------------------------------------------------------------------ + + + END diff --git a/s/vdu/vdugrafd b/s/vdu/vdugrafd new file mode 100644 index 0000000000000000000000000000000000000000..e8f96993a4e4ff3ee1e013fcdaea65225db6145b --- /dev/null +++ b/s/vdu/vdugrafd @@ -0,0 +1,566 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.VduGrafD + +; +; ARTHUR OPERATING SYSTEM - Vdu Drivers +; ======================= +; +; Vdu driver code - Block Copy and Move +; +; Author R C Manby +; Date 2.10.86 +; + +; ***************************************************************************** +; +; BlockCopyMove - Copy/Move a rectangular area +; +; in: OldCs marks start of area to copy/move +; ICursor marks end of area to copy/move +; NewPt is lower left of destination area +; R2 = plot number &B8..&BF +; +; out: R0..R11 corrupt +; + +BlockCopyMove ROUT + TST R2, #3 ; Do nowt on 'MoveOnly' codes + MOVEQS PC, R14 + + SaveRetAdr + + ADD R0, WsPtr, #BgEcfStore ; Select 'store' in background + STR R0, [WsPtr, #GColAdr] ; to be used by HLine when + ; clearing source & dest lines + +; Build up source & destination data as follows +; +; R0 R1 R2 R3 R4 R5 R6 R7 R8 +; SrcL,SrcB,SrcR,SrcT,DestL,DestB,DestR,DestT,CopyFlag + + AND R8, R2, #2 ; 0/2 means Move/Copy + + ADD R11, WsPtr, #OldCsX + LDMIA R11, {R0,R1, R2,R3, R4,R5} ; OldCs, ICursor, NewPt + + SortT R0, R2, R6 ; Order SrcL,SrcB,SrcR,SrcT + SortT R1, R3, R6 ; R0 , R1 , R2 , R3 + + SUB R6, R2, R0 + ADD R6, R6, R4 ; DestR := SrcR-SrcL+DestL + + SUB R7, R3, R1 + ADD R7, R7, R5 ; DestT := SrcT-SrcB+DestB + + ADD R11, WsPtr, #CMSrc + STMIA R11, {R0-R7,R8} ; Unclipped src & dest areas + ; and CopyFlag + LDR R11, [WsPtr, #CursorFlags] + TST R11, #ClipBoxEnableBit + BLNE ClipBlockCopyMove + +; now work out ACTUAL area to copy +; first, we window destination area + + LDR R10, [WsPtr, #GWLCol] + LDR R11, [WsPtr, #GWRCol] + + SUBS R8, R10, R4 ; R8 = GWLCol - DestL + ADDGT R4, R4, R8 ; if > 0 then DestL := GWLCol + ADDGT R0, R0, R8 ; and adjust SrcL to match + + SUBS R8, R6, R11 ; R8 = DestR - GWRCol + SUBGT R6, R6, R8 ; if > 0 then DestR := GWRCol + SUBGT R2, R2, R8 ; and adjust SrcR to match + + CMP R6, R4 ; check DestR >= DestL + BLT EraseSource ; if not then just erase source + ; if a block move + + STR R4, [WsPtr, #CMDest2L] ; save horizontal dest coords + STR R6, [WsPtr, #CMDest2R] ; windowed at dest + + SUBS R8, R10, R0 ; R8 = GWLCol - SrcL + ADDGT R0, R0, R8 ; if > 0 then SrcL := GWLCol + ADDGT R4, R4, R8 ; and adjust DestL to match + + SUBS R8, R2, R11 ; R8 = SrcR - GWRCol + SUBGT R2, R2, R8 ; if > 0 then SrcR := GWRCol + SUBGT R6, R6, R8 ; and adjust DestR to match + + LDR R10, [WsPtr, #GWBRow] + LDR R11, [WsPtr, #GWTRow] + + SUBS R8, R10, R5 ; R8 = GWBRow - DestB + ADDGT R5, R5, R8 ; if > 0 then DestB := GWBRow + ADDGT R1, R1, R8 ; and adjust SrcB to match + + SUBS R8, R7, R11 ; R8 = DestT - GWTRow + SUBGT R7, R7, R8 ; if > 0 then DestT := GWTRow + SUBGT R3, R3, R8 ; and adjust SrcT to match + + CMP R7, R5 ; check DestT >= DestB + BLT EraseSource ; if not then just erase source + ; if a block move + + STR R5, [WsPtr, #CMDest2B] ; save vertical dest coords + STR R7, [WsPtr, #CMDest2T] ; windowed at dest + + SUBS R8, R10, R1 ; R8 = GWBRow - SrcB + ADDGT R1, R1, R8 ; if > 0 then SrcB := GWBRow + ADDGT R5, R5, R8 ; and adjust DestB to match + + SUBS R8, R3, R11 ; R8 = SrcT - GWTRow + SUBGT R3, R3, R8 ; if > 0 then SrcT := GWTRow + SUBGT R7, R7, R8 ; and adjust DestT to match + +; now R0-R3 is source windowed both ways +; R4-R7 is dest windowed both ways + + ADD R8, WsPtr, #CMDest3L + STMIA R8, {R4-R7} ; save destination windowed + ; both ways + + CMP R2, R0 ; check SrcR >= SrcL + SUBGES R8, R3, R1 ; and SrcT >= SrcB (R8=lines-1) + BLT EraseDest ; if not, then go to wiping out + ; destination stage + + STR R8, [WsPtr, #CMVertCount] ; no. of vertical lines -1 + + LDR R9, [WsPtr, #Log2BPC] + LDR R10, [WsPtr, #XShftFactor] + LDR R11, [WsPtr, #NPix] + + MOV R8, R6, LSR R10 ; DestR word offset + SUB R8, R8, R4, LSR R10 ; -DestL word offset + STR R8, [WsPtr, #CMDestCount] ; No. of dest words -1 + + AND R8, R6, R11 ; R8 = DestR pixel offset + ADD R14, WsPtr,#RAMMaskTb + LDR R8, [R14, R8, LSL #2] ; R8 = mask for right pixel + SUB R14, R8, #1 ; In rh mask, set all bits lower than + ORR R14, R14, R8 ; pixel, RHM := RHM OR (RHM-1) + STR R14, [WsPtr, #CMRMask] + + AND R8, R4, R11 ; R8 = DestL pixel offset + ADD R14, WsPtr, #RAMMaskTb + LDR R8, [R14, R8, LSL #2] ; R8 = mask for left pixel + RSB R14, R8, #0 ; In lh mask, set all bits higher than + ORR R14, R14, R8 ; pixel, LHM := LHM OR (0-LHM) + STR R14, [WsPtr, #CMLMask] + + CMP R0, R4 ; test whether SrcL >= DestL + BLT SrcHLTDest + +; source is to the right of dest, so start at left hand side + + AND R8, R4, R11 ; R8 = DestL pixel offset + AND R14, R0, R11 ; R14 = SrcL pixel offset + SUB R11, R14, R8 ; R11 = Src-Dest pixel offset + MOV R11, R11, LSL R9 ; R11 = Src-Dest bit offset + + CMP R11, #0 ; if rightshift < 0 + ADDLT R11, R11, #32 ; if < 0, correct result + MOVGE R10, #0 + MOVLT R10, #-4 ; and subtract 4 off src addr + + STR R11, [WsPtr, #CMRShift] + RSB R11, R11, #32 + STR R11, [WsPtr, #CMLShift] + + LDR R6, [WsPtr, #LineLength] ; (no longer need DestR) + + CMP R1, R5 ; if SrcB >= DestB + RSBGE R6, R6, #0 ; then go upwards + STR R6, [WsPtr, #CMVertDir] + + MOVLT R1, R3 ; else go down + MOVLT R5, R7 ; so use top coords + + BL ScreenAddr ; R2 = address of src corner + ADD R2, R2, R10 + STR R2, [WsPtr, #CMSourceAddr] + + MOV R0, R4 + MOV R1, R5 + BL ScreenAddr ; R2 = address of dest corner + STR R2, [WsPtr, #CMDestAddr] + + ADD R11, WsPtr, #CMStuff + LDMIA R11, {R0-R6} ; src,dest,cnt,rtshf,lfshf,rtmsk,ltmsk +10 + TEQ R2, #0 ; only one word on a line ? + ANDEQ R5, R5, R6 ; then rightmask:=rightmask AND lftmask + LDREQ R14, [R0], #4 ; and load first word up + BEQ %FT45 ; and do endword + +; do first word + + LDMIA R0!, {R11,R14} ; load 2 words + ShiftR R11, R14, R3, R4 ; shift them + AND R11, R11, R6 ; AND with leftmask + LDR R10, [R1] ; load word from dest + BIC R10, R10, R6 ; clear out bits in leftmask + ORR R10, R10, R11 ; OR in new bits + STR R10, [R1], #4 + SUBS R2, R2, #1 ; decrement count + BEQ %FT40 ; if zero, do finish word + + SUBS R2, R2, #7 ; can we do 7 words ? + BCC %FT30 ; no, then do 1 word at a time + +; do 7 words at a time + + TEQ R3, #0 ; if rightshf = 0 + BEQ %FT60 ; then do non-shifting version +20 + [ {TRUE} ; TMD optimisation 12-May-93 + MOV R5, R14, LSR R3 + LDMIA R0!, {R6-R11,R14} + ORR R5, R5, R6, LSL R4 + | + MOV R5, R14 + LDMIA R0!, {R6-R11,R14} ; load next 7 words + ShiftR R5, R6, R3, R4 + ] + ShiftR R6, R7, R3, R4 + ShiftR R7, R8, R3, R4 + ShiftR R8, R9, R3, R4 + ShiftR R9, R10, R3, R4 + ShiftR R10, R11, R3, R4 + ShiftR R11, R14, R3, R4 + STMIA R1!, {R5-R11} + SUBS R2, R2, #7 + BCS %BT20 + +30 + ADDS R2, R2, #7 + BEQ %FT40 ; if count expired, do last word + +; do 1 word at a time + +35 + MOV R5, R14 + LDR R14, [R0], #4 + ShiftR R5, R14, R3, R4 + STR R5, [R1], #4 + SUBS R2, R2, #1 + BNE %BT35 + +; do last word + +40 + LDR R5, [WsPtr, #CMRMask] ; load right mask +45 + +; now test if any bits would be used (so we don't go off end of memory) + + MOV R11, #&FFFFFFFF + TST R5, R11, LSL R4 ; NE => safe to read from here + LDRNE R11, [R0], #4 ; R14 = left word; R11 = right word + ShiftR R14, R11, R3, R4 ; form single word + AND R14, R14, R5 ; mask source word + LDR R10, [R1] ; load dest word + BIC R10, R10, R5 ; mask dest word + ORR R10, R10, R14 ; OR two words + STR R10, [R1], #4 ; store back + +; now go on to next row + + LDR R7, [WsPtr, #CMVertCount] + SUBS R7, R7, #1 + BCC EraseDest ; finished, so go to erase dest stage + STR R7, [WsPtr, #CMVertCount] + ADD R11, WsPtr, #CMStuff + LDMIA R11, {R0-R6} ; load up info again + LDR R7, [WsPtr, #CMVertDir] + ADD R0, R0, R7 ; move source pointer + ADD R1, R1, R7 ; and dest pointer + STMIA R11, {R0,R1} ; store these back + B %BT10 ; and loop + +; non-shifting version, for speed +; do 7 words at a time + +60 + MOV R5, R14 + LDMIA R0!, {R6-R11,R14} ; load next 7 words + STMIA R1!, {R5-R11} + SUBS R2, R2, #7 + BCS %BT60 + ADDS R2, R2, #7 + BNE %BT35 ; count not expired, do last few words + B %BT40 ; count expired, do last word + +; ***************************************************************************** + +; source is to the left of dest, so start at right hand side + +SrcHLTDest ROUT + MOV R0, R2 ; rt coords are relevant ones + MOV R4, R6 + + AND R8, R4, R11 ; R8 = DestR pixel offset + AND R14, R0, R11 ; R14 = SrcR pixel offset + SUB R11, R14, R8 ; R11 = Src-Dest pixel offset + MOV R11, R11, LSL R9 ; R11 = Src-Dest bit offset + + RSB R11, R11, #32 ; R11 = leftshift + CMP R11, #32 ; if >= 32 + SUBCS R11, R11, #32 ; then put in range + MOVCC R10, #4 ; else add 4 + MOVCS R10, #0 ; to src addr + + STR R11, [WsPtr, #CMLShift] + RSB R11, R11, #32 + STR R11, [WsPtr, #CMRShift] + + LDR R6, [WsPtr, #LineLength] ; (no longer need R6) + + CMP R1, R5 ; if SrcB >= DestB + RSBGE R6, R6, #0 ; then go upwards + STR R6, [WsPtr, #CMVertDir] + + MOVLT R1, R3 ; else go down + MOVLT R5, R7 ; so use top coords + + BL ScreenAddr ; R2 = address of src corner + ADD R2, R2, R10 + STR R2, [WsPtr, #CMSourceAddr] + + MOV R0, R4 + MOV R1, R5 + BL ScreenAddr ; R2 = address of dest corner + STR R2, [WsPtr, #CMDestAddr] + + ADD R11, WsPtr, #CMStuff + LDMIA R11, {R0-R6} ; src,dest,cnt,rtshf,lfshf,rtmsk,ltmsk +10 + TEQ R2, #0 ; only one word on a line ? + ANDEQ R6, R6, R5 ; then leftmask:=leftmask AND rightmask + LDREQ R5, [R0], #-4 ; and load first word up + BEQ %FT45 ; and do endword + +; do first word + + LDMDA R0!, {R11,R14} ; load 2 words + ShiftL R11, R14, R3, R4 ; shift them + AND R14, R14, R5 ; AND with rightmask + LDR R10, [R1] ; load word from dest + BIC R10, R10, R5 ; clear out bits in rightmask + ORR R10, R10, R14 ; OR in new bits + STR R10, [R1], #-4 + MOV R5, R11 + SUBS R2, R2, #1 ; decrement count + BEQ %FT40 ; if zero, do finish word + + SUBS R2, R2, #7 ; can we do 7 words ? + BCC %FT30 ; no, then do 1 word at a time + +; do 7 words at a time + + TEQ R4, #0 ; if leftshf=0 + BEQ %FT60 ; then do non-shifting version +20 + [ {TRUE} ; TMD optimisation 12-May-93 + MOV R14, R5, LSL R4 + LDMDA R0!, {R5-R11} + ORR R14, R14, R11, LSR R3 + | + MOV R14, R5 + LDMDA R0!, {R5-R11} ; load next 7 words + ShiftL R11, R14, R3, R4 + ] + ShiftL R10, R11, R3, R4 + ShiftL R9, R10, R3, R4 + ShiftL R8, R9, R3, R4 + ShiftL R7, R8, R3, R4 + ShiftL R6, R7, R3, R4 + ShiftL R5, R6, R3, R4 + STMDA R1!, {R6-R11,R14} + SUBS R2, R2, #7 + BCS %BT20 + +30 + ADDS R2, R2, #7 + BEQ %FT40 ; if count expired, do last word + +; do 1 word at a time + +35 + MOV R14, R5 + LDR R5, [R0], #-4 + ShiftL R5, R14, R3, R4 + STR R14, [R1], #-4 + SUBS R2, R2, #1 + BNE %BT35 + +; do last word + +40 + LDR R6, [WsPtr, #CMLMask] ; load left mask +45 + +; now test if any bits would be used (so we don't go off start of memory) + + MOV R11, #&FFFFFFFF + TST R6, R11, LSR R3 ; NE => safe to read from here + LDRNE R11, [R0], #-4 ; R11 = left word; R5 = right word + ShiftL R11, R5, R3, R4 ; form single word + AND R5, R5, R6 ; mask source word + LDR R10, [R1] ; load dest word + BIC R10, R10, R6 ; mask dest word + ORR R10, R10, R5 ; OR two words + STR R10, [R1], #-4 ; store back + +; now go on to next row + + LDR R7, [WsPtr, #CMVertCount] + SUBS R7, R7, #1 + BCC EraseDest ; finished, so go to erase dest stage + STR R7, [WsPtr, #CMVertCount] + ADD R11, WsPtr, #CMStuff + LDMIA R11, {R0-R6} ; load up info again + LDR R7, [WsPtr, #CMVertDir] + ADD R0, R0, R7 ; move source pointer + ADD R1, R1, R7 ; and dest pointer + STMIA R11, {R0,R1} ; store these back + B %BT10 ; and loop + +; non-shifting version, for speed +; do 7 words at a time + +60 + MOV R14, R5 + LDMDA R0!, {R5-R11} ; load next 8 words + STMDA R1!, {R6-R11,R14} + SUBS R2, R2, #7 + BCS %BT60 + ADDS R2, R2, #7 + BNE %BT35 ; count not expired, do last few words + B %BT40 ; count expired, do last word + +; ***************************************************************************** + +; Erase the area Dest2\Dest3 + +EraseDest ROUT + +; first do the flat rectangle + + ADD R8, WsPtr, #CMDest2L + LDMIA R8, {R0-R7} ; R0..R3 = Dest2; R4..R7 = Dest3 + BL EraseDifference + +; and drop thru to ... + +EraseSource + LDR R8, [WsPtr, #CMCopyFlag] ; 0 => move, 2 => copy + TEQ R8, #0 ; is it a move + Return NE ; no, then exit + + ADD R8, WsPtr, #CMSrc ; R0..R3 = unclipped src + LDMIA R8, {R0-R7} ; R4..R7 = unclipped dest + +; window both source and destination in source domain + + LDR R10, [WsPtr, #GWLCol] + LDR R11, [WsPtr, #GWRCol] + + SUBS R8, R10, R0 ; R8 = GWLCol - SrcL + ADDGT R0, R0, R8 ; if > 0 then SrcL := GWLCol + ADDGT R4, R4, R8 ; and adjust DestL to match + + SUBS R8, R2, R11 ; R8 = SrcR - GWRCol + SUBGT R2, R2, R8 ; if > 0 then SrcR := GWRCol + SUBGT R6, R6, R8 ; and adjust DestR to match + + CMP R2, R0 ; check SrcR >= SrcL + Return LT ; if not then nothing to erase + + LDR R10, [WsPtr, #GWBRow] + LDR R11, [WsPtr, #GWTRow] + + SUBS R8, R10, R1 ; R8 = GWBRow - SrcB + ADDGT R1, R1, R8 ; if > 0 then SrcB := GWBRow + ADDGT R5, R5, R8 ; and adjust DestB to match + + SUBS R8, R3, R11 ; R8 = SrcT - GWTRow + SUBGT R3, R3, R8 ; if > 0 then SrcT := GWTRow + SUBGT R7, R7, R8 ; and adjust DestT to match + + CMP R3, R1 ; check SrcT >= SrcB + Return LT ; if not then nothing to erase + +; now window the dest coords to the source + + CMP R7, R3 ; if DestT >= SrcT + MOVGE R7, R3 ; then DestT := SrcT + MOVLT R5, R1 ; else DestB := SrcB + CMP R6, R2 ; if DestR >= SrcR + MOVGE R6, R2 ; then DestR := SrcR + MOVLT R4, R0 ; else DestL := SrcL + + Pull R14 + +; and drop thru to ... + +; ***************************************************************************** +; +; EraseDifference - Erase the difference between two rectangles with at +; least one vertical and one horizontal shared boundary +; +; in: R0-R3 = larger one +; R4-R7 = smaller one +; + +EraseDifference ROUT + +; first do the flat rectangle + + CMP R6, R4 ; check for Dest3 being null + CMPGE R7, R5 + BLT RectFillA ; if is, just clear Dest2 + + Push "R0-R7,R14" + + TEQ R3, R7 ; if Dest2T = Dest3T + SUBEQ R3, R5, #1 ; then top = Dest3B -1 + ADDNE R1, R7, #1 ; else bottom = Dest3T +1 + CMP R3, R1 ; if top >= bottom + BLGE RectFillA + +; now do the tall rectangle + + Pull "R0-R7" + + TEQ R3, R7 ; if Dest2T = Dest3T + MOVEQ R1, R5 ; then bottom = Dest3B + MOVNE R3, R7 ; else top = Dest3T + + TEQ R0, R4 ; if Dest2L = Dest3L + ADDEQ R0, R6, #1 ; then left = Dest3R +1 + SUBNE R2, R4, #1 ; else right = Dest3L -1 + + CMP R3, R1 ; if top >= bottom + CMPGE R2, R0 ; and right >= left + BLGE RectFillA ; then fill it + + Pull PC + + + END diff --git a/s/vdu/vdugrafdec b/s/vdu/vdugrafdec new file mode 100644 index 0000000000000000000000000000000000000000..d7311c39c88772763b1f371a90f5956ecf50d5ea --- /dev/null +++ b/s/vdu/vdugrafdec @@ -0,0 +1,308 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > &.Source.VduGrafDec +; +; ARTHUR OPERATING SYSTEM - Vdu Drivers +; ======================= +; +; Graphics workspace and macro declarations +; +; Author R C Manby +; Date 5.9.86 +; + + GBLL UseNewerHLine +UseNewerHLine SETL 1=1 + + +; +; Graphics work space, overlaid in main vdu w/s area +; + + + ^ GraphicWs + +Line1Blk # 4*9 ;Parameter block for a crudeline + ASSERT @ < EndGraphicWs + + + ^ GraphicWs + +LineBlk # 4*5 ;Parameter block for a crudeline + +LineEcfBase # 4 ; -- +LineEcfIndx # 4 ; | +LineDeltaY # 4 ; | +LineScanStp # 4 ; -- + +LineEndPtFlags # 4 ;Bit0 set - plot start pt, bit1 set - plot end pt +LineDotPtr # 4 ;Holds 0/Adr(LineDotCnt) for Solid/Dotted lines + +DotCycleStartX # 4 +DotCycleStartY # 4 +DotCycleEndX # 4 +DotCycleEndY # 4 +DotCycleCount # 4 +PostCycleCount # 4 + +;The following are defined in Hdr.System +; LineDotCnt # 4 ;Count down to restarting pattern +; LineDotPatLSW # 4 ;Current state of pattern LSWord +; LineDotPatMSW # 4 ; " " " " MSWord + ASSERT @ < EndGraphicWs + + + ^ GraphicWs + +TLine1 # 4*9 ;Line parameters used by Tri & Par fill +TLine2 # 4*9 +TEndY # 4 +Vertex1X # 4 ; -- +Vertex1Y # 4 ; | +Vertex2X # 4 ; | +Vertex2Y # 4 ; | +Vertex3X # 4 ; | +Vertex3Y # 4 ; | +Vertex4X # 4 ; | +Vertex4Y # 4 ; -- + ASSERT @ < EndGraphicWs + + + ^ GraphicWs + +CircleBlk # 4*8 ;Parameter block for circle arc segments etc -- +CLine0 # 4*9 ;Line parameters used by Arc, Segment & Sector | +CLine1 # 4*9 ; -- +CLine2 # 4*9 ;CLine2 & CLine3 used only for segments +CLine3 # 4*9 ; + +UpperSegLinePtr # 4 ;Address of CLine2 or 0 - used only for segments +LowerSegLinePtr # 4 ;Address of CLine3 or 0 - used only for segments + +CircleRadSquare # 4 ;Square of radius of circle + +CLine0EndX * CLine0+7*4 +CLine0EndY * CLine0+8*4 +CLine1EndX * CLine1+7*4 +CLine1EndY * CLine1+8*4 +CLine0Far * CLine0 +CLine0Near * CLine0EndX +CLine1Far * CLine1 +CLine1Near * CLine1EndX + +Quad0Control # 1 ;Control bytes for each quadrant for -- +Quad1Control # 1 ; Arc, Segment & Sector plotting | +Quad2Control # 1 ; | +Quad3Control # 1 ; | + ; | +Quad0StateChange # 1 ;Flag to indicate line/circle | +Quad1StateChange # 1 ; intersection | +Quad2StateChange # 1 ; | +Quad3StateChange # 1 ; | + ; | +Quad0Draw # 1 ;Controls point/line plotting | +Quad1Draw # 1 ; | +Quad2Draw # 1 ; | +Quad3Draw # 1 ; -- + +ArcPoint0X # 4 ; -- +ArcPoint0Y # 4 ; | +ArcPoint1X # 4 ; | +ArcPoint1Y # 4 ; | +ArcPoint2X # 4 ; | +ArcPoint2Y # 4 ; | +ArcPoint3X # 4 ; | +ArcPoint3Y # 4 ; -- + + ASSERT @ < EndGraphicWs + + + ^ GraphicWs + +EllBlk # 4*8 ;Parameter block for ellipses + +EllBlkSliceCnt * EllBlk +EllBlkEllY * EllBlk + 4*4 + + +EllPrevL # 4 ;Slice limits for previous line -- +EllPrevR # 4 ; | +EllThisL # 4 ; current line | +EllThisR # 4 ; | +EllNextL # 4 ; next line | +EllNextR # 4 ; -- + +EllHLineWs # 4*5 ;This could be pushed to the stack +EllDoubleHLineWs # 4*5 ;This could be pushed to the stack + ASSERT @ < EndGraphicWs + + + ^ GraphicWs + +CMSrc # 4*4 ;Unclipped source area -- +CMDest # 4*4 ;Unclipped destination area | +CMCopyFlag # 4 ; 0/2 means Move/Copy area -- + +CMDest2L # 4 ; destination coords clipped at dest +CMDest2B # 4 +CMDest2R # 4 +CMDest2T # 4 +CMDest3L # 4 ; destination coords clipped both ways +CMDest3B # 4 +CMDest3R # 4 +CMDest3T # 4 + +CMStuff # 0 ; these 7 loaded together +CMSourceAddr # 4 ; source screen address +CMDestAddr # 4 ; destination screen address +CMDestCount # 4 ; no. of destination words per line -1 +CMRShift # 4 ; LSR shift factor +CMLShift # 4 ; LSL shift factor +CMRMask # 4 ; right mask +CMLMask # 4 ; left mask + +CMVertCount # 4 ; no. of lines to do -1 +CMVertDir # 4 ; offset to add to source/dest on each line + + ASSERT @ < EndGraphicWs + + + ^ GraphicWs + +LineFillBlk # 4 * 11 + +FldLeftXLimit # 4 ;-- +FldY # 4 ; | +FldRightXLimit # 4 ;-- + +FldBoundaryCol # 4 +FldBoundaryFlag # 4 +FldYWindLimit # 4 + +QueuePtrs # 4*4 ; head, tail, end, start + +FldSaveArea # 5*4 ; saved Y, target colour, NPix, zgora, zgeor +FldSaveY * FldSaveArea +0 + +FldStackLevel # 4 + [ med_00001_userma +flood_cda_rma # 4 ; amount we've changed the rma size by + ] + + ASSERT @ < EndGraphicWs + + + ^ GraphicWs + +RetnReg0 # 4 ;Save area for SWI SpriteOp -- +RetnReg1 # 4 ; | +RetnReg2 # 4 ; | +RetnReg3 # 4 ; | +RetnReg4 # 4 ; | +RetnReg5 # 4 ; | +RetnReg6 # 4 ; | +RetnReg7 # 4 ; | +RetnReg8 # 4 ; | +RetnReg9 # 4 ; | +RetnLink # 4 ; -- + +SprReadNColour # 4 ;Vdu vars for the mode the -- +SprWriteNColour # 4 ; the sprite is in | +SprBytesPerChar # 4 ; | +SprXShftFactor # 4 ; | +SprNPix # 4 ; | +SprLog2BPC # 4 ; -- + +NameBuf # 16 ; 12 char name + gap for good measure + +SpriteWs # 0 + + + + ^ SpriteWs ;Sprite plot & ScreenLoad + +SPltWidth # 4 ;Don't try re-arranging this lot unless +SPltHeight # 4 ; you fully understand the code!! +SPltScrOff # 4 +SPltMemOff # 4 +SPltScrAdr # 4 +SPltColCnt # 4 +SPltMemAdr # 4 +SPltShftR # 4 +SPltShftL # 4 +SPltMskAdr # 4 +SPltLMask # 4 +SPltRMask # 4 +; SPltzgooPtr # 4 +SPltEcfPtr # 4 +SPltEcfIndx # 4 +SPltPixPerWord # 4 +SPltBPP # 4 +SPltMaskBit # 4 +SPltMaskPtr # 4 +SPltMaskRowBit # 4 +SPltMaskRowPtr # 4 +SPltMaskRowLen # 4 + +SPltzgooMasks # 16 ; zgoo, zgeo, zgoe, zgee + +ScrLoaHandle # 4 ; -- +ScrLoaBufAdr # 4 ; | +ScrLoaBytes # 4 ; | +ScrLoaFilPtr # 4 ; | +ScrLoaFilOfst # 4 ; -- + +ScrLoaAreaCB # SpriteAreaCBsize + +SPltAction # 4 ; Plot action used (0 => store) + +SloadModeSel # 48 ; Mode selector for screenloading new sprites + + ASSERT @ < EndGraphicWs + + + ^ SpriteWs ;SGet,SCreate & ScreenSave + +SGetTopLeft # 8 ; top and left of 'on screen' area + +SGetTopMargin # 4 +SGetBotMargin # 4 +SGetLWrdMargin # 4 +SGetLBitMargin # 4 +SGetRWrdMargin # 4 +SGetRBitMargin # 4 + +SGetColWCnt # 4 +SGetRowOfst # 4 +SGetEcfIndx # 4 + +SGetNext # 4 ; -- +SGetName # 12 ;Name is 3 words (12 chars) ; | +SGetWidth # 4 ; | +SGetHeight # 4 ; | +SGetLBit # 4 ; | +SGetRBit # 4 ; | +SGetImage # 4 ; | +SGetTrans # 4 ; | +SGetMode # 4 ; | +SGetPalette # 0 ; -- + + ASSERT @ < EndGraphicWs + + ^ ScrSavCommon +ScrSavAreaCB # SpriteAreaCBsize +ScrSavSpriteCB # SpriteCBsize + MaxSpritePaletteSize + + END diff --git a/s/vdu/vdugrafe b/s/vdu/vdugrafe new file mode 100644 index 0000000000000000000000000000000000000000..7cebda2714ba152ca6bbfbf23a068666aef5d035 --- /dev/null +++ b/s/vdu/vdugrafe @@ -0,0 +1,874 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.VduGrafE +; +; ARTHUR OPERATING SYSTEM - Vdu Drivers +; ======================= +; +; Vdu driver code - Line Fill L & R and Flood Fill +; +; Author R C Manby +; Date 17.10.86 +; + +; ***************************************************************************** +; +; FillLRnonBg +; =========== +; +; On entry, R0 (X), R1 (Y) hold point to fill from +; +; On exit, R0..R11 corrupt +; + +FillLRtoFg + ADD R2, WsPtr, #FgEcf + MOV R3, #0 + B FillLRnonBg10 ; Fill L <-> R + +FillLRnonBg + ADD R2, WsPtr, #BgEcf + MOV R3, #&80000000 +FillLRnonBg10 + SaveRetAdr + BL FillAlong2 + SUBCS R1, R1, #1 ; indicate nothing filled by Y-=1 + STR R0, [WsPtr, #GCsIX] ; left X + STR R1, [WsPtr, #GCsIY] ; Y + Return CS ; external new pt hasn't changed + STR R2, [WsPtr, #NewPtX] ; right X + MOV R0, R2 + BL IEGB ; update external version of new NewPt + Return ; then things get shuffled + +; ***************************************************************************** +; +; FillLRtoBg (Really only fill right!) +; ========== +; +; On entry, R0 (X), R1 (Y) hold point to fill from +; +; On exit, R0..R11 corrupt +; + +FillLRnonFg + ADD R2, WsPtr, #FgEcf + MOV R3, #&80000000 + B FillLRtoBg10 ; Fill -> R + +FillLRtoBg + ADD R2, WsPtr, #BgEcf + MOV R3, #&0 +FillLRtoBg10 + SaveRetAdr + STR R0, [WsPtr, #GCsIX] ; "left hand point" = given point + STR R1, [WsPtr, #GCsIY] + BL GenLineFillParm ; if C=1 (nothing can be plotted) + SUBCS R0, R0, #1 ; then NewPtX-=1 ie NewPtX < GCsIX + BLCC FillLineRightRegs ; else fill right + STR R0, [WsPtr, #NewPtX] ; Convert NewPt(X,Y) (internal) into + LDR R1, [WsPtr, #NewPtY] ; GCs(X,Y) (external) + BL IEGB + Return ; On returning, cursors are shuffled + ; which updates GCsI(X,Y) + +; ***************************************************************************** +; +; GenLineFillParm +; =============== +; +; On entry, R0 (X), R1 (Y) hold point to fill from +; R2 points to delimiting colour (FgEcf/BgEcf) +; R3 fill flag, 0/&80000000 for fill to/to-non +; +; On exit, Carry=0, valid parameter setup, R0-R10 contain copy of control block +; Carry=1, point outside window, R0 preserved, R1-R10 undefined +; +; Format of control block +; +; R0 - StartX +; R1 - DelimitColour +; R2 - FillFlag +; R3 - ScreenAdr +; R4 - PixelMsk +; R5 - zgora +; R6 - zgeor +; R7 - GWLCol +; R8 - GWRCol +; R9 - BytesPerChar +; R10 - NPix +; +GenLineFillParm + WINDow R0,R1, R7,R8,R9,R10 ; Window(R0,R1) using R7-R10 + ; gives GE if in window + ORRLTS PC, Link, #C_bit ; If point outside window + ; then quit with carry set + Push "R2,R3,R7,R9,Link" ; Save colourptr, fillflag + ; GWLCol, GWRCol + BL ScreenAddr ; Returns R2 = Addr, R3 = Mask + + LDR R9, [WsPtr, #YWindLimit] + SUB R9, R9, R1 ; Flip Ycoord + AND R9, R9, #7 ; Line within ecf + LDR R5, [WsPtr, #GColAdr] ; Base address of ecf pattern + ADD R5, R5, R9, LSL #3 + LDMIA R5, {R5, R6} ; Get zgora,zgeor + + MOV R4, R3 + MOV R3, R2 + + Pull "R1,R2,R7,R8,Link" ; restore other registers + LDR R1, [R1, R9, LSL #2] ; load delimiting colour + LDR R9, [WsPtr, #BytesPerChar] + LDR R10, [WsPtr, #NPix] + + ADD R11, WsPtr, #LineFillBlk ; now save completed control block + STMIA R11, {R0-R10} + + LDR R11, [R3] ; load screen + EOR R11, R11, R1 ; screen EOR boundary + TST R11, R4 ; just look at this pixel + TEQ R2, PC, LSL #1 ; N := (Z EOR R2) ie invert test if + ; stopping on non-colour + BICPLS PC, Link, #C_bit ; point can be filled, exit CC + ORRMIS PC, Link, #C_bit ; point cannot be filled, exit CS + +; ***************************************************************************** +; +; FillLineRight - Fill right from point upto delimiting colour +; ============= or graphics window +; +; +; R0 - RightLimitX +; R1 - LimitColour +; R2 - FillFlag +; R3 - ScreenAdr +; R4 - PixelMsk +; R5 - zgora +; R6 - zgeor +; R7 - GWLCol /BPC/NPIX +; R8 - GWRCol +; R9 - ScreenWord +; R10 - NPix +; R11 - MultPixMsk / temp +; +; out: PSR must be preserved +; +FillLineRight ROUT + ADD R11, WsPtr, #LineFillBlk + LDMIA R11, {R0-R10} +FillLineRightRegs + Push R14 + RSB R7, R9, #32 ; shift factor for next pixel position + SUB R0, R8, R0 +10 + MOV R11, #0 ; clear partial word mask + LDR R9, [R3] ; screen word EOR delimit colour + EOR R14, R9, R1 +30 + TST R14, R4 ; test pixel position for delimiting + TEQ R2, PC, LSL #1 ; invert condition if necessary + + ORRPL R11, R11, R4 ; add pixel to partial word mask + SUBPLS R0, R0, #1 ; "increment" X; if on edge of window + BMI %FT40 ; then give up and plot partial word + + TEQ R4, #0 ; test for end of word + MOV R4, R4, ROR R7 ; shift pixel mask left + BPL %BT30 + + AND R14, R5, R11 ; fill partial word, using pixel mask + AND R11, R6, R11 ; in R11 + ORR R9, R9, R14 + EOR R9, R9, R11 + STR R9, [R3], #4 + + CMP R2, #2 ; CC => filling until pixel=target + BCC %BT10 ; so do it slowly (goto next word) + + RSB R0, R0, #0 ; make X in range GWLCol-GWRCol .. 0 + ADDS R0, R0, R10 ; move R0 to end of word + BGT %FT36 ; outside window, continue slowly + + ORR R14, R1, R5 ; word to store if going fast + EOR R14, R14, R6 + +32 + LDR R9, [R3] ; screen word + CMP R9, R1 ; EOR target colour (CS if EQ) + BNE %FT36 + STR R14, [R3], #4 + ADCS R0, R0, R10 ; C=1, so add NPix+1 + BLE %BT32 +36 + SUBS R0, R10, R0 ; R0 back to start of word and negate + BGE %BT10 ; if still inside, continue slowly + B %FT50 + +40 + AND R14, R5, R11 ; fill partial word, using pixel mask + AND R11, R6, R11 ; in R11 + ORR R9, R9, R14 + EOR R9, R9, R11 + STR R9, [R3] +50 + SUB R0, R8, R0 ; make back into normal coord again + SUB R0, R0, #1 ; correct end point + Pull R14 + MOVS PC, R14 + +; ***************************************************************************** +; +; FillLineLeft - Fill left from point upto delimiting colour +; ============ or graphics window +; +; N.B. Starts one pixel left of point given, since +; FillLineRight will have already plotted it. +; +; R0 - LeftLimitX +; R1 - LimitColour +; R2 - FillFlag +; R3 - ScreenAdr +; R4 - PixelMsk +; R5 - zgora +; R6 - zgeor +; R7 - GWLCol } Slightly different from FillLineRight +; R8 - GWRCol /BPC/NPIX } +; R9 - ScreenWord +; R10 - LimitEorScreen / temp +; R11 - MultPixMsk / temp +; +; +; +FillLineLeft ROUT + ADD R11, WsPtr, #LineFillBlk + LDMIA R11, {R0-R10} +FillLineLeftRegs + Push R14 + MOV R8, R9 ; shift factor for next pixel position + + SUB R0, R0, R7 + LDR R9, [R3] ; screen word EOR delimit colour + EOR R14, R9, R1 + MOVS R11, #0 ; clear partial word mask (and set PL) + B %FT31 + +10 + MOV R11, #0 ; clear partial word mask + LDR R9, [R3] ; screen word EOR delimit colour + EOR R14, R9, R1 + +30 + TST R14, R4 ; test pixel position for delimiting + TEQ R2, PC, LSL #1 ; invert condition if appropriate + ORRPL R11, R11, R4 ; add pixel to partial word mask +31 + SUBPLS R0, R0, #1 ; decrement X; if on edge of window + BMI %FT40 ; then give up and plot partial word + + MOVS R4, R4, ROR R8 ; test for end of word + BPL %BT30 ; loop until mask exhausted + + AND R14, R5, R11 ; fill partial word, using pixel mask + AND R11, R6, R11 ; in R11 + ORR R9, R9, R14 + EOR R9, R9, R11 + STR R9, [R3], #-4 + + CMP R2, #2 ; CC => filling until pixel=target + BCC %BT10 ; so do it slowly (goto next word) + + SUBS R0, R0, R10 ; move R0 to beginning of word + BCC %FT36 ; if outside window continue slowly + ADD R10, R10, #1 + ORR R14, R1, R5 ; compute target word + EOR R14, R14, R6 +32 + LDR R9, [R3] ; screen word + CMP R9, R1 + BNE %FT35 ; NZ => terminate + STR R14, [R3], #-4 + SUBS R0, R0, R10 + BCS %BT32 +35 + SUB R10, R10, #1 +36 + ADDS R0, R0, R10 ; point R0 back to end of word + BGE %BT10 ; if still inside, continue but slowly + B %FT50 + +40 + AND R14, R5, R11 ; fill partial word, using pixel mask + AND R11, R6, R11 ; in R11 + ORR R9, R9, R14 + EOR R9, R9, R11 + STR R9, [R3] +50 + ADD R0, R0, R7 ; add GWLCol back on + ADD R0, R0, #1 ; Correct endpoint value + Pull R14 + MOVS PC, R14 + +; ***************************************************************************** +; +; FillAlong - Fill left and right from point given +; ========= +; +; On entry, R0 (X), R1(Y) hold point to fill from +; +; On exit, R0 (X) End of scan left +; R1 (Y) Preserved +; R2 (X) End of scan right +; +; Carry set = no fill performed ie outside window or already filled +; Carry clear = fill occured +; + ASSERT FldBoundaryFlag = FldBoundaryCol +4 + +FillAlong + ADD R2, WsPtr, #FldBoundaryCol + LDMIA R2, {R2,R3} ; R2 = colour, R3 = flag +FillAlong2 ; entry point when R2, R3 loaded + Push "R1, R14" + BL GenLineFillParm ; On exit C=1 if nothing can be plotted + BLCC FillLineRightRegs + Push R0 ; New RightX + BLCC FillLineLeft + Pull R2 ; Recover RightX + Pull "R1, PC" ; Recover Y, C=1 <=> fill occured + +; ***************************************************************************** +; +; FloodFill +; ========= +; +; On entry, R0 (X), R1 (Y) hold point to flood from +; R2 Delimit colour, pointer to FgEcf/BgEcf +; R3 0/&80000000 for flood until/over +; + ASSERT FldBoundaryFlag = FldBoundaryCol +4 + ASSERT FldY = FldLeftXLimit +4 + ASSERT FldRightXLimit = FldLeftXLimit +8 + +FloodToFg + ADD R2, WsPtr, #FgEcf ; delimit colour + MOV R3, #0 ; flood until + B FloodFill + +FloodNonBg + ADD R2, WsPtr, #BgEcf ; delimit colour + MOV R3, #&80000000 ; flood over +FloodFill ROUT + Push R14 + STR R13, [WsPtr, #FldStackLevel] ; save stack level ! + + ADD R14, WsPtr, #FldBoundaryCol + LDR R4, [WsPtr, #YWindLimit] + STMIA R14, {R2-R4} ; store colour, flag, YWindLimit + + [ med_00001_userma + + ; the idea here is to try to use between 48k and 128k of rma instead of 16k of + ; scratchspace. if there's less than 48k of rma in the first place we go back to + ; scratchspace. if there's 128k or more we claim the 128k and proceed. For values + ; between 48k and 128k we first grow the rma by 128k-largest_free_space. If this + ; results in a lump of 128k now being free we claim it and proceed. If the largest + ; free space hasn't grown to 128k we then claim the additional balance needed to + ; have 128k available. Should either grow fail, we just use whatever (over 48k) + ; was available + + ;R3-R7 spare at presenet + Push "R0-R2" + MOV R0, #0 + STR R0, [WsPtr, #flood_cda_rma] ; set amount to change dyn. area by + MOV R0, #ModHandReason_RMADesc + SWI XOS_Module ; get the largest free space in rma + BVC %FT91 ; if that failed, use scratchspace + +use_scratchspace + LDR R3, =FldQueueStart ; head ptr (== scratchspace) + MOV R4, R3 ; tail ptr + ADD R5, R3, #FldQueueSize ; end ptr (== scratchspace size) + MOV R6, R3 ; start ptr + B %FT92 +91 + CMP R2, #smallest_rma_size ; compare against small threshold + BLT use_scratchspace ; not enough free - use scratchspace + CMP R2, #largest_rma_size ; compare against high threshold + BHS %FT96 ; lots free - use largest ceiling value + + RSB R1, R2, #largest_rma_size ; work out how much more to claim + MOV R0, #1 ; rma + SWI XOS_ChangeDynamicArea + STRVC R1, [WsPtr, #flood_cda_rma] ; save the amount we grew the rma + BVS %FT94 ; if it failed, use the minimum<size<maximum lump + + MOV R0, #ModHandReason_RMADesc ; reread the largest free space to see if + SWI XOS_Module ; it has risen to maximum + BVS use_scratchspace + CMP R2, #largest_rma_size + BHS %FT96 ; it has, so claim the maximum + + LDR R1, [WsPtr, #flood_cda_rma] ; the free space didn't grow to maximum, so the + RSB R1, R1, #largest_rma_size ; largest space wasn't at the end. Do a second + MOV R0, #1 ; grow of the rma to make the maximum + SWI XOS_ChangeDynamicArea + LDRVC R0, [WsPtr, #flood_cda_rma] ; if it succeeded, update the amount that we + ADDVC R0, R0, R1 ; need to shrink the rma by + STRVC R0, [WsPtr, #flood_cda_rma] + ; and fall into the claim largest space routine +94 + MOV R0, #ModHandReason_RMADesc + SWI XOS_Module + BVS use_scratchspace ; find the largest lump now available + CMP R2, #largest_rma_size +96 + MOVGT R3, #largest_rma_size + MOVLE R3, R2 ; cap it at the maximum size we want + MOV R0, #ModHandReason_Claim ; try to claim it + SWI XOS_Module + BVS use_scratchspace + + ADD R5, R2, R3 ; do it in a slightly different order so + MOV R3, R2 ; we can use the R2 and R3 back from the claim + MOV R4, R3 ; (R2=where, R3=size) + MOV R6, R3 + +92 + ADD R7, WsPtr, #QueuePtrs + STMIA R7, {R3, R4, R5, R6} ; initialise queue + Pull "R0-R2" + | + LDR R3, =FldQueueStart ; head ptr + MOV R4, R3 ; tail ptr + ADD R5, R3, #FldQueueSize ; end ptr + MOV R6, R3 ; start ptr + ADD R7, WsPtr, #QueuePtrs + STMIA R7, {R3, R4, R5, R6} ; initialise queue + ] + + BL FillAlong ; try filling L&R from given point + Pull PC, CS ; quit if can't be filled + + MOV R3, #3 ; bit0 => fill up, bit1 => fill down +10 + ADD R14, WsPtr, #FldLeftXLimit + STMIA R14, {R0-R2} ; store leftX, Y, rightX + + TST R3, #1 + BEQ %FT20 + + LDR R10, [WsPtr, #GWTRow] ; if below Top of window + CMP R10, R1 + BLE %FT20 + + ADD R4, WsPtr, #FldBoundaryCol ; R4=target colour ptr,R5=flag, + LDMIA R4, {R4,R5,R6} ; R6=YWindLimit + + ORR R5, R5, #FillingUpBit ; fill line above + Push R3 + BL CheckAlong ; (will bomb out if queue explodes) + Pull R3 + + ADD R14, WsPtr, #FldLeftXLimit + LDMIA R14, {R0,R1} ; reload leftX, Y +20 + TST R3, #2 + BEQ %FT30 + + LDR R10, [WsPtr, #GWBRow] ; if above bottom of window + CMP R1, R10 + BLE %FT30 + + ADD R4, WsPtr, #FldBoundaryCol ; R4=target colour ptr,R5=flag, + LDMIA R4, {R4,R5,R6} ; R6=YWindLimit + +; BIC R5, R5, #FillingUpBit ; fill line below + BL CheckAlong ; (will bomb out if queue explodes) +30 + ADD R11, WsPtr, #QueuePtrs ; unqueue one item + LDMIA R11, {R3,R4,R5} ; head,tail,limit + TEQ R3, R4 ; if queue empty + [ med_00001_userma + BLEQ release_memory + ] + Pull PC, EQ ; then exit + + [ med_00001_twowords + LDR R1, [R3], #4 + MOV R0, R1, LSR #16 ; LeftX + MOV R2, R1 + EOR R2, R2, R0, LSL #16 ; RightX (with LeftX EORed out) + LDR R1, [R3], #4 ; Recover Y + | + LDR R1, [R3], #4 ; then load word + MOV R2, R1, LSR #21 ; Recover RightX + EOR R1, R1, R2, LSL #21 ; clear those bits out + MOV R0, R1, LSR #10 ; Recover LeftX + EOR R1, R1, R0, LSL #10 ; Recover Y + ] + TEQ R3, R5 ; if at limit + LDREQ R3, [R11, #12] ; then reload with start + STR R3, [R11, #0] ; store head ptr back + + MOV R3, #2 ; indicate fill down + CMP R2, R0 ; if right < left then subtract 1 off + ; larger and swap + SBCCC R0, R0, R2 ; R0 := large-small-1 + ADDCC R2, R0, R2 ; R2 := (large-small-1)+small = large-1 + SUBCC R0, R2, R0 ; R0 := (large-1)-(large-small-1)=small + MOVCC R3, #1 ; and indicate fill up + B %BT10 + +; ***************************************************************************** +; +; CheckAlong - Fill and skip background between LeftXLimit & RightXLimit +; ========== +; +; On entry, R0 LeftXLimit +; R1 Y +; R4 target colour +; R5 fill flag +; R6 YWindLimit +; +; Exits using R14 if normal termination +; Exits using FldStackLevel if queue full +; + +FillingUpBit * 1 + + ASSERT FldBoundaryFlag = FldBoundaryCol +4 + ASSERT FldYWindLimit = FldBoundaryCol +8 + + ASSERT FldY = FldLeftXLimit +4 + ASSERT FldRightXLimit = FldLeftXLimit +8 + +CheckAlong ROUT + Push R14 + + TST R5, #FillingUpBit ; if going up + ADDNE R1, R1, #1 ; then increment Y + SUBEQ R1, R1, #1 ; else decrement Y + + BL ScreenAddr ; R2=screen addr, R3=mask + + SUB R6, R6, R1 ; flip Y + AND R6, R6, #7 ; ecf offset + LDR R4, [R4, R6, LSL #2] ; R4=target colour + LDR R7, [WsPtr, #GColAdr] ; base address of plot ecf + ADD R7, R7, R6, LSL #3 ; R7 -> zgora, zgeor + LDMIA R7, {R10,R11} ; R10=zgora, R11=zgeor + LDR R6, [WsPtr, #BytesPerChar] ; R6=pixel shift + LDR R9, [WsPtr, #NPix] ; R9=no. of pixels per word-1 + + ADD R7, WsPtr, #FldSaveArea ; save Y, target colour, + STMIA R7, {R1, R4, R9, R10, R11} ; NPix, zgora, zgeor + +; test first pixel, to see if we can go left + + LDR R7, [R2] + EOR R1, R7, R4 + TST R1, R3 + TEQ R5, PC, LSL #1 ; PL => it's fillable + RSBMI R6, R6, #32 ; not fillable, reverse pixel shift + LDRMI R8, [WsPtr, #GWRCol] ; load right window limit + BMI %FT37 ; and skip left+right filling bit + + Push "R0, R2, R3" ; save X, screen address, mask + LDR R8, [WsPtr, #GWLCol] + SUB R0, R0, R8 ; make X in range 0..GWRCol-GWLCol + MOVS R14, #0 ; clear partial word mask (and set PL) + B %FT14 + +10 + MOV R14, #0 ; clear partial word mask + LDR R7, [R2] ; R7 = screen + EOR R1, R7, R4 +12 + TST R1, R3 ; test pixel position for delimiter + TEQ R5, PC, LSL #1 ; PL => it's fillable + ORRPL R14, R14, R3 ; add pixel to partial word mask +14 + SUBPLS R0, R0, #1 ; decrement X; if on edge of window + BMI %FT22 ; then give up and plot partial word + + MOVS R3, R3, ROR R6 ; test for end of word + BPL %BT12 ; loop until mask wraps + + AND R1, R10, R14 ; R1 := zgora AND pixmask + ORR R7, R7, R1 ; screen := screen OR R1 + AND R1, R11, R14 ; R1 := zgeor AND pixmask + EOR R7, R7, R1 ; screen := screen EOR R1 + STR R7, [R2], #-4 + + CMP R5, #2 ; CC => filling until target + BCC %BT10 ; so do it slowly (do next word) + + SUBS R0, R0, R9 ; move R0 to start of word + BCC %FT20 ; if outside window continue slowly + + ADD R9, R9, #1 ; R9 := pixels per word + ORR R1, R4, R10 ; compute word to plonk on screen + EOR R1, R1, R11 +16 + LDR R7, [R2] ; screen word + CMP R7, R4 + BNE %FT18 ; NZ => terminate + STR R1, [R2], #-4 + SUBS R0, R0, R9 ; back another word + BCS %BT16 +18 + SUB R9, R9, #1 ; R9 := pixels per word -1 +20 + ADDS R0, R0, R9 ; point R0 back to end of word + BGE %BT10 ; if still inside, continue but slowly + B %FT24 ; else exit + + [ :LNOT: AssemblingArthur + MALIGN 16, 0 ; try to get %FT30 aligned ! + ] +22 + AND R1, R10, R14 ; R1 := zgora AND pixmask + ORR R7, R7, R1 ; screen := screen OR R1 + AND R1, R11, R14 ; R1 := zgeor AND pixmask + EOR R7, R7, R1 ; screen := screen EOR R1 + STR R7, [R2] +24 + ADD R0, R0, R8 ; add GWLCol back on + ADD R0, R0, #1 + Pull "R1, R2, R3" ; restore X, screen addr, mask + Push R0 ; save left-of-line coordinate + MOV R0, R1 ; R0 = start X + RSB R6, R6, #32 ; reverse pixel shift + LDR R8, [WsPtr, #GWRCol] ; load right window limit + +; now the filling right part + +26 + SUB R0, R8, R0 ; make X in range GWRCol-GWLCol .. 0 + +; start of each word + +27 + MOV R14, #0 + LDR R7, [R2] ; screen word + EOR R1, R7, R4 +28 + TST R1, R3 ; test pixel position for delimiter + TEQ R5, PC, LSL #1 ; PL => it's fillable + ORRPL R14, R14, R3 ; add pixel to partial word mask + SUBPLS R0, R0, #1 ; "increment" X; if on edge of window + BMI %FT34 ; then give up and plot partial word + + TEQ R3, #0 ; test for end of word + MOV R3, R3, ROR R6 ; shift pixel mask + BPL %BT28 ; loop until mask wraps + + AND R1, R10, R14 ; R1 := zgora AND pixmask + ORR R7, R7, R1 ; screen := screen OR R1 + AND R1, R11, R14 ; R1 := zgeor AND pixmask + EOR R7, R7, R1 ; screen := screen EOR R1 + STR R7, [R2], #4 + + CMP R5, #2 ; CC => filling until target + BCC %BT27 ; so do it slowly (do next word) + + RSB R0, R0, #0 ; make X in range GWLCol-GWRCol .. 0 + ADDS R0, R0, R9 ; move R0 to end of word + BGT %FT32 ; outside window, continue slowly + + ORR R1, R4, R10 ; word to store if going fast + EOR R1, R1, R11 + + [ :LNOT: AssemblingArthur + ASSERT ((.-ArthurVduDriver):AND:15) = 0 + ] +30 + LDR R7, [R2] ; screen word + CMP R7, R4 ; EOR target colour (CS if EQ) + BNE %FT32 ; NZ => terminate + STR R1, [R2], #4 + ADCS R0, R0, R9 ; C=1, so add NPix +1 + BLE %BT30 +32 + SUBS R0, R9, R0 ; R0 back to start of word and negate + BGE %BT27 ; if still inside, continue slowly + B %FT36 ; else exit + +34 + AND R1, R10, R14 ; R1 := zgora AND pixmask + ORR R7, R7, R1 ; screen := screen OR R1 + AND R1, R11, R14 ; R1 := zgeor AND pixmask + EOR R7, R7, R1 ; screen := screen EOR R1 + STR R7, [R2] +36 + SUB R0, R8, R0 ; make back into normal coord again + +; now queue this segment + + Pull R4 ; R4 := LH end point + SUB R7, R0, #1 ; R7 := corrected RH end point + LDR R1, [WsPtr, #FldSaveY] ; reload Y coordinate of THIS segment + BL Queue + + ADD R14, WsPtr, #FldLeftXLimit ; load lxlim, (Y+?), rxlim + LDMIA R14, {R7,R10,R11} + + EOR R5, R5, #FillingUpBit ; invert direction + + SUB R7, R7, #2 ; lxlim -2 + CMP R4, R7 ; if leftX <= lxlim-2 + BLLE Queue ; then Q LH end bit in opposite dir + + ADD R4, R11, #2 ; rxlim +2 + SUB R7, R0, #1 ; R7 = RH end point + CMP R7, R4 ; if rightX >= rxlim+2 + BLGE Queue ; then Q RH end bit in opposite dir + + EOR R5, R5, #FillingUpBit ; invert direction back again + + SUB R4, R4, #3 ; rxlim -1 + CMP R7, R4 ; if rightX >= rxlim-1 + Pull PC, GE ; no point in skipping any more + +; now do the skipping +; R0 points to first non-fillable pixel; R3=correct mask for this pixel + + ADD R7, WsPtr, #FldSaveArea ; reload target colour, NPix, + LDMIB R7, {R4, R9, R10, R11} ; zgora, zgeor +37 + LDR R1, [WsPtr, #FldRightXLimit] +38 + LDR R7, [R2], #4 + EOR R7, R7, R4 ; screen EOR target +40 + TST R7, R3 ; if pixel is fillable + TEQ R5, PC, LSL #1 + SUBPL R2, R2, #4 ; then correct address + Push R0, PL ; and push new X coord + BPL %BT26 ; and go to fill right bit +50 + CMP R0, R1 ; on limit of segment ? + Pull PC, CS ; yes, so give up + ADD R0, R0, #1 ; step coord + TEQ R3, #0 ; test for mask wrap + MOV R3, R3, ROR R6 ; rotate mask to next pixel + BPL %BT40 ; continue within this word + B %BT38 ; continue with next word + +; ***************************************************************************** +; +; Queue - Queue a line segment +; +; in: R1 = Y coordinate of segment +; R4 = left X coordinate +; R5 = fill flag (Bit0=0/1 => look downwards/upwards) +; R7 = right X coordinate +; +; out: R0-R8, R11, R12 preserved +; R9,R10 corrupted +; exits by pulling stacked R14 if queue was full +; + +Queue ROUT + Push "R0,R11,R14" + TEQ R5, R5, LSR #1 ; CS => mangle coords + + MOVCC R9, R4 + MOVCC R10, R7 + + SUBCS R9, R7, R4 ; R9 = R-L + SUBCS R10, R7, R9 ; R10 = R-(R-L) = L + ADCCS R9, R9, R10 ; R9 = (R-L)+L+1 = R+1 + + [ med_00001_twowords + ; revised packing, expanded to two words, LeftX in 31..16 of word 1, + ; RightX in 15..0 of word 1, and Y in 15..0 of word 2 + + MOV R9, R9, LSL #16 ; shift LeftX up + ORR R9, R9, R10 ; combine in RightX + + ADD R0, WsPtr, #QueuePtrs + LDMIA R0, {R10, R11, R14} ; head,tail,limit + + STR R9, [R11], #4 ; store word at tail and move on + STR R1, [R11], #4 ; store second word + | + ; pack Y into bits 0..9, L into bits 10..20, R into bits 21..31 + + ORR R9, R1, R9, LSL #10 ; R9 = Y + (L << 10) + ORR R9, R9, R10, LSL #21 ; R9 = Y + (L << 10) + (R <<21) + + ADD R0, WsPtr, #QueuePtrs + LDMIA R0, {R10, R11, R14} ; head,tail,limit + + STR R9, [R11], #4 ; store word at tail and move on + ] + + TEQ R11, R14 ; if at limit + LDREQ R11, [R0, #12] ; then reload with start ptr + CMP R11, R10 ; EQ and CS if queue full + STRNE R11, [R0, #4] ; store tail ptr back if OK + + Pull "R0,R11,PC", NE ; queue not full, terminate normally + + [ med_00001_userma + BL release_memory + ] + LDR R13, [WsPtr, #FldStackLevel] + Pull PC ; else bomb out + +; ***************************************************************************** + + [ med_00001_userma +release_memory + ROUT + Push "R0-R5,lr" + + ADD R0, WsPtr, #QueuePtrs + LDMIA R0, {R0-R3} + + [ med_00001_debug + LDR R0, =med_00001_debug_start + STR R3, [R0], #4 + STR R2, [R0], #4 + LDR R5, [WsPtr, #flood_cda_rma] + STR R5, [R0] + ] + + LDR R5, =FldQueueStart + + CMP R3, R5 ; did we use scratchspace ? + BEQ %FT20 + + MOV R2, R3 + MOV R0, #ModHandReason_Free + SWI XOS_Module +20 + LDR R0, [WsPtr, #flood_cda_rma] + CMP R0, #0 + BEQ %FT30 ; no need to shrink rma + + RSB R1, R0, #0 ; get the signed negative value + MOV R0, #1 ; rma + SWI XOS_ChangeDynamicArea +30 + CMP r0, r0 ; ensure we return EQ set + Pull "r0-r5,pc" + ] + +; ***************************************************************************** + + END diff --git a/s/vdu/vdugraff b/s/vdu/vdugraff new file mode 100644 index 0000000000000000000000000000000000000000..b86a3bd4b4aa7f4789dfbd4437cfe3f4f90c0cae --- /dev/null +++ b/s/vdu/vdugraff @@ -0,0 +1,880 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > &.Source.VduGrafF +; +; ARTHUR OPERATING SYSTEM - Vdu Drivers +; ======================= +; +; Vdu driver code - Solid & Dotted Line drawing routines +; +; Author R C Manby +; Date 27.10.86 +; + + +; +; +; +;------------------------------------------------------------------------------ +; +; DoOsbyte163_242 - Set dotted line length and return status information +; =============== +; +; We are only interested in OsByte 163,242,0..66 +; +; OsByte 163,242,0..64 set dotted line length +; 163,242,0 set default dot pattern and length +; 163,242,1..64 set specified pattern length +; +; OsByte 163,242,65 return graphics status +; returns R1 = &Cn (means GXR on & flood on (for GXR)) +; (means SpriteRom on (for master/compact)) +; n = dotted line length MOD 64 +; R2 = number of sprite pages +; +; OsByte 163,242,66 return sprite status +; returns R1 = R2 = 0 if no sprite selected +; R1 = current sprite width +; R2 = current sprite height +; +; When entered, we know it is FX 163,242,n +; Exit by MOV PC, R14 if still don't understand (ie n>66) +; Otherwise exit with Pull PC + +DoOsbyte163_242 ROUT + CMP R2,#66 + MOVHI PC, R14 ; Not 0..66, so pass it on + + Push "R3-R12" ; Preserve the world + VDWS WsPtr ; Point R12 at Vdu driver workspace + + CMP R2,#65 + BLLT SetPatLength ; R2 holds 0/1..64 ; PSR preserved + BLT OsByte_QuitA + BGT OsByte163_242_66 + +OsByte163_242_65 ; OsByte 163,242,65 - graphics status + LDR R1,[WsPtr,#DotLineLength] + AND R1,R1,#&3F ; Dot count MOD 64 + ORR R1,R1,#&C0 ; GXR on, Flood on + LDR R2,[WsPtr,#SpAreaStart] + CMP R2,#0 + LDRNE R2,[R2,#saEnd] ; SpriteWS size + B OsByte_QuitA + +OsByte163_242_66 ; OsByte 163,242,66 - sprite status + + MOV R0,#SpriteReason_ReadSpriteSize + LDR R2,=SpChooseName + ADD R2,R2,WsPtr ; Sprite name ptr + + SWI XOS_SpriteOp + + MOVVS R1,#0 ; If no sprite memory, or no sprite + MOVVS R2,#0 ; chosen, return 0,0 as width,height + + MOVVC R1,R3 ; else return width,height in pixels + MOVVC R2,R4 + +OsByte_QuitA + Pull "R3-R12,PC" ; restore registers and claim call +; +; +; +;------------------------------------------------------------------------------ + + + + + MACRO + WriteToScreen $Adr,$Msk,$Ecf, $a,$b,$c + LDMIA $Ecf,{$a,$b} + AND $a,$a,$Msk + AND $b,$b,$Msk + LDR $c,[$Adr] + ORR $c,$c,$a + EOR $c,$c,$b + STR $c,[$Adr] + MEND + + +; +; +; +;------------------------------------------------------------------------------ + + + + +rXCnt RN 0 +rYCnt RN 1 +rBres RN 2 +rDeltaY RN 3 +rPixShft RN 4 +rScrAdr RN 5 +rPixMsk RN 6 +rDotPtr RN 7 + +rEcfPtr RN 8 + +rEcfBase RN 8 +rEcfIndx RN 9 +rDeltaX RN 10 +rScanStp RN 11 + +rDotCnt RN 9 +rDotPatLSW RN 10 +rDotPatMSW RN 11 + +rDOTCnt RN 10 +rDOTPatLSW RN 11 +rDOTPatMSW RN 14 + + +; +;------------------------------------------------------------------------------ +; +; LineDraw - General line drawing routine +; ======== +; +; On entry, ICursor is the start point of the line +; NewPt is the end point +; +; R2 holds plot code, where bits mean :- +; bit 5 clear/set - include/exclude initial point +; bit 4 clear/set - solid/dotted line +; bit 3 clear/set - include/exclude final point +; +; bit 5 implies - restart/continue dot pattern +; +LineDrawSolid + TST R2, #&03 ; if a no action one + MOVEQ PC, R14 ; then do nowt, just shunt coords +LineDrawDotted ROUT + EOR R11, R2, #&18 ; Flip solid/dotted flag, and final point flag + ; bit 4 set/clear - solid/dotted line + ; bit 3 set/clear - include/exclude final point + MOV R9, #0 + ADD R10, WsPtr, #LineDotCnt + + TST R11, #&10 + STRNE R9, [WsPtr, #LineDotPtr] ; Solid line + STREQ R10, [WsPtr, #LineDotPtr] ; Dotted line + + TSTEQ R11, #&20 ; If dotted line & first point included + STREQ R9, [WsPtr, #LineDotCnt] ; then force a restart of the pattern + + STR R9, [WsPtr, #PostCycleCount] ; Assume all dots get plotted + + ADD R0,WsPtr,#GCsIX ;Start ICursor + LDMIA R0,{R0,R1,R2,R3} ;End NewPt + + TEQ R1, R3 ; If line is horizontal + BEQ TryHLine ; try to use HLine + [ UseVLineOnSolidLines + TEQ R0, R2 ; If line is vertical + BEQ TryVLine ; try to use VLine +CantUseVLine + ] +CantUseHLineOrVLine + SaveRetAdr + + Difference R4,R0,R2 + Difference R5,R1,R3 + Greatest R10,R4,R5 + ADD R10,R10,#1 ;Total number of dots on line + + BL GenLineParm ;Generate line control block + ; in R0..R8 + + TST R11,#&20 ;If first point excluded + BLNE AdvLineParm ; then advance to first pixel and + SUBNE R10,R10,#1 ; dec DotCycleCount + + TST R11,#&08 ;If last point excluded + SUBEQ R10,R10,#1 ; then dec DotCycleCount + + CMP R10,#0 ;IF DotCycleCount <= 0 + Return LE ; then nothing to plot + + STR R10,[WsPtr,#DotCycleCount] + STR R11,[WsPtr,#LineEndPtFlags] + + WINDow R0,R1, R9,R10,R11,R14 ;If start point outside window + BLLT LineStartsOutsideWindow ; then panic {won't return if whole + ; line outside window} + + WINDow R7,R8, R9,R10,R11,R14 ;If end point outside window + BLLT LineEndsOutsideWindow ; then panic as well + +; +; R0 ,R1 ,R2 ,R3 ,R4 ,R5 ,R6 +; StartX,StartY,Bres,DeltaX,DeltaY,StepX,StepY +; + + ;Modify StepX (+1/-1 means right/left) + CMP R5,#0 ; to give PixelMask shift factor + LDR R5,[WsPtr,#BytesPerChar] ; "Left" + RSBPL R5,R5,#0 ; "Right" + + ;Modify StepY (+1/-1 means up/down) + CMP R6,#0 ; to give offset to next scan line + LDR R6,[WsPtr,#LineLength] ; "Down" + RSBPL R6,R6,#0 ; "Up" + + Push "R2-R6" ;Bres,DeltaX,DeltaY,StepX,StepY + + BL ScreenAddr + MOV R7,R2 ;Screen Adr + MOV R8,R3 ;Pixel Mask + + LDR R9,[WsPtr, #YWindLimit] + SUB R9,R9,R1 ;subtract Y from YWindLimit + AND R9,R9,#7 ;EcfIndx + + Pull "R2-R6" ;Bres,DeltaX,DeltaY,StepX,StepY + + LDR R0,[WsPtr,#DotCycleCount] ;Number of on screen pixels + CMP R0,#0 ; An LPO line starting outside & ending + Return LE ; on the window leaves zero dots! + + LDR R1,[WsPtr,#LineDotPtr] + CMP R1,#0 + BNE DotDashLine + +SolidLine ROUT + Push R12 + LDR R1, [WsPtr, #GColAdr] ; Base address of ECF + ADD R1, R1, R9, LSL #3 ; current address of ECF +; +; R0 ,R1 ,R2 ,R3 ,R4 ,R5 ,R6 ,R7 ,R8 ,R9 +; PixCnt,EcfBase,Bres,DeltaX,DeltaY,MskShft,LineStp,ScrAdr,Mask,Indx +; + + LDMIA R1, {R9, R10} ; R9 = zgora; R10 = zgeor +20 + MOV R12, R8 +30 + SUBS R0, R0, #1 ; Dec pixel count + BEQ %FT57 ; if zero, then finish off + +40 +; Advance the screen address and pixel mask one pixel + + TEQ R2, #0 ; If Bres positive + BPL %FT55 ; then advance in X dirn only + ; else advance in Y direction, which + ; may involve advancing X afterwards +45 + AND R14, R9, R12 ; R14 = zgora AND pixmask + LDR R11, [R7] ; R11 = word from screen + ORR R11, R11, R14 ; OR with screen + AND R14, R10, R12 ; R14 = zgeor AND pixmask + EOR R11, R11, R14 ; EOR with screen + STR R11, [R7], R6 ; and store back, moving on + + CMP R6, #&80000000 ; C=1 => going up the screen + TSTCS R1, #63 ; so check being at word 0 of ECF + SUBCS R1, R1, #8 ; and then subtract 2 words + ADDCC R1, R1, #8 ; else add on 2 words first + TSTCC R1, #63 ; and then test for wrap + BEQ %FT60 + LDMIA R1, {R9, R10} ; reload zgora and zgeor + ADDS R2, R2, R3 ; Advance Bres, in Y dirn + + BMI %BT20 ; [don't need to move in X direction] +50 + MOV R12, #0 ; clear total pixel mask +55 +; +; Advance in X direction +; + CMP R5, #&80000000 ; if +ve then RORing, so test if + TSTCC R8, #1 ; bottom bit set before shifting + MOV R8, R8, ROR R5 ; shift word + TSTCS R8, #1 ; else test after shifting + SUB R2, R2, R4 ; always advance Bres in X direction + ORREQ R12, R12, R8 ; if not wrapped, OR in new pixel + BEQ %BT30 ; and loop + +57 + AND R14, R9, R12 ; R14 = zgora AND pixmask + LDR R11, [R7] ; R11 = word from screen + ORR R11, R11, R14 ; OR with screen + AND R14, R10, R12 ; R14 = zgeor AND pixmask + EOR R11, R11, R14 ; EOR with screen + STRCC R11, [R7], #-4 ; and store back + STRCS R11, [R7], #4 ; incrementing or decrementing + + MOV R12, R8 ; reset total pixel mask + + SUBS R0, R0, #1 + Pull "R12, PC", LT ; exit if COMPLETELY finished + BEQ %BT57 ; if no more to do, then output word! + TEQ R2, #0 ; test Bres again + BPL %BT55 + B %BT45 + +; come here when ECF wraps (ie every eight Y coords) + +60 + ADDCS R1, R1, #64 ; if wrap and going up, then add 64 + SUBCC R1, R1, #64 ; if wrap and going down, subtract 64 + LDMIA R1, {R9, R10} ; reload zgora and zgeor + ADDS R2, R2, R3 ; Advance Bres, in Y dirn + BMI %BT20 ; [don't need to move in X direction] + B %BT50 + +; ***************************************************************************** +; +; TryHLine - Try to use HLine (we already know Y1=Y2) +; +; in: R0 = X1 +; R1 = R3 = Y +; R2 = X2 +; R11 = plot code EOR &18 +; bit 3 set => include last point +; bit 4 set => solid +; bit 5 set => exclude first point +; + +TryHLine ROUT + TST R11, #&10 ; is it dotted + BEQ CantUseHLineOrVLine ; yes, then can't use HLine + + CMP R2, R0 + MOVGE R4, #1 + MOVLT R4, #-1 + TST R11, #&20 ; if first point excluded + ADDNE R0, R0, R4 ; then move R0 one pixel towards R2 + TST R11, #&08 ; if last point excluded + SUBEQ R2, R2, R4 ; then move R2 one pixel towards R0 + + CMP R2, R0 ; check order again + EORLT R0, R0, R2 ; make sure R0 <= R2 + EORLT R2, R0, R2 + EORLT R0, R0, R2 + RSBLT R4, R4, #0 ; if swapped, then invert sign of R4 + TEQNE R4, #1 ; if order is now different + ; (and they're not equal now) + MOVNE PC, R14 ; then there's nothing to plot + B NewHLine ; else go and do it! + +; ***************************************************************************** +; +; TryVLine - Try to use VLine (we already know X1=X2) +; +; in: R0 = R2 = X +; R1 = Y1 +; R3 = Y2 +; R11 = plot code EOR &18 +; bit 3 set => include last point +; bit 4 set => solid +; bit 5 set => exclude first point +; + +TryVLine ROUT + TST R11, #&10 ; is it dotted + BEQ CantUseHLineOrVLine ; yes, then can't use VLine (or HLine) + +; now make sure that we are using a solid pattern (not an ECF) +; this is true if the appropriate GCOL action is < 8 + + AND R4, R11, #3 ; look at bottom 2 bits of R11 + CMP R4, #2 ; to check which action + ; (already ruled out 0 (no action)) + LDRCC R4, [WsPtr, #GPLFMD] ; <2 => 1 => foreground action + MOVEQ R4, #4 ; =2 => 2 => invert action + LDRHI R4, [WsPtr, #GPLBMD] ; >2 => 3 => background action + CMP R4, #8 ; is it a solid action + BCS CantUseVLine + + CMP R3, R1 + MOVGE R4, #1 + MOVLT R4, #-1 + TST R11, #&20 ; if first point excluded + ADDNE R1, R1, R4 ; then move R1 one pixel towards R3 + TST R11, #&08 ; if last point excluded + SUBEQ R3, R3, R4 ; then move R3 one pixel towards R1 + + CMP R3, R1 ; check order again + EORLT R1, R1, R3 ; make sure R1 <= R3 + EORLT R3, R1, R3 + EORLT R1, R1, R3 + RSBLT R4, R4, #0 ; if swapped, then invert sign of R4 + TEQNE R4, #1 ; if order is now different + ; (and they're not equal now) + MOVNE PC, R14 ; then there's nothing to plot + B NewVLine ; else go and do it! + + +; +; +; +DotDashLine + +; +; R0 ,R1 ,R2 ,R3 ,R4 ,R5 ,R6 ,R7 ,R8 ,R9 +; PixCnt,DotPtr,Bres,DeltaX,DeltaY,MskShft,LineStp,ScrAdr,Mask,Indx +; + +DotDash20 + LDMIA R1,{rDOTCnt,rDOTPatLSW,rDOTPatMSW} + + CMP rDOTCnt,#0 + + ADDEQ rDOTCnt,WsPtr,#DotLineStyle ;Restart pattern + LDMEQIA rDOTCnt,{rDOTPatLSW,rDOTPatMSW} + LDREQ rDOTCnt,[WsPtr,#DotLineLength] + + SUB rDOTCnt,rDOTCnt,#1 + + MOVS rDOTPatMSW,rDOTPatMSW,LSL #1 + ORR rDOTPatMSW,rDOTPatMSW,rDOTPatLSW,LSR #31 + MOV rDOTPatLSW,rDOTPatLSW,LSL #1 + + STMIA R1,{rDOTCnt,rDOTPatLSW,rDOTPatMSW} + + BCC DotDash30 ;Don't plot this dot + + LDR R10,[WsPtr,#GColAdr] ;Base address of ECF + ADD R10,R10,R9,LSL #3 ;Address of ECFora & ECFeor + WriteToScreen R7,R8,R10, R10,R11,R14 + +DotDash30 + SUBS R0,R0,#1 ;Dec pixel count + BEQ DotDash60 ;Finished on screen + +DotDash40 +; +; Advance the screen address and pixel mask one pixel +; + + CMP R2,#0 ;If Bres positive + BPL DotDash50 ;then advance in X dirn only + ;else advance in Y direction, which may + ; involve advancement in X afterwards + + CMP R6,#0 ;Advance Ecf to next scanline + SUBLT R9,R9,#1 ; "Up" = (Old-1) Mod 7 + ADDGE R9,R9,#1 ; "Doun" = (Old+1) Mod 7 + AND R9,R9,#7 + + ADD R7,R7,R6 ;Advance screen address one scanline + + ADDS R2,R2,R3 ;Advance Bres, in Y dirn + BMI DotDash20 ; + ; may now need advancing in X dirn +DotDash50 +; +; Advance in X direction +; +; Rotate PixMsk to next pixel position, altering ScrAdr if we cross to +; the next word. +; + + TST R8, R5 ;If PixMsk at MSEnd of word + ; and shifting left + ADDMI R7, R7, #4 ;then inc ScrAdr {PixMsk will wrap} + + MOVS R8, R8, ROR R5 ;Move PixMsk + + ;If PixMsk now at MSEnd of word + RSBMIS R11, R5, #0 ; and shift was right + SUBMI R7, R7, #4 ;then dec ScrAdr {PixMsk wrapped} + + SUB R2, R2, R4 ;Advance Bres, in X dirn + B DotDash20 + +DotDash60 + + LDR R0,[WsPtr,#PostCycleCount] + CMP R0,#0 + BLNE AdvanceDotPattern + + Return + + LTORG + + DCD 0 ; *** Inserted for diagnostic purposes ! *** + +; +; +; +;------------------------------------------------------------------------------ +; +; LineEndsOutSideWindow +; ===================== +; +LineEndsOutsideWindow + + Push "R0-R8,Link" ;Push whole parameter block + + ADD R0,WsPtr,#GCsIX ;Start ICursor + LDMIA R0,{R0,R1,R2,R3} ;End NewPt + Swap R0,R2 + Swap R1,R3 + + BL GenLineParm ;Generate line control block + ; in R0..R8 + LDR R11,[WsPtr,#LineEndPtFlags] + + TST R11,#&08 ;If last point excluded + BLEQ AdvLineParm ; then advance to actual last point + + Push "R0,R1" ;EndX,EndY + + WindowRes R11,R0,R1, R7,R8,R9,R10 ;R11 := Window(End) + +; +; R0 ,R1 ,R2 ,R3 ,R4 ,R5 ,R6 , ,R11 +; EndX,EndY,Bres,DeltaX,DeltaY,StepX,StepY, ,WEnd +; + + TST R11,#&C ;If above/below window + BEQ LEO10 + + BL InYWind ; then bring Y into window + + WindowRes R11,R0,R1, R7,R8,R9,R10 ;R11 := Window(NewEnd) + +LEO10 + TST R11,#&3 + BEQ LEO20 ;If start outside X window + + BL InXWind + + WindowRes R11,R0,R1, R7,R8,R9,R10 ;R11 := Window(NewEnd) + +LEO20 + Pull "R9,R10" ;EndX,EndY + + Difference R0,R0,R9 + Difference R1,R1,R10 + Greatest R0,R0,R1 + + LDR R1,[WsPtr,#DotCycleCount] + SUB R1,R1,R0 + STR R1,[WsPtr,#DotCycleCount] + STR R0,[WsPtr,#PostCycleCount] + + Pull "R0-R8,PC" +; +; +; +;------------------------------------------------------------------------------ +; +; LineStartsOutSideWindow +; ======================= +; +LineStartsOutsideWindow + + Push Link + Push "R0,R1" ;StartX,StartY + + Push "R5,R6" + WindowRes R10,R0,R1, R5,R6,R9,R14 ;R10 := Window(Start) + WindowRes R11,R7,R8, R5,R6,R9,R14 ;R11 := Window(End) + Pull "R5,R6" + + TST R10,R11 + BNE LineOutsideWindow ;Line completely outside window + + +; +; R0 ,R1 ,R2 ,R3 ,R4 ,R5 ,R6 ,R7 ,R8 ,R10 ,R11 +; StartX,StartY,Bres,DeltaX,DeltaY,StepX,StepY,EndX,EndY ,WStart,WEnd +; + + TST R10,#&C ;If above/below window + BEQ LSO10 + + Push R11 + BL InYWind ; then bring Y into window + Pull R11 + + Push "R6-R8" + WindowRes R10,R0,R1, R6,R7,R8,R9 ;R10 := Window(NewStart) + Pull "R6-R8" + + TST R10,R11 + BNE LineOutsideWindow ;Line completely outside window +LSO10 + TST R10,#&3 + BEQ LSO20 ;If start outside X window + + Push R11 + BL InXWind + Pull R11 + + Push "R6-R8" + WindowRes R10,R0,R1, R6,R7,R8,R9 ;R10 := Window(NewStart) + Pull "R6-R8" + CMP R10,#0 + + BNE LineOutsideWindow ;Cannot clip to window +LSO20 + Pull "R9,R10" ;StartX,StartY + + Push "R0-R8" + Difference R0,R0,R9 + Difference R1,R1,R10 + Greatest R0,R0,R1 + BL AdvanceDotPattern + Pull "R0-R8" + + Pull "PC" + + +LineOutsideWindow + Pull "R0,R1" ;Balance the stack + LDR R0,[WsPtr,#DotCycleCount] + BL AdvanceDotPattern + + Pull "Link" + Return ;To caller of the line routine +; +; +; +;------------------------------------------------------------------------------ +; + + +lpStartX RN 0 +lpStartY RN 1 +lpBres RN 2 +lpDeltaX RN 3 +lpDeltaY RN 4 +lpStepX RN 5 +lpStepY RN 6 + + + + + + +; +; InYWind - Bring a set of line parameters into the Y window +; ======= +; +; On entry, R0-R6 contain a line parameter block +; R0 - StartX +; R1 - StartY +; R2 - Bres +; R3 - DeltaX +; R4 - DeltaY +; R5 - StepX (+1/-1) (Equv bit6 of Sign in 6502 version) +; R6 - StepY (+1/-1) (Equv bit7 of Sign in 6502 version) +; R7 - EndX +; R8 - EndY +; +; R9 - gwbrow +; R10 - gwtrow +; +; Algorithm: +; 1. Calculate distance to Y window +; 2. Change StartY by (distance-1) +; 3. Add (distance-1)*DeltaX to Bres +; 4. Divide Bres by DeltaY +; 5. Subtract (quotient+1)*DeltaY from Bres +; 6. Change StartX by (quotient+1) +; 7. Do one more pixel advance by AdvLineParm +; (N.B. this is always the Bres -ve case) +; +; +; +InYWind + SaveRetAdr + + LDR R9,[WsPtr,#GWBRow] + LDR R10,[WsPtr,#GWTRow] + ;(1) + CMP lpStepY,#0 + SUBGE R11,R9,lpStartY + SUBLT R11,lpStartY,R10 + SUB R11,R11,#1 ;(Distance to window) - 1 + + BL InYW30 ;Steps 2-6 + + BL AdvLineParm ;Step to first pixel in window + Return +; +; Flags still valid, GE/LT +; +; R11 holds distance to window -1 +; +InYW30 ;(2) + ADDGE lpStartY,lpStartY,R11 ;StartY := GWBRow-1 + SUBLT lpStartY,lpStartY,R11 ;StartY := GWTRow+1 + ;(3) + MOV R10,lpDeltaX + MUL R9,R11,R10 + ADDS lpBres,lpBres,R9 ;Bres := Bres+(dist-1)*DeltaX + + ;If lpBres now -ve, + MOVLT PC,Link ;then don't modify StartX + ; (quotient+1 is 0) + ;else + MOV R10,lpDeltaY +; *****Change made by DJS +; Use new DivRem macro, not old DIVREM +; Original code was: +; DIVREM R11,lpBres,R10,R9 + DivRem R11,lpBres,R10,R9 +; *****End of change made by DJS + SUB lpBres,lpBres,lpDeltaY + + ADD R11,R11,#1 ; quotient := 1+bres/deltay + ;(6) + CMP lpStepX,#0 + ADDGE lpStartX,lpStartX,R11 + SUBLT lpStartX,lpStartX,R11 + + MOV PC,Link + + + + +; +; InXWind - Bring a set of line parametres into the X window +; ======= +; +; On entry, R0-R6 contain a line parameter block +; R0 - StartX +; R1 - StartY +; R2 - Bres +; R3 - DeltaX +; R4 - DeltaY +; R5 - StepX (+1/-1) (Equv bit6 of Sign in 6502 version) +; R6 - StepY (+1/-1) (Equv bit7 of Sign in 6502 version) +; R7 - EndX +; R8 - EndY +; +; R9 - gwlcol +; R10 - gwrcol +; +; Algorithm: +; 1. Replace Bres by -Bres-1 +; 2. Swap StartX and StartY +; 3. Swap DeltaX and DeltaY +; 3a Swap StepX and StepY +; 4. Calculate distance to X window +; 5. Do steps 2-6 of InYWind +; 6. Repeat steps 1-3 +; 7. Do one more pixel advance by AdvLineParm +; (N.B. this is always the Bres +ve case) +; +InXWind + SaveRetAdr + + LDR R9,[WsPtr,#GWLCol] + LDR R10,[WsPtr,#GWRCol] + ;(1) + MVN lpBres,lpBres + ;(2)(3) + Push "lpStartX,lpDeltaX,lpStepX" + Push "lpStartY,lpDeltaY,lpStepY" + Pull "lpStartX,lpDeltaX,lpStepX" + Pull "lpStartY,lpDeltaY,lpStepY" + + CMP lpStepY,#0 ;Really StepX + SUBGE R11,R9,lpStartY + SUBLT R11,lpStartY,R10 + SUB R11,R11,#1 ;(Distance to window) - 1 + + BL InYW30 ;Steps 2-6 + ;(1) + MVN lpBres,lpBres + ;(2)(3) + Push "lpStartX,lpDeltaX,lpStepX" + Push "lpStartY,lpDeltaY,lpStepY" + Pull "lpStartX,lpDeltaX,lpStepX" + Pull "lpStartY,lpDeltaY,lpStepY" + + BL AdvLineParm ;Step to first pixel in window + Return + + + + +; +; rDotPtr RN 7 +; rDotCnt RN 9 +; rDotPatLSW RN 10 +; rDotPatMSW RN 11 + +; +; On entry R0 holds number of places to step dot pattern +; +AdvanceDotPattern + LDR R1,[WsPtr,#DotCycleCount] + SUB R1,R1,R0 + STR R1,[WsPtr,#DotCycleCount] + + LDR rDotPtr,[WsPtr,#LineDotPtr] + CMP rDotPtr,#0 + MOVEQ PC,Link + + LDR R1,[WsPtr,#DotLineLength] + MOV R2,R1 +; *****Change made by DJS +; Use new DivRem macro, not old DIVREM +; Original code was: +; DIVREM R3,R0,R2,R4 ;R0:=R0 REM DotLineLength + DivRem R3,R0,R2,R4 ;R0:=R0 REM DotLineLength +; *****End of change made by DJS + + LDMIA rDotPtr,{rDotCnt,rDotPatLSW,rDotPatMSW} + + CMP rDotCnt,R0 + SUBLT R0,R0,rDotCnt + + ADDLT rDotCnt,WsPtr,#DotLineStyle ;Restart pattern + LDMLTIA rDotCnt,{rDotPatLSW,rDotPatMSW} + LDRLT rDotCnt,[WsPtr,#DotLineLength] + + SUB rDotCnt,rDotCnt,R0 ;New value + + [ {TRUE} + +; need special code if R0 > 32 + + RSBS R1, R0, #32 + MOVLT rDotPatMSW, rDotPatLSW + MOVLT rDotPatLSW, #0 ; probably not necessary + SUBLT R0, R0, #32 + RSBLT R1, R0, #32 + + MOV rDotPatMSW,rDotPatMSW,LSL R0 + ORR rDotPatMSW,rDotPatMSW,rDotPatLSW,LSR R1 + MOV rDotPatLSW,rDotPatLSW,LSL R0 + | + +; old code + + RSB R1,R0,#32 + MOV rDotPatMSW,rDotPatMSW,LSL R0 + ORR rDotPatMSW,rDotPatMSW,rDotPatLSW,LSR R1 + MOV rDotPatLSW,rDotPatLSW,LSL R0 + ] + + STMIA rDotPtr,{rDotCnt,rDotPatLSW,rDotPatMSW} + + MOVS PC,Link +; +;--------------------------------------------------------------------------- +; + + END diff --git a/s/vdu/vdugrafg b/s/vdu/vdugrafg new file mode 100644 index 0000000000000000000000000000000000000000..3808b187f434e9781ab80dec8afa978e85bc786a --- /dev/null +++ b/s/vdu/vdugrafg @@ -0,0 +1,2685 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > &.Source.VduGrafG +; +; ARTHUR OPERATING SYSTEM - Vdu Drivers +; ======================= +; +; Vdu driver code - Sprite stuff +; +; Author R C Manby +; Date 10.11.86 +; + +RangeB * 256 +RangeC * 512 + +; Macros for various sprite operations + + MACRO + KillSpChoosePtr + MOV R0, #0 + STR R0, [WsPtr, #SpChoosePtr] + MEND + + MACRO + CopyDown $to,$from,$bytes, $tmp, $tmp2 + LDR $tmp2, [WsPtr, #VduSprite] ; sprite being output to by Vdu + ADD $tmp, $from, $bytes + SUB $tmp, $tmp, #1 ; from + bytes -1 + CMP $tmp2, $to ; if VOTS >= to + CMPCS $tmp, $tmp2 ; and from+bytes-1 >= VOTS + BCC %FT00 + Push "R0, R14" + SUB R0, $to, $from ; then adjust address vars + BL AdjustSpriteAddress ; by offset = to-from + Pull "R0, R14" +00 + CMP $bytes, #0 ; bytes must be a multiple of 4 +01 + LDRNE $tmp, [$from], #4 + STRNE $tmp, [$to], #4 + SUBNES $bytes, $bytes, #4 + BNE %BT01 + MEND + + MACRO + CopyUp $to,$from,$bytes, $tmp, $tmp2 + LDR $tmp2, [WsPtr, #VduSprite] ; sprite being output to by Vdu + ADD $tmp, $to, $bytes + SUB $tmp, $tmp, #1 ; to + bytes -1 + CMP $tmp2, $from ; if VOTS >= from + CMPCS $tmp, $tmp2 ; and to+bytes-1 >= VOTS + BCC %FT00 + Push "R0, R14" + SUB R0, $to, $from ; then adjust address vars + BL AdjustSpriteAddress ; by offset = to-from + Pull "R0, R14" +00 +01 + SUBS $bytes, $bytes, #4 + LDRCS $tmp, [$from, $bytes] + STRCS $tmp, [$to, $bytes] + BHI %BT01 + MEND + +; copy R0 bytes from R3 to R2 (R2+:=R0; R3+:=R0) +; corrupts R0, R4-R11, R14 +; NB not used at present + + MACRO + CopyDownFast + SUBS R0, R0, #9*4 +10 + LDMCSIA R3!, {R4-R11,R14} + STMCSIA R2!, {R4-R11,R14} + SUBCSS R0, R0, #9*4 + BCS %BT10 + ADDS R0, R0, #9*4 +20 + LDRNE R4, [R3], #4 + STRNE R4, [R2], #4 + SUBNES R0, R0, #4 + BNE %BT20 + MEND + + MACRO + ClearWords $from,$words, $tmp + MOV $tmp,#0 +01 + SUBS $words, $words, #1 + STRCS $tmp, [$from], #4 + BHI %BT01 + MEND + +; ***************************************************************************** +; +; AdjustSpriteAddress - Move VduSprite, ScreenStart, CursorAddr and +; InputCursorAddr by R0 +; +; Internal routine, called by routines that use macros +; CopyDown, CopyUp +; +; in: R0 = no. of bytes to add on (can be -ve) +; + +AdjustSpriteAddress ROUT + Push R14 + LDR R14, [WsPtr, #VduSprite] + ADD R14, R14, R0 + STR R14, [WsPtr, #VduSprite] + LDR R14, [WsPtr, #ScreenStart] + ADD R14, R14, R0 + STR R14, [WsPtr, #ScreenStart] + B AdjustCursorVars ; update CursorAddr, InputCursorAddr + +; ***************************************************************************** +; +; SpriteInit - Setup sprite workspace on reset (called whenever break +; is pressed) +; + +SpriteInit ROUT + Push R14 + [ :LNOT: AssemblingArthur + LDR R0, =SvcTable ; intercept SWI SpriteOp + ADR R1, SwiSpriteOp + STR R1, [R0, #(OS_SpriteOp*4)] + + ADRL R1, SwiReadPoint ; might as well catch ReadPoint + STR R1, [R0, #(OS_ReadPoint*4)] ; here + ] + + BL ClearSpritePtrName ; clear SpChoosePtr,SpChooseName + + [ :LNOT: NewStyle_SpriteArea + [ AssemblingArthur + MOV R0, #0 + LDRB R0, [R0, #OsbyteVars + :INDEX: LastBREAK] + CMP R0, #0 ; Soft=0,POR=1,Hard=2 + BNE %FT10 ; If CtrlBreak or PowerOnReset setup default + Pull PC, EQ ; sprite area + +; LDR R1, [WsPtr, #SpAreaStart] +; CMP R1, #0 +; BEQ %FT20 +; BL ValidateSpriteArea +; BVC %FT20 + ] +10 + [ AssemblingArthur :LOR: Module + MOV R2, #0 + LDR R2, [R2, #SpriteSize] ; Tony sez this is (0..n)*(8or32)Kbytes + CMP R2, #0 + STREQ R2, [WsPtr, #SpAreaStart] ; EQ means no workspace + Pull PC, EQ + + LDR R1, =SpriteSpaceAddress + STR R1, [WsPtr, #SpAreaStart] +; SUB R2, R2, #16 ; Lose 4 words in case we overshoot + + MOV R3, #0 ; no sprites + MOV R4, #SpriteAreaCBsize ; saFirst + MOV R5, #SpriteAreaCBsize ; saFree + + STMIA R1, {R2,R3,R4,R5} ; saEnd,saNumber,saFirst,saFree + | + MOV R1, #0 + STR R1, [WsPtr, #SpAreaStart] ; no sprite workspace + ] +20 + ] + Pull PC + + LTORG + +; ***************************************************************************** +; +; Vdu23_27 - SCHOOSE/SGET a numbered sprite +; +; in: QQ?0 = 0 => Select sprite STR$(QQ?1) for plotting +; QQ?0 = 1 => Sget an area of screen and put it in sprite STR$(QQ?1) +; + +Vdu23_27 ROUT + LDRB R0, [WsPtr, #QQ+1] + CMP R0, #1 + MOVCC R3, #SpriteReason_SelectSprite ; 0-Select sprite + MOVEQ R3, #SpriteReason_GetSprite ; 1-Pickup sprite + MOVHI PC, R14 + + Push R14 + + LDRB R0, [WsPtr, #QQ+2] ; sprite number + ADD R1, WsPtr, #NameBuf + MOV R2, #4 + SWI XOS_BinaryToDecimal + MOV R0, #13 + STRB R0, [R1, R2] ; $NameBuf := STR$(n) + + MOV R0, R3 ; R0 = sprite-op reason code + MOV R2, R1 ; R2 -> sprite name + MOV R3, #0 ; extension gap size + SWI XOS_SpriteOp ; perform operation, ignore errors + + Pull PC + +; ***************************************************************************** +; +; SpritePlot - PLOT &E8-&EF,X,Y +; +; in: R2 = plot code +; +; The 2 LSBits of the plot code specify fg/bg colour and action as :- +; 0 => No effect eqv. of Gcol(5,c) +; 1 => Plot sprite using foreground Gcol action +; 2 => Invert eqv. of Gcol(4,c) +; 3 => Plot mask in background colour and Gcol action +; + +SpritePlot ROUT + Push R14 + + AND R3, R2, #3 ; 2 LSBits of plot code + CMP R3, #1 + MOVCC R5, #5 ; gcol action - no effect + LDREQ R5, [WsPtr, #GPLFMD] ; foreground + MOVHI R5, #4 ; invert or background + + AND R5, R5, #&0F ; knock out any ecf bits + + LDR R2, [WsPtr, #SpChoosePtr] ; If ChoosePtr <> 0 + CMP R2, #0 + BNE %FT10 ; then use as pointer to sprite + + MOV R0, #SpriteReason_SelectSprite ; else select it first + LDR R2, =SpChooseName + ADD R2, R2, WsPtr ; sprite name ptr + SWI XOS_SpriteOp + LDR R2, [WsPtr, #SpChoosePtr] + +10 ; R2 points to the sprite + CMP R3, #3 + MOVNE R0, #RangeC+SpriteReason_PutSprite + LDREQ R0, =RangeC+SpriteReason_PlotMask + LDR R1, [WsPtr, #SpAreaStart] + SWI XOS_SpriteOp ; perform operation, ignoring errors + + Pull PC + +; ***************************************************************************** +; +; SwiSpriteOp - Entry point for SWI OS_SpriteOp +; +; in: R0 = sprite op reason code +; R1 -> sprite area (usually) +; R2 -> sprite (usually) +; R3..? parameters +; + +SwiSpriteOp ROUT + Push R14 + BranchNotJustUs %F10, SpriteV, R11, R14 + +; we are sole owners of SpriteV, so call our internal routine + + Push PC ; push address of SwiSpriteReturn + B SpriteVecHandler + & 0 + +SwiSpriteReturn + Pull R14 + ORRVS R14, R14, #V_bit ; if error, set V_bit in link + ExitSWIHandler + +; we are not the sole owners of SpriteV, so call the vector + +10 + MOV R10, #SpriteV + BL %FT20 + Pull R14 + ORRVS R14, R14, #V_bit ; if error, set V_bit in link + ExitSWIHandler + +20 + CallAVector + +; ***************************************************************************** +; +; SpriteVecHandler - Default owner of SpriteV +; +; in: R0-R7 contain our entry parameters +; +; out: R0-R7 contain exit parameters +; R8-R12 are preserved +; + + MACRO + SpriteOpDispatch $cond + ADD$cond PC, R10, R11, ASR #8 + MEND + + MACRO + SpriteOpEntry $addr, $flags + & (($addr - SwiSpriteOpCallTb) :SHL: 8) + $flags + MEND + +; The end of this code is put before the beginning, so that +; SpriteDispatchReturn + SVC_mode is within ADR reach of the dispatcher + +BadReasonCode ROUT + ADRL R0, SpriteErr_BadReasonCode + [ International + BL TranslateError + ] + B %FT20 +SpriteIsCurrentDest + ADRL R0, SpriteErr_SpriteIsCurrentDest + [ International + BL TranslateError + ] + B %FT20 + +15 + ADRL R0, SpriteErr_DoesntExist + [ International + BL TranslateError + ] + +20 ; Exit SWI with error, error code in R0 + STR R0, [WsPtr, #RetnReg0] +30 + SETV ; indicate an error + +; and drop thru to... + +SpriteDispatchReturn + ADD R11, WsPtr, #RetnReg0 + LDMIA R11, {R0-R9} ; Restore R0-R9 + [ Fix5 + MOV R10, R13 ; Point at old returned registers + Push "R0-R9" ; Save new returned registers on stack + LDMIA R10, {R0-R9} ; Load old returned registers + STMIA R11, {R0-R9} ; and put them in the dump area + Pull "R0-R9" ; restore new returned registers + ADD R13, R13, #10*4 ; remove stack frame + ] + [ :LNOT: AssemblingArthur :LAND: :LNOT: Module + SWIVS XOS_GenerateError + ] + Pull "R10-R12,PC" + +SpriteVecHandler + Push "R10-R12" + TEQP PC, #SVC_mode ; Re-enable interupts + + VDWS WsPtr ; Point R12 at Vdu driver workspace + ADD R11, WsPtr, #RetnReg0 + + [ Fix5 + SUB R13, R13, #10*4 ; Create stack frame for old RetnRegs + MOV R10, R13 ; Keep pointer to this frame + Push "R0-R9" ; Save new regs while we copy old ones + LDMIA R11, {R0-R9} ; Load old regs + STMIA R10, {R0-R9} ; and push them onto stack + Pull "R0-R9" ; Restore new regs + ] + STMIA R11, {R0-R9} ; Dump R0-R9 + + CMP R0, #RangeC + &100 ; if top bits out of range + BCS BadReasonCode ; then error + + CMP R0, #RangeB ; if Range A type + LDRCC R1, [WsPtr, #SpAreaStart] ; then point at MOS sprite area + + AND R0, R0, #&FF ; Kill the range bits + CMP R0, #SpriteReason_BadReasonCode + BCS BadReasonCode + + ADR R10, SwiSpriteOpCallTb + ADR R14, SpriteDispatchReturn + SVC_mode ; return address + LDR R11, [R10, R0, LSL #2] ; load (offset<<8) + flags + + TST R11, #SSO_ScreenNotAllowed ; if call can specify screen (R2=0) + TEQEQ R2, #0 ; and it is specified + MOVEQ R1, #0 ; then make sprite area ptr 0 as well + TSTNE R11, #SSO_NeedsSomething ; or nothing needed anyway + SpriteOpDispatch EQ ; then dispatch + + TEQ R1, #0 ; else needs sprite area ptr + ADREQ R0, SpriteErr_NoWorkSpace ; so if zero then invalid + [ International + BLEQ TranslateError + ] + BEQ %BT20 + + TST R11, #SSO_DangerAreaOp ; if not a danger area op + BEQ %FT32 ; then skip + + LDR R9, [WsPtr, #VduSpriteArea] ; else check if sprite area is same + TEQ R9, R1 + BEQ SpriteIsCurrentDest ; and error if so + +32 + TST R11, #SSO_NeedsSprite ; if doesn't need sprite + BNE %FT33 + + TEQ R0,#SpriteReason_CreateSprite + BEQ %FT21 + + TEQ R0,#SpriteReason_ScreenSave + TEQNE R0,#SpriteReason_GetSprite + TEQNE R0,#SpriteReason_GetSpriteUserCoords + + SpriteOpDispatch NE ; let it go if we're not interested in it + + LDR R9,[WsPtr, #Log2BPP] ; fetch the current bpp + + CMP R9,#4 + SpriteOpDispatch CC ; let it go if below 16bpp +22 + CMP R3,#0 + BNE %FT34 ; bang if it has a palette + + SpriteOpDispatch ; then dispatch + +21 ;createsprite. R6=mode number or sprite mode word, or => mode descriptor + Push "R0-R3,R14" + MOV R0,R6 + MOV R1,#VduExt_Log2BPP + SWI XOS_ReadModeVariable + MOVCS R2,#0 + CMP R2,#4 + Pull "R0-R3,R14" + SpriteOpDispatch CC + B %BT22 + +33 + TEQ R2, #0 ; if sprite ptr is zero it's a boob + BEQ %BT15 ; so say SpriteDoesntExist + + LDR R9, [WsPtr, #RetnReg0] + CMP R9, #RangeC ; if not range C then must look up + BCS %FT35 ; sprite name and convert to pt4 + Push R14 + BL SpriteCtrlBlk ; in: R2 -> name; out: R2 -> sprite + Pull R14 + BVS %BT15 ; no such sprite + +35 + +;medusa note. +; +;On Medusa masks and palettes for 16/32bpp sprites are in a transient state +;Medusa will fault 16/32bpp mask/palette operations, in readiness for the +;introduction of new (more compact) mask/palette formats. +; +;another medusa note. +; +;Mask operations using 1bpp masks on new format sprites are now being included. +;However palettes on 16/32bpp are still not allowed. +; + +;amg 12/11/93, sort out the logic here so that palettes on new format sprites +;really do get faulted + +;amg 25th May 1994. We now allow palettes on new format sprites of 8bpp +;and below + + ; find the sprite type + LDR R9,[R2,#spMode] + + MOVS R9,R9,LSR #27 ; put the sprite type at b0 + BEQ %FT37 ; t=0 (ie old format) +39 + + CMP R9,#SpriteType_New16bpp ; check sprite type number + BCC %FT37 ; despatch if new format and under 8bpp + + ; so, does it have a palette + Push "R14" ; I need another register for CMP + + ; now check for a palette + ADD R9,R2,#spImage + LDMIA R9,{R9,R14} ; pick up offsets to mask & image + CMP R9,R14 + MOVGT R9,R14 ; R9->top of palette block + SUBS R9,R9,#spPalette ; R9 = size of palette block + Pull "R14" + BEQ %FT38 ; no palette, so no error + +34 + ADRL R0, SpriteErr_NoMaskOrPaletteAllowedInThisDepth + [ International + BL TranslateError + ] + B %BT20 + +37 ;however, until mode selectors work there are some 16/32bpp old modes + Push "R0-R3,R14" ; save context + MOV R0,R9 + MOV R1,#VduExt_Log2BPP + SWI XOS_ReadModeVariable ; read log2bpp for the sprite's mode + MOV R9,R2 ; and move it for posterity + Pull "R0-R3,R14" + CMP R9,#4 + BCS %BT39 ; log2bpp of 4 = 16bpp, so see if we want to fault it +38 + TST R11, #SSO_DangerOp ; if a destructive op + BEQ %FT40 + + LDR R9, [WsPtr, #VduSprite] + TEQ R9, R2 + BEQ SpriteIsCurrentDest ; then stop him! + +40 + TST R11, #SSO_NeedsSpriteModeData + SpriteOpDispatch EQ + + Push "R5-R7, R10, R11, R14" + BL SetupSprModeData + Pull "R5-R7, R10, R11, R14" + SpriteOpDispatch VC + + B %BT30 ; Invalid spMode field + + +SSO_ScreenNotAllowed * 1 :SHL: 0 +SSO_NeedsSomething * 1 :SHL: 1 +SSO_NeedsSprite * 1 :SHL: 2 +SSO_NeedsSpriteModeData * 1 :SHL: 3 +SSO_DangerOp * 1 :SHL: 4 +SSO_DangerAreaOp * 1 :SHL: 5 + +Group1 * SSO_ScreenNotAllowed +Group2 * Group1 + SSO_NeedsSomething +Group3 * Group2 + SSO_NeedsSprite +Group4 * Group3 + SSO_NeedsSpriteModeData +Group5 * SSO_NeedsSomething + SSO_NeedsSprite + +SwiSpriteOpCallTb + SpriteOpEntry DoesNowt, Group1 + + [ AssemblingArthur :LOR: Module + SpriteOpEntry DoesNowt, Group1 + | + SpriteOpEntry ClaimSpace, Group1 ; *SSpace <size> + ] + + SpriteOpEntry ScreenSave, Group1 + SpriteOpEntry ScreenLoad, Group1 + SpriteOpEntry DoesNowt, Group1 + SpriteOpEntry DoesNowt, Group1 + SpriteOpEntry DoesNowt, Group1 + SpriteOpEntry DoesNowt, Group1 + +; The following need valid workspace + + SpriteOpEntry ReadAreaCB, Group2 + SpriteOpEntry ClearSprites, Group2 + SSO_DangerAreaOp ; *SNew + SpriteOpEntry LoadSpriteFile, Group2 + SSO_DangerAreaOp + ; *SLoad <filename> + SpriteOpEntry MergeSpriteFile, Group2 + SSO_DangerAreaOp + ; *SMerge <filename> + SpriteOpEntry SaveSpriteFile, Group2 ; *SSave <filename> + SpriteOpEntry ReturnName, Group2 + SpriteOpEntry GetSprite, Group2 ; *SGet <name> + SpriteOpEntry CreateSprite, Group2 + SpriteOpEntry GetSpriteUserCoords, Group2 + SpriteOpEntry DoesNowt, Group2 + SpriteOpEntry DoesNowt, Group2 + SpriteOpEntry DoesNowt, Group2 + SpriteOpEntry DoesNowt, Group2 + SpriteOpEntry DoesNowt, Group2 + SpriteOpEntry DoesNowt, Group2 + SpriteOpEntry DoesNowt, Group2 + +; The following need a sprite + + SpriteOpEntry SelectSprite, Group3 ; *SChoose <n> [<m>] + SpriteOpEntry DeleteSprite, Group3 + SSO_DangerOp ; *SDelete <n> + SpriteOpEntry RenameSprite, Group3 ; *SRename + SpriteOpEntry CopySprite, Group3 ; *SCopy + SpriteOpEntry PutSprite, Group3 + SpriteOpEntry CreateMask, Group3 + SpriteOpEntry RemoveMask, Group3 + SSO_DangerOp + SpriteOpEntry InsertRow, Group3 + SSO_DangerOp + SpriteOpEntry DeleteRow, Group3 + SSO_DangerOp + SpriteOpEntry FlipAboutXAxis, Group3 + SpriteOpEntry PutSpriteUserCoords, Group3 + SpriteOpEntry DoesNowt, Group3 + SpriteOpEntry DoesNowt, Group3 + SpriteOpEntry DoesNowt, Group3 + SpriteOpEntry DoesNowt, Group3 + SpriteOpEntry DoesNowt, Group3 + +; The following need sprite mode data + + SpriteOpEntry ReadSpriteSize, Group4 + SpriteOpEntry ReadPixelColour, Group4 + SpriteOpEntry WritePixelColour, Group4 + SpriteOpEntry ReadPixelMask, Group4 + SpriteOpEntry WritePixelMask, Group4 + SpriteOpEntry InsertCol, Group4 + SSO_DangerOp + SpriteOpEntry DeleteCol, Group4 + SSO_DangerOp + SpriteOpEntry FlipAboutYAxis, Group4 + SSO_DangerOp + SpriteOpEntry PlotMask, Group4 + SpriteOpEntry PlotMaskUserCoords, Group4 + SpriteOpEntry DoesNowt, Group4 ; 50 ; PlotMaskScaled + SpriteOpEntry DoesNowt, Group4 ; 51 ; PaintCharScaled + SpriteOpEntry DoesNowt, Group4 ; 52 ; PutSpriteScaled + SpriteOpEntry DoesNowt, Group4 ; 53 ; PutSpriteGreyScaled + SpriteOpEntry RemoveLeftHandWastage, Group4 + SpriteOpEntry DoesNowt, Group4 ; 55 PlotMaskTransformed + SpriteOpEntry DoesNowt, Group4 ; 56 PutSpriteTransformed + SpriteOpEntry DoesNowt, Group4 ; 57 InsertDeleteRows + SpriteOpEntry DoesNowt, Group4 ; 58 InsertDeleteColumns + SpriteOpEntry DoesNowt, Group4 ; 59 pseudo reason used by Wimp + +; The following need (sprite area + sprite) or (anything + 0), meaning screen + + SpriteOpEntry SwitchOutputToSprite, Group5 ; 60 + SpriteOpEntry SwitchOutputToMask, Group5 ; 61 + SpriteOpEntry ReadSaveAreaSize, Group5 ; 62 + +; ***************************************************************************** +; +; SetupSprModeData - Set up registers and variables from the sprite mode +; +; Internal routine: called by sprite dispatch, CreateHeader +; +; in: R2 -> sprite +; +; out: R0-R5 preserved +; R6 = ReadNColour (for a single screen pixel) +; R7 = WriteNColour (=R6 except in double pixel modes) +; R8 = BytesPerChar } +; R9 = XShftFactor } calculated from Log2BPC which is BitsPerPix +; R10 = NPix } corrected for double pixel modes +; R11 = Log2BPC } +; +; SprReadNColour..SprLog2BPC setup accordingly +; +; If error, then RetnReg0 updated + +SetupSprModeData ROUT + Push R14 + LDR R11, [R2, #spMode] + [ ModeSelectors + CMP r11, #&100 ; check for mode selector/new format sprite word + BCC %FT05 ; [it's a mode number so check for known ones] + TST r11, #1 ; if it's a new format sprite word + BNE %FT10 ; then call pushmodeinfo to get info on it + B %FT20 ; else it's a mode selector, which is illegal as a sprite mode word +05 + ] + BranchIfKnownMode R11, %FA10 + Push "R2-R4" + MOV R2, R11 + BL OfferModeExtensionAnyMonitor + Pull "R2-R4" + BNE %FT20 + +10 + MOV R10, R11 + BL PushModeInfoAnyMonitor + BVS %FT30 ; if duff new format sprite word, return error + + LDR R11, [R13, #wkModeFlags] + TST R11, #Flag_NonGraphic + BNE %FT15 ; non-graphic mode + + LDR R6, [R13, #wkNColour] ; ReadNColour + ;changed by amg 12/11/93 to stop it mistaking 16/32bpp for 8 +; TST R6, #&F0 ; 256 colour mode ? +; MOVNE R6, #&FF ; then use &FF + CMP R6,#63 + MOVEQ R6,#255 + LDR R11, [R13, #wkLog2BPC] ; Log2BPC + + ADD R13, R13, #PushedInfoSize +11 + MOV R7, #1 + RSB R9, R11, #5 ; XShftFactor + RSB R10, R7, R7, LSL R9 ; NPix + MOV R8, R7, LSL R11 ; BytesPerChar + RSB R7, R7, R7, LSL R8 ; WriteNColour + + Push R5 + ADD R5, WsPtr, #SprReadNColour + STMIA R5, {R6-R11} ; SprRead..SprLog2BPC + Pull "R5, R14" + BICS PC, R14, #V_bit + +15 + ADD R13, R13, #PushedInfoSize +20 + ADRL R0, SpriteErr_InvalidSpriteMode + [ International + BL TranslateError + ] +30 + STR R0, [WsPtr, #RetnReg0] + SETV + Pull pc + + +; ***************************************************************************** + +; Blocks for sprite errors + +SpriteErr_NoWorkSpace MakeErrorBlock Sprite_NoWorkSpace +SpriteErr_NoRoom MakeErrorBlock Sprite_NoRoom +SpriteErr_DoesntExist MakeErrorBlock Sprite_DoesntExist +SpriteErr_NoSprites MakeErrorBlock Sprite_NoSprites +SpriteErr_NotGraphics MakeErrorBlock Sprite_NotGraphics +SpriteErr_NotEnoughRoom MakeErrorBlock Sprite_NotEnoughRoom +SpriteErr_BadSpriteFile MakeErrorBlock Sprite_BadSpriteFile +SpriteErr_NoRoomToMerge MakeErrorBlock Sprite_NoRoomToMerge +SpriteErr_Bad2ndPtr MakeErrorBlock Sprite_Bad2ndPtr +SpriteErr_InvalidRowOrCol MakeErrorBlock Sprite_InvalidRowOrCol +SpriteErr_InvalidHeight MakeErrorBlock Sprite_InvalidHeight +SpriteErr_InvalidWidth MakeErrorBlock Sprite_InvalidWidth +SpriteErr_NoRoomToInsert MakeErrorBlock Sprite_NoRoomToInsert +SpriteErr_SpriteAlreadyExists MakeErrorBlock Sprite_SpriteAlreadyExists +SpriteErr_InvalidSpriteMode MakeErrorBlock Sprite_InvalidSpriteMode +SpriteErr_BadReasonCode MakeErrorBlock Sprite_BadReasonCode +SpriteErr_CantInTeletext MakeErrorBlock Sprite_CantInTeletext +SpriteErr_InvalidSaveArea MakeErrorBlock Sprite_InvalidSaveArea +SpriteErr_SpriteIsCurrentDest MakeErrorBlock Sprite_SpriteIsCurrentDest +SpriteErr_NoMaskOrPaletteAllowedInThisDepth MakeErrorBlock Sprite_NoMaskOrPaletteAllowedInThisDepth + +; ***************************************************************************** +; +; ClearSprites - Clear sprite area (*SNEW) +; +; External routine + dropped thru to +; + +ClearSprites ROUT + LDR R2, [R1, #saFirst] + STR R2, [R1, #saFree] + MOV R2, #0 + STR R2, [R1,#saNumber] + + LDR R0, [WsPtr, #RetnReg0] ; if rangeb or rangec + CMP R0, #RangeB + BICCSS PC, R14, #V_bit ; then return immediately + +; else its rangea, so drop thru to ... + +ClearSpritePtrName ROUT + MOV R0, #0 + STR R0, [WsPtr, #SpChoosePtr] + STR R0, [WsPtr, #SpChooseName] + STR R0, [WsPtr, #SpChooseName+4] + STR R0, [WsPtr, #SpChooseName+8] + MOV R0, #13 + STRB R0, [WsPtr, #SpChooseName+12] ; *SChoose <null name> +DoesNowt + BICS PC, R14, #V_bit + +; ***************************************************************************** +; +; ReadAreaCB - Read information from sprite area CB into registers +; +; External routine +; +; in: R1 -> sprite area +; +; out: R2 = offset to end of sprite area (ie total size) +; R3 = number of sprites in area +; R4 = offset to first sprite +; R5 = offset to first free word +; + +ReadAreaCB ROUT + LDMIA R1, {R2,R3,R4,R5} ; saEnd,saNumber,saFirst,saFree + ADD R11, WsPtr, #RetnReg2 + STMIA R11, {R2,R3,R4,R5} + BICS PC, R14, #V_bit + +; ***************************************************************************** +; +; SelectSprite - Select a named sprite for use by PLOT &E8..&EF +; +; External routine + called by GetSprite +; +; in: R2 -> sprite CB +; +; out: R0, R9..R11 corrupted +; If not using system sprite area, then R2 -> address of sprite +; + +SelectSprite ROUT + Push R14 + LDR R0, [WsPtr, #RetnReg0] ; if not in system sprite area + CMP R0, #RangeB + STRCS R2, [WsPtr, #RetnReg2] ; return the sprite address + Pull PC, CS + + STR R2, [WsPtr, #SpChoosePtr] ; else store name & address + ADD R14, R2, #spName ; for use by PLOT + LDMIA R14, {R9,R10,R11} ; load 12 bytes of name + LDR R14, =SpChooseName + ADD R14, R14, WsPtr ; RetnReg2 NOT altered, so user + STMIA R14, {R9,R10,R11} ; can't poke the workspace + Pull PC + +; ***************************************************************************** +; +; ReturnName - Return name of nth sprite in sprite area as a string +; +; External routine +; +; in: R1 -> sprite area +; R2 -> buffer +; R3 = max buffer length +; R4 = sprite number (n) +; +; out: R3 actual string length +; RetnReg3 updated +; + +ReturnName ROUT + LDR R5, [R1, #saNumber] ; check for 1 <= R4 <= saNumber + CMP R4, #1 + CMPGE R5, R4 + + ADRLTL R0, SpriteErr_DoesntExist ; out of range, so generate error + [ International + Push "lr",LT + BLLT TranslateError_VClear + Pull "lr",LT + ] + STRLT R0, [WsPtr, #RetnReg0] + ORRLTS PC, R14, #V_bit + + LDR R5, [R1, #saFirst] + ADD R5, R5, R1 ; ptr to 1st sprite +10 + SUBS R4, R4, #1 + LDRNE R6, [R5, #spNext] ; if not sprite we want + ADDNE R5, R5, R6 ; chain to next one + BNE %BT10 + + ADD R5, R5, #spName ; found sprite, R5 -> name + + SUBS R3, R3, #1 + MOVLS R3, #0 ; if was 0 or 1 then set R3 to 0 + STRLS R3, [WsPtr, #RetnReg3] + STREQB R3, [R2] ; if was 1 then store 0 terminator + BICLSS PC, R14, #V_bit ; if was 0 or 1 then exit + + CMP R3, #SpriteNameSize ; if length > maximum sprite name len + MOVHI R3, #SpriteNameSize ; then limit to maximum sprite name len + +; R3 is now maximum number of characters to store, excluding terminator + + MOV R6, R2 ; remember start address +20 + LDRB R4, [R5], #1 ; load a byte from sprite name + CMP R4, #" " ; if char > " " + STRHIB R4, [R2], #1 ; then store character and inc ptr + SUBHIS R3, R3, #1 ; and decrement character count + BHI %BT20 ; loop until char<=" " or count expired + + MOV R4, #0 ; store terminating 0 + STRB R4, [R2] + SUB R3, R2, R6 ; R3 = no. of characters, + STR R3, [WsPtr, #RetnReg3] ; excluding terminator + BICS PC, R14, #V_bit ; indicate no error + +; ***************************************************************************** +; +; RenameSprite - Rename a sprite +; +; External routine (AlreadyExists is used by CopySprite) +; +; in: R2 -> sprite +; R3 -> new name +; + +RenameSprite ROUT + Push "R2, R14" + MOV R2, R3 + BL GetName ; returns name in R9-R11 + BL SpriteCtrlBlk ; try to find sprite of that name + BVC AlreadyExists + Pull "R2, R14" + ADD R8, R2, #spName + STMIA R8, {R9-R11} + KillSpChoosePtr ; in case it points to renamed sprite + BICS PC, R14, #V_bit + +AlreadyExists ; sprite with new name already exists + Pull "R3, R14" + TEQ R2, R3 ; if it's the same one, then exit VC + BICEQS PC, R14, #V_bit ; (SRename/SCopy fred fred is allowed) + + ADRL R0, SpriteErr_SpriteAlreadyExists + [ International + Push "lr" + BL TranslateError + Pull "lr" + ] + STR R0, [WsPtr,#RetnReg0] + ORRS PC, R14, #V_bit + +; ***************************************************************************** +; +; CopySprite - Make a copy of a sprite +; +; External routine +; +; in: R1 -> sprite area +; R2 -> sprite +; R3 -> new name +; + +CopySprite ROUT + Push "R2, R14" ; save ptr to sprite to be copied + MOV R2, R3 + BL GetName ; returns new name in R9-R11 + BL SpriteCtrlBlk ; try to find sprite of that name + BVC AlreadyExists ; [we found one of that name] + Pull R2 + LDR R8, [R1, #saFree] + ADD R8, R8, R1 ; address sprite will be copied to + ADD R8, R8, #spName ; address of its name field + BL AppendSprite ; copy it + STMVCIA R8, {R9-R11} ; if copy OK, rename it + Pull PC ; exit with V clear/set appropriately + +; ***************************************************************************** +; +; ReadSpriteSize - Read sprite size and other info +; +; External routine +; +; in: R2 -> sprite +; +; out: R1,R2 preserved +; R3 = width in pixels +; R4 = height in pixels +; R5 = 0/1 for solid/transparent +; R6 = mode sprite was defined in +; +; RetnReg3..RetnReg6 updated +; + +ReadSpriteSize ROUT + ADD R3, R2, #spWidth + LDMIA R3, {R3,R4,R5,R6} ; spWidth,spHeight,spLBit,spRBit + ADD R4, R4, #1 ; R4 := height in pixels + ADD R3, R3, #1 ; R3 := width in words + RSB R3, R5, R3, LSL #5 ; convert to bits and sub LH wastage + SUB R3, R3, #31 ; subtract RH wastage + ADD R3, R3, R6 + LDR R11, [WsPtr, #SprLog2BPC] + MOV R3, R3, LSR R11 ; number of pixels in row + LDR R5, [R2, #spImage] + LDR R6, [R2, #spTrans] + SUBS R5, R5, R6 + MOVNE R5, #1 ; if spImage=spTrans then no mask + LDR R6, [R2, #spMode] + + ADD R11, WsPtr, #RetnReg3 + STMIA R11, {R3-R6} + + BICS PC, R14, #V_bit + +; ***************************************************************************** +; +; ReadSpriteWidth - Read width of a sprite +; +; Internal routine, called by PlotMask, InsertCol, DeleteCol +; +; in: R2 -> sprite +; +; out: R0 = sprite width in pixels +; All other registers preserved +; + +ReadSpriteWidth ROUT + Push "R4-R6, R14" + ADD R0, R2, #spWidth + LDMIA R0, {R0,R4,R5,R6} ; spWidth,spHeight,spLBit,spRBit + ADD R0, R0, #1 ; width in words + RSB R0, R5, R0, LSL #5 + SUB R0, R0, #31 + ADD R0, R0, R6 ; total number of bits in row + LDR R5, [WsPtr, #SprLog2BPC] + MOV R0, R0, LSR R5 ; number of pixels in row + Pull "R4-R6, PC" + +; ***************************************************************************** +; +; DeleteSpriteByName +; +; Internal routine, called by MergeSprite, GetSprite, CreateSprite +; +; in: R1 -> sprite area +; R2 -> name of sprite to be deleted +; +; out: All registers preserved +; + +DeleteSpriteByName ROUT + Push "R2-R4, R14" + BL SpriteCtrlBlk ; R2: In , SpriteNamePtr + ; Out, SpriteCBptr + BLVC DeleteSprite ; if found, then delete it + Pull "R2-R4, PC" + +; ***************************************************************************** +; +; DeleteSprite +; +; External routine + called by DeleteSpriteByName +; +; in: R1 -> sprite area +; R2 -> sprite +; +; out: All registers preserved +; + +DeleteSprite ROUT + Push "R0, R3,R4, R14" + LDR R3, [R2, #spNext] + ADD R3, R3, R2 + LDR R0, [R1, #saFree] + ADD R0, R0, R1 + SUB R0, R0, R3 + CopyDown R2, R3, R0, R14, R4 + LDR R3, [R1, #saNumber] ; decrement sprite count + SUB R3, R3, #1 + STR R3, [R1, #saNumber] + SUB R3, R2, R1 ; (R2 points to first free location) + STR R3, [R1, #saFree] ; update saFree + + KillSpChoosePtr ;Because the sprites have moved + + Pull "R0, R3,R4, PC" + +; ***************************************************************************** +; +; GetName - Read sprite name into buffer, lower cased, padded to 12 chars +; +; Internal routine, called by RenameSprite, CopySprite, +; SpriteCtrlBlk, CreateHeader +; +; in: R2 -> sprite name (terminated by char <= 32) +; +; out: Name returned in R9-R11 and NameBuf +; All other registers preserved +; + +GetName ROUT + Push "R2-R5, R14" + ADD R3, WsPtr, #NameBuf + MOV R4, #SpriteNameSize +10 + LDRB R5, [R2], #1 + uk_LowerCase R5, R14 + CMP R5, #" " + STRHIB R5, [R3], #1 + SUBHIS R4, R4, #1 ; loop until char<=32 or done 12 chars + BHI %BT10 + + MOV R5, #0 + CMP R4, #0 ; pad with 0 or more nulls +20 + STRHIB R5, [R3], #1 + SUBHIS R4, R4, #1 + BHI %BT20 + + ADD R9, WsPtr, #NameBuf + LDMIA R9, {R9-R11} ; name returned in R9-R11 and NameBuf + + Pull "R2-R5, PC" + +; ***************************************************************************** +; +; SpriteCtrlBlk - Search for control block of named sprite +; +; Internal routine, called by sprite dispatch, RenameSprite, +; CopySprite, DeleteSpriteByName +; +; in: R1 -> sprite area +; R2 -> sprite name +; +; out: V=0 => R2 -> sprite +; V=1 => sprite not found +; R2 -> first free byte (this fact not used by anyone yet) +; All other registers preserved +; + +SpriteCtrlBlk ROUT + Push "R3-R11, R14" + LDMIA R1, {R3,R4,R5} ; saEnd, saNumber, saFirst + ADD R3, R5, R1 ; point to first sprite/free space + CMP R4, #0 + BEQ %FT20 ; no sprites, exit with R3 pointing + ; at free space and R4=0 + BL GetName ; search name in R9-R11 and NameBuf +10 + LDMIA R3, {R5, R6,R7,R8} ; spNext, spName(0..2) + CMP R6, R9 + CMPEQ R7, R10 + CMPEQ R8, R11 ; (V:=0 if equal) + BEQ %FT30 ; sprite found + + ADD R3, R3, R5 + SUBS R4, R4, #1 ; try next sprite + BNE %BT10 +20 + SETV ; indicate not found +30 + MOV R2, R3 ; R2 -> sprite or to free space + Pull "R3-R11, PC" + +; ***************************************************************************** +; +; InternaliseCoords - Convert from external to internal coords +; for sprite plotting +; +; Internal routine called by PutSpriteUserCoords, PlotMaskUserCoords +; +; in: R3 = external X coordinate +; R4 = external Y coordinate +; +; out: R3 = internal X coordinate +; R4 = internal Y coordinate +; R1, R2, R5 preserved +; + +InternaliseCoords ROUT + Push "R1,R2,R5, R14" + MOV R0, R3 ; put external coordinate in R0,R1 + MOV R1, R4 + ADD R7, WsPtr, #GCsX + LDMIA R7, {R8,R9} ; preserve GCsX,GCsY around EIG + MOV R2, #4 ; indicate absolute coords + BL EIG + STMIA R7, {R8,R9} ; restore GcsX,GCsY + MOV R3, R0 ; internal coord of plotting point + MOV R4, R1 + Pull "R1,R2,R5, PC" + +; ***************************************************************************** +; +; PutSpriteUserCoords - Draw sprite to screen using given ext. coords +; +; External routine +; +; in: R1 -> sprite area (not used) +; R2 -> sprite +; R3 = X coordinate to plot at +; R4 = Y coordinate to plot at +; R5 = GCOL action to be used +; + +PutSpriteUserCoords ROUT + Push R14 + BL InternaliseCoords + Pull R14 + B PutSpri20 + +; ***************************************************************************** +; +; PutSprite - Draw sprite to screen at NewPt +; +; External routine + PutSpri20 called by PutSpriteUserCoords +; (also external) +; +; in: R1 -> sprite area (not used) +; R2 -> sprite +; R5 = GCOL action to be used +; + +; Values held in Ram +; +; N.B. The ordering of these variables is VERY important +; rearrange at your peril +; +; Within the 'memory to screen' drawing loop, WsPtr (R12) points at +; ScrAdr, variables either side being loaded/saved in groups using +; LDMDB / STMIA / LDMIB +; +; SPltWidth } +; SPltHeight } +; SPltScrOff } +; SPltMemOff } LDMDB +; WsPtr -> SPltScrAdr } STMIA +; SPltColCnt } } LDMIB +; SPltMemAdr } +; SPltShftR } +; SPltShftL } +; +; SPltMskAdr +; +; SPltLMask +; SPltRMask +; +; SPltzgooPtr +; +; + +PutSprite ROUT + ASSERT NewPtY = NewPtX +4 + ADD R3, WsPtr, #NewPtX + LDMIA R3, {R3, R4} ; plot sprite at NewPt(X,Y) +PutSpri20 + [ {TRUE} + GraphicsMode R0 + ADRNEL R0, SpriteErr_NotGraphics + [ International + Push "lr",NE + BLNE TranslateError + Pull "lr",NE + ] + STRNE R0, [WsPtr, #RetnReg0] + ORRNES PC, R14, #V_bit ; quit with error if not graphics mode + | + LDR R0, [WsPtr, #NPix] + TEQ R0, #0 + ADREQL R0, SpriteErr_NotGraphics + [ International + Push "lr",EQ + BLEQ TranslateError + Pull "lr",EQ + ] + STREQ R0, [WsPtr, #RetnReg0] + ORREQS PC, R14, #V_bit ; quit with error if not graphics mode + ] + Push "WsPtr, R14" ; push both so R12,R14 are free for use + + Push "R2" ; save the pointer to the sprite + + BL GenSpritePlotParmBlk + + Pull "R11" + + BVS SpriteOffScreen + + SWI XOS_RemoveCursors ; assume no error can occur! + + LDR R5, [WsPtr, #SPltMemAdr] + LDR R6, [WsPtr, #SPltMskAdr] + TEQ R6, #0 + BEQ %FT20 + + ADD R6, R6, R5 + STR R6, [WsPtr, #SPltMskAdr] + + LDR R14, [R11, #spMode] + MOV R14,R14,LSR #27 + + ;note: new format 1bpp sprites are thrown at the old routine, since it + ;will render them faster + + CMP R14, #2 + BCC TransPlot ; it's got transparent bits in it! ( + BCS NewTransPlot ; it's got 1bpp transparent bits in it!!! +20 + +; Plot sprite ignoring transparency mask (if any) + + + ADD R11, WsPtr, #SPltzgooMasks + LDMIA R11, {R8-R11} ; masks for screen access (zgoo..zgee) + + LDR R2, [WsPtr, #SPltAction] ; GCOL action + ADD WsPtr, WsPtr, #SPltScrAdr ; repoint WsPtr at SPltScrAdr + LDMIA WsPtr, {R0-R1,R5-R7} + + TEQ R2, #0 + BNE SolPl10 ; not store, do it slowly + +; SimpleCase + +SolPlFast10 + +; R0 ,R1 , R5 ,R6 ,R7 ,(R8 ,R9 ,R10 ,R11 ) +; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,(zgoo,zgeo,zgoe,zgee) + +; Plot the first (leftmost) word + + LDMIA R5, {R2,R3} + ADD R5, R5, #4 + + ShiftR R2,R3, R6,R7 ; shift R3,R2 right R6 places + ; we only need result word R2 + LDR R4, [WsPtr, #SPltLMask-SPltScrAdr] ; on leftmost word + AND R2, R2, R4 ; mask down to just the required pixels + + LDR R3, [R0] ; plot 1 word + BIC R3, R3, R4 ; knock out mask bits + ORR R3, R3, R2 ; and or sprite bits + STR R3, [R0], #4 + + SUBS R1, R1, #1 + BLT SolPlFast50 ; if all plotted, try next scanline + ; else try for blocks of 7 + SUBS R1, R1, #7 + BLT SolPlFast30 + +SolPlFast20 + +; R0 ,R1 ,R5 ,R6 ,R7 +; ScrAdr,ColCnt, ,MemAdr,ShftR,ShftL + + LDMIA R5, {R2-R4,R8-R11,R14} ; 8 words needed, gives 7 after shift + ADD R5, R5, #7*4 ; advance source ptr 7 words + + ShiftR R2,R3, R6,R7 ; shift right R6 bits + ShiftR R3,R4, R6,R7 ; we only want result words + ShiftR R4,R8, R6,R7 ; R2-R4, R8-R11 + ShiftR R8,R9, R6,R7 + ShiftR R9,R10, R6,R7 + ShiftR R10,R11, R6,R7 + ShiftR R11,R14, R6,R7 + + STMIA R0!, {R2-R4,R8-R11} ; write 7 words back to screen + SUBS R1, R1, #7 + BGE SolPlFast20 + +SolPlFast30 ; try 1 word at a time + ADDS R1, R1, #7 + +; R0 ,R1 , R5 ,R6 ,R7 +; ScrAdr,ColCnt, MemAdr,ShftR,ShftL + +; If EQ this is rightmost word + +SolPlFast40 + LDMIA R5, {R2,R3} + ADD R5, R5, #4 + + ShiftR R2,R3, R6,R7 ; shift R3,R2 right R6 places + ; we only need result word R2 + LDREQ R4, [WsPtr, #SPltRMask-SPltScrAdr] ; if rightmost word, + ANDEQ R2, R2, R4 ; mask down to just the required pixels + + LDREQ R3, [R0] + BICEQ R3, R3, R4 + ORREQ R2, R2, R3 + STR R2, [R0], #4 + + SUBS R1, R1, #1 + BGE SolPlFast40 + +SolPlFast50 ; now try the next scanline + LDMDB WsPtr, {R1,R2,R3,R4} ; R1 ,R2 ,R3 ,R4 + ; Width,Height,ScrOff,MemOff + ADD R0, R0, R3 + ADD R5, R5, R4 + SUBS R2, R2, #1 + STRGE R2, [WsPtr, #SPltHeight-SPltScrAdr] + BGE SolPlFast10 ; plot next scanline +ComplicatedExit + SWI XOS_RestoreCursors +SpriteOffScreen + Pull "WsPtr, R14" + BICS PC, R14, #V_bit + +; Complicated case + +SolPl10 + +; R0 ,R1 , R5 ,R6 ,R7 ,R8 ,R9 ,R10 ,R11 +; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,zgoo,zgeo,zgoe,zgee + +; Plot the first (leftmost) word + + LDMIA R5, {R2,R3} + ADD R5, R5, #4 + + ShiftR R2,R3, R6,R7 ; shift R3,R2 right R6 places + ; we only need result word R2 + + OrrEor R3,R2, R10,R11 ; form EOR mask + OrrEor R2,R2, R8,R9 ; form OR mask + + LDR R4, [WsPtr, #SPltLMask-SPltScrAdr] ; on leftmost word + AND R2, R2, R4 ; mask down to just the required pixels + AND R3, R3, R4 + + LDR R4, [R0] ; plot 1 word + OrrEor R4,R4, R2,R3 + STR R4, [R0], #4 + + SUBS R1, R1, #1 + BLT SolPl50 ; if all plotted, try next scanline + ; else try for blocks of 4 + SUBS R1, R1, #4 + BLT SolPl30 + +SolPl20 + STMIA WsPtr, {R0,R1} ; save ScrAdr,ColCnt + +; R0 ,R1 ,R5 ,R6 ,R7 ,R8 ,R9 ,R10 ,R11 +; ScrAdr,ColCnt, ,MemAdr,ShftR,ShftL,zgoo,zgeo,zgoe,zgee + + LDMIA R5, {R0-R4} ; 5 words needed, gives 4 after shift + ADD R5, R5, #16 ; advance source ptr 4 words + STR R5, [WsPtr, #SPltMemAdr-SPltScrAdr] + + ShiftR R0,R1, R6,R7 ; shift R4-R0 right R6 bits + ShiftR R1,R2, R6,R7 ; we only want result words R3-R0 + ShiftR R2,R3, R6,R7 + ShiftR R3,R4, R6,R7 + + LDR R4, [WsPtr] ; get screen address + LDMIA R4, {R4-R7} ; get 4 screen words + + ORoreorEORoreor R4,R0, R8,R9,R10,R11, R14 + ORoreorEORoreor R5,R1, R8,R9,R10,R11, R14 + ORoreorEORoreor R6,R2, R8,R9,R10,R11, R14 + ORoreorEORoreor R7,R3, R8,R9,R10,R11, R14 + + LDR R0, [WsPtr] ; screen address + STMIA R0!, {R4-R7} ; write 4 words back to screen + LDMIB WsPtr, {R1,R5-R7} ; reload anything we shat on + + SUBS R1, R1, #4 + BGE SolPl20 + +SolPl30 ; try 1 word at a time + ADDS R1, R1, #4 + +; R0 ,R1 , R5 ,R6 ,R7 ,R8 ,R9 ,R10 ,R11 +; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,zgoo,zgeo,zgoe,zgee + +; If EQ this is rightmost word + +SolPl40 + LDMIA R5, {R2,R3} + ADD R5, R5, #4 + + ShiftR R2,R3, R6,R7 ; shift R3,R2 right R6 places + ; we only need result word R2 + OrrEor R3,R2, R10,R11 ; form EOR mask + OrrEor R2,R2, R8,R9 ; form OR + + LDREQ R4, [WsPtr, #SPltRMask-SPltScrAdr] ; if rightmost word, + ANDEQ R2, R2, R4 ; mask down to just the + ANDEQ R3, R3, R4 ; required pixels + + LDR R4, [R0] + OrrEor R4,R4, R2,R3 + STR R4, [R0], #4 + + SUBS R1, R1, #1 + BGE SolPl40 + +SolPl50 ; now try the next scanline + LDMDB WsPtr, {R1,R2,R3,R4} ; R1 ,R2 ,R3 ,R4 + ; Width,Height,ScrOff,MemOff + ADD R0, R0, R3 + ADD R5, R5, R4 + SUBS R2, R2, #1 + STRGE R2, [WsPtr, #SPltHeight-SPltScrAdr] + BGE SolPl10 ; plot next scanline + B ComplicatedExit + +; ***************************************************************************** +; +; NewTransPlot - Plot sprite using 1 bpp transparency mask +; Called with R11 -> sprite +; TransPlot is used for 1bpp new sprites since it will be faster + +NewTransPlot ROUT + + ; need to derive: bpp, and 1<<(5-log2bpp) + + LDR R10, [R11, #spMode] + MOV R10, R10, LSR #27 + ADRL R0, NSM_bpptable-4 + LDR R10, [R0, R10, LSL #2] ; get the log2bpp to R10 + + ;R10=log2bpp, R11=>sprite + + LDR R8, [R11, #spWidth] ; words-1 + + ADD R9, R8, #1 + MOV R9, R9, LSL #2 ; number of bytes per row + STR R9, [WsPtr, #SPltMaskRowPtr] + + LDR R9, [R11, #spRBit] ; last bit used + ADD R9, R9, #1 ; change to number of bits + MOV R9, R9, LSR R10 ; number of pixels + + RSB R0, R10, #5 + MOV R8, R8, LSL R0 ; number of pixels for full words + + ADD R8, R8, R9 ; total number of pixels + + ANDS R9, R8, #&1F + MOVNE R9, #4 + BIC R8, R8, #&1F + ADD R9, R9, R8, LSR #3 ; number of bytes per mask row + + STR R9, [WsPtr, #SPltMaskRowLen] + + LDR R8, [R11, #spImage] + LDR R9, [R11, #spTrans] + ADD R8, R8, R11 + ADD R9, R9, R11 + + ;RSB R0, R10, #5 <- DONE ABOVE + + MOV R1, #1 + MOV R2, R1, LSL R0 ; r2 holds number of pixels per word + + MOV R3, R1, LSL R10 ; r3 holds bits per pixel + + ADD WsPtr, WsPtr, #SPltScrAdr ; repoint WsPtr, at SPltScrAdr + + LDMIA WsPtr, {R0-R1,R5-R7,R14} + + STR R2, [WsPtr, #SPltPixPerWord-SPltScrAdr] + STR R3, [WsPtr, #SPltBPP-SPltScrAdr] + + ; sort out where to begin in 1bpp mask (rewritten Aug '93) + + MOV LR, R9 ; LR = mask pointer + MOV R3, #0 ; R3 = mask bit + CMP R5, R8 ; R5=>data to plot, R8=>start of sprite + + BEQ %FT11 ; nothing to do, go store R3 & LR + BCC %FT13 ; start is before sprite data + + ;R3, R9, r10, R11 free + ;R2 comes in holding pix per word + + ;if R6 is non zero the image will be a word early. + MOV R9, R5 ; working copy of pointer within sprite + CMP R6, #0 + ADDNE R9, R9, #4 ; take out the extra word for now + + LDR R11,[WsPtr, #SPltMaskRowLen-SPltScrAdr] ; bytes per mask row + + SUBS R10, R9, R8 ; difference in bytes + + LDR R8,[WsPtr, #SPltMaskRowPtr-SPltScrAdr] ; loaded with bytes per image row + BEQ %FT13 +14 + ;is it less than a row of data + CMP R10, R8 + BCC %FT12 ; yes it is + + ;deal with a row (or more of data) + SUB R10, R10, R8 + ADD LR, LR, R11 + B %BT14 + +12 ;start point is on this row. subtract 4 from difference and add + ;pix per word to mask bit/ptr until diff=0 + CMP R10, #0 + BEQ %FT13 + + SUB R10, R10, #4 + + ADD R3, R3, R2 + CMP R3, #32 + SUBCS R3, R3, #32 + ADDCS LR, LR, #4 + CMP R10, #0 + BNE %BT12 + +13 + ;deal with R6 + CMP R6,#0 + BEQ %FT11 + + SUBS R3, R3, R2 ;subtract pix per word + ADDMI R3, R3, #32 + SUBMI LR, LR, #4 ;deal with going into previous word + +11 + STR R3, [WsPtr, #SPltMaskBit-SPltScrAdr] + STR LR, [WsPtr, #SPltMaskPtr-SPltScrAdr] + + ; and save it for the end of row increments + STR R3, [WsPtr, #SPltMaskRowBit-SPltScrAdr] + STR LR, [WsPtr, #SPltMaskRowPtr-SPltScrAdr] + + ADD R11, WsPtr, #SPltzgooMasks-SPltScrAdr + LDMIA R11, {R8-R11} ; masks for screen access (zgoo..zgee) + +NTrnPl10 + +; R0 ,R1 , R5 ,R6 ,R7 ,R8 ,R9 ,R10 ,R11, R14 +; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,zgoo,zgeo,zgoe,zgee, +; +; As far as possible this is based on the original transplot. +; + +; Plot the first (leftmost) word + + BL getmaskword + MOV R2, R3 + + BL getmaskword_noinc + ShiftR R2,R3, R6,R7 ; we only need result word R2 + + LDMIA R5, {R3,R4} ; fetch and shift image + ADD R5, R5, #4 + ShiftR R3,R4, R6,R7 ; shift R4,R3 right R6 places + + OrrEor R4,R3, R10,R11 ; form EOR mask + OrrEor R3,R3, R8,R9 ; form OR mask + + AND R3, R3, R2 ; clear out any transparent pixels + AND R4, R4, R2 + + LDR R2, [WsPtr, #SPltLMask-SPltScrAdr] ; on leftmost word + AND R3, R3, R2 ; mask down to just the required pixels + AND R4, R4, R2 + + LDR R2, [R0] ; plot 1 word + OrrEor R2,R2, R3,R4 + STR R2, [R0], #4 + + SUBS R1, R1, #1 + BLT NTrnPl50 ; if all plotted, try next scanline + ; else try for blocks of 2 + SUBS R1, R1, #2 + BLT NTrnPl30 + +NTrnPl20 + STMIA WsPtr, {R0,R1} ; ScrAdr,ColCnt + +; R0 ,R1 ,R5 ,R6 ,R7 ,R8 ,R9 ,R10 ,R11 , R14 +; ScrAdr,ColCnt, ,MemAdr,ShftR,ShftL,zgoo,zgeo,zgoe,zgee, MskAdr + + + BL getmaskword + MOV R0, R3 + BL getmaskword + MOV R1, R3 + + BL getmaskword_noinc + MOV R2, R3 + ShiftR R0,R1, R6,R7 + ShiftR R1,R2, R6,R7 ; aligned mask in R0,R1 + + LDMIA R5, {R2-R4} ; 3 image words needed, gives 2 after + ADD R5, R5, #8 ; shifting + STR R5, [WsPtr, #SPltMemAdr-SPltScrAdr] + ShiftR R2,R3, R6,R7 + ShiftR R3,R4, R6,R7 ; aligned image in R2,R3 + + LDR R4, [WsPtr] ; screen address + LDMIA R4, {R4,R5} ; 2 screen words + + ORoreorEORoreorMASK R4,R2,R0, R8,R9,R10,R11, R14 + ORoreorEORoreorMASK R5,R3,R1, R8,R9,R10,R11, R14 + + LDR R0, [WsPtr] ; screen address + STMIA R0!, {R4,R5} ; write 2 words back to screen + LDMIB WsPtr, {R1,R5,R6} ; reload anything we shat on + + SUBS R1, R1, #2 + BGE NTrnPl20 + +NTrnPl30 ; try 1 word at a time + ADDS R1, R1, #2 + +; R0 ,R1 , R5 ,R6 ,R7 ,R8 ,R9 ,R10 ,R11 +; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,zgoo,zgeo,zgoe,zgee + +; If EQ this is rightmost word + +NTrnPl40 + + BL getmaskword + MOV R2, R3 + + BL getmaskword_noinc + ShiftR R2,R3, R6,R7 ; shift R3,R2 right R6 places, result in R2 + + LDMIA R5, {R3,R4} ; fetch and align image + ADD R5, R5, #4 + ShiftR R3,R4, R6,R7 ; shift R4,R3 right R6 places, result in R3 + + OrrEor R4,R3, R10,R11 ; form EOR mask + OrrEor R3,R3, R8,R9 ; form OR + + AND R3, R3, R2 ; clear out transparant pixels + AND R4, R4, R2 + + LDREQ R2, [WsPtr, #SPltRMask-SPltScrAdr] ; if rightmost word, + ANDEQ R3, R3, R2 ; mask down to just the + ANDEQ R4, R4, R2 ; required pixels + + LDR R2, [R0] + OrrEor R2,R2, R3,R4 + STR R2, [R0], #4 + + SUBS R1, R1, #1 + BGE NTrnPl40 + +NTrnPl50 + ; now try the next scanline + + ; BEWARE ... genspriteplotparmblock returns values for memoff and + ; scroff which take account of alignment of screen and sprite data + ; + ; Do not alter the logic below unless you really know what + ; to expect from this routine!! + + LDR LR, [WsPtr, #SPltMaskRowPtr-SPltScrAdr] + LDR R3, [WsPtr, #SPltMaskRowBit-SPltScrAdr] + + LDR R2, [WsPtr, #SPltMaskRowLen-SPltScrAdr] + + ADD LR, LR, R2 + + STR LR, [WsPtr, #SPltMaskPtr-SPltScrAdr] + STR R3, [WsPtr, #SPltMaskBit-SPltScrAdr] + STR LR, [WsPtr, #SPltMaskRowPtr-SPltScrAdr] + STR R3, [WsPtr, #SPltMaskRowBit-SPltScrAdr] + + LDMDB WsPtr, {R1,R2,R3,R4} ; R1 ,R2 ,R3 ,R4 + ; Width,Height,ScrOff,MemOff + + ADD R0, R0, R3 + ADD R5, R5, R4 + + SUBS R2, R2, #1 + STRGE R2, [WsPtr, #SPltHeight-SPltScrAdr] + BGE NTrnPl10 ; plot next scanline + + SWI XOS_RestoreCursors + + Pull "WsPtr, R14" + BICS PC, R14, #V_bit + +; get a mask word without incrementing the pointers + +getmaskword_noinc ROUT + Push "R4, R5, LR" + + LDR R4, [WsPtr, #SPltMaskBit-SPltScrAdr] + LDR R5, [WsPtr, #SPltMaskPtr-SPltScrAdr] + BL getmaskword + STR R4, [WsPtr, #SPltMaskBit-SPltScrAdr] + STR R5, [WsPtr, #SPltMaskPtr-SPltScrAdr] + + LDMFD R13!,{R4,R5,R15}^ + +; get a mask word, and increment pointers + +getmaskword ROUT + Push "R2,R4,R5,R6,R7,R14" + +;R6 -> mask +;R7 = bit offset + +;return in R3, update R6, R7, restore other registers + + MOV R3, #0 ; initial result + LDR LR, [WsPtr, #SPltPixPerWord-SPltScrAdr] ; pixels per word + LDR R2, [WsPtr, #SPltBPP-SPltScrAdr] ; bpp + + LDR R7, [WsPtr, #SPltMaskBit-SPltScrAdr] + LDR R6, [WsPtr, #SPltMaskPtr-SPltScrAdr] + + LDR R4, [R6] ; get the mask word +10 + CMP R7, #0 + LDREQ R4, [R6] ; fetch a new word if required + MOV R5, R4, LSR R7 ; shift desired bit down to bit 0 + + MOV R3, R3, LSR #1 ; shift down the result by one bit + ORR R3, R3, R5, LSL #31 ; and put bit 0 in at bit 31 + + ; now use an ASR of bpp-1 to finish off + SUB R5, R2, #1 + MOV R3, R3, ASR R5 + + ADD R7, R7, #1 ; next mask bit + + CMP R7, #32 ; on to next word ? + ADDEQ R6, R6, #4 ; increment mask word pointer + MOVEQ R7, #0 ; bit pointer back to 0 + ; but don't fetch new word until it is needed! + + SUBS LR, LR, #1 ; one pixel done + BNE %BT10 + + STR R7, [WsPtr, #SPltMaskBit-SPltScrAdr] + STR R6, [WsPtr, #SPltMaskPtr-SPltScrAdr] + + ;result in R3, MaskBit/MaskPtr adjusted + + LDMFD R13!,{R2,R4,R5,R6,R7,R15}^ ; must save flags + + LTORG + +; ***************************************************************************** +; +; TransPlot - Plot sprite using transparency mask +; + +TransPlot + ADD R11, WsPtr, #SPltzgooMasks + LDMIA R11, {R8-R11} ; masks for screen access (zgoo..zgee) + + ADD WsPtr, WsPtr, #SPltScrAdr ; repoint WsPtr, at SPltScrAdr + + LDMIA WsPtr, {R0-R1,R5-R7,R14} + +TrnPl10 + +; R0 ,R1 , R5 ,R6 ,R7 ,R8 ,R9 ,R10 ,R11, R14 +; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,zgoo,zgeo,zgoe,zgee, MskAdr + +; Plot the first (leftmost) word + + LDMIA R14, {R2,R3} ; fetch and shift mask right R6 places + ADD R14, R14, #4 + ShiftR R2,R3, R6,R7 ; we only need result word R2 + + LDMIA R5, {R3,R4} ; fetch and shift image + ADD R5, R5, #4 + ShiftR R3,R4, R6,R7 ; shift R4,R3 right R6 places + ; we only need result word R3 + OrrEor R4,R3, R10,R11 ; form EOR mask + OrrEor R3,R3, R8,R9 ; form OR mask + + AND R3, R3, R2 ; clear out any transparent pixels + AND R4, R4, R2 + + LDR R2, [WsPtr, #SPltLMask-SPltScrAdr] ; on leftmost word + AND R3, R3, R2 ; mask down to just the required pixels + AND R4, R4, R2 + + LDR R2, [R0] ; plot 1 word + OrrEor R2,R2, R3,R4 + STR R2, [R0], #4 + + SUBS R1, R1, #1 + BLT TrnPl50 ; if all plotted, try next scanline + ; else try for blocks of 2 + SUBS R1, R1, #2 + BLT TrnPl30 + +TrnPl20 + STMIA WsPtr, {R0,R1} ; ScrAdr,ColCnt + +; R0 ,R1 ,R5 ,R6 ,R7 ,R8 ,R9 ,R10 ,R11 , R14 +; ScrAdr,ColCnt, ,MemAdr,ShftR,ShftL,zgoo,zgeo,zgoe,zgee, MskAdr + + LDMIA R14, {R0-R2} ; 3 mask words, gives 2 after shifting + ADD R14, R14, #8 ; advance mask ptr 2 words + ShiftR R0,R1, R6,R7 + ShiftR R1,R2, R6,R7 ; aligned mask in R0,R1 + + LDMIA R5, {R2-R4} ; 3 image words needed, gives 2 after + ADD R5, R5, #8 ; shifting + STR R5, [WsPtr, #SPltMemAdr-SPltScrAdr] + ShiftR R2,R3, R6,R7 + ShiftR R3,R4, R6,R7 ; aligned image in R2,R3 + + LDR R4, [WsPtr] ; screen address + LDMIA R4, {R4,R5} ; 2 screen words + + ORoreorEORoreorMASK R4,R2,R0, R8,R9,R10,R11, R6 + ORoreorEORoreorMASK R5,R3,R1, R8,R9,R10,R11, R6 + + LDR R0, [WsPtr] ; screen address + STMIA R0!, {R4,R5} ; write 2 words back to screen + LDMIB WsPtr, {R1,R5-R6} ; reload anything we shat on + + SUBS R1, R1, #2 + BGE TrnPl20 + +TrnPl30 ; try 1 word at a time + ADDS R1, R1, #2 + +; R0 ,R1 , R5 ,R6 ,R7 ,R8 ,R9 ,R10 ,R11 +; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,zgoo,zgeo,zgoe,zgee + +; If EQ this is rightmost word + +TrnPl40 + LDMIA R14, {R2,R3} ; fetch and align trans mask + ADD R14, R14, #4 + ShiftR R2,R3, R6,R7 ; shift R3,R2 right R6 places, result in R2 + + LDMIA R5, {R3,R4} ; fetch and align image + ADD R5, R5, #4 + ShiftR R3,R4, R6,R7 ; shift R4,R3 right R6 places, result in R3 + + OrrEor R4,R3, R10,R11 ; form EOR mask + OrrEor R3,R3, R8,R9 ; form OR + + AND R3, R3, R2 ; clear out transparant pixels + AND R4, R4, R2 + + LDREQ R2, [WsPtr, #SPltRMask-SPltScrAdr] ; if rightmost word, + ANDEQ R3, R3, R2 ; mask down to just the + ANDEQ R4, R4, R2 ; required pixels + + LDR R2, [R0] + OrrEor R2,R2, R3,R4 + STR R2, [R0], #4 + + SUBS R1, R1, #1 + BGE TrnPl40 + +TrnPl50 ; now try the next scanline + LDMDB WsPtr, {R1,R2,R3,R4} ; R1 ,R2 ,R3 ,R4 + ; Width,Height,ScrOff,MemOff + ADD R0, R0, R3 + ADD R5, R5, R4 + ADD R14, R14, R4 + SUBS R2, R2, #1 + STRGE R2, [WsPtr, #SPltHeight-SPltScrAdr] + BGE TrnPl10 ; plot next scanline + + SWI XOS_RestoreCursors + + Pull "WsPtr, R14" + BICS PC, R14, #V_bit + + LTORG + +; ***************************************************************************** +; +; PlotMaskUserCoords - Draw a rectangle through a sprite mask +; using given external coordinates +; +; External routine +; +; in: R1 -> sprite area (not used) +; R2 -> sprite +; R3 = X coordinate to plot at +; R4 = Y coordinate to plot at +; + +PlotMaskUserCoords ROUT + Push R14 + BL InternaliseCoords + Pull R14 + B PlotMa20 + +; ***************************************************************************** +; +; PlotNewMask +; +; Version of PlotMask for new 1bpp format sprites + +PlotNewMask ROUT + + LDR R10, [R2, #spMode] + MOV R10, R10, LSR #27 + ADRL R0, NSM_bpptable-4 + LDR R10, [R0, R10, LSL #2] ;get the log2bpp + + ;derive mask row length + ;r10=log2bpp, r2=>sprite + + LDR R8, [R2, #spWidth] ; words-1 + + ADD R9, R8, #1 ; total words for a line of image + MOV R9, R9, LSL #2 ; total bytes for a line of image + STR R9, [WsPtr, #SPltMaskRowPtr] + ; save it for determining mask start position + + LDR R9, [R2, #spRBit] ; last bit used + ADD R9, R9, #1 ; change to number of bits + MOV R9, R9, LSR R10 ; number of pixels + + RSB R0, R10, #5 + MOV R8, R8, LSL R0 ; number of pixels for full words + + ADD R8, R8, R9 ; total number of pixels + + ANDS R9, R8, #&1F + MOVNE R9, #4 + BIC R8, R8, #&1F + ADD R9, R9, R8, LSR #3 ; number of bytes per mask row + + STR R9, [WsPtr, #SPltMaskRowLen] + + MOV R1, #1 + MOV R0, R1, LSL R0 ;number of pixels + + MOV R6, R1, LSL R10 ;bits per pixel + + STR R0, [WsPtr, #SPltPixPerWord] + STR R6, [WsPtr, #SPltBPP] + + LDR R0, [R2, #spHeight] + ADD R0, R0, R4 + LDR R10, [WsPtr, #GWTRow] + Least R0, R0, R10 ; top scanline within window + + LDR R10, [WsPtr, #YWindLimit] + SUB R0, R10, R0 ; flip Y + AND R0, R0, #7 + STR R0, [WsPtr, #SPltEcfIndx] ; index into Ecf + + ADD R0, WsPtr, R0, LSL #3 + ADD R0, R0, #BgEcfOraEor + STR R0, [WsPtr, #SPltEcfPtr] ; ptr to ECF for highest row plotted + + ;STR R2, [WsPtr, #SPltMaskRowPtr] ;temp, to save it + + LDR R8, [R2, #spImage] + LDR R9, [R2, #spTrans] + ADD R8, R8, R2 + ADD R9, R9, R2 + + Push "WsPtr, R14" ; push both so R12,R14 are free for use + Push "R2" + + BL GenSpritePlotParmBlk + + Pull "R2" + + BVS SpriteOffScreen + SWI XOS_RemoveCursors ; assume no error can occur! + + ;LDR R2, [WsPtr, #SPltMaskRowPtr] ;recover pointer to sprite + + LDR R8, [R2, #spImage] ;offset to image + LDR R9, [R2, #spTrans] ;offset to mask + ADD R8, R8, R2 ;change to address of image + ADD R9, R9, R2 ;change to address of mask + + LDR R5, [WsPtr, #SPltMemAdr] ;start memory address to plot + LDR LR, [WsPtr, #SPltMskAdr] ;start mask address to plot + TEQ LR, #0 ;off screen ? + BEQ SpriteOffScreen ;so plot nothing + + ;amg 19/1/94 rip out the original algorithm and replace it with the correct one + ;used with newtransplot which correctly handles genspriteplotparmblk's oddities + + ;now deal with sprites where we aren't starting + ;at the beginning.... + LDR R2, [WsPtr, #SPltPixPerWord] ;pick up pixels per word + + MOV LR, R9 ;save mask address + MOV R3, #0 ;set mask pixel counter to 0 + CMP R5, R8 ;memory address to plot from = image address ? + BEQ %FT11 ;yes - no fudging needed + BCC %FT13 + + MOV R9, R5 ;working copy of plot start within sprite + CMP R6, #0 + ADDNE R9, R9, #4 ;take out the extra word for now + + LDR R11, [WsPtr, #SPltMaskRowLen] ;bytes per mask row + SUBS R10, R9, R8 ;difference between plot start & sprite start + LDR R8, [WsPtr, #SPltMaskRowPtr] ;bytes per image row + BEQ %FT13 ;no difference + +14 + ;is it less than a row of data different ? + CMP R10, R8 + BCC %FT12 ;yes, it is + + ;deal with whole rows + SUB R10, R10, R8 ;decrease difference by size of image row + ADD LR, LR, R11 ;increase mask pointer by size of mask row + B %BT14 ;and loop until less than a row to do + +12 ;start pointer is on this row. reduce the difference and increase the mask start + ;point until they match + + CMP R10, #0 ;check for nothing to do + BEQ %FT13 + + SUB R10, R10, #4 ;reduce image by a word + + ADD R3, R3, R2 ;increase mask start pixel by the number of + ;pixels in that word + + CMP R3, #32 + SUBCS R3, R3, #32 + ADDCS LR, LR, #4 ;get the mask bit back into a word's worth + + CMP R10, #0 ;extra test down here to avoid taking two + BNE %BT12 ;branches + +13 ;remember R6 ? uncompensate now + CMP R6, #0 + BEQ %FT11 + + SUBS R3, R3, R2 ;go back by the number of pixels in a word + ADDMI R3, R3, #32 + SUBMI LR, LR, #4 ;deal with going back into previous mask word + +11 + STR R3, [WsPtr, #SPltMaskBit] ;starting mask bit to plot + STR LR, [WsPtr, #SPltMaskPtr] ;starting mask word to plot + + ; and save it for the end of row increments + STR R3, [WsPtr, #SPltMaskRowBit] + STR LR, [WsPtr, #SPltMaskRowPtr] + + STR LR, [WsPtr, #SPltMskAdr] + STR LR, [WsPtr, #SPltMemAdr] + + ADD WsPtr, WsPtr, #SPltScrAdr ; repoint WsPtr at SPltScrAdr + + LDMIA WsPtr, {R0-R1,R5-R7} + + LDR R5, [WsPtr, #SPltMaskPtr-SPltScrAdr] + LDR R8, [WsPtr, #SPltEcfPtr-SPltScrAdr] +10 + LDMIA R8, {R8,R9} ; ora,eor for this row + +; R0 ,R1 , R5 ,R6 ,R7 ,R8 ,R9 +; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,ora,eor + +; Plot the first (Leftmost) word + + BL getmaskword + MOV R2, R3 + + BL getmaskword_noinc + + ShiftR R2,R3, R6,R7 ; shift R3,R2 right R6 places + ; we only need result word R2 + LDR R10, [WsPtr, #SPltLMask-SPltScrAdr] ; on leftmost word + AND R2, R2, R10 ; mask down to just the required pixels + + LDR R4, [R0] ; plot 1 word + OrrEorMASK R4,R2, R8,R9, R14 + STR R4, [R0], #4 + + SUBS R1, R1, #1 + BLT %FT50 ; if all plotted, try next scanline + ; else try for blocks of 4 + SUBS R1, R1, #4 + BLT %FT30 + +20 + STMIA WsPtr, {R0,R1} ; save ScrAdr,ColCnt + +; R0 ,R1 ,R5 ,R6 ,R7 +; ScrAdr,ColCnt, ,MemAdr,ShftR,ShftL + + + BL getmaskword + MOV R0, R3 + BL getmaskword + MOV R1, R3 + BL getmaskword + MOV R2, R3 + BL getmaskword + MOV R8, R3 + BL getmaskword_noinc + MOV R4,R3 + MOV R3,R8 + + ShiftR R0,R1, R6,R7 ; shift R4-R0 right R6 bits + ShiftR R1,R2, R6,R7 ; we only want result words R3-R0 + ShiftR R2,R3, R6,R7 + ShiftR R3,R4, R6,R7 + + LDR R4, [WsPtr] ; get screen address + LDMIA R4, {R8-R11} ; get 4 screen words + + LDR R6, [WsPtr, #SPltEcfPtr-SPltScrAdr] + LDMIA R6, {R6,R7} ; ora,eor for this row + + OrrEorMASK R8,R0, R6,R7, R14 ; Scr:=ScrOR(oraANDmsk)EOR(eorANDmsk) + OrrEorMASK R9,R1, R6,R7, R14 + OrrEorMASK R10,R2, R6,R7, R14 + OrrEorMASK R11,R3, R6,R7, R14 + + LDR R0, [WsPtr] ; screen address + STMIA R0!, {R8-R11} ; write 4 words back to screen + LDMIB WsPtr, {R1,R5-R7} ; reload anything we shat on + + SUBS R1, R1, #4 + BGE %BT20 + +30 ; try 1 word at a time + ADDS R1, R1, #4 + +; R0 ,R1 , R5 ,R6 ,R7 ,R8 ,R9 +; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,ora,eor + +; If EQ this is rightmost word + + LDR R8, [WsPtr, #SPltEcfPtr-SPltScrAdr] + LDMIA R8, {R8,R9} ; ora,eor for this row + LDR R10, [WsPtr, #SPltRMask-SPltScrAdr] +40 + + BL getmaskword + MOV R2, R3 + + BL getmaskword_noinc + ShiftR R2,R3, R6,R7 ; shift R3,R2 right R6 places, result in R2 + ; we only need result word R2 + + ANDEQ R2, R2, R10 ; if rightmost word, mask down to just the + ; required pixels + LDR R4, [R0] + OrrEorMASK R4,R2, R8,R9, R14 + STR R4, [R0], #4 + + SUBS R1, R1, #1 + BGE %BT40 + +50 ; now try the next scanline + ; BEWARE ... genspriteplotparmblock returns values for memoff and + ; scroff which take account of alignment of screen and sprite data + ; + ; Do not alter the logic below unless you really know what + ; to expect from this routine!! + + LDMDB WsPtr, {R1,R2,R3,R4} ; R1 ,R2 ,R3 ,R4 + ; Width,Height,ScrOff,MemOff + + + LDR LR, [WsPtr, #SPltMaskRowPtr-SPltScrAdr] + LDR R3, [WsPtr, #SPltMaskRowBit-SPltScrAdr] + + LDR R2, [WsPtr, #SPltMaskRowLen-SPltScrAdr] + + ADD LR, LR, R2 + + STR LR, [WsPtr, #SPltMaskPtr-SPltScrAdr] + STR R3, [WsPtr, #SPltMaskBit-SPltScrAdr] + STR LR, [WsPtr, #SPltMaskRowPtr-SPltScrAdr] + STR R3, [WsPtr, #SPltMaskRowBit-SPltScrAdr] + + LDMDB WsPtr, {R1,R2,R3,R4} ; R1 ,R2 ,R3 ,R4 + ; Width,Height,ScrOff,MemOff + ADD R0, R0, R3 + + ADD R10, WsPtr, #(SPltEcfPtr-SPltScrAdr) + + LDMIA R10, {R8,R9} ; EcfPtr,EcfIndx + ADD R8, R8, #8 ; step both to next row in Ecf + ADD R9, R9, #1 + CMP R9, #8 + MOVGE R9, #0 ; it's a wrap! + SUBGE R8, R8, #(8*8) + STMIA R10, {R8,R9} + + SUBS R2, R2, #1 + STRGE R2, [WsPtr, #SPltHeight-SPltScrAdr] + BGE %BT10 ; plot next scanline + + SWI XOS_RestoreCursors + + Pull "WsPtr, R14" + BICS PC, R14, #V_bit + +; ***************************************************************************** +; +; PlotMask - Draw a rectangle through a sprite mask +; +; External routine + PlotMa20 called by PlotMaskUserCoords +; (also external) +; +; in: R1 -> sprite area (not used) +; R2 -> sprite +; + +PlotMask ROUT + ASSERT NewPtY = NewPtX +4 + ADD R3, WsPtr, #NewPtX + LDMIA R3, {R3, R4} ; plot sprite at NewPt(X,Y) +PlotMa20 + [ {TRUE} + GraphicsMode R0 + ADRNEL R0, SpriteErr_NotGraphics + [ International + Push "lr",NE + BLNE TranslateError + Pull "lr",NE + ] + STRNE R0, [WsPtr, #RetnReg0] + ORRNES PC, Link, #V_bit ; quit with error if not graphics mode + | + LDR R0, [WsPtr, #NPix] + TEQ R0, #0 + ADREQL R0, SpriteErr_NotGraphics + [ International + Push "lr",EQ + BLEQ TranslateError + Pull "lr",EQ + ] + STREQ R0, [WsPtr, #RetnReg0] + ORREQS PC, Link, #V_bit ; quit with error if not graphics mode + ] + + LDR R5, [WsPtr, #GPLBMD] ; background GCOL action + ORR R5, R5, #8 ; force 'use mask' + LDR R10, [R2, #spImage] + LDR R11, [R2, #spTrans] + TEQ R10, R11 ; spImage=spTrans if no mask + BEQ %FT90 ; so plot a rectangle + + LDR R0, [R2, #spMode] + MOVS R0, R0, LSR #27 + BNE PlotNewMask + + LDR R0, [R2, #spHeight] + ADD R0, R0, R4 + LDR R10, [WsPtr, #GWTRow] + Least R0, R0, R10 ; top scanline within window + + LDR R10, [WsPtr, #YWindLimit] + SUB R0, R10, R0 ; flip Y + AND R0, R0, #7 + STR R0, [WsPtr, #SPltEcfIndx] ; index into Ecf + + ADD R0, WsPtr, R0, LSL #3 + ADD R0, R0, #BgEcfOraEor + STR R0, [WsPtr, #SPltEcfPtr] ; ptr to ECF for highest row plotted + + Push "WsPtr, R14" ; push both so R12,R14 are free for use + BL GenSpritePlotParmBlk + BVS SpriteOffScreen + SWI XOS_RemoveCursors ; assume no error can occur! + + LDR R5, [WsPtr, #SPltMemAdr] + LDR R6, [WsPtr, #SPltMskAdr] + TEQ R6, #0 + BEQ SpriteOffScreen + + ADD R6, R6, R5 + STR R6, [WsPtr, #SPltMskAdr] + STR R6, [WsPtr, #SPltMemAdr] + + ADD WsPtr, WsPtr, #SPltScrAdr ; repoint WsPtr at SPltScrAdr + + LDMIA WsPtr, {R0-R1,R5-R7} + LDR R8, [WsPtr, #SPltEcfPtr-SPltScrAdr] +10 + LDMIA R8, {R8,R9} ; ora,eor for this row + +; R0 ,R1 , R5 ,R6 ,R7 ,R8 ,R9 +; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,ora,eor + +; Plot the first (Leftmost) word + + LDMIA R5, {R2,R3} + ADD R5, R5, #4 + + ShiftR R2,R3, R6,R7 ; shift R3,R2 right R6 places + ; we only need result word R2 + LDR R10, [WsPtr, #SPltLMask-SPltScrAdr] ; on leftmost word + AND R2, R2, R10 ; mask down to just the required pixels + + LDR R4, [R0] ; plot 1 word + OrrEorMASK R4,R2, R8,R9, R14 + STR R4, [R0], #4 + + SUBS R1, R1, #1 + BLT %FT50 ; if all plotted, try next scanline + ; else try for blocks of 4 + SUBS R1, R1, #4 + BLT %FT30 + +20 + STMIA WsPtr, {R0,R1} ; save ScrAdr,ColCnt + +; R0 ,R1 ,R5 ,R6 ,R7 +; ScrAdr,ColCnt, ,MemAdr,ShftR,ShftL + + LDMIA R5, {R0-R4} ; 5 words needed, gives 4 after shift + ADD R5, R5, #16 ; advance source ptr 4 words + STR R5, [WsPtr, #SPltMemAdr-SPltScrAdr] + + ShiftR R0,R1, R6,R7 ; shift R4-R0 right R6 bits + ShiftR R1,R2, R6,R7 ; we only want result words R3-R0 + ShiftR R2,R3, R6,R7 + ShiftR R3,R4, R6,R7 + + LDR R4, [WsPtr] ; get screen address + LDMIA R4, {R8-R11} ; get 4 screen words + + LDR R6, [WsPtr, #SPltEcfPtr-SPltScrAdr] + LDMIA R6, {R6,R7} ; ora,eor for this row + + OrrEorMASK R8,R0, R6,R7, R14 ; Scr:=ScrOR(oraANDmsk)EOR(eorANDmsk) + OrrEorMASK R9,R1, R6,R7, R14 + OrrEorMASK R10,R2, R6,R7, R14 + OrrEorMASK R11,R3, R6,R7, R14 + + LDR R0, [WsPtr] ; screen address + STMIA R0!, {R8-R11} ; write 4 words back to screen + LDMIB WsPtr, {R1,R5-R7} ; reload anything we shat on + + SUBS R1, R1, #4 + BGE %BT20 + +30 ; try 1 word at a time + ADDS R1, R1, #4 + +; R0 ,R1 , R5 ,R6 ,R7 ,R8 ,R9 +; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,ora,eor + +; If EQ this is rightmost word + + LDR R8, [WsPtr, #SPltEcfPtr-SPltScrAdr] + LDMIA R8, {R8,R9} ; ora,eor for this row + LDR R10, [WsPtr, #SPltRMask-SPltScrAdr] +40 + LDMIA R5, {R2,R3} + ADD R5, R5, #4 + + ShiftR R2,R3, R6,R7 ; shift R3,R2 right R6 places + ; we only need result word R2 + + ANDEQ R2, R2, R10 ; if rightmost word, mask down to just the + ; required pixels + LDR R4, [R0] + OrrEorMASK R4,R2, R8,R9, R14 + STR R4, [R0], #4 + + SUBS R1, R1, #1 + BGE %BT40 + +50 ; now try the next scanline + + LDMDB WsPtr, {R1,R2,R3,R4} ; R1 ,R2 ,R3 ,R4 + ; Width,Height,ScrOff,MemOff + ADD R0, R0, R3 + ADD R5, R5, R4 + + ADD R10, WsPtr, #(SPltEcfPtr-SPltScrAdr) + + LDMIA R10, {R8,R9} ; EcfPtr,EcfIndx + ADD R8, R8, #8 ; step both to next row in Ecf + ADD R9, R9, #1 + CMP R9, #8 + MOVGE R9, #0 ; it's a wrap! + SUBGE R8, R8, #(8*8) + STMIA R10, {R8,R9} + + SUBS R2, R2, #1 + STRGE R2, [WsPtr, #SPltHeight-SPltScrAdr] + BGE %BT10 ; plot next scanline + + SWI XOS_RestoreCursors + + Pull "WsPtr, R14" + BICS PC, R14, #V_bit + +; Sprite has no mask or gcol says dont use it, so draw a rectangle + +90 + Push R14 + BL ReadSpriteWidth ; on exit R0=width in pixels + ADD R5, R3, R0 + MOV R0, R3 ; x0 + MOV R1, R4 ; y0 + + LDR R3, [R2, #spHeight] + ADD R3, R3, R4 ; y1 + SUB R2, R5, #1 ; x1 + + LDR R4, [WsPtr, #CursorFlags] + TST R4, #ClipBoxEnableBit + BLNE ClipPlotMask + + ADD R4, WsPtr, #BgEcfOraEor ; select Bg colour & action + STR R4, [WsPtr, #GColAdr] + B RectFillB + +ClipPlotMask ROUT + Push "R0-R7,R10,R11, R14" + ADD R10, R13, #2*4 ; R10 -> last point (R2,R3) + MOV R11, #2 ; merge two points + BL MergeR11PointsFromR10 + Pull "R0-R7,R10,R11, PC" + +; ***************************************************************************** +; +; GenSpritePlotParmBlk - Generate lots of useful variables to help us +; to plot sprite +; +; Internal routine, called by PutSprite, PlotMask, ScreenLoad +; +; in: R2 -> sprite +; R3 = X coordinate to plot at +; R4 = Y coordinate to plot at +; R5 = GCOL action +; + +GenSpritePlotParmBlk ROUT + Push R14 + AND R5, R5, #&F ; lose any ECF colour bits + LDR R6, [R2, #spImage] + LDR R7, [R2,#spTrans] + SUB R6, R7, R6 ; offset from Image to Trans mask + ; =0 if no mask + STR R5, [WsPtr, #SPltAction] ; save action for simple case spotting + CMP R5, #8 ; if GCOL action < 8 + MOVLT R6, #0 ; plot as solid anyway + STR R6, [WsPtr, #SPltMskAdr] + + AND R5, R5, #7 + MOV R5, R5, LSL #2 ; 4 bits for each + LDR R6, =TBscrmasks + MOV R6, R6, ROR R5 ; put correct bits in top 4 bits + MOV R7, R6, ASR #31 ; set R7 to 0 or -1 on bit 31 + MOV R6, R6, LSL #1 + MOV R8, R6, ASR #31 ; set R8 to 0 or -1 on bit 30 + MOV R6, R6, LSL #1 + MOV R9, R6, ASR #31 ; set R9 to 0 or -1 on bit 29 + MOV R6, R6, LSL #1 + MOV R10, R6, ASR #31 ; set R10 to 0 or -1 on bit 28 + + ADD R6, WsPtr, #SPltzgooMasks + STMIA R6, {R7-R10} ; store zgoo, zgeo, zgoe, zgee + + MOV R14, R2 ; leave sprite CB ptr in R14 + MOV R0, R3 ; leave X coord in R0 + MOV R1, R4 ; leave Y coord in R1 + + ADD R11, R14, #spWidth + LDMIA R11, {R2,R3} ; Width-1, Height-1 + + ADD R4, WsPtr, #GWLCol ; R4 ,R5 ,R6 ,R7 + LDMIA R4, {R4,R5,R6,R7} ; LCol,BRow,RCol,TRow + + SUBS R5, R5, R1 + MOVLT R5, #0 ; no. of rows below window + + ADD R1, R1, R3 ; Coord of topLH of sprite + + SUBS R7, R1, R7 + MOVLT R7, #0 ; no. of rows above window + SUB R1, R1, R7 ; clipped topLH coord + + ADD R5, R5, R7 ; reduction factor for height + + ADD R2, R2, #1 + + MOV R8, R14 + LDR R9, [WsPtr, #CursorFlags] + TST R9, #ClipBoxEnableBit + BLNE ClipSpritePlot + MOV R14, R8 + + MUL R3, R7, R2 ; word offset into sprite image + + Push "R3,R5" ; word offset and height reduction + + Push R14 + BL ScreenAddr + Pull R14 + MOV R4, R2 ; address of top left corner + + LDR R5, [R14, #spImage] + ADD R5, R5, R14 ; address of sprite image + + Pull R6 + ADD R5, R5, R6, LSL #2 + + LDR R9, [WsPtr, #XShftFactor] + LDR R10, [WsPtr, #NPix] + LDR R11, [WsPtr, #Log2BPC] + + BitLOffset R7,R0, R9,R10,R11 ; R7 := bit position to align to + WordOffset R8,R0, R9,R10,R11 ; R8 := word offset on line + + LDR R0, [WsPtr, #GWRCol] + BitROffset R1,R0, R9,R10,R11 + WordOffset R2,R0, R9,R10,R11 + Push "R1,R2" + + LDR R0, [WsPtr, #GWLCol] + BitLOffset R1,R0, R9,R10,R11 + WordOffset R2,R0, R9,R10,R11 + + Push "R1,R2,R8" + + ADD R11, R14, #spWidth + LDMIA R11, {R0,R1,R6,R8} ; Width-1, Height-1, LBit, RBit + + MOV R3, #0 ; offset to next row in sprite + + SUBS R6, R6, R7 ; no. of bits to shift sprite + ; before plotting + ; use R7 as LBit + SUBS R8, R8, R6 ; calculate new RBit + ADDLT R8, R8, #32 + ADDLT R3, R3, #4 + + CMP R8, #32 + SUBGE R8, R8, #32 + SUBGE R3, R3, #4 + +; R9 Offset on line to plot point, R7 LBit +; R11 Offset on line to GWLCol R10 bit position + + Pull "R10,R11" + Pull R9 + + SUBS R9, R11, R9 + SUBLT R11, R11, R9 + + ADDGT R4, R4, R9, LSL #2 + ADDGT R5, R5, R9, LSL #2 + ADDGT R3, R3, R9, LSL #2 + + CMPEQ R10, R7 + MOVGT R7, R10 + +; R10 Offset to GWRCol, R9 bit position +; R11 Offset to RHedge of sprite, R8 RBit + + ADD R11, R11, R0 + SUB R11, R11, R3, ASR #2 + + Pull "R9,R10" + + SUBS R10, R11, R10 + ADDGT R3, R3, R10, LSL #2 + + CMPEQ R8, R9 + MOVGT R8, R9 + + Pull R10 + + SUBS R1, R1, R10 ; correct height + BLT %FT20 + + SUBS R0, R0, R3, ASR #2 ; corrected width + BLT %FT20 + + LDR R2,[WsPtr,#LineLength] + SUB R2, R2, #4 + SUB R2, R2, R0, LSL #2 ; offset to next screen line + + MOV R9, #&FFFFFFFE ; RHand partial word mask + MVN R9, R9, LSL R8 + MOV R8, #&FFFFFFFF + MOV R8, R8, LSL R7 ; LHand partial word mask + + ANDEQ R8, R8, R9 ; if width=0, combine LH & RH masks + MOVEQ R9, R8 + + CMP R6, #0 + ADDLT R6, R6, #32 ; correct if neg + SUBLT R5, R5, #4 + RSB R7, R6, #32 ; its complement + + ADD R11, WsPtr, #SPltWidth + STMIA R11, {R0,R1,R2,R3,R4} ; SPltWidth..SPltScrAdr + + ADD R11, WsPtr, #SPltColCnt + STMIA R11, {R0,R5,R6,R7} ; SPltColCnt..SPltShftL + + ADD R11, WsPtr, #SPltMskAdr + STMIB R11, {R8,R9} ; SPltLMask,SPltRMask + + Pull R14 + BICS PC, R14, #V_bit ; VC some/all of sprite in window + +20 + Pull R14 + ORRS PC, R14, #V_bit ; VS sprite completely outside window + + + END diff --git a/s/vdu/vdugrafh b/s/vdu/vdugrafh new file mode 100644 index 0000000000000000000000000000000000000000..b7f6206b171c3834981d7e7d8ce1bc9213f9707d --- /dev/null +++ b/s/vdu/vdugrafh @@ -0,0 +1,1189 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.VduGrafH +; +; ARTHUR OPERATING SYSTEM - Vdu Drivers +; ======================= +; +; Vdu driver code - Sprite stuff +; +; Authors RManby, TDobson +; Started 10.11.86 + +; ************************************************************ +; *** C h a n g e L i s t (better late than never!) *** +; ************************************************************ + +; Date Description +; ---- ----------- +; 17-Feb-88 Created change list +; Fixed bug in SLOAD (errors weren't reported) +; 08-Apr-88 Changed LoadFile to use open with nodir + mustopen +; 20-May-88 Changed NoRoomToLoad to NotEnoughRoom + +; ***************************************************************************** +; +; MergeSpriteFile - Merge sprite file from filing system +; +; External routine +; +; in: R1 -> sprite area +; R2 -> filename +; + +MergeSpriteFile ROUT + Push R14 + KillSpChoosePtr + LDR R3, [R1, #saFree] + ADD R3, R3, R1 + BL LoadFile ; R1 -> sprite area, R2 -> filename + Pull PC, VS ; R3 -> free space + SUB R2, R3, #4 + BL MergeSpriteAreas ; in: R1 -> destination, R2 -> source, V=0 + Pull R14 + BICS PC, R14, #V_bit + +; ***************************************************************************** +; +; LoadSpriteFile - Load sprite file from filing system +; +; External routine +; +; in: R1 -> sprite area +; R2 -> filename +; + +LoadSpriteFile ROUT + KillSpChoosePtr + ADD R3, R1, #saNumber ; R3 = load address + +; and drop thru to LoadFile (V will be set/cleared by that routine) + +; ***************************************************************************** +; +; LoadFile - Load sprite file to particular address +; +; Internal routine, called by LoadSpriteFile, MergeSpriteFile +; +; in: R1 -> sprite area +; R2 -> filename +; R3 = load address +; +; out: VS => error during load, R0 -> error +; VC => loaded OK, R0 undefined +; R1-R11 preserved +; + +LoadFile ROUT + Push "R1-R6, R14" + + ; new version (07-Dec-89) to help broadcast loader a bit + + Push "R2,R3" ; filename ptr, load address + LDR R6, [R1, #saEnd] + ADD R6, R6, R1 + SUB R6, R6, R3 ; free space = saEnd-LoadAddress + + MOV R0, #OSFile_ReadInfo + MOV R1, R2 ; filename ptr + SWI XOS_File ; OSFILE(5), returns R0 type, R4 length + BVS %FT10 ; R0 file type, R4 length + + TEQ R0, #object_file ; if not a file + BNE %FT08 ; then make into suitable error + + CMP R6, R4 ; will file fit in available space ? + ADRCCL R0, SpriteErr_NotEnoughRoom + [ International + BLCC TranslateError + ] + BCC %FT10 + +; There is room to load file, so load the lot + + MOV R0, #OSFile_Load + Pull "R1, R2" ; filename ptr, load address + MOV R3, #0 ; use given address + SWI XOS_File + BVS %FT20 + +; TMD 07-Oct-91 (G-RO-9262) +; New code inserted here +; Check validity of sprite file +; R4 = file length from XOS_File above + +; TMD 06-Mar-92 (RP-0589) +; Validity check weakened to only check that +; offset to first sprite is < length of file + + LDR R3, [sp, #2*4] ; R3 = load address + LDR R1, [R3, #saFirst-4] ; offset to first sprite must be < length of file + CMP R1, R4 + Pull "R1-R6, PC",CC ; R0 is corrupt, R1-R11 preserved, V=0 + +; it was a bad file, so make it look like an empty sprite area before erroring +; so that in SLoad case we don't get a naff sprite area. + +05 + MOV R0, #0 + STR R0, [R3, #saNumber-4] + MOV R0, #SpriteAreaCBsize + STR R0, [R3, #saFirst-4] + STR R0, [R3, #saFree-4] + + ADRL R0, SpriteErr_BadSpriteFile + [ International + BL TranslateError + ] + B %FT20 + +08 + MOV R2, R0 + MOV R0, #OSFile_MakeError ; then make into suitable error + SWI XOS_File +10 + ADD R13, R13, #2*4 ; balance stack +20 + Pull "R1-R6, R14" ; return with error + STR R0, [WsPtr, #RetnReg0] + ORRS PC, R14, #V_bit ; R1-R11 preserved + +; ***************************************************************************** +; +; SaveSpriteFile - Save sprite area to filing system +; +; External routine +; +; in: R1 -> sprite area +; R2 -> filename +; + +SaveSpriteFile ROUT + LDR R3, [R1, #saNumber] ; if no sprites + TEQ R3, #0 + BEQ %FT10 ; then quit with error + + Push R14 + ADD R4, R1, #saNumber ; save sprite area, excluding + LDR R5, [R1, #saFree] ; free space or saEnd + ADD R5, R5, R1 + + [ AssemblingArthur :LOR: Module + MOV R0, #OSFile_SaveStamp + MOV R1, R2 ; filename ptr + LDR R2, =&FF9 ; type=SpriteFile + MOV R3, #0 ; junk + | + MOV R0, #0 ; normal save + MOV R1, R2 ; filename ptr + MOV R2, #0 + MOV R3, #0 + ] + + SWI XOS_File ; save file + STRVS R0, [WsPtr, #RetnReg0] + Pull PC + +10 + ADRL R0, SpriteErr_NoSprites + [ International + Push "lr" + BL TranslateError + Pull "lr" + ] + STR R0, [WsPtr, #RetnReg0] + ORRS PC, R14, #V_bit + + LTORG + +; ***************************************************************************** +; +; MergeSpriteAreas - Merge two sprite areas +; +; Internal routine, called by MergeSpriteFile +; +; in: R1 -> destination sprite area +; R2 -> source sprite area +; V=0 +; +; out: All registers preserved +; + +MergeSpriteAreas ROUT + TEQ R2, #0 ; validate R2 (R1 already checked) + BEQ %FT30 + Push "R1-R4, R14" + + LDR R4, [R2, #saNumber] ; number of sprites to merge + TEQ R4, #0 + BEQ %FT20 ; nothing to merge + + LDR R3, [R2, #saFirst] + ADD R2, R2, R3 +10 ; R1 -> dest area CB, + BL MergeSprite ; R2 -> to sprite CB + ; return R2 -> next sprite + BVS %FT20 ; error 'NoRoomToMerge' + SUBS R4, R4, #1 ; (V:=0 if becoming zero) + BNE %BT10 +20 + Pull "R1-R4, PC" ; exit with V already set up + +30 + ADRL R0, SpriteErr_Bad2ndPtr + [ International + Push "lr" + BL TranslateError + Pull "lr" + ] + STR R0, [WsPtr, #RetnReg0] + ORRS PC, R14, #V_bit + +; ***************************************************************************** +; +; MergeSprite - Merge sprite into sprite area +; +; Internal routine, called by MergeSpriteAreas +; +; in: R1 -> destination area +; R2 -> source sprite +; +; out: R2 -> past end of source sprite (ie next sprite) +; + +MergeSprite ROUT + Push "R1, R3-R5, R14" + ADD R2, R2, #spName + BL DeleteSpriteByName ; in: R1-R2; out: all preserved + SUB R2, R2, #spName +AddSprite + LDR R3, [R1, #saFree] + LDR R5, [R1, #saEnd] + SUB R5, R5, R3 ; amount of free ram in dest area + + LDR R4, [R2, #spNext] ; space needed for sprite + CMP R5, R4 + BCC %FT10 + + ADD R3, R3, R1 ; first free locn in dest. area + CopyDown R3,R2,R4,R5,R14 ; NB CopyDown will exit with R3 -> end + ; of dest area + LDR R4, [R1, #saNumber] ; update number of sprites + ADD R4, R4, #1 + STR R4, [R1, #saNumber] + + SUB R3, R3, R1 ; and free space offset + STR R3, [R1, #saFree] + + Pull "R1, R3-R5, R14" + BICS PC, R14, #V_bit ; ignore 'not found' from DeleteSprite + +10 + Pull "R1, R3-R5, R14" + ADRL R0, SpriteErr_NoRoomToMerge + [ International + Push "lr" + BL TranslateError + Pull "lr" + ] + STR R0, [WsPtr, #RetnReg0] + ORRS PC, R14, #V_bit + +; ***************************************************************************** +; +; AppendSprite - Append sprite to sprite area +; +; Internal routine, called by CopySprite +; +; in: R1 -> destination area +; R2 -> source sprite +; +; out: R2 -> past end of source sprite (ie next sprite) +; + +AppendSprite ROUT + Push "R1, R3-R5, R14" + B AddSprite + +; ***************************************************************************** +; +; ExtendHorizontally - Add one column to RHS of the sprite +; +; Internal routine, called by InsertCol +; +; in: R1 -> sprite area +; R2 -> sprite +; + +ExtendHorizontally ROUT + Push "R3-R6, R9-R11, R14" + LDR R3, [R2, #spRBit] + LDR R4, [WsPtr, #SprBytesPerChar] + ADD R3, R3, R4 ; alter spRBit to include next pixel + CMP R3, #32 + BCC %FT20 + ; >=32 means add 1 word to each row + LDR R3, [R2, #spHeight] + ADD R3, R3, #1 ; extend by (spHeight+1) words + BL ExtendSprite ; (space doubled if mask present) + Pull "R3-R6, R9-R11, PC", VS ; no room, then give error + + MOV R4, #0 + BL MaskOffset ; use spHeight+1 as row counter, + MOVNE R3, R3, LSL #1 ; doubled if mask present + + LDRNE R5, [R2, #spTrans] ; correct mask ptr, if mask present + ADDNE R5, R5, R3, LSL #1 ; R3 is words*2, hence LSL + STRNE R5, [R2, #spTrans] + + BL InsertWords ; Insert R3 words at position R4 in + ; sprite, ie at beginning + LDR R5, [R2, #spWidth] + ADD R5, R5, #1 ; new spWidth + STR R5, [R2, #spWidth] + + LDR R9, [R2, #spImage] + ADD R9, R9, R2 ; to + ADD R10, R9, R3, LSL #2 ; from + +10 + MOV R11, R5, LSL #2 + ; move one row + CopyDown R9,R10,R11,R14,R6 ; To,From,Size, Temp + + STR R4, [R9], #4 ; add 1 word at RH end of row + SUBS R3, R3, #1 + BHI %BT10 ; next row + + LDR R3, [WsPtr, #SprBytesPerChar] + SUBS R3, R3, #1 +20 + STR R3, [R2, #spRBit] + Pull "R3-R6, R9-R11, R14" + BICS PC, R14, #V_bit + +; ***************************************************************************** +; +; ReduceHorizontally - Remove some bits from the RHS of the sprite +; +; Internal routine, called by DeleteCol +; +; in: R0 = number of bits to delete off right hand side +; R1 -> sprite area +; R2 -> sprite +; + +ReduceHorizontally ROUT + Push "R3-R6, R9-R11, R14" + LDR R3, [R2, #spRBit] + SUBS R3, R3, R0 ; alter spRBit to exclude those bits + ADDCC R3, R3, #32 ; if underflow then extract whole word + STR R3, [R2, #spRBit] + BCS %FT20 + ; < 0 means remove 1 word per row + LDR R3, [R2, #spHeight] + ADD R3, R3, #1 ; remove (spHeight+1) words + MOV R4, #0 + BL MaskOffset + MOVNE R3, R3, LSL #1 ; doubled if mask present + + LDRNE R5, [R2, #spTrans] ; correct mask ptr, if mask present + SUBNE R5, R5, R3, LSL #1 ; R3 is words*2, hence LSL + STRNE R5, [R2, #spTrans] + + LDR R9, [R2, #spImage] + ADD R9, R9, R2 ; to + MOV R10, R9 ; from + LDR R5, [R2, #spWidth] +10 + MOV R11, R5, LSL #2 + ; move one row + CopyDown R9,R10,R11,R14,R6 ; To,From,Size, Temp + + + ADD R10, R10, #4 ; skip unwanted word + SUBS R3, R3, #1 + BHI %BT10 ; next row + +; R9 -> past end of this sprite +; R10 -> next sprite + + SUB R3, R10, R9 + MOV R3, R3, LSR #2 ; no. of words to remove + SUB R4, R9, R2 + LDR R9, [R2, #spImage] + SUB R4, R4, R9 ; byte offset within image + + BL RemoveWords + + LDR R5, [R2, #spWidth] + SUB R5, R5, #1 ; new spWidth + STR R5, [R2, #spWidth] +20 + Pull "R3-R6, R9-R11, R14" + BICS PC, R14, #V_bit + +; ***************************************************************************** +; +; InsertRow - Insert blank row into sprite +; +; External routine +; +; in: R1 -> sprite area +; R2 -> sprite +; R3 = row number to insert below (0 => bottom, spHeight+1 => above top) +; + +InsertRow ROUT + Push "R0,R4,R14" + MOV R0, #57 ; SpriteOp reason code for insert/delete rows + ORR R0, R0, #512 ;Set it to use pointers to user area & sprite + MOV R4, #1 ; We're only inserting one row! (put 1 in) + SWI XOS_SpriteOp + BVS %FT20 + + Pull "R0,R4,R14" + BICS PC, R14, #V_bit ; exit OK + +20 + STR R0, [WsPtr, #RetnReg0] + Pull "R0,R4,R14" + ORRS PC, R14, #V_bit ; exit with error + +; ***************************************************************************** +; +; DeleteRow - Delete row from sprite +; +; External routine +; +; in: R1 -> sprite area +; R2 -> sprite +; R3 = row number to remove (0=bottom, spHeight=top) +; + +DeleteRow ROUT + Push "R0,R4,R14" + MOV R0, #57 ; SpriteOp reason code for insert/delete rows + ORR R0, R0, #512 ;Set it to use pointers to user area & sprite + MVN R4, #0 ; We're only removing one row! (put -1 in) + SWI XOS_SpriteOp + BVS %FT20 + + Pull "R0,R4,R14" + BICS PC, R14, #V_bit ; exit OK + +20 + STR R0, [WsPtr, #RetnReg0] + Pull "R0,R4,R14" + ORRS PC, R14, #V_bit ; exit with error + +; ***************************************************************************** +; +; InsertCol - Insert blank column into sprite +; +; External routine +; +; in: R1 -> sprite area +; R2 -> sprite +; R3 = column to insert at (0 => before left..width => after right) +; + +InsertCol ROUT + Push "R0,R4,R14" + MOV R0, #58 ; SpriteOp reason code for insert/delete cols + ORR R0, R0, #512 ;Set it to use pointers to user area & sprite + MOV R4, #1 ; We're only inserting one column! (put 1 in) + SWI XOS_SpriteOp + BVS %FT20 + + Pull "R0,R4,R14" + BICS PC, R14, #V_bit ; exit OK + +20 + STR R0, [WsPtr, #RetnReg0] + Pull "R0,R4,R14" + ORRS PC, R14, #V_bit ; exit with error + +; ***************************************************************************** +; +; DeleteCol - Delete column from sprite +; +; External routine, and LHWastageEntry called from RemoveLeftHandWastage +; +; in: R1 -> sprite area +; R2 -> sprite +; R3 = column number to remove (0 => left, width-1 => right) +; + +DeleteCol ROUT + Push "R0,R4,R14" + MOV R0, #58 ; SpriteOp reason code for insert/delete cols + ORR R0, R0, #512 ;Set it to use pointers to user area & sprite + MVN R4, #0 ; We're only removing one row! (put -1 in) + SWI XOS_SpriteOp + BVS %FT20 + + Pull "R0,R4,R14" + BICS PC, R14, #V_bit ; exit OK + +20 + STR R0, [WsPtr, #RetnReg0] + Pull "R0,R4,R14" + ORRS PC, R14, #V_bit ; exit with error + +; ***************************************************************************** +; +; ExtendSprite - Add R3 words to the end of the sprite (R3*2 if mask) +; +; Internal routine, called by ExtendHorizontally, InsertRow, CreateMask, +; and ExtendSpriteByR3 called by GetSprite +; +; in: R1 -> sprite area +; R2 -> sprite +; R3 = no. of words to insert (gets doubled if mask present) +; + +ExtendSpriteByR3 ROUT + Push "R3, R8-R11, R14" + B ExtendSprite10 + +ExtendSprite ROUT + Push "R3, R8-R11, R14" + BL MaskOffset + MOVNE R3, R3, LSL #1 ; double no. of words if mask present +ExtendSprite10 + LDR R10, [R1, #saEnd] + LDR R11, [R1, #saFree] + SUB R10, R10, R3, LSL #2 + CMP R10, R11 + BCC %FT10 + + LDR R10, [R2, #spNext] + ADD R10, R10, R2 ; copy source + ADD R9, R10, R3, LSL #2 ; copy destination + + LDR R11, [R1, #saFree] + ADD R11, R11, R1 + SUB R11, R11, R10 ; size (bytes) to copy + CopyUp R9,R10,R11, R14, R8 ; To,From,Size,Temp, Temp2 + + LDR R9, [R1, #saFree] + ADD R9, R9, R3, LSL #2 + STR R9, [R1, #saFree] ; update saFree + + LDR R9, [R2, #spNext] + ADD R9, R9, R3, LSL #2 + STR R9, [R2, #spNext] ; update spNext + + Pull "R3, R8-R11, R14" + BICS PC, R14, #V_bit + +10 + ADRL R0, SpriteErr_NoRoomToInsert + [ International + BL TranslateError + ] + STR R0, [WsPtr, #RetnReg0] + Pull "R3, R8-R11, R14" + ORRS PC, R14, #V_bit + +; ***************************************************************************** +; +; InsertWords - Insert R3 words into given sprite at specified position +; +; Internal routine, called by ExtendHorizontally, InsertRow +; +; in: R1 -> sprite area +; R2 -> sprite +; R3 = number of words to insert +; R4 = insertion point (byte offset within sprite image) +; +; NB Assumes ExtendSprite has been called to leave R3 extra words +; at the end of the sprite +; +; out: All registers preserved +; + +InsertWords ROUT + Push "R8-R11, R14" + LDR R10, [R2, #spImage] + ADD R10, R10, R2 + ADD R10, R10, R4 ; copy source + ADD R9, R10, R3, LSL #2 ; copy destination + LDR R11, [R2, #spNext] + ADD R11, R11, R2 + SUB R11, R11, R9 ; size (bytes) to copy + CopyUp R9,R10,R11, R14,R8 ; To,From,Size,Temp, Temp2 + Pull "R8-R11, R14" + BICS PC, R14, #V_bit + +; ***************************************************************************** +; +; ClearWords - Clear R3 words in sprite +; +; Internal routine, called by InsertRow, CreateSprite +; +; in: R1 -> sprite area +; R2 -> sprite +; R3 = number of words to clear +; R4 = byte offset within sprite image to clear from +; +; out: All registers preserved +; + +ClearWords ROUT + Push "R9-R11, R14" + LDR R10, [R2, #spImage] + ADD R10, R10, R2 + ADD R10, R10, R4 ; clear from + MOVS R9, R3 + MOVNE R11, #0 +10 + STRNE R11, [R10], #4 + SUBNES R9, R9, #1 + BNE %BT10 + Pull "R9-R11, R14" + BICS PC, R14, #V_bit + +; ***************************************************************************** +; +; RemoveWords - Delete R3 words from given sprite +; +; Internal routine, called by ReduceHorizontally, DeleteRow, RemoveMask, +; GetSprite +; +; in: R1 -> sprite area +; R2 -> sprite +; R3 = number of words to remove +; R4 = removal point (byte offset within sprite image) +; +; out: All registers preserved +; spNext (in sprite) and spFree (in sprite area) updated +; + +RemoveWords ROUT + Push "R8-R11, R14" + LDR R9, [R2, #spImage] + ADD R9, R9, R2 + ADD R9, R9, R4 ; copy destination + ADD R10, R9, R3, LSL #2 ; copy source + LDR R11, [R1, #saFree] + ADD R11, R11, R1 + SUB R11, R11, R10 ; size (bytes) to copy + CopyDown R9,R10,R11, R14,R8 ; To,From,Size,Temp, temp2 + SUB R9, R9, R1 + STR R9, [R1, #saFree] ; update saFree + LDR R9, [R2, #spNext] + SUB R9, R9, R3, LSL #2 + STR R9, [R2, #spNext] ; update spNext + Pull "R8-R11, PC" + +; ***************************************************************************** +; +; MaskOffset - Read mask size (0 if absent) +; +; Internal routine, called by ExtendHorizontally, ReduceHorizontally, +; InsertRow, DeleteRow, ExtendSprite, FlipAboutXAxis +; +; in: R2 -> sprite +; +; out: R0 = 0 if no mask, otherwise mask size +; EQ if no mask, NE if mask present +; + +MaskOffset ROUT + Push R14 + LDR R0, [R2, #spImage] + LDR R14, [R2, #spTrans] + SUBS R0, R14, R0 ; offset from Image to Trans mask + ; =0 if no mask + Pull PC ; return EQ/NE for nomask/mask + +; ***************************************************************************** +; +; ReadPixelColour - Read colour of a pixel in a given sprite +; +; External routine +; +; in: R1 -> sprite area +; R2 -> sprite +; R3 = X coordinate of pixel (0 = left) +; R4 = Y coordinate of pixel (0 = bottom) +; +; out: RetnReg5 = colour (0..NColour) or 0..63 +; RetnReg6 = tint 0 or 0/64/128/192 +; + +ReadPixelColour ROUT + Push R14 + BL SpriteGenAddr ; returns R6, R7 + Pull PC, VS ; Address, Bit position + LDR R5, [R6] ; word from sprite + LDR R6, [WsPtr, #SprReadNColour] + + CMP R6, #63 ; check for 256 colour + MOVEQ R6, #255 + + AND R0, R6, R5, LSR R7 ; extract one pixel (bit0..) + + CMP R6, #255 + + MOVNE R2, R0 ; colour = pixel + MOVNE R3, #0 ; tint = 0 + BNE %FT10 + + ;now check for size of palette + ADD R2, R2, #spImage ; point to image/mask start + LDMIA R2, {R2, R3} + CMP R3, R3 + MOVGT R3, R3 + SUB R2, R2, #spPalette + CMP R2, #&0800 + + ;see comment below - for this call to work we have to temporarily + ;set NColour to SprReadNColour + + LDRNE R8,[WsPtr,#NColour] + STRNE R6,[WsPtr,#NColour] + + BLNE ExtractTintAndColour ; else extract colour & tint from pixel + + STRNE R8,[WsPtr,#NColour] + + MOVEQ R2, R0 + MOVEQ R3, #0 +10 + STR R2, [WsPtr, #RetnReg5] ; pass colour in R5 + STR R3, [WsPtr, #RetnReg6] ; and tint in R6 + Pull R14 + BICS PC, R14, #V_bit + +; ***************************************************************************** +; +; WritePixelColour - Write a pixel in a given sprite +; +; External routine +; +; in: R1 -> sprite area +; R2 -> sprite +; R3 = X coordinate of pixel (0 = left) +; R4 = Y coordinate of pixel (0 = bottom) +; R5 = pixel colour +; R6 = tint +; +; out: R1-R11 preserved +; + +; amg: note. need to handle full palettes differently here - since the GCOL and TINT +; model should not apply. Check for a full palette on an 8bpp sprite and deal with +; it accordingly. +; amg: bug fix to MED-01885. Although ReadPixel and WritePixel use SprReadNColour, +; then call AddTintToColour which uses NColour - being the screen's value not the +; sprites. Therefore, the safest fix this near freeze is to simply temporarily change +; the NColour value for the call, and then restore it. + +WritePixelColour ROUT + Push "R1-R4, R14" + LDR R8, [WsPtr, #SprReadNColour] + + AND R0, R5, R8 ; limit colour to 0..NColour + + CMP R8, #63 ; check for 256 colours + CMPNE R8, #255 + BNE %FT08 ; despatch non 8bpp + + ;now need to determine size of 8bpp sprite's palette + ADD R3, R2, #spImage ; point to image/mask start + LDMIA R3, {R2, R3} ; fetch them + CMP R2, R3 ; which is higher + MOVGT R2, R3 ; use the lesser + SUB R2, R2, #spPalette ; subtract start offset + CMP R2, #&800 + + MOVNE R3, R6 ; then combine + + ;see comment above - for this call to work we have to temporarily + ;set NColour to SprReadNColour + + LDRNE R7,[WsPtr,#NColour] + STRNE R8,[WsPtr,#NColour] + + BLNE AddTintToColour ; colour & tint + + STRNE R7,[WsPtr,#NColour] + + B %FT05 ; 8 bpp take this branch +08 + ADDCC R0, R0, R8 ; else index into full colour table + ADRCCL R5, TBFullCol + LDRCCB R0, [R5, R0] ; N.B. a table of bytes + BCC %FT05 ; 1,2,4 bpp take this branch + + ; if 16bpp only need to shift round once, if 32bpp not at all + LDR LR, [R2, #spMode] + MOV LR, LR, LSR #27 + CMP LR, #6 + MOV R5, R0 + BCS %FT06 ; 32 bpp takes this branch + + B %FT07 ; and 16 bpp takes this one +05 + ORR R5, R0, R0, LSL #8 ; expand byte value into a word +07 + ORR R5, R5, R5, LSL #16 +06 + Pull "R1-R4" + BL SpriteGenAddr ; returns R6, R7 + Pull PC, VS ; Address, Bit position + LDR R8, [WsPtr, #SprWriteNColour] + AND R5, R5, R8 ; limit colour to pixel width + LDR R0, [R6] ; word from sprite + BIC R0, R0, R8, LSL R7 + ORR R0, R0, R5, LSL R7 + STR R0, [R6] + Pull R14 + BICS PC, R14, #V_bit + +; ***************************************************************************** +; +; ReadPixelMask - Read mask state for a pixel in a given sprite +; +; External routine +; +; in: R1 -> sprite area +; R2 -> sprite +; R3 = X coordinate of pixel (0 = left) +; R4 = Y coordinate of pixel (0 = bottom) +; +; out: RetnReg5 = 0/1 (transparent/solid) +; + +ReadPixelMask ROUT + Push R14 + LDR R5, [R2, #spImage] + LDR R6, [R2, #spTrans] + SUBS R5, R6, R5 ; offset from Image to Trans mask + MOVEQ R5, #1 ; if =0, no mask so pixel is solid + BEQ %FT10 + BL SpriteMaskAddr ; returns R6, R7 + Pull PC, VS ; Address, Bit position + LDR R5, [R6, R5] ; word from mask + + LDR LR, [R2, #spMode] ; check for 1bpp masks + MOVS LR, LR, LSR #27 + MOVNE R6, #1 + LDREQ R6, [WsPtr, #SprReadNColour] + + ANDS R5, R6, R5, LSR R7 ; extract one mask pixel (bit0..) + MOVNE R5, #1 +10 + STR R5, [WsPtr, #RetnReg5] + Pull R14 + BICS PC, R14, #V_bit + +; ***************************************************************************** +; +; WritePixelMask - Write a pixel in the mask for a given sprite +; +; External routine +; +; in: R1 -> sprite area +; R2 -> sprite +; R3 = X coordinate of pixel (0 = left) +; R4 = Y coordinate of pixel (0 = bottom) +; R5 = pixel mask 0/1 (transparent/solid) +; + +WritePixelMask ROUT + Push R14 + LDR R8, [R2, #spImage] + LDR R9, [R2, #spTrans] + SUBS R9, R9, R8 ; offset from Image to Trans mask + BEQ %FT10 ; if =0, no mask so quit + BL SpriteMaskAddr ; returns R6, R7 + Pull PC, VS ; Address, Bit position + + LDR LR, [R2, #spMode] + MOVS LR, LR, LSR #27 + LDREQ R8, [WsPtr, #SprWriteNColour] + MOVNE R8, #1 ; adjust for new format sprites + + TEQ R5, #0 + MOVNE R5, R8 + LDR R0, [R6, R9] ; word from mask + BIC R0, R0, R8, LSL R7 + ORR R0, R0, R5, LSL R7 + STR R0, [R6, R9] +10 + Pull R14 + BICS PC, R14, #V_bit + +; ***************************************************************************** +; +; SpriteGenAddr - Generate address for a given (X,Y) position +; +; SpriteMaskAddr - For use on mask (copes with old/new masks) +; +; Internal routine, called by InsertCol, DeleteCol, ReadPixelColour, +; WritePixelColour, ReadPixelMask, WritePixelMask +; +; Note that InsertCol and DeleteCol are *not* being altered for the +; present round of 1bpp mask work. +; +; +; in: R1 -> sprite area +; R2 -> sprite +; R3 = X coordinate of pixel (0 = left) +; R4 = Y coordinate of pixel (0 = bottom) +; +; out: R6 = address +; R7 = bit position of pixel +; R1-R5, R8-R11 preserved +; V=1 => outside sprite, R0 -> error +; + +SpriteMaskAddr ROUT + Push "R1-R5, R8-R11, LR" + + LDR LR, [R2, #spMode] + MOVS LR, LR, LSR #27 ; get the sprite type from the mode word + BEQ %FT10 ; branch: old format, use old routine as is + + ADD R5, R2, #spWidth + LDMIA R5, {R5-R8} ; R5 ,R6 ,R7 ,R8 + ; spWidth,spHeight,spLBit,spRBit + SUBS R4, R6, R4 ; invert Y coord + BCC %FT90 ; must be in range 0..spHeight + + BL GetMaskspWidth ; change R5 to suit the mask width + ; and R8 to new last bit used + + MLA R0, R5, R4, R4 ; word offset to row = Y*(width+1) + + ;for new format masks the depth is fixed, so... + + MOV R9, #5 ; XShftFactor + MOV R10, #31 ; SprNPix + MOV R11, #0 ; Log2BPC + + B %FT20 ; and continue in the old code + +SpriteGenAddr + Push "R1-R5, R8-R11, LR" +10 + ADD R5, R2, #spWidth + LDMIA R5, {R5-R8} ; R5 ,R6 ,R7 ,R8 + ; spWidth,spHeight,spLBit,spRBit + SUBS R4, R6, R4 ; invert Y coord + BCC %FT90 ; must be in range 0..spHeight + + MLA R0, R5, R4, R4 ; word offset to row = Y*(width+1) + + LDR R9, [WsPtr, #SprXShftFactor] + LDR R10, [WsPtr, #SprNPix] + LDR R11, [WsPtr, #SprLog2BPC] +20 + BitLOffset R6,R3, R9,R10,R11 + WordOffset R3,R3, R9,R10,R11 + +; sprite starts LBit bits into word +; so add LBit to bit offset + + ADD R7, R6, R7 + ADD R3, R3, R7, LSR #5 ; if offset>=32 then inc word address + AND R7, R7, #31 ; force offset into range 0..31 + + CMP R3, R5 ; R3 should now be in range 0..spWidth + CMPEQ R7, R8 ; if R3=spWidth, then check bit posn + BHI %FT90 ; is within sprite + + ADD R6, R0, R3 ; word offset into sprite + ADD R6, R2, R6, LSL #2 + LDR R8, [R2, #spImage] + ADD R6, R6, R8 ; byte address of word in sprite + + Pull "R1-R5, R8-R11, LR" + BICS PC,Link,#V_bit + +90 + ADRL R0, SpriteErr_InvalidRowOrCol + [ International + Push "lr" + BL TranslateError + Pull "lr" + ] + STR R0, [WsPtr, #RetnReg0] + Pull "R1-R5, R8-R11, LR" + ORRS PC, R14, #V_bit + + +; ***************************************************************************** +; +; GetMaskspWidth - convert spWidth for data to spWidth for mask (1bpp masks) +; +; Internal routine, called from spritemaskaddr & switchouputtomask +; +; in: R5 = spWidth (ie width in words-1) +; (expects R2->sprite) +; +; out: R5 = spWidth (words -1) for mask data +; R8 modified for new last bit used in mask data + +; should only be called for new format sprites, but will cope with old too + +;NOTE: If any changes are made to this routine, please look at the SpriteExtend +;source too, as there is a very similiar routine there too (in SprAdjSize). WT + +GetMaskspWidth ROUT + Push "R0,LR" + + LDR LR, [R2, #spMode] ; fetch the sprite mode + MOVS LR, LR, LSR #27 ; isolate the sprite type and test for =0 + + Pull "R0,PC",EQ ; if an old format sprite, return R5 unchanged + + ; treat any T>max sprites as 32bpp + CMP LR, #SpriteType_MAX + MOVCS LR, #SpriteType_Substitute + + ; bugfix 9/8/93: get log2bpp this way + ADRL R0, NSM_bpptable-4 + LDR LR, [R0, LR, LSL #2] ; get the log2bpp to LR + + RSB LR, LR, #5 ; and change to 5-log2bpp + + MOV R5, R5, LSL LR ; number of pixels for full words + + RSB LR, LR, #5 ; now switch back to log2bpp + LDR R0, [R2, #spRBit] + ADD R0, R0, #1 + ADD R5, R5, R0, LSR LR + + ANDS LR, R5, #&1F ; fit exactly in a number of words ? + SUB R8, LR, #1 ; alter the last bit used for the mask data + ; fix bug MED-01130.... + AND R8, R8, #&1F ; ....bring back into range 00-1F (may be -1 here) + MOVNE LR, #1 ; if not, add an extra word + ADD R5, LR, R5, LSR #5 ; add the whole number of words + SUB R5, R5, #1 ; returns as words-1 + + Pull "R0,PC" + + +; ***************************************************************************** +; +; RemoveLeftHandWastage - Remove left-hand wastage from a sprite +; +; Internal routine, but made external for testing +; +; in: R1 -> sprite area +; R2 -> sprite +; + +RemoveLeftHandWastage ROUT + LDR R0, [R2, #spLBit] + TEQ R0, #0 ; is there any wastage ? + BICEQS PC, R14, #V_bit ; no, then exit straight away + + Push "R1, R2, R14" ; get stack the same as in DeleteCol + LDR R11, [R2, #spImage] + ADD R11, R11, R2 ; R11 := address of first word + MOV R7, #0 ; bit position of first pixel + STR R7, [R2, #spLBit] ; pretend LBit = 0 + MOV R10, #0 ; byte offset from LH end to delete pt. + + LDR R9, [R2, #spWidth] + MOV R9, R9, LSL #2 ; byte offset from delete pt to LH end + ; of next row -4 + LDR R8, [R2, #spNext] + ADD R8, R8, R2 ; first byte after sprite + + MOV R2, R0 ; number of bits to delete +LHWastageEntry + RSB R3, R2, #32 ; LShft := 32-RShft + + MOV R4, #1 + RSB R4, R4, R4, LSL R7 ; mask for pixels left of deletion pt. + MVN R5, R4 ; inclusive & right of extractn. pt. + +; R0, R1, R2 ,R3 ,R4 ,R5 ,R6 ,R7 ,R8 ,R9 ,R10 .R11 +; , , RShft,LShft,LMask,RMask, ,WordCnt,EndAdr,WordOff,RowOff,Adr + +; R11 -> LH end of row + +10 + ADD R11, R11, R10 ; step to deletion point + LDR R0, [R11] + AND R1, R5, R0, LSR R2 ; extract & shift rightmost pixels + ; (ie MSBits) + AND R0, R4, R0 ; extract leftmost pixels (ie LSBits) + ORR R0, R0, R1 ; recombine (unwanted pixel removed) + LDR R1, [R11, #4] ; shift leftmost pixel of next word + ORR R0, R0, R1, LSL R3 ; in at rightmost end of this word + STR R0, [R11], #4 ; NB #4 to cope with naff rowoff (R10) + CMP R9, #0 + BEQ %FT30 + MOV R7, R9 +20 + LDMIA R11,{R0,R1} ; now do a 1 pixel shift left + MOV R0, R0, LSR R2 ; of the rest of the row + ORR R0, R0, R1, LSL R3 + STR R0, [R11], #4 + SUBS R7, R7, #4 + BGT %BT20 + +; R11 -> LH end of next row + +30 + CMP R8, R11 + BHI %BT10 ; if EndAdr>Adr, do next row + + MOV R0, R2 ; R0 = number of bits to delete + LDMFD R13, {R1,R2} + BL ReduceHorizontally + Pull "R1-R2, R14" + BICS PC, R14, #V_bit + +60 + STR R0, [WsPtr, #RetnReg0] +70 + Pull "R1-R2, R14" + ORRS PC, R14, #V_bit + + +; ****************************************************************************** +; +; bounce_new_format_masks - object to masks on new format sprites +; +; enter with R2->sprite +; either returns with all registers preserved, or VS and R0->error + +bounce_new_format_masks ROUT + STMFD R13!,{R0,R14} + LDR LR, [R2, #spMode] ; fetch the sprites mode + MOVS LR, LR, LSR #27 ; set NE if new format + LDMEQFD R13!,{R0,R15} ; out now if old format + BL MaskOffset ; returns R0=mask size, EQ if no mask, NE if mask + LDMEQFD R13!,{R0,R15} ; out now if no mask + ADRL R0, SpriteErr_NoMaskOrPaletteAllowedInThisDepth + [ International + BL TranslateError + ] + SETV + STR R0,[R13] + STR R0,[WsPtr, #RetnReg0] + LDMFD R13!,{R0,R15} + + END diff --git a/s/vdu/vdugrafi b/s/vdu/vdugrafi new file mode 100644 index 0000000000000000000000000000000000000000..459ab061fd38a1c9e250af1b32b886903b5f1ea0 --- /dev/null +++ b/s/vdu/vdugrafi @@ -0,0 +1,346 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.VduGrafI +; +; ARTHUR OPERATING SYSTEM - Vdu Drivers +; ======================= +; +; Vdu driver code - Sprite stuff +; +; Author R C Manby +; Date 10.11.86 +; +; CHANGES +; ------- +; 12.04.94 W Turner Updated to allow the use of 1bpp masks +; 12.01.95 G Simms Fixed MED-04130 where New format sprites with +; LH wastage were being created. + +; ***************************************************************************** +; +; FlipAboutXAxis - Flip sprite about X axis +; +; External routine +; +; in: R2 -> sprite +; + +FlipAboutXAxis ROUT + Push R14 + + BL MaskOffset + MOV R7, R0 ; 0/offset for nomask/mask + LDR R4, [R2, #spWidth] ; width-1 + LDR R5, [R2, #spHeight] ; height-1 + LDR R6, [R2, #spImage] + TEQ R5, #0 + BEQ %FT05 ; nothing to do, if only 1 row + + ADD R0, R2, R6 ; R0 -> top row in image + ADD R3, R4, #1 ; width + MUL R1, R5, R3 ; R1 = word offset to bottom row + ADD R1, R0, R1, LSL #2 ; R1 -> bottom row in image + + Push "R0-R1, R2, R4-R5, R7" ; preserve ptrs & mask offset + BL FlipAbX10 ; flip main image + Pull "R0-R1, R2, R4-R5, R7" + + CMP R7, #0 + BEQ %FT05 ; No mask so skip this bit + + ADD R0, R0, R7 ; Update the start pointer + + ;If a new format sprite (we know it has a mask) + ;redo R1 & call the 'GetMaskspWidth' routine to alter R3 + + LDR R8, [R2, #spMode] ; Get sprite mode + MOVS R8, R8, LSR #27 ; Isolate sprite type & test for 0 + + ADDEQ R1, R1, R7 ; Old format, so simple + BEQ %FT04 + + ;Here, we know it is a 1bpp mask + MOV R6, R5 ; Better keep R5 safe, we'll need it in a bit + MOV R5, R4 ; The sub wants R4 in r5 + BL GetMaskspWidth ; Update the 'width' if needed + ADD R3, R5, #1 ; R3=width in words + + MUL R1, R6, R3 ; R1 = word offset to bottom row + ADD R1, R0, R1, LSL #2 ; R1 -> Bottom row in image +04 + BL FlipAbX10 ; flip mask +05 + Pull R14 + BICS PC, R14, #V_bit + +; ***************************************************************************** +; +; FlipAbX10 - Flip area given ptrs and width +; +; Internal routine, called by FlipAboutXAxis +; +; in: R0 -> top row +; R1 -> bottom row +; R3 = width in words +; +; out: R0-R2,R4-R11 corrupted +; R3 preserved +; + +FlipAbX10 ROUT +10 + SUBS R2, R3, #4 ; initialise width count + BLT %FT30 +20 ; flip in blocks of 4 words + LDMIA R0, {R4-R7} + LDMIA R1, {R8-R11} + STMIA R1!, {R4-R7} + STMIA R0!, {R8-R11} + SUBS R2, R2, #4 + BGE %BT20 +30 + ADDS R2, R2, #4 + BLE %FT50 +40 ; do remaining words one by one + LDR R4, [R0] + LDR R8, [R1] + STR R4, [R1], #4 + STR R8, [R0], #4 + SUBS R2, R2, #1 + BNE %BT40 +50 + SUB R1, R1, R3, LSL #3 ; point to previous row + CMP R1, R0 + BHI %BT10 ; loop until pointers meet or cross + MOVS PC, R14 ; only R3 preserved + +; ***************************************************************************** +; +; FlipAboutYAxis - Flip a sprite about Y axis +; +; External routine +; +; in: R2 -> sprite +; + +FlipAboutYAxis ROUT + Push R14 + + BL MaskOffset + MOV R8, R0 ;Bung result in R8 'till we want it... + + ADD R3, R2, #spWidth + LDMIA R3, {R3-R7} ; R3 ,R4 ,R5 ,R6 ,R7 + ; spWidth,spHeight,spLBit,spRBit,spImage + ADD R3, R3, #1 ; use width as row offset (words) + + MUL R4, R3, R4 ; R4=width x (height-1) in words + ADD R4, R4, R3 ; R4=width x height in words + ADD R4, R7, R4, LSL #2 ; offset past end of sprite image + ADD R4, R4, R2 ; address past end of image + + RSB R5, R5, #31 ; reflect LBit & RBit + RSB R6, R6, #31 + STR R5, [R2, #spRBit] ; new RBit := 31- old LBit + STR R6, [R2, #spLBit] ; new LBit := 31- old RBit + ADD R0, R2, R7 ; R0 -> start of first row + LDR R11, [WsPtr, #SprBytesPerChar] ; shift factor to + ; reach next pixel + LDR R9, [WsPtr, #SprWriteNColour] ; mask for leftmost pixel + MOV R10, R9, ROR R11 ; mask for rightmost pixel + + Push "R0, R2, R5-R8" + BL FlipAbY10 ; Do the sprite image + Pull "R0, R2, R5-R8" + + Push "R0,R8" + LDR R8, [R2, #spMode] ; Get sprite mode + MOVS R8, R8, LSR #27 ; Isolate sprite type & test for 0 + BEQ %FT03 ; If old format ignore next bit + + ; If this is a new format sprite we may have to remove any LH + ; wastage that was created by the flip. + CMP R6, #0 ; Is there any LH wastage? + BEQ %FT03 ; If not skip the next bit. + MOV R8, R6 + BL RemLHWastage + ; If this is a new format sprite then LH wastage = 0 and the RH wastage + ; is the same as it was to start with. + RSB R5, R6, #31 ; restore old RBit + MOV R6, #0 + STR R5, [R2, #spRBit] ; new RBit := 31- old LBit + STR R6, [R2, #spLBit] ; new LBit := 0 +03 + Pull "R0,R8" + CMP R8, #0 ; Does the sprite have a mask? + BEQ %FT05 ; Nope, so skip the mask flip! + + ;Now, is it an old or new sprite? + LDR R1, [R2, #spMode] ; Get sprite mode + ADD R0, R0, R8 ; R0 points to start of mask + MOVS R1, R1, LSR #27 ; Isolate sprite type & test for 0 + + ADDEQ R4, R4, R8 ;R4 points to end of mask now + BEQ %FT04 ;Skip the next bit (it's for new format only) + + Push "R5" + LDR R5, [R2, #spWidth] + BL GetMaskspWidth + ADD R3, R5, #1 ;R3 is new row offset (words) + Pull "R5" + + Push "R8" ;Last Bit used for mask, this will enable + ;us to remove the left hand wastage after + ;the flip + + LDR R4, [R2, #spHeight] + LDR R8, [R2, #spTrans] + MUL R4, R3, R4 ; R4=width x (height-1) in words + ADD R4, R4, R3 ; R4=width x height in words + ADD R4, R8, R4, LSL #2 ; offset past end of sprite mask + ADD R4, R4, R2 ; address past end of mask + + ADD R0, R2, R8 ; R0 -> start of first row of mask +; LDR R11, [WsPtr, #SprBytesPerChar] ; shift factor to + ; reach next pixel +; LDR R9, [WsPtr, #SprWriteNColour] ; mask for leftmost pixel + + MOV R11, #1 + MOV R9, #1 +;************** + Push R0 + MOV R0, #&6000 + STR R9, [R0] + STR R11, [R0, #4] + Pull R0 +;************** + + MOV R10, R9, ROR R11 ; mask for rightmost pixel + + Push "R0" + BL FlipAbY10 ; Now do the mask + Pull "R0" + Pull "R8" ; Retrieve last bit used to find LHwastage + RSB R8, R8, #31 + CMP R8, #0 + BEQ %FT05 + BL RemLHWastage + B %FT05 +04 + BL FlipAbY10 ; Now do the mask +05 + Pull R14 + BICS PC, R14, #V_bit + +; ***************************************************************************** +; +; FlipAbY10 - Flip area given ptrs and width +; +; Internal routine, called by FlipAboutYAxis +; +; N.B. This reflects 'user pixels', ie in double pixel modes it +; reflects pairs of screen pixels, this should not matter. +; +; ON ENTRY, we have R0, R3-R4, R9-R11 +; ON EXIT, of these, only R0 is corrupted + +; Internally: +; R0 RowPtr, R1 LPtr , R2 RPtr , R3 Row offset, R4 EndAdr +; R5 LWord , R6 RWord, R7 LTemp, R8 RTemp , R9 LPixMask +; R10 RPixMask, R11 ShftFactor, R14 Cnt + +; R0-R2, R5-R8 get corrupted + +FlipAbY10 + Push R14 +10 + MOV R1, R0 ; R1 -> left end of row + ADD R0, R0, R3, LSL #2 ; R0 -> past right end of row + MOV R2, R0 ; R2 := R0 +20 + LDR R5, [R1] + LDR R6, [R2, #-4]! + MOV R14, #32 ; total number of bits to process +30 ; circular pixel shift of LWord & RWord + AND R7, R5, R9 ; leftmost pixel (LSPart of LWord) + AND R8, R6, R10 ; rightmost pixel (MSPart of RWord) + ORR R5, R8, R5, LSR R11 + ORR R6, R7, R6, LSL R11 + SUBS R14, R14, R11 ; process next pixel + BNE %BT30 ; TMD 12-Jan-88 bug fixed here + ; I had changed RCM's code and put BCS + + STR R5, [R1], #4 + STR R6, [R2] + CMP R2, R1 + BHI %BT20 ; loop until pointers meet or cross + + CMP R0, R4 + BCC %BT10 ; if address < end, reflect next row + + Pull R14 + MOVS PC, R14 + +; ***************************************************************************** +; +; RemLHWastage - Dedicated routine to remove x bits of LH wastage +; after a new format Sprite has been flipped +; +; On Entry: R0 = Start of data +; R3 = Row Offset +; R4 = End of data +; R8 = No. Bits to Remove +; R0 RowPtr, R1 LPtr , R2 RPtr , R3 Row offset, R4 EndAdr + +RemLHWastage + Push "R1,R2,R5-R8,R14" +10 +;start of loop for each line + MOV R1, R0 ; R1 -> left end of row + ADD R0, R0, R3, LSL #2 ; R0 -> past right end of row + SUB R2, R0, #4 ; R2 -> last word in row + ; (used for loop check) + LDR R5, [R1] ; load current word +20 +;Start of loop for each word + CMP R2, R1 + ;If we have reached the last word then just shift and store + MOVEQ R5, R5, LSR R8 + STREQ R5, [R1] + BEQ %FT99 + ;There are more words left so we need to shift in the LSBits from the next + ;word. + LDR R6, [R1, #4] ; load next word + MOV R5, R5, LSR R8 ; Throw away wastage bits in current word + RSB R14, R8, #32 + MOV R7, R6, LSL R14 ; Move LSBs from next word to current + ORR R5, R5, R7 + STR R5, [R1],#4 ; store current word + MOV R5, R6 ; move next word to current word ready for + ; next loop iteration. + + B %BT20 +; CMP R2, R1 +; BHI %BT20 ; loop until pointers meet or cross + +99 + CMP R0, R4 + BCC %BT10 ; if address < end, reflect next row + + Pull "R1,R2,R5-R8,R14" + MOVS PC, R14 + + + END diff --git a/s/vdu/vdugrafj b/s/vdu/vdugrafj new file mode 100644 index 0000000000000000000000000000000000000000..987d96e8d2b808491001072ec380f6209c5dc0ca --- /dev/null +++ b/s/vdu/vdugrafj @@ -0,0 +1,1321 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.VduGrafJ +; +; ARTHUR OPERATING SYSTEM - Vdu Drivers +; ======================= +; +; Vdu driver code - Sprite stuff +; +; Author R C Manby +; Date 10.11.86 +; + +; ***************************************************************************** +; +; GetSpriteUserCoords - Pick up area of screen as sprite using +; given external coordinates +; +; External routine +; +; in: R1 -> sprite area +; R2 -> sprite name +; R3 = 0 => exclude palette data +; 1 => include palette data +; R4,R5 = (X,Y) EXTERNAL coordinates of one corner of box +; R6,R7 = (X,Y) EXTERNAL coordinates of opposite corner of box +; + +GetSpriteUserCoords ROUT + Push "R1-R3, R14" + ADD R8, WsPtr, #GCsX + LDMIA R8, {R9,R10} ; preserve GCsX,GCsY around EIG + + MOV R0, R4 + MOV R1, R5 + MOV R2, #4 ; indicate absolute coord + BL EIG + MOV R4, R0 + MOV R5, R1 + + MOV R0, R6 + MOV R1, R7 + BL EIG + MOV R6, R0 + MOV R7, R1 + + STMIA R8, {R9,R10} ; restore GcsX,GCsY + Pull "R1-R3, R14" + B GetSpr05 + +; ***************************************************************************** +; +; GetSprite - Pick up area of screen bounded by OldCs and GCsI as sprite +; +; External routine + GetSpr05 called by GetSpriteUserCoords +; (also external) +; +; in: R1 -> sprite area +; R2 -> sprite name +; R3 = 0 => exclude palette data +; 1 => include palette data +; OldCsX,OldCsY = (X,Y) INTERNAL coordinates of one corner of box +; GCsIX, GCsIY = (X,Y) INTERNAL coordinates of opposite corner of box +; + +GetSprite ROUT + ADD R4, WsPtr, #OldCsX ; pickup area given by OldCs + LDMIA R4, {R4-R7} ; and GCsIX +GetSpr05 + Push R14 + [ {TRUE} + GraphicsMode R0 + BNE %FT70 + | + LDR R0, [WsPtr, #NPix] + TEQ R0, #0 + BEQ %FT70 ; quit with error if not graphics mode + ] + + KillSpChoosePtr + + SortT R4, R6, R8 ; R4 ,R5, R6 ,R7 N.B. BotL & + SortT R5, R7, R8 ; sL ,sB, sR ,sT TopR + + LDR R8, [WsPtr, #YWindLimit] + SUB R8, R8, R7 ; use inverted sT as index + AND R8, R8, #7 ; into EcfPatternTable + STR R8, [WsPtr, #SGetEcfIndx] + + LDR R0, [WsPtr, #ModeNo] + STR R0, [WsPtr, #SGetMode] ; needs setting up before CreateHeader + + Push R2 + BL SpriteCtrlBlk + BVC %FT90 ; sprite already exists, so be clever + Pull R2 ; restore name pointer + + ; R1 ,R2 ,R3 ,R4,R5,R6,R7 + BL CreateHeader ; In : AreaPtr,NamePtr,Palette ,sl,sb,sr,st + ; Out: ImageSize,lx,ty, + BVS %FT80 ; Error, (no room/not a graphics mode) + + BL GetSpriteData + +; R1 -> sprite area, R2 -> sprite +; now add the sprite to the sprite area + + LDR R3, [R2, #spNext] ; total size of new sprite + LDMIA R1, {R4-R7} ; saEnd,saNumber,saFirst,saFree + ADD R5, R5, #1 + ADD R7, R7, R3 + STMIA R1, {R4-R7} + +; have we made a new format sprite ? if so no left hand wastage is allowed. + + LDR R3, [R2, #spMode] + CMP R3, #256 + + BLCS RemoveLeftHandWastage + + BL SelectSprite + SWI XOS_RestoreCursors + Pull R14 + BICS PC, R14, #V_bit + +70 + ADRL R0, SpriteErr_NotGraphics + [ International + BL TranslateError + ] +75 + STR R0, [WsPtr, #RetnReg0] +80 ; return point after an error + Pull R14 + ORRS PC, R14, #V_bit + +; come here if sprite already exists +; we want to extend or reduce existing sprite as necessary + +90 + ADD R13, R13, #4 ; throw away stacked name ptr + LDR R14, [WsPtr, #VduSprite] + TEQ R14, R2 ; if same as vdu output sprite + ADREQL R0, SpriteErr_SpriteIsCurrentDest + [ International + BLEQ TranslateError + ] + BEQ %BT75 ; then error + + ADR R14, %FT95 + SVC_mode + Push "R1, R14" + ADD R8, WsPtr, #NameBuf + LDMIA R8, {R9-R11} ; load 3 words of name + ADD R8, WsPtr, #SGetName + STMIA R8, {R9-R11} ; and store in SGetName + + Push "R1, R2, R3" ; save sprite area, sprite, palflag + BL PreCreateHeader + Pull "R1, R2" ; restore sprite area ptr + sprite ptr + BVS %FT93 + ; R4 = total size of sprite + Push R4 ; save new size of sprite + LDR R0, [R2, #spNext] + SUBS R3, R4, R0 ; compare required size with existing + MOV R3, R3, ASR #2 ; no. of words to extend/reduce by + BEQ %FT94 ; [is exactly right already] + BHI %FT92 ; need to extend sprite + +; need to reduce sprite + + RSB R3, R3, #0 ; no. of words to reduce by + LDR R4, [R2, #spImage] + SUB R4, R0, R4 ; offset from Image to Next + SUB R4, R4, R3, LSL #2 ; dest. start as offset from spImage + BL RemoveWords + RSB R3, R3, #0 ; put R3 back to no. of words to extend + B %FT94 + +; need to extend sprite + +92 + BL ExtendSpriteByR3 +93 + ADDVS R13, R13, #4*4 ; junk size, palflag, + ; sprite area, fake return address + BVS %BT80 ; no room to extend sprite +94 + Pull R4 ; restore new size of sprite + B PostCreateHeader + +; come back to here after PostCreateHeader exits +; R1 -> sprite area, R2 -> sprite, R3 = no. of words to extend by + +95 + BL GetSpriteData + BL SelectSprite + +; have we made a new format sprite ? if so no left hand wastage is allowed. + + LDR R3, [R2, #spMode] + CMP R3, #256 + BLCS RemoveLeftHandWastage + + SWI XOS_RestoreCursors + Pull R14 + BICS PC, R14, #V_bit + +; ***************************************************************************** + +GetSpriteData ROUT + Push "R1-R3, R14" + SWI XOS_RemoveCursors + MOV R0, R4 + MOV R1, R5 + BL ScreenAddr + MOV R0, R2 ; screen addr of TopL of area + LDMIA R13, {R4,R5} ; R4->sprite area, R5->sprite + LDR R1, [WsPtr, #SGetImage] + ADD R1, R1, R5 ; memory address + LDR R2, [WsPtr, #SGetWidth] + ADD R2, R2, #1 ; sprite width (words) + LDR R3, [WsPtr, #SGetHeight] ; height + ADD R3, R3, #1 + + LDR R8, [WsPtr, #SGetTopMargin] ; gap above window (rows) + LDR R9, [WsPtr, #SGetBotMargin] ; below (rows) + LDR R10, [WsPtr, #SGetLWrdMargin] ; left of (words) + LDR R11, [WsPtr, #SGetRWrdMargin] ; right of (words) + + SUB R2, R2, R10 + SUBS R2, R2, R11 ; number words in window per scanline + BLEQ PaintSprite ; Left or Right of window + BEQ %FT60 + + SUB R3, R3, R8 + SUBS R3, R3, R9 ; number of rows in window + BLEQ PaintSprite ; above or below window + BEQ %FT60 + + LDR R14, [WsPtr, #LineLength] ; offset from RHend of row to LHend + SUB R14, R14, R2, LSL #2 ; of next row + STR R14, [WsPtr, #SGetRowOfst] + + LDR R11, [WsPtr, #SGetLBitMargin] + MOV R5, #&FFFFFFFF + MOV R5, R5, LSL R11 ; LmarginMask + + LDR R11, [WsPtr, #SGetRBitMargin] + MOV R6, #&FFFFFFFE + MVN R6, R6, LSL R11 ; RmarginMask + + SUBS R2, R2, #1 + STR R2, [WsPtr, #SGetColWCnt] ; if only one word in window per row + ANDEQ R5, R5, R6 ; then combine L&R masks + MOVEQ R6, R5 + STR R5, [WsPtr, #SGetLBitMargin] + STR R6, [WsPtr, #SGetRBitMargin] + + LDR R5, [WsPtr, #SGetTopMargin] ; paint TopMargin (if any) + CMP R5, #0 + BLNE PaintBlock + +; R0 ,R1 ,R2 ,R3 ,R4 .. R11 +; ScrAdr,MemAdr,ColWCnt,RowCnt,{8 words from screen}, + +10 + LDR R4, [WsPtr, #SGetLWrdMargin] ; paint 1 row of LHmargin (if any) + CMP R4, #0 + BLNE PaintRow ; on exit R6 holds word of BgEcf, if not called + ; R6 is corrupt, but it doesn't matter + LDR R2, [WsPtr, #SGetColWCnt] ; on screen word count ( >0 in words) + LDR R5, [WsPtr, #SGetLBitMargin] + LDR R4, [R0], #4 ; get first on screen word + AND R4, R4, R5 + BIC R6, R6, R5 ; Write BgEcf (or nonsense) to out of window + ORR R4, R4, R6 ; pixels + STR R4, [R1], #4 + SUBS R2, R2, #1 + BLT %FT50 ; if all plotted + + SUBS R2, R2, #8 ; try for 8 words +20 + LDMCSIA R0!, {R4-R11} ; copy 8 words from screen to memory + STMCSIA R1!, {R4-R11} + SUBCSS R2, R2, #8 + BCS %BT20 +30 + ADDS R2, R2, #8 + LDR R6, [WsPtr,#SGetEcfIndx] + ADD R6, WsPtr, R6, LSL #2 + LDR R6, [R6, #BgEcf] ; BgEcf for this scanline + LDR R5, [WsPtr,#SGetRBitMargin] + BIC R6, R6, R5 +40 + LDR R4, [R0], #4 + ANDEQ R4, R4, R5 + ORREQ R4, R4, R6 + STR R4, [R1], #4 + SUBS R2, R2, #1 + BCS %BT40 +50 + LDR R4, [WsPtr, #SGetRWrdMargin] + CMP R4, #0 + BLNE PaintRow + + LDR R2, [WsPtr, #SGetColWCnt] + LDR R4, [WsPtr, #SGetRowOfst] + LDR R5, [WsPtr,#SGetEcfIndx] + ADD R0, R0, R4 ; offset ScrAdr to next row + ADD R5, R5, #1 + AND R5, R5, #7 + STR R5, [WsPtr, #SGetEcfIndx] ; update EcfIndx to next row + SUBS R3, R3, #1 + BGT %BT10 ; do next screen line + + LDR R5, [WsPtr, #SGetBotMargin] ; paint bottom margin (if any) + CMP R5, #0 + BLNE PaintBlock +60 + Pull "R1-R3, PC" + + +; ***************************************************************************** +; +; PaintSprite - Paint the whole of the sprite in background colour +; +; Internal routine, called by GetSprite when all area is outside window +; +; in: R1 -> first byte in sprite +; + +PaintSprite ROUT + LDR R5, [WsPtr, #SGetHeight] + ADD R5, R5, #1 ; R5 = number of rows in sprite + +; and drop thru to ... + +; ***************************************************************************** +; +; PaintBlock - Paint a number of rows of the sprite in background colour +; +; Internal routine, called by GetSprite to do area above and below window +; and dropped thru to by PaintSprite +; +; in: R1 -> start of first row to paint +; R5 = number of rows to do +; +; out: Flags preserved + +PaintBlock ROUT + Push R14 + LDR R4, [WsPtr, #SGetWidth] + ADD R4, R4, #1 +10 + BL PaintRow + LDR R6, [WsPtr, #SGetEcfIndx] + ADD R6, R6, #1 + AND R6, R6, #7 + STR R6, [WsPtr, #SGetEcfIndx] + SUBS R5, R5, #1 + BNE %BT10 + + Pull R14 + MOVS PC, R14 ; we must preserve the flags + +; ***************************************************************************** +; +; PaintRow - Paint part of a row in sprite with background colour +; +; Internal routine, called by GetSprite to do areas left+right of window +; and by PaintBlock +; +; in: R1 -> first word to paint +; R4 = number of words to paint +; +; out: R4 preserved +; + +PaintRow ROUT + Push R4 + LDR R6, [WsPtr, #SGetEcfIndx] + ADD R6, WsPtr, R6, LSL #2 + LDR R6, [R6, #BgEcf] ; BgEcf for this scanline +10 + STR R6, [R1], #4 + SUBS R4, R4, #1 + BNE %BT10 + Pull R4 + MOVS PC, R14 + +; ***************************************************************************** +; +; CreateSprite - Create a sprite with given attributes +; +; External routine +; +; in: R1 -> sprite area +; R2 -> sprite name +; R3 = 0/1 => exclude/include palette data +; R4 = width in pixels +; R5 = height in pixels +; R6 = mode number of sprite +; + +CreateSprite ROUT + Push R14 + KillSpChoosePtr + BL DeleteSpriteByName ; delete any existing sprite + STR R6, [WsPtr, #SGetMode] ; needs setting up before CreateHeader + SUB R6, R4, #1 ; width in pixels-1 + SUB R7, R5, #1 ; height-1 + MOV R4, #0 + MOV R5, #0 + ; R3 ,R4,R5,R6,R7 + BL CreateHeader ; In : Palette,sl,sb,sr,st + ; Out: ImageSize + Pull PC, VS ; if error, then bomb out + + MOV R4, #0 ; clear R3 words at offset 0 in sprite + BL ClearWords ; ie clear image to 0 + + ; Now add the sprite to the sprite area + + LDR R3, [R2, #spNext] ; total size of new sprite + LDMIA R1, {R4-R7} ; saEnd,saNumber,saFirst,saFree + ADD R5, R5, #1 + ADD R7, R7, R3 + STMIA R1, {R4-R7} + + Pull R14 + BICS PC, R14, #V_bit + +; ***************************************************************************** +; +; CreateHeader - Create a header and info for a sprite +; +; Internal routine, called by GetSprite, CreateSprite, ScreenSave +; +; in: R1 -> sprite area +; R2 -> sprite name +; R3 = 0/1 => exclude/include palette data +; R4,R5 = (X,Y) INTERNAL coordinate of bottom left +; R6,R7 = (X,Y) INTERNAL coordinate of top right +; +; out: R1 preserved +; R2 -> new sprite +; R3 = size of image in words +; R4,R5 = (X,Y) INTERNAL coordinate of top left of on screen area +; R0, R6-R11 corrupted +; + +CreateHeader ROUT + Push "R1, R14" + Push R3 + + BL GetName ; name returned in R9-R11 + ADD R8, WsPtr, #SGetName + STMIA R8, {R9-R11} ; save the name away + + BL PreCreateHeader + + Pull "R0, R1, PC", VS + +; now the updating the sprite area bit + + LDR R1, [R13, #1*4] ; reload sprite area ptr off stack + LDR R2, [R1, #saFree] + LDR R5, [R1, #saEnd] + SUB R5, R5, R2 + CMP R5, R4 + BCC %FT10 + + ADD R2, R2, R1 ; address of new sprite + +PostCreateHeader + ADD R5, WsPtr, #SGetName + LDMIA R5, {R5-R11} + +; R4 spNext, R5-R7 spName(0..2), +; R8 spWidth, R9 spHeight, R10 spLBit, R11 spRBit + + STMIA R2, {R4-R11} ; write control block for sprite + LDR R11, [WsPtr, #SGetImage] + STR R11, [R2, #spImage] + STR R11, [R2, #spTrans] ; spImage=spTrans ie no mask + + LDR R11, [WsPtr, #SGetMode] + + [ {FALSE} ; TMD 08-Jun-93: SGetMode sanitation done in PreCreateHeader now +; Previously we simply copied the current SGetMode straight into spmode. +; With the advent of mode descriptors and the new sprite mode word this +; has to get a bit more intelligent. New logic is: +; i) is the value > 256 (unsigned) ? Y - mode descriptor - have to make +; a new sprite mode word, N - proceed to next... +; ii) is this higher than 8bpp ? Y - have to use a new sprite mode word +; N - use the mode number + +; Note: Once all the mode descriptor work is complete the second test +; may be removed, since no 16/32bpp modes will have mode numbers +; associated with them. However, until then it stays. + + ! 0,"vdugrafj: remove marked section when mode descriptors" + ! 0," work, and no 16/32bpp modes have old mode numbers." + + CMP R11, #256 + BCC %FT20 ;branch if under 256 + +30 ; this mode is not available in RISC OS 3, so give it a new format + ; sprite mode word instead + + Push "R0-R3" + + MOV R0,R11 + MOV R1,#VduExt_Log2BPP + SWI XOS_ReadModeVariable + + MOV R11,#1 ;bit 0 is always set + + ADD LR, R2, #1 ;turn it into the sprite type + ORR R11, R11, LR, LSL #27 ;and put it into position + + MOV R1, #VduExt_XEigFactor + SWI XOS_ReadModeVariable + + MOV R4, #180 + MOV LR, R4, LSR R2 ;convert to a dpi (180 >> eig) + ORR R11, R11, LR, LSL #1 ;and put it into position + + MOV R1, #VduExt_YEigFactor + SWI XOS_ReadModeVariable + + MOV LR, R4, LSR R2 ;convert to a dpi (180 >> eig) + ORR R11, R11, LR, LSL #14 ;and put it into position + + Pull "R0-R3" + + B %FT40 + +20 ;************************************************************************** + ;The test and branch below should be removed once mode descriptors are done + ;************************************************************************** + + ; ,---------------- BEGIN REMOVE SECTION ################################## + ; v # + Push "R0-R3" ; # + MOV R0,R11 ; # + MOV R1,#VduExt_Log2BPP ; # + SWI XOS_ReadModeVariable ; # + CMP R2, #4 ; # + Pull "R0-R3" ; # + BCS %BT30 ;over 3 ?, put in a new sprite mode word # + ; ^ # + ; '---------------- END REMOVE SECTION #################################### + + ; it is an old fashioned mode number, so use that to allow RO 3.00/3.10 + ; to understand this sprite +40 + ] + STR R11, [R2, #spMode] + MOVS LR, R11, LSR #27 ; do we have an old or new sprite ? EQ=old + + ADD R4, WsPtr, #SGetTopLeft + LDMIA R4, {R4, R5} ; (R4,R5) = TopLeft of 'on screen' area + Pull R11 ; R11 = 0/1 for (ex/in)clude palette + +;amg 25th May 1994. We now allow palettes on new format sprites in 8bpp and below + + CMP LR,#SpriteType_New16bpp + BCS %FT11 ; check for new 16/32 bpp + + TEQ R11,#0 ; was a palette wanted in the first place? + BLNE WritePaletteToSprite ; do it if so + +; ;only allow palette data to be written if EQ and R11<>0 +; +; BNE %FT11 +; +; TEQ R11, #0 +; BLNE WritePaletteToSprite + +11 + Pull "R1, R14" + BICS PC, R14, #V_bit + +10 + ADRL R0, SpriteErr_NoRoom + [ International + BL TranslateError + ] + STR R0, [WsPtr, #RetnReg0] + Pull "R0, R1, R14" ; junk palflag, sprite area ptr + ORRS PC, R14, #V_bit + +; ***************************************************************************** +; +; SanitizeSGetMode - Convert SGetMode into a new format sprite word if necessary +; +; If SGetMode is either a) a mode selector pointer, or +; b) a mode number which has more than 8bpp +; then SGetMode is replaced by a suitable sprite mode word +; +; amg: 15/10/93: changed to be more keen to generate old format mode numbers. It is +; now also called from createsprite, so it will pass through a new +; sprite mode word unchanged. Mode numbers will be unchanged. Mode +; selectors will be changed to a mode number if one of suitable +; eigs and depth exists --- size of screen is *not* taken into +; account here. + + +; in: WsPtr -> VDU workspace +; +; out: If OK, then +; V=0 +; All registers preserved +; else +; V=1 +; r0 -> error +; RetnReg0 -> error +; endif +; + +SanitizeSGetMode ENTRY "r0-r4,r11" + LDR r11, [WsPtr, #SGetMode] + + CMP r11, #&100 + BCC %FT20 ; [not a mode selector or new format sprite word] + + TST r11, #1 ; is it already a new format sprite word? + EXIT NE +10 + MOV r0, r11 ; r0 -> mode selector + [ ModeSelectors + BL ValidateModeSelector + STRVS r0, [sp] + STRVS r0, [WsPtr, #RetnReg0] + EXIT VS + ] + +15 +; convert to new format sprite word + + MOV r4, r11 ; preserve the mode for later + + MOV r11,#1 ; bit 0 is always set + + MOV r1, #VduExt_XEigFactor + SWI XOS_ReadModeVariable + + MOV lr, #180 + MOV lr, lr, LSR r2 ; cope with 45, 90, 180 dpi + + ORR r11, r11, lr, LSL #1 ; put into xdpi position + + MOV r1, #VduExt_YEigFactor + SWI XOS_ReadModeVariable + + MOV lr, #180 + MOV lr, lr, LSR r2 + ORR r11, r11, lr, LSL #14 ; put into ydpi position + + ;amg: add check for log2bpp=log2bpc + + MOV r0, r4 + MOV r1, #VduExt_Log2BPC + SWI XOS_ReadModeVariable + MOV R3,R2 + + MOV r0, r4 + MOV r1, #VduExt_Log2BPP + SWI XOS_ReadModeVariable + + CMP R3, R2 + BNE %FT20 + + ADD lr, r2, #1 ; turn it into the sprite type + ORR r11, r11, lr, LSL #27 ; and put it into position + + STR r11, [WsPtr, #SGetMode] ; store new value + + ;now check if we can force it back to a mode number + + ;if the bpp is > 8 the answer is no + CMP r2, #4 + EXIT CS + + BIC r0, r11, #&F8000000 ; take off the type information + ADR r1, substitute_list + ADD r2, r1, #12 ; end of list +27 + LDR r3, [r1], #4 + TEQ r3, r0 + BEQ %FT28 + TEQ r1, r2 + EXIT EQ ; can't do anything with it + BNE %BT27 +28 + ADD r1, r1, #8 ; point at modes word, allowing for post inc + ADD r1, r1, r11, LSR #27 ; add in the sprite's type + SUB r1, r1, #1 ; and reduce it by one + LDRB r1, [r1] ; fetch the right mode number + + ;if we got 255, we can't save the day + CMP r1,#255 + STRNE r1, [WsPtr, #SGetMode] ; and store it + + EXIT + +substitute_list + DCD &001680B5 ;90 X 90 DPI, X/Y EIG 1 1 + DCD &000B40B5 ;90 X 45 DPI, X/Y EIG 1 2 + DCD &000B405B ;45 X 45 DPI, X/Y EIG 2 2 + + ;amg: used to use mode 4 for 2 colour eig 2 x 2 - now doesn't because of + ;confusion about double pixels + + DCD &1C1B1A19 ;modes 25, 26, 27, 28 for 90 x 90 + DCD &0F0C0800 ;modes 0, 8, 12, 15 for 90 x 45 + DCD &0D0901FF ;modes n/a, 1, 9, 13 for 45 x 45 +20 + MOV r0, r11 ; check if bpp for mode is > 8 + MOV r1, #VduExt_Log2BPP + SWI XOS_ReadModeVariable + CMP r2, #4 + BCS %BT15 ; if so then convert to new format sprite as well + EXIT + +; ***************************************************************************** + +PreCreateHeader ROUT + Push R14 + BL SanitizeSGetMode ; convert SGetMode to new format sprite if nec. + Pull PC, VS ; duff mode selector + + ;amg 25th May 1994 + ;We now allow palettes on new format sprites of 8bpp and below + +; ;force to no palette space if a new format sprite +; LDR LR, [WsPtr, #SGetMode] ; get the mode +; MOVS LR, LR, LSR #27 ; set NE if new +; MOVNE R3, #0 ; turn off palette + + LDR LR, [WsPtr, #SGetMode] ; get the sprite mode word + MOV LR, LR, LSR #27 ; isolate the sprite type + CMP LR, #SpriteType_New16bpp ; check for 16/32bpp + MOVCS R3, #0 ; turn off the palette request + + TEQ R3, #0 ; convert R3 into mask to (ex/in)clude + MOVNE R3, #&FF ; space for palette data + +; amg need more palette space in case it's going to be a full palette + ORRNE R3, R3, #&300 + + Push "R6, R7" ; preserve R6,R7 over the call + ADD R2, WsPtr, #SGetNext + BL SetupSprModeData + +; R6 ,R7 ,R8 ,R9 ,R10 ,R11 +; Out: RdNCol,WrNCol,BytePC,XShft,NPix,Log2BPC + +; amg 26th October 1993 - kill another bit of Arthur compatibility in favour +; of full palette 8bpp sprites +; AND R6, R6, #63 ; make 64 palette entries like MOS 1.2 + + LDR R7,[WsPtr,#ModeFlags] + TST R7, #Flag_FullPalette + ANDEQ R6, R6, #63 + + ADD R6, R6, #1 ; number of palette entries in this mode + AND R3, R3, R6 ; if (palette not wanted) OR (256 colour mode) + ; then R3=0 else R3=number of palette entries + ; N.B. in 256 colour modes we end up ignoring + ; the palette + Pull "R6,R7" + Pull PC, VS ; error, not a graphics mode + + MOV R3, R3, LSL #3 ; two words per palette entry + ADD R3, R3, #SpriteCBsize + STR R3, [WsPtr, #SGetImage] ; R0-R3 now free for use + ; R4 ,R5, R6 ,R7 + ; sL ,sB, sR ,sT + SUB R0, R7, R5 ; height-1 + STR R0, [WsPtr, #SGetHeight] + ADD R0, R0, #1 ; actual height in rows + + LDR R1, [WsPtr, #GWTRow] ; if SpriteTopRow > GWTopRow + SUBS R2, R7, R1 + MOVGT R7, R1 ; then clip for ScreenAddr's benefit + MOVLE R2, #0 + Least R2, R2, R0 + STR R2, [WsPtr, #SGetTopMargin] ; number of blank rows at top + + LDR R1, [WsPtr, #GWBRow] + SUBS R2, R1, R5 + MOVLT R2, #0 + Least R2, R2, R0 + STR R2, [WsPtr, #SGetBotMargin] ; number of blank rows at bottom + + WordOffset R0,R4, R9,R10,R11 ; offset to sL + WordOffset R1,R6, R9,R10,R11 ; to sR + SUB R2, R1, R0 ; width-1 + STR R2, [WsPtr, #SGetWidth] + ADD R2, R2, #1 ; actual width in words + + BitLOffset R3,R4, R9,R10,R11 ; LBit + STR R3, [WsPtr, #SGetLBit] + BitROffset R3,R6, R9,R10,R11 ; RBit + STR R3, [WsPtr, #SGetRBit] + + LDR R8, [WsPtr, #GWLCol] + Greatest R4,R4,R8 + WordOffset R3,R4, R9,R10,R11 ; offset to clipL + SUB R3, R3, R0 + Least R3,R3,R2 + STR R3, [WsPtr, #SGetLWrdMargin] ; no. of blank words at left + BitLOffset R3,R4, R9,R10,R11 + STR R3, [WsPtr, #SGetLBitMargin] ; no. of blank words at right + + LDR R8, [WsPtr, #GWRCol] + Least R6, R6, R8 + WordOffset R3,R6, R9,R10,R11 ; offset to clipR + SUB R3, R1, R3 + Least R3, R3, R2 + STR R3, [WsPtr, #SGetRWrdMargin] + BitROffset R3,R6, R9,R10,R11 + STR R3, [WsPtr, #SGetRBitMargin] + + ADD R0, WsPtr, #SGetTopLeft + STMIA R0, {R4, R7} ; store top & left of 'on screen' area + LDR R0, [WsPtr, #SGetWidth] + LDR R1, [WsPtr, #SGetHeight] + ADD R0, R0, #1 ; width in words + ADD R1, R1, #1 ; height in words + + MUL R3, R1, R0 ; image size in words + LDR R4, [WsPtr, #SGetImage] + ADD R4, R4, R3, LSL #2 ; total size in bytes + + Pull R14 + BICS PC, R14, #V_bit + +; ***************************************************************************** +; +; Decide mask size +; +; Internal routine called from CreateMask +; +; in: R1 -> sprite area +; R2 -> sprite +; R3 = size of image data (bytes) +; +; out: R3 = size of mask data (words) + +DecideMaskSize ROUT + Push "R0-R2,R4-R5,R14" + + LDR LR, [R2, #spMode] ; get the sprite mode + MOVS LR, LR, LSR #27 ; isolate the type + + MOVEQ R3,R3,LSR #2 ; if T=0 then return the same size as + Pull "R0-R2,R4-R5,R15",EQ ; the image (but returns in words not + ; bytes) + + ADRL R5, NSM_bpptable-4 + LDR R4, [R5, LR, LSL #2] ; get the log2bpp value + + LDR R5, [R2, #spWidth] ; number of words-1 per row + + LDR LR, [R2, #spRBit] ; fetch the last bit used + ADD LR, LR, #1 ; turn into a number of bits rather than bit number + MOV LR, LR, LSR R4 ; turn into a number of pixels + + RSB R4, R4, #5 + MOV R5, R5, LSL R4 ; number of pixels on the row for the full words + + ADD R5, R5, LR + + ANDS LR, R5, #&1F ; is it a whole number of words + MOVNE LR, #1 ; if not start at 1 not 0 + ADD LR, LR, R5, LSR #5 ; add the number of whole words + + ; now have number of words per mask row + + LDR R5, [R2, #spHeight] ; number of rows (minus 1) + ADD R5, R5, #1 + MUL R3, LR, R5 ; number of words for the mask + + Pull "R0-R2,R4-R5,R15" + +; ***************************************************************************** +; +; CreateMask - Add mask to sprite or set existing mask to 'solid' +; +; External routine +; +; in: R1 -> sprite area +; R2 -> sprite +; + +CreateMask ROUT + Push R14 + KillSpChoosePtr + LDR R4, [R2, #spNext] + LDR R5, [R2, #spImage] ; NB Image=Trans if NO mask + LDR R6, [R2, #spTrans] + SUB R3, R4, R6 + + BL DecideMaskSize ; returns R3=size of mask (words) + + TEQ R5, R6 + BNE %FT10 ; mask exists + + MOV R6, R4 + BL ExtendSprite + ADRVSL R0, SpriteErr_NotEnoughRoom ; only error is NoRoomToInsert + [ International + BLVS TranslateError + ] + STRVS R0, [WsPtr, #RetnReg0] ; correct this to 'Not enough room' + Pull PC, VS + + STR R6, [R2, #spTrans] ; new spTrans := old spNext +10 ; R3 mask size (words), R6 spTrans + ADD R6, R6, R2 + MOV R4, #&FFFFFFFF +20 + STR R4, [R6], #4 + SUBS R3, R3, #1 + BNE %BT20 + + Pull R14 + BICS PC, R14, #V_bit + +; ***************************************************************************** +; +; RemoveMask - Remove mask from sprite +; +; External routine +; +; in: R1 -> sprite area +; R2 -> sprite +; + +RemoveMask ROUT + Push R14 + KillSpChoosePtr + LDR R4, [R2, #spNext] + LDR R5, [R2, #spImage] ; NB spTrans = spImage, if NO mask + LDR R6, [R2, #spTrans] + TEQ R5, R6 + BEQ %FT10 ; no mask so ignore + + SUB R3, R4, R6 + + BL DecideMaskSize ; returns R3=size in words + + SUB R4, R6, R5 + BL RemoveWords + LDR R5, [R2, #spImage] ; spTrans := spImage, ie NO mask + STR R5, [R2, #spTrans] +10 + Pull R14 + BICS PC, R14, #V_bit + +; ***************************************************************************** +; +; WritePaletteToSprite - Write palette information into sprite CB +; +; Internal routine, called by CreateHeader +; +; in: R2 -> sprite +; +; out: All registers preserved +; + +WritePaletteToSprite ROUT + Push "R0-R4, R14" + LDR R0, [WsPtr, #SprReadNColour] ; highest palette entry + +; amg 26th October 1993 - this bit of Arthur compatibility bites the +; dust to make screensaving full palette sprites work properly +; AND R0, R0, #63 ; make 63 if 255 like MOS 1.20 + LDR R4, [WsPtr,#ModeFlags] + TST R4, #Flag_FullPalette + ANDEQ R0, R0, #63 + + ADD R4, R2, R0, LSL #3 + ADD R4, R4, #spPalette ; ptr to last pal pos in spPalette +10 + MOV R1, #16 ; read 'normal' colour + SWI XOS_ReadPalette + STMIA R4, {R2,R3} + SUB R4, R4, #8 + SUBS R0, R0, #1 + BCS %BT10 + Pull "R0-R4,PC" + +; ***************************************************************************** +; +; WritePaletteFromSprite - Write palette from information in sprite CB +; +; Internal routine, called by ScreenLoad +; +; in: R2 -> sprite +; +; out: All registers preserved +; + +WritePaletteFromSprite ROUT + Push "R0-R6, R14" + LDR R0, [WsPtr, #ModeNo] + LDR R1, [R2, #spMode] + + [ {TRUE} :LAND: ModeSelectors + + ;logic for this routine + ; + ;[WsPtr, #ModeNo] is the current mode/ptr to mode selector + ;R2 points at sprite data + ;[WsPtr, #SloadModeSel] is 36 bytes for building a mode selector for the sprite + ; + ;sprite mode < 256 ? + ;yes: equal to current mode ? + ; yes: already in correct mode. done. + ; no: change to mode sprite wants, done. + ;no: build a mode selector for the sprite + ; check pixel depth, xres, yres, xdpi and ydpi + ; all identical ? + ; yes: already in suitable mode. done. + ; no: change mode. done. + ;if we do a mode change, remember to re-remove cursors + + ;amg 15 Oct '93 Screensave is about to be changed to use a representative + ;mode number of the eigs and depth (only), so screenload no longer believes + ;the screen mode number in the file. + + ;amg 21 Dec '93 Slight modification - if the screen mode change failed, and + ;we have an old screen mode number, use that as a last gasp + +; CMP R1, #256 +; BCS %FT30 ;branch if a new format sprite mode word + +; CMP R1, R0 ;are we in the right (old style) mode ? +; BEQ %FT10 + +; MOV R0,#ScreenModeReason_SelectMode +; SWI XOS_ScreenMode +; STRVS R0, [WsPtr, #RetnReg0] ;exit on error +; Pull "R0-R6,PC", VS +; B %FT40 ;otherwise get on with it + +30 ; new format sprite mode word + ; build the mode selector at SLoadModeSel + + MOV R5, R1 ;keep the mode number/sprite mode word safe + + ;do the absolutes first + MOV R3, #-1 + STR R3, [WsPtr, #SloadModeSel+ModeSelector_FrameRate] + STR R3, [WsPtr, #SloadModeSel+ModeSelector_ModeVars+16] ;list terminator after two pairs + STR R3, [WsPtr, #SloadModeSel+ModeSelector_ModeVars+32] ;list terminator after four pairs + MOV R3, #128 + STR R3, [WsPtr, #SloadModeSel+ModeSelector_ModeVars+20] ;modeflags value, if needed + MOV R3, #VduExt_NColour + STR R3, [WsPtr, #SloadModeSel+ModeSelector_ModeVars+24] + MOV R3, #255 + STR R3, [WsPtr, #SloadModeSel+ModeSelector_ModeVars+28] + + + MOV R3, #1 + STR R3, [WsPtr, #SloadModeSel+ModeSelector_Flags] + MOV R3, #VduExt_XEigFactor + STR R3, [WsPtr, #SloadModeSel+ModeSelector_ModeVars] ; modevar 1 = xeig + MOV R3, #VduExt_YEigFactor + STR R3, [WsPtr, #SloadModeSel+ModeSelector_ModeVars+8] ; modevar 2 = Yeig + + ;now the things from the sprite +; MOV R3, R1, LSR #27 ;sprite type +; ADRL R4, NSM_bpptable-4 ;readmodevar's table +; LDR R3, [R4, R3, LSL #2] ;word index +; STR R3, [WsPtr, #SloadModeSel+ModeSelector_PixelDepth] + + ;change to calling read mode variable to cope with mode number or sprite mode word + MOV R4, R2 ;save the sprite pointer + MOV R0, R5 ;sprite mode word/mode number + MOV R1, #VduExt_Log2BPP + SWI XOS_ReadModeVariable + STR R2, [WsPtr, #SloadModeSel+ModeSelector_PixelDepth] + MOV R3, R2 + + ;if log2bpp=3, and size of palette data indicates full palette, we need to force + ;a suitable mode + CMP R3, #3 + BNE %FT40 + + ADD LR, R4, #spImage ;point to image/mask start + LDMIA LR,{R2,LR} ;fetch them + CMP R2,LR ;which is bigger ? + MOVGT R2,LR ;use the least + SUB R2,R2,#spPalette ;and the palette size is... + + CMP R2,#&800 ;full entry 256 colour + + ;change the mode selector so it includes a modeflags word + ;(following two words already set up) + + MOVEQ R2, #0 + ;amg 28/4/94 bugfix - following inst wasn't conditional + STREQ R2, [WsPtr, #SloadModeSel+ModeSelector_ModeVars+16] + +40 + MOV R2, R4 ;restore the sprite pointer + + LDR R4, [R2, #spWidth] ;number of words + MOV R4, R4, LSL #5 ;convert to a number of bits + LDR LR, [R2, #spRBit] ;last bit used + ADD LR, LR, #1 ;convert to number of bits + ADD R4, R4, LR ;combine + MOV R4, R4, LSR R3 ;and convert to pixels + STR R4, [WsPtr, #SloadModeSel+ModeSelector_XRes] + + LDR R3, [R2, #spHeight] + ADD R3, R3, #1 + STR R3, [WsPtr, #SloadModeSel+ModeSelector_YRes] + MOV R6, R2 ;save the sprite pointer for later + + ;that leaves the x and y eig factors, which are derived + ;from the dpi + + MOV R0, R5 ;R0 = sprite mode word + MOV R1, #VduExt_XEigFactor + SWI XOS_ReadModeVariable + STRCC R2, [WsPtr, #SloadModeSel+ModeSelector_ModeVars+4] + MOVCC R1, #VduExt_YEigFactor + SWICC XOS_ReadModeVariable + STRCC R2, [WsPtr, #SloadModeSel+ModeSelector_ModeVars+12] + BCS %FT90 ;we canna take it captain.... + + ;do the comparison which involve the mode selectors first + + ;depth + LDR LR, [WsPtr, #ModeNo] + + LDR R3, [LR, #ModeSelector_PixelDepth] + LDR R4, [WsPtr, #SloadModeSel+ModeSelector_PixelDepth] + TEQ R3, R4 + BNE %FT80 ;need to change mode to new mode selr + + LDR R3, [LR, #ModeSelector_XRes] + LDR R4, [WsPtr, #SloadModeSel+ModeSelector_XRes] + TEQ R3, R4 + BNE %FT80 ;need to change mode to new mode selr + + LDR R3, [LR, #ModeSelector_YRes] + LDR R4, [WsPtr, #SloadModeSel+ModeSelector_YRes] + TEQ R3, R4 + BNE %FT80 ;need to change mode to new mode selr + + ;now the eigs + LDR R3, [WsPtr, #XEigFactor] + LDR R4, [WsPtr, #SloadModeSel+ModeSelector_Flags+4] + TEQ R3, R4 + BNE %FT80 ;need to change mode to new mode selr + + LDR R3, [WsPtr, #YEigFactor] + LDR R4, [WsPtr, #SloadModeSel+ModeSelector_Flags+12] + TEQ R3, R4 + + BEQ %FT10 ;this mode is suitable + +80 + MOV R0,#ScreenModeReason_SelectMode + ADD R1,WsPtr,#SloadModeSel + SWI XOS_ScreenMode + + + [ {TRUE} + ;ensure we preserve the error pointer in situations where we can't try to + ;fall back to the mode number in the sprite header + + ;if it errored try again if there's a mode number available + BVC %FT40 + + LDR R1, [R6, #spMode] + BICS R14, R1, #&FF ; EQ if sprite mode is a number (< 256), (V still set afterwards) + MOVEQ R0, #ScreenModeReason_SelectMode + SWIEQ XOS_ScreenMode ; if called, will set V appropriately + | + ;if it errored try again if there's a mode number available + BVC %FT40 + + MOV R0, #ScreenModeReason_SelectMode + LDR R1, [R6, #spMode] + BICS R14, R1, #&FF ; EQ if sprite mode is a number (< 256), (V still set afterwards) + SWIEQ XOS_ScreenMode ; if called, will set V appropriately + ] + + STRVS R0, [WsPtr, #RetnReg0] ;exit on error + Pull "R0-R6,PC", VS + B %FT40 ;otherwise get on with it +90 + ADRL R0,SpriteErr_InvalidSpriteMode + [ International + BL TranslateError + ] + STR R0, [WsPtr, #RetnReg0] + SETV + Pull "R0-R6,PC" + | + + ;as originally done this code tended to compare mode specifiers against new + ;sprite mode words, and worse still tried to select a mode from a new sprite + ;mode word. the rewrite above takes a more logical approach + + CMP R0, R1 ; if already in correct mode + BEQ %FT10 ; then skip + + [ ModeSelectors + MOV r0, #ScreenModeReason_SelectMode + SWI XOS_ScreenMode + | + MOV R0, #22 + SWI XOS_WriteC + MOVVC R0, R1 + SWIVC XOS_WriteC + ] + STRVS R0, [WsPtr, #RetnReg0] + Pull "R0-R6,PC", VS + ] +40 + SWI XOS_RemoveCursors ; remove cursors again +10 + MOV R2, R6 + LDR R3, [R2, #spImage] + CMP R3, #spPalette ; will clear V if EQ + Pull "R0-R6, PC", EQ ; no palette data + + LDR R4, [WsPtr, #NColour] + + ADD R3, R2, #spPalette + ADD R3, R3, R4, LSL #3 +20 + LDMIA R3, {R1,R2} + MOV R0, R4 + + BL SendPalettePair + Pull "R0-R6, PC", VS + + SUB R3, R3, #8 + SUBS R4, R4, #1 ; (V will be cleared by this) + BCS %BT20 + Pull "R0-R6, PC" + +; ***************************************************************************** +; +; SendPalettePair - Program palette with flash pair +; +; Internal routine, called by WritePaletteFromSprite +; +; in: R0 = logical colour +; R1 = first flash colour +; R2 = second flash colour +; +; out: R1 corrupted +; + +SendPalettePair ROUT + Push "R0-R3, R14" + TEQ R1, R2 ; are colours the same ? + BNE %FT10 ; if not then do in two halves + + MOV R3, #16 + BL SendPaletteEntry ; then send with 16 + Pull "R0-R3, PC" +10 + MOV R3, #17 ; else send 1st flash with 17 + BL SendPaletteEntry + MOVVC R1, R2 + MOVVC R3, #18 ; then 2nd flash with 18 + BLVC SendPaletteEntry + Pull "R0-R3, PC" + +; ***************************************************************************** +; +; SendPaletteEntry - Program one palette entry +; +; Internal routine, called by SendPalettePair +; +; in: R0 = logical colour +; R1 = physical colour BGRx +; R3 = PP field to use +; +; out: All registers preserved +; + +SendPaletteEntry ROUT + Push "R0,R1, R14" + BIC R1, R1, #&7F ; clear all bits except sup. bit + ORR R1, R1, R3 ; or in new bits + MOV R0, R0, LSL #24 ; move log. col. up to top 8 bits + Push "R0, R1" ; create an OSWORD block at R13+3 + + MOV R0, #12 + ADD R1, R13, #3 ; R1 -> block + SWI XOS_Word + STRVS R0, [WsPtr, #RetnReg0] + ADD R13, R13, #8 + Pull "R0,R1, PC" + + END diff --git a/s/vdu/vdugrafk b/s/vdu/vdugrafk new file mode 100644 index 0000000000000000000000000000000000000000..e6079e3269e85a2c9fdb8085ebb3e5a789105969 --- /dev/null +++ b/s/vdu/vdugrafk @@ -0,0 +1,449 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.VduGrafK +; +; ARTHUR OPERATING SYSTEM - Vdu Drivers +; ======================= +; +; Vdu driver code - Sprite stuff +; +; Author R C Manby +; Date 5.3.87 +; + +; ***************************************************************************** +; +; ScreenSave - Save screen within graphics window as a sprite file +; +; External routine +; +; in: R2 -> file name +; R3 = 0/1 => exclude/include palette data +; + +ScreenSave ROUT + Push R14 + SWI XOS_RemoveCursors + + [ {TRUE} + GraphicsMode R0 + BNE %FT20 + | + LDR R0, [WsPtr, #NPix] + CMP R0, #0 + BEQ %FT20 ; quit with error if not graphics mode + ] + + ; build a temporary sprite area header + ADD R1, WsPtr, #ScrSavAreaCB + MOV R4, #&7FFFFFFF ; size, very large + MOV R5, #1 ; one sprite + LDR R6, =(ScrSavSpriteCB-ScrSavAreaCB) ;saFirst + MOV R7, R6 ; saFree=saFirst + STMIA R1, {R4-R7} + + ADD R11, WsPtr, #GWLCol ; R4 ,R5 ,R6 ,R7 + LDMIA R11, {R4,R5,R6,R7} ; wL ,wB ,wR ,wT + + LDR R0, [WsPtr, #ModeNo] + STR R0, [WsPtr, #SGetMode] ; needs setting up before CreateHeader + + Push R2 ; preserve file name pointer + + ; if it is a mode selector mode with >256 colours force it to have no + ; palette. CreateHeader will deal with <=256. + LDR R2, [WsPtr, #Log2BPP] + CMP R2, #4 + MOVCS R3, #0 + + ; amg 25th May 1994. The above is no longer completely true. We still + ; don't allow palettes on 16/32bpp. Below that (whether new or old + ; format of sprite) palettes are now allowed. No actual code change + ; here, but CreateHeader has been changed. + + ADR R2, ScrSavSpriteName + ; R3 ,R4,R5,R6,R7 + BL CreateHeader ; In : Palette,sl,sb,sr,st + ADDVS sp, sp, #4 ; (if error, junk stacked filename ptr and exit) + BVS %FT35 + ; Out: ImageSize + ; now add the sprite to the sprite area + LDR R3, [R2, #spNext] ; total size of new sprite + LDMIA R1, {R4,R5,R6,R7} ; saEnd,saNumber,saFirst,saFree + ADD R7, R7, R3 ; new saFree + MOV R4, R7 + STMIA R1, {R4,R5,R6,R7} + +; Create file to prevent "Can't extend" + + [ AssemblingArthur :LOR: Module + MOV R0, #OSFile_CreateStamp + LDR R1, [R13, #0] ; R1 -> filename + LDR R2, =&FF9 ; Type=SpriteFile + MOV R3, #0 ; Junk + MOV R4, #0 + SUB R5, R7, #4 ; File size (ie exclude saEnd) + SWI XOS_File + | + CLRV + ] + Pull R1 + BVS %FT30 + +; OpenUp file and save the Sprite area and sprite headers + + [ AssemblingArthur :LOR: Module + MOV R0, #open_update :OR: open_mustopen :OR: open_nodir + | + MOV R0, #open_write + ] + SWI XOS_Find + BVS %FT30 + + MOV R1, R0 + MOV R0, #2 ; write bytes to file + + LDR R2, =(ScrSavAreaCB+saNumber) + ADD R2, R2, WsPtr + LDR R3, =(ScrSavSpriteCB+spImage) + LDR R3, [WsPtr, R3] + ADD R3, R3, #(SpriteAreaCBsize-saNumber) + + MOV R4, #0 + SWI XOS_GBPB + BVS %FT40 ; FileSwitchGotYa ! + + Push R1 + LDR R0, [WsPtr, #GWLCol] + LDR R1, [WsPtr, #GWTRow] + BL ScreenAddr ; R2 = ScrAdr of TopL of area + Pull R1 + + LDR R5, [WsPtr, #SGetWidth] + ADD R5, R5, #1 + MOV R5, R5, LSL #2 ; width (bytes) + LDR R6, [WsPtr, #SGetHeight] ; height-1 + + LDR R7, [WsPtr, #LineLength] + SUBS R7, R7, R5 ; zero then can do as one lump + MLAEQ R5, R6, R5, R5 ; R5 = R5*(R6+1) + MOVEQ R6, #0 ; only one chunk to do + +; +; R0 ,R1 ,R2 ,R3 ,R4 ,R5 ,R6 ,R7 +; ,Handle,ScrAdr,Size , ,Width,RowCnt,RowOfSt + +10 + MOV R0, #2 + MOV R3, R5 + SWI XOS_GBPB + BVS %FT40 ; something went wrong + + ADD R2, R2, R7 ; step to next screen line + SUBS R6, R6, #1 + BGE %BT10 + + MOV R0, #0 ; close file + SWI XOS_Find + BVS %FT30 + SWI XOS_RestoreCursors + Pull R14 + BICS PC, R14, #V_bit ; no error, return VC + +20 + ADRL R0, SpriteErr_NotGraphics + [ International + BL TranslateError + | + SETV + ] + B %FT30 + +40 ; return point after an error + STR R0, [WsPtr, #RetnReg0] ; R0 ptr to message, R1 file handle + MOV R0, #0 ; close file + SWI XOS_Find +30 ; return point after an error + STRVS R0, [WsPtr, #RetnReg0] ; R0 ptr to message +35 + SWI XOS_RestoreCursors + Pull R14 + ORRS PC, R14, #V_bit + +ScrSavSpriteName + = "screendump", 0 + ALIGN + + LTORG + +; ***************************************************************************** +; +; ScreenLoad - Plot sprite file directly into graphics window +; +; External routine +; +; in: R2 -> file name +; + +ScreenLoad ROUT + Push R14 + SWI XOS_RemoveCursors + + MOV R0, #open_read+open_mustopen+open_nodir + MOV R1, R2 + SWI XOS_Find + BVS %FT80 + + STR R0, [WsPtr, #ScrLoaHandle] + MOV R1, R0 + MOV R0, #4 ; read areaCB from file + ADD R2, WsPtr, #ScrLoaAreaCB+saNumber + MOV R3, #(SpriteAreaCBsize-saNumber) + MOV R4, #0 + SWI XOS_GBPB + BVS %FT70 ; FileSwitchGotYa ! + + MOV R0, #3 ; read spriteCB from file + ADD R2, WsPtr, #ScrLoaSpriteCB + MOV R3, #SpriteCBsize + ADD R3, R3, #MaxSpritePaletteSize + LDR R4, [WsPtr, #(ScrLoaAreaCB+saFirst)] + SUB R4, R4, #4 + SWI XOS_GBPB + BVS %FT70 + + ADD R2, WsPtr, #ScrLoaSpriteCB + BL WritePaletteFromSprite ; mode change (if needed) + ;branch to 75 rather than 70 because RetnRegR0 is already set up + BVS %FT75 ; and palette setting + + [ {TRUE} + GraphicsMode R0 + BNE %FT60 + | + LDR R0, [WsPtr, #NPix] + CMP R0, #0 + BEQ %FT60 ; quit with error if not graphics mode + ] + +; now check for being able to do it all at once + + ADD R0, WsPtr, #GWLCol ; R3=GWLCol; R4=GWBRow + LDMIA R0, {R3-R6} ; R5=GWRCol; R6=GWTRow + + ADD R0, WsPtr, #ScrLoaSpriteCB + ADD R0, R0, #spWidth ; R7=width-1; R8=height-1 + LDMIA R0, {R7-R10} ; R9=LBit; R10=RBit + + SUB R5, R5, R3 ; R5 = window width + LDR R0, [WsPtr, #XWindLimit] + TEQ R0, R5 ; if window width=full screen + TEQEQ R9, #0 ; and LBit=0 + TEQEQ R10, #31 ; and RBit=31 + BNE %FT05 + + ADD R5, R5, #1 ; R5 = screen width in pixels + ADD R7, R7, #1 ; R7 = sprite width in words + LDR R0, [WsPtr, #NPix] + MLA R0, R7, R0, R7 ; R0 = width*(npix+1) + TEQ R0, R5 ; and spritewidth=full screen + BNE %FT05 + +; we know we can do it all in one chunk +; work out screen address and sprite offset + + LDR R1, [WsPtr, #CursorFlags] ; if computing clip box + TST R1, #ClipBoxEnableBit + Push "R0-R4", NE + BLNE SetClipBoxToFullScreen ; then set to full screen + Pull "R0-R4", NE ; above routine preserves PSR + + MOV R7, R7, LSL #2 ; R7 = line width in bytes + ADD R1, R8, R4 ; R1 = height-1 + GWBRow = YT + SUBS R9, R1, R6 ; if YT > GWTRow then + ; start at row (YT-GWTRow) + MOVHI R1, R6 ; and YT=GWTRow, else + MOVLS R9, #0 ; start at row 0 (and YT=YT) + + LDR R0, [WsPtr, #ScrLoaAreaCB+saFirst] + ADD R2, WsPtr, #ScrLoaSpriteCB + LDR R2, [R2, #spImage] + ADD R0, R0, R2 + SUB R0, R0, #4 ; R0=offset into file of image + MLA R4, R7, R9, R0 ; add on vertical wastage*width + + SUB R9, R8, R9 ; R9 = height-1-wastage + MLA R9, R7, R9, R7 ; number of bytes to transfer + + MOV R0, #0 + BL ScreenAddr ; R2 := screen address + MOV R3, R9 + + LDR R1, [WsPtr, #ScrLoaHandle] + MOV R0, #3 ; read from this position + SWI XOS_GBPB + BVS %FT70 ; if error + B %FT52 ; no error + +; can't do it all at once; R3 = GWLCol, R4 = GWBRow + +05 + ADD R2, WsPtr, #ScrLoaSpriteCB ; point at the spriteCB + MOV R5, #0 + BL GenSpritePlotParmBlk ; "plotting" at (GWLCol,GWBRow) + BVS %FT55 ; off screen (not an error) + + ADD R2, WsPtr, #ScrLoaSpriteCB + LDR R4, [WsPtr, #SPltMemAdr] ; convert MemAdr into + LDR R5, [WsPtr, #ScrLoaAreaCB+saFirst] + SUB R4, R4, #4 + SUB R4, R4, R2 + ADD R4, R4, R5 + STR R4, [WsPtr, #ScrLoaFilPtr] ; file ptr + + LDR R4, [R2, #spWidth] ; convert spWidth into + ADD R4, R4, #1 + MOV R4, R4, LSL #2 + STR R4, [WsPtr, #ScrLoaFilOfst] ; file ptr offset + + LDR R4, [WsPtr, #SPltColCnt] + ADD R4, R4, #2 + MOV R4, R4, LSL #2 + STR R4, [WsPtr, #ScrLoaBytes] + + ADD R4, WsPtr, #ScrLoaBuffer + STR R4, [WsPtr, #SPltMemAdr] + STR R4, [WsPtr, #ScrLoaBufAdr] + +10 ; read row from file + ADD R1, WsPtr, #ScrLoaHandle + LDMIA R1, {R1,R2,R3,R4} ; Handle,BufAdr,Bytes,FilPtr + MOV R0, #3 + SWI XOS_GBPB + BVS %FT70 + + ADD R0, WsPtr, #SPltScrAdr + LDMIA R0, {R0-R1,R5-R7} ; R0 ,R1 , R5 ,R6 ,R7 + ; ScrAdr,ColCnt, BufAdr,ShftR,ShftL + + LDMIA R5, {R2,R3} ; plot the first (leftmost) word + ADD R5, R5, #4 + + ShiftR R2,R3, R6,R7 ; shift R3,R2 right R6 places + ; we only need result word R2 + + LDR R3, [WsPtr, #SPltLMask] ; on leftmost word, mask down + AND R2, R2, R3 ; to just the required pixels + + LDR R4, [R0] ; plot 1 word + BIC R4, R4, R3 + ORR R4, R4, R2 + STR R4, [R0], #4 + + SUBS R1, R1, #1 + BLT %FT50 ; if all plotted, try next scanline + ; else try for blocks of 4 + SUBS R1, R1, #4 + BLT %FT30 + +20 + ;R0 ,R1 ,R5 ,R6 ,R7 + ;ScrAdr,ColCnt, ,BufAdr,ShftR,ShftL + + LDMIA R5, {R2,R3,R8-R10} ; 5 words needed, gives 4 after shift + ADD R5, R5, #16 ; advance source ptr 4 words + + ShiftR R2,R3, R6,R7 ; shift R4-R0 right R6 bits + ShiftR R3,R8, R6,R7 ; we only want result words R3-R0 + ShiftR R8,R9, R6,R7 + ShiftR R9,R10,R6,R7 + + STMIA R0!, {R2,R3,R8-R9} ; write 4 words back to screen + SUBS R1, R1, #4 + BGE %BT20 + +30 ; try 1 word at a time + ADDS R1, R1, #4 + +;R0 ,R1 , R5 ,R6 ,R7 +;ScrAdr,ColCnt, BufAdr,ShftR,ShftL +; +; If EQ this is rightmost word + + BEQ %FT45 +40 + LDMIA R5, {R2,R3} + ADD R5, R5, #4 + + ShiftR R2,R3, R6,R7 ; shift R3,R2 right R6 places + ; we only need result word R2 + STR R2, [R0], #4 + SUBS R1, R1, #1 + BGT %BT40 + +45 + LDMIA R5, {R2,R3} + ADD R5, R5, #4 + + ShiftR R2,R3, R6,R7 ; shift R3,R2 right R6 places + ; we only need result word R2 + + LDR R3, [WsPtr, #SPltRMask] ; rightmost word, so mask down to + AND R2, R2, R3 ; just the required pixels + + LDR R4, [R0] + BIC R4, R4, R3 + ORR R4, R4, R2 + STR R4, [R0], #4 + +50 ; now try the next scanline + ADD R11, WsPtr, #SPltWidth + LDMIA R11, {R1,R2,R3,R4} ; Width,Height,ScrOff,MemOff + ADD R5, R0, R3 + SUBS R2, R2, #1 + STMIA R11, {R1,R2,R3,R4,R5} ; Width,Height,ScrOff,MemOff,ScrAdr + + ADD R11, WsPtr, #ScrLoaHandle ; R1 ,R2 ,R3 ,R4 ,R5 + LDMIA R11, {R1,R2,R3,R4,R5} ; Handle,BufAdr,Bytes,FilPtr,FilOfst + ADD R4, R4, R5 + STR R4, [WsPtr, #ScrLoaFilPtr] + BGE %BT10 ; plot next scanline +52 + MOV R0, #0 ; close file + SWI XOS_Find + BVS %FT80 +55 + SWI XOS_RestoreCursors + Pull R14 + BICS PC, R14, #V_bit + +60 + ADRL R0,SpriteErr_NotGraphics + [ International + BL TranslateError + ] +70 ; return point after an error + STR R0, [WsPtr, #RetnReg0] ; R0 ptr to message, R1 file handle +75 + MOV R0, #0 ; close file + SWI XOS_Find +80 ; error, file not open + STRVS R0, [WsPtr, #RetnReg0] + SWI XOS_RestoreCursors + Pull R14 + ORRS PC, R14, #V_bit + + + END diff --git a/s/vdu/vdugrafl b/s/vdu/vdugrafl new file mode 100644 index 0000000000000000000000000000000000000000..8be3f53acc503f32821dbe236a593274593acf72 --- /dev/null +++ b/s/vdu/vdugrafl @@ -0,0 +1,675 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.VduGrafL +; +; ARTHUR OPERATING SYSTEM - Vdu Drivers +; ======================= +; +; Vdu driver code - Sprite stuff +; +; Author T M Dobson +; Date 22-Sep-87 +; + +; ***************************************************************************** +; +; ReadSaveAreaSize - Read size of a VDU context save area +; +; in: R0 = SpriteReason_ReadSaveAreaSize +; R1 -> sprite area +; R2 -> sprite (0 => screen (possibly)) +; +; out: R3 = size of an area suitable for this sprite +; + +ReadSaveAreaSize ROUT + MOV R3, #MainSize ; I was kidding about it depending + STR R3, [WsPtr, #RetnReg3] ; on the sprite! + MOV PC, R14 + +; ***************************************************************************** +; +; SwitchOutputToSprite - Make VDU(graphics) output go to a sprite +; +; External routine +; +; in: R0 = SpriteReason_SwitchOutputTo <Sprite or Mask> +; R1 -> sprite area +; R2 -> sprite (0 => screen) +; R3 -> save area for VDU variables relating to sprite +; 0 => no save area, initialise variables from mode number of sprite +; or display mode number +; 1 => use MOS's save area +; +; First word of save area = 0 => uninitialised save area +; "VOTS" => initialised save area +; else error +; + +; From Medusa onwards, things are further complicated here by the fact that +; the sprite may have a new sprite mode word rather than a mode number. When +; the former case occurs calling pushmodeinfoanymonitor doesn't really help +; very much. Instead, when a sprite mode word is given, it will derive or +; fudge all the variables that it is really interested from the sprite mode +; word directly. + +SwitchOutputToSprite ROUT +SwitchOutputToMask ROUT + CMP R3, #1 ; check for values 0 and 1 + MOVCC R4, #0 ; R3=0 => no save area, so not inited + + ADDEQ R5, WsPtr, #VduSaveArea ; R3=1 => MOS's area + MOVHI R5, R3 ; else user area + LDRCS R4, [R5, #InitFlag] ; if is an area, load R4 with init flag + LDR R5, VOTS ; compare with initialised identifier + TEQ R4, R5 ; if not initialised + TEQNE R4, #0 ; and not uninitialised + BNE InvalidSaveArea + +; no more errors can be generated, so update returned registers + + ADD R5, WsPtr, #VduOutputCurrentState + LDMIA R5, {R6-R9} + ADD R5, WsPtr, #RetnReg0 + STMIA R5, {R6-R9} + + Push "R0-R4,R14" + + ASSERT SpriteMaskSelect = VduOutputCurrentState +0 + ASSERT VduSpriteArea = VduOutputCurrentState + 4 + ASSERT VduSprite = VduOutputCurrentState + 8 + + ORR R0, R0, #RangeC ; make R0 into &2nn + + ADD R5, WsPtr, #VduOutputCurrentState + STMIA R5, {R0-R2} + + BL PreWrchCursor ; remove cursor + BL PackVars ; save away current vars into save area + ; (if any) + Pull "R0-R4" + STR R3, [WsPtr, #VduSaveAreaPtr] ; save new save area ptr + + TEQ R2, #0 ; if switching to screen + LDREQ R9, [WsPtr, #DisplayScreenStart] ; then load up new ScreenStart + LDREQ R11, [WsPtr, #DisplayModeNo] ; and mode number + BEQ %FT20 ; and skip sprite stuff + +; do stuff for switching to sprite + + Push R0 + BL RemoveLeftHandWastage ; then remove LH wastage from sprite + Pull R0 ; (spLBit := 0) + + ASSERT spHeight = spWidth +4 + ASSERT spLBit = spWidth +8 + ASSERT spRBit = spWidth +12 + ASSERT spImage = spWidth +16 + ASSERT spTrans = spWidth +20 + ASSERT spMode = spWidth +24 + + ADD R5, R2, #spWidth ; R5=width:R6=height:R7=LBit(=0) + LDMIA R5, {R5-R11} ; R8=RBit:R9=Image:R10=Trans:R11=Mode + + TEQ R0, #SpriteReason_SwitchOutputToMask + BNE %FT23 + + MOV R9, R10 ; point at mask instead of image + MOVS R0, R11, LSR #27 + BEQ %FT23 ; check for old format masks + + BL GetMaskspWidth ; adjust R5 and R8 to mask dimensions + BIC R11, R11, #&F8000000 + ORR R11, R11, #&08000000 ; force it to a type 1 (1bpp) sprite +23 + ADD R9, R9, R2 ; R9 -> sprite data or mask +20 + STR R9, [WsPtr, #ScreenStart] + STR R11, [WsPtr, #ModeNo] ; new mode number + + MOV R10, R11 + BL PushModeInfoAnyMonitor + MOV R11, R13 + + TEQ R2, #0 ; if outputting to screen + LDREQ R5, [R11, #wkLineLength] ; then load up values + LDREQ R6, [R11, #wkYWindLimit] ; from mode table + LDREQ R7, [R11, #wkXWindLimit] + LDREQ R8, [R11, #wkScrRCol] + LDREQ R10, [R11, #wkScrBRow] + BEQ %FT30 ; and skip more sprite stuff + + ADD R5, R5, #1 + MOV R5, R5, LSL #2 ; R5 = width in bytes + + ADD R7, R8, R5, LSL #3 ; R7 = LineLength*8 + spRBit + SUB R7, R7, #31 ; R7=active area width in bits + + LDR R8, [R11, #wkLog2BPC] + MOV R7, R7, LSR R8 ; R7 = width in pixels + MOV R8, R7, LSR #3 ; R8 = width in text columns + SUB R7, R7, #1 ; R7 = max value of GWRCol + + SUB R8, R8, #1 ; R8 = max column number + + ADD R10, R6, #1 ; R10 = no. of pixel rows + MOV R10, R10, LSR #3 ; R10 = number of char rows + SUB R10, R10, #1 ; R4 = maximum row number + +30 + STR R5, [WsPtr, #LineLength] + STR R6, [WsPtr, #YWindLimit] + STR R7, [WsPtr, #XWindLimit] + STR R8, [WsPtr, #ScrRCol] + STR R10, [WsPtr, #ScrBRow] + + LDR R0,[R11, #wkNColour] + STR R0,[WsPtr, #NColour] ; copy number of colours -1 + + ADD R11, R11, #wkmiddle + MOV R0, #wkmidend-wkmiddle ; number of bytes to do + ADD R1, WsPtr, #YShftFactor ; first mode variable that we do + +40 + LDR R5, [R11], #4 ; copy byte from mode table + STR R5, [R1], #4 ; into word variable + SUBS R0, R0, #4 ; decrement count + BNE %BT40 ; loop until finished + + ADD R13, R13, #PushedInfoSize ; junked stacked info + +; now create other variables from simple ones + + LDR R0, [WsPtr, #Log2BPP] + LDR R1, [WsPtr, #Log2BPC] + LDR R5, [WsPtr, #XEigFactor] + LDR R6, [WsPtr, #ModeFlags] + TEQ R2, #0 + ORRNE R6, R6, #Flag_HardScrollDisabled ; if sprite then disable hard + BICEQ R6, R6, #Flag_HardScrollDisabled ; scroll, else enable it + STR R6, [WsPtr, #ModeFlags] + + ;if switching to a sprite, check for full palette 8bpp, and set modeflags and + ;NColour to suit. + + TEQ R2, #0 + BEQ %FT65 ; switching to a sprite ? + + CMP R0, #3 + BNE %FT65 ; which is 8bpp ? + + ADD R7, R2, #spImage ; point R7 at the image/mask start pair + LDMIA R7, {R7, LR} ; fetch them + CMP R7, LR ; which is lower + MOVGT R7, LR ; use the lowest + SUB R7, R7, #spPalette ; get the size of the palette + CMP R7, #&800 ; full 8bpp palette ? + BNE %FT65 + + ORR R6, R6, #Flag_FullPalette + STR R6, [WsPtr, #ModeFlags] ; set the full palette flag + + MOV R7, #255 + STR R7, [WsPtr, #NColour] ; and set the number of colours + +65 + TST R6, #Flag_DoubleVertical + ADREQL R7, WrchNbitTab ; point to correct table + ADRNEL R7, WrchNbitDoubleTab + LDR R8, [R7, R1, LSL #2] ; get offset to correct code + ADD R8, R8, R7 ; convert to absolute address + STR R8, [WsPtr, #WrchNbit] + + ADRL R7, CursorNbitTab + LDR R8, [R7, R1, LSL #2] + ADD R8, R8, R7 + TST R6, #Flag_Teletext + ADRNEL R8, CursorTeletext + STR R8, [WsPtr, #CursorNbit] + + TST R6, #Flag_NonGraphic + MOVEQ R7, #32 ; if graphic mode + MOVEQ R7, R7, LSR R1 ; then = (32 >> lbpc)-1 + SUBEQ R7, R7, #1 + MOVNE R7, #0 ; else = 0 ;;; NOT REALLY SAFE BET ANYMORE!!! + STR R7, [WsPtr, #NPix] + + RSB R7, R1, #5 ; XShftFactor = 5-log2bpc + STR R7, [WsPtr, #XShftFactor] + + LDR R7, [WsPtr, #YEigFactor] + SUBS R7, R5, R7 ; XEigFactor-YEigFactor + MOVLT R7, #2 ; X<Y => 2 (vert rect) + MOVGT R7, #1 ; X>Y => 1 (horz rect) + ; else X=Y => 0 (square) + STR R7, [WsPtr, #AspectRatio] + + MOV R8, #1 + MOV R7, R8, LSL R0 ; bpp = 1 << lbpp + STR R7, [WsPtr, #BitsPerPix] + + MOV R7, R8, LSL R1 ; bpc = 1 << lbpc + STR R7, [WsPtr, #BytesPerChar] + + TST R6, #Flag_BBCGapMode ; is it a BBC gap mode ? + MOVNE R7, #&55 ; yes, then use colour 1 + BNE %FT70 + TEQ R0, #2 ; if (1<<2=4) bits per pixel + MOVEQ R7, #&77 ; then use colour 7 for cursor + MOVNE R7, #&FF ; else use colour 15 +70 + ORR R7, R7, R7, LSL #8 ; fill out to whole word + ORR R7, R7, R7, LSL #16 + STR R7, [WsPtr, #CursorFill] + + TST R6, #Flag_DoubleVertical + MOVEQ R7, #8 ; if single vertical then 8 pixels + MOVNE R7, #16 ; if double vertical then 16 pixels + STR R7, [WsPtr, #TCharSizeY] + TST R6, #Flag_GapMode + ADDNE R7, R7, R7, LSR #2 ; make 10 or 20 if gap mode + STR R7, [WsPtr, #RowMult] + STR R7, [WsPtr, #TCharSpaceY] + MOV R8, #8 + STR R8, [WsPtr, #TCharSizeX] + STR R8, [WsPtr, #TCharSpaceX] + + LDR R8, [WsPtr, #LineLength] + MUL R7, R8, R7 + STR R7, [WsPtr, #RowLength] + +; finished doing other variables + + SWI XColourTrans_InvalidateCache ; let ColourTrans know we've changed mode + ; so that colours get set up correctly + + TEQ R4, #0 ; initialising from a save area ? + BEQ %FT80 ; no, then set to defaults + + BL UnpackVars + BL AddressCursors + BL ValidateVars + BL PlainBit + BL SetColour + LDR R6, [WsPtr, #CursorFlags] + ORR R6, R6, #TEUpdate ; TextExpand needs updating + STR R6, [WsPtr, #CursorFlags] + B %FT90 +80 + +; *****Change made by DJS +; Original code was: +; MOV R0, #0 +; STR R0, [WsPtr, #ECFShift] +; STR R0, [WsPtr, #ECFYOffset] +; This needed to be changed to make the bottom left of the screen (rather +; than the top left) be the default ECF origin. + LDR R0, [WsPtr, #YWindLimit] + ADD R0, R0, #1 + AND R0, R0, #7 + STR R0, [WsPtr, #ECFYOffset] + MOV R0, #0 + STR R0, [WsPtr, #ECFShift] +; *****End of change made by DJS + + STR R0, [WsPtr, #ClipBoxEnable] + STRB R0, [R0, #OsbyteVars + :INDEX: VDUqueueItems] + + MOV R0, #8 + STR R0, [WsPtr, #GCharSizeX] ; chars are 8x8 by default + STR R0, [WsPtr, #GCharSizeY] + STR R0, [WsPtr, #GCharSpaceX] ; and with 8x8 spacing + STR R0, [WsPtr, #GCharSpaceY] + + LDR R1, [WsPtr, #ModeFlags] + + LDR R0, [WsPtr, #CursorFlags] + BIC R0, R0, #(ActualState :OR: Vdu5Bit) + BIC R0, R0, #(CursorsSplit :OR: PageMode :OR: TeletextMode :OR: ClipBoxEnableBit) + TST R1, #Flag_Teletext ; is it teletext ? + ORRNE R0, R0, #TeletextMode ; yes, then set bit + STR R0, [WsPtr, #CursorFlags] + BLNE TeletextInit ; initialise TTX if appropriate + + BL InitCursor ; initialise cursor after + ; cursorflags + BL PlainBit ; also sets up RAMMaskTb + BL DefaultColours ; N.B. SetColour is called by both + BL DefaultEcfPattern ; of these. + BL DefaultLineStyle + BL DefaultWindows + BL Home +90 + BL PostWrchCursor + + MOV R1, #Service_SwitchingOutputToSprite ; call Ran's service + ADD R2, WsPtr, #VduOutputCurrentState + LDMIA R2, {R2-R5} ; load the registers that were in R0-R3 on entry + IssueService + + Pull R14 + BICS PC, R14, #V_bit + +InvalidSaveArea + ADRL R0, SpriteErr_InvalidSaveArea + [ International + Push "lr" + BL TranslateError + Pull "lr" + ] + STR R0, [WsPtr, #RetnReg0] + ORRS PC, R14, #V_bit + +VOTS = "VOTS" + + +; ***************************************************************************** + +; Specially saved items + + ^ 0 +InitFlag # 4 ; 0 => uninit, "VOTS" => init +SavedSpoolFileH # 1 ; an OSBYTE variable +SavedWrchDest # 1 ; --------""-------- +SavedVDUqueueItems # 1 ; --------""-------- + # 1 ; padding to word align it +SavedDataOffset # 0 ; start of compressed data + + GBLA FirstOffset + GBLA NextOffset + GBLA CompressedSize + + MACRO + CompStart +FirstOffset SETA -1 +NextOffset SETA -1 +CompressedSize SETA 0 + MEND + + MACRO + Compress $v0, $v1, $v2, $v3, $v4, $v5, $v6, $v7 + [ "$v0"<>"" + Compo $v0 + ] + [ "$v1"<>"" + Compo $v1 + ] + [ "$v2"<>"" + Compo $v2 + ] + [ "$v3"<>"" + Compo $v3 + ] + [ "$v4"<>"" + Compo $v4 + ] + [ "$v5"<>"" + Compo $v5 + ] + [ "$v6"<>"" + Compo $v6 + ] + [ "$v7"<>"" + Compo $v7 + ] + MEND + + MACRO + Compo $var + [ FirstOffset <> -1 + [ $var = NextOffset +NextOffset SETA ($var)+4 + | + DCW FirstOffset + DCW NextOffset +CompressedSize SETA CompressedSize + (NextOffset-FirstOffset) +FirstOffset SETA $var +NextOffset SETA ($var)+4 + ] + | +FirstOffset SETA $var +NextOffset SETA ($var)+4 + ] + MEND + + MACRO + CompMult $start, $size + [ FirstOffset <> -1 + [ $start = NextOffset +NextOffset SETA $start + $size + | + DCW FirstOffset + DCW NextOffset +CompressedSize SETA CompressedSize + (NextOffset-FirstOffset) +FirstOffset SETA $start +NextOffset SETA $start + $size + ] + | +FirstOffset SETA $start +NextOffset SETA $start + $size + ] + MEND + + MACRO + CompRange $start, $end + CompMult $start, ($end+4-$start) + MEND + + MACRO + CompEnd + [ FirstOffset <> -1 + DCW FirstOffset + DCW NextOffset +CompressedSize SETA CompressedSize + (NextOffset-FirstOffset) + ] + & -1 + MEND + +CompressionTable + CompStart + +; CompMult FgEcf, 8*4 ; recreated from GCOLs + ecfs by +; CompMult BgEcf, 8*4 ; call to SetColour + + Compress GPLFMD, GPLBMD, GFCOL, GBCOL, GWLCol, GWBRow, GWRCol, GWTRow + CompRange qqqPad, JVec + +; Compress ScreenStart ; worked out from sprite address each time + + Compress TWLCol, TWBRow, TWRCol, TWTRow + CompRange OrgX, NewPtY + Compress TForeCol, TBackCol, CursorX, CursorY + +; Compress CursorAddr, InputCursorAddr - computed from (Input)CursorX,Y + + Compress InputCursorX, InputCursorY + + Compress VduStatus + Compress CursorDesiredState, CursorStartOffset, CursorEndOffset + Compress CursorCounter, CursorSpeed, Reg10Copy + +; Compress CursorFill, CursorNbit - computed from mode variables + +; Compress DriverBankAddr - refers to screen always + + CompRange Ecf1, Ecf4+4 + CompMult DotLineStyle, 8 + +; Compress ModeNo - stored in sprite itself + + Compress TFTint, TBTint, GFTint, GBTint + Compress CursorFlags, CursorStack + Compress ECFShift, ECFYOffset + + Compress GCharSizeX, GCharSizeY, GCharSpaceX, GCharSpaceY +; Compress TCharSizeX, TCharSizeY ; recomputed from mode number +; Compress TCharSpaceX, TCharSpaceY ; each time + +; CompMult FgEcfOraEor, 64 ; recreated from GCOLs and ecfs +; CompMult BgEcfOraEor, 64 ; by call to SetColour +; CompMult BgEcfStore, 64 ; + + Compress LineDotCnt, LineDotPatLSW, LineDotPatMSW, DotLineLength + Compress BBCcompatibleECFs + +; Compress WrchNbit - computed from mode number + + CompRange ClipBoxEnable, ClipBoxTRow + + CompMult FgPattern, 4*8 + CompMult BgPattern, 4*8 + + Compress TextFgColour + Compress TextBgColour + + CompEnd +CompressionTableEnd +MainSize * CompressedSize + SavedDataOffset + + ASSERT MainSize <= SaveAreaSize + ! 0, "Space free in VDU save area = ":CC::STR:(SaveAreaSize-MainSize) + + [ {FALSE} ; don't allow teletext mode for now +TTXCompressionTable + CompStart + CompMult TTXDoubleCounts, 28 ; (25 rounded up to a word) + CompMult TTXMap, 41*25*4 + CompEnd +TTXCompressionTableEnd +TTXSize * CompressedSize + ] + + +; ***************************************************************************** +; +; PackVars - Pack variables into save area +; + +PackVars ROUT + CLC ; clear carry - indicate packing +PackOrUnpack + Push "R0-R4,R14" + LDR R0, [WsPtr, #VduSaveAreaPtr] + TEQ R0, #0 + Pull "R0-R4,PC", EQ ; ptr=0 => no area + + TEQ R0, #1 + ADDEQ R0, WsPtr, #VduSaveArea ; ptr=1 => use MOS's save area + + BL DoSpecialVars ; process special vars + + ADD R0, R0, #SavedDataOffset ; move on to compressed data + ADR R1, CompressionTable +10 + LDR R2, [R1], #4 + MVNS R3, R2 ; set Z if it was -1 (end of table) + Pull "R0-R4,PC", EQ ; (preserves C) + + ADD R3, WsPtr, R2, LSR #16 ; R3 = end pointer + MOV R2, R2, LSL #16 + ADD R2, WsPtr, R2, LSR #16 ; R2 = start pointer +20 + LDRCC R4, [R2], #4 ; load a word from vars + LDRCS R4, [R0], #4 ; or from save area + STRCC R4, [R0], #4 ; store into save area + STRCS R4, [R2], #4 ; or into vars + TEQ R2, R3 ; end of this block ? + BNE %BT20 ; [no, so loop] + B %BT10 ; go back for another block + +; ***************************************************************************** +; +; UnpackVars - Unpack variables from save area +; + +UnpackVars ROUT + SEC ; set carry - indicate unpacking + B PackOrUnpack + +; ***************************************************************************** +; +; DoSpecialVars - Pack/unpack special vars: CursorAddr, InputCursorAddr, +; (stored relative to ScreenStart); SpoolFileH, WrchDest, VDUqueueItems +; +; in: R0 -> save area +; +; out: R0 preserved +; R1-R2 corrupted +; Flags preserved +; + +DoSpecialVars ROUT + BYTEWS R1 + BCS %FT10 + LDRB R2, [R1, #:INDEX: SpoolFileH] + STRB R2, [R0, #SavedSpoolFileH] + LDRB R2, [R1, #:INDEX: WrchDest] + STRB R2, [R0, #SavedWrchDest] + LDRB R2, [R1, #:INDEX: VDUqueueItems] + STRB R2, [R0, #SavedVDUqueueItems] + LDR R1, VOTS ; initialised save area identifier + STR R1, [R0, #InitFlag] + MOV PC, R14 + +; unpack special vars (R1 -> ByteWS) + +10 + LDRB R2, [R0, #SavedSpoolFileH] + STRB R2, [R1, #:INDEX: SpoolFileH] + LDRB R2, [R0, #SavedWrchDest] + STRB R2, [R1, #:INDEX: WrchDest] + LDRB R2, [R0, #SavedVDUqueueItems] + STRB R2, [R1, #:INDEX: VDUqueueItems] + MOV PC, R14 + +; ***************************************************************************** +; +; ValidateVars - Validate unpacked variables (windows, cursor posns) +; + +ValidateVars ROUT + Push R14 + ASSERT ScrBRow = ScrRCol + 4 + ADD R4, WsPtr, #ScrRCol + LDMIA R4, {R4, R5} ; R4 = ScrRCol; R5 = ScrBRow + + ADD R6, WsPtr, #TWLCol ; R0 = TWLCol; R1 = TWBRow + LDMIA R6, {R0-R3} ; R2 = TWRCol; R3 = TWTRow + + MOV R7, #0 + MOV R8, R5 + MOV R9, R4 + MOV R10, #0 + STMIA R6, {R7-R10} ; set up default window + + BL FSRegs ; and attempt to define text window + + ASSERT YWindLimit = XWindLimit + 4 + ADD R0, WsPtr, #XWindLimit + LDMIA R0, {R2, R3} ; R2 = XWindLimit; R3 = YWindLimit + + ADD R8, WsPtr, #GWLCol ; R4 = GWLCol; R5 = GWBRow + LDMIA R8, {R4-R7} ; R6 = GWRCol; R7 = GWTRow + + CMP R6, R2 ; if GWRCol > XWindLimit + CMPLS R7, R3 ; or GWTRow > YWindLimit + + MOVHI R0, #0 + MOVHI R1, #0 + STMHIIA R8, {R0-R3} ; then set default graphics window + + Pull PC + + END diff --git a/s/vdu/vdumodes b/s/vdu/vdumodes new file mode 100644 index 0000000000000000000000000000000000000000..e3dedce8d9dc6d179530a47a78013a4ac9ebee61 --- /dev/null +++ b/s/vdu/vdumodes @@ -0,0 +1,997 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Kernel.Source.VduModes +; 24-May-91 + +; general purpose mode macros + +; pixel rate specifiers + + [ VIDC_Type = "VIDC20" + + MACRO + Moduli $pixrate, $v, $r, $d + [ ($v=$r) +CRPix_$pixrate * CR_RCLK :OR: ($d-1) :SHL: CR_PixelDivShift +FSyn_$pixrate * ((64-1):SHL:FSyn_VShift) :OR: ((64-1):SHL:FSyn_RShift) + | +CRPix_$pixrate * CR_VCLK :OR: ($d-1) :SHL: CR_PixelDivShift +FSyn_$pixrate * (($v-1):SHL:FSyn_VShift) :OR: (($r-1):SHL:FSyn_RShift) + ] + MEND + + [ MorrisSupport +; Morris only values by RCM 28-Oct-94 + + MACRO + Moduli32 $pixrate, $v, $r, $d + [ ($v=$r) +CRPix32_$pixrate * CR_RCLK :OR: ($d-1) :SHL: CR_PixelDivShift +FSyn32_$pixrate * ((64-1):SHL:FSyn_VShift) :OR: ((64-1):SHL:FSyn_RShift) + | +CRPix32_$pixrate * CR_VCLK :OR: ($d-1) :SHL: CR_PixelDivShift +FSyn32_$pixrate * (($v-1):SHL:FSyn_VShift) :OR: (($r-1):SHL:FSyn_RShift) + ] + MEND + + +; +; Values suitable for any machine with rclk=32MHz (eg Morris based machines) +; + Moduli32 24000, 6, 2, 4 + Moduli32 16000, 2, 2, 2 + Moduli32 12000, 6, 2, 8 + Moduli32 8000, 2, 2, 4 + Moduli32 6000, 2, 2, 5 ; 6.4000000 + + Moduli32 25175, 22, 7, 4 ; 25.1428571 + Moduli32 16783, 21, 8, 5 ; 16.8000000 + Moduli32 12587, 11, 4, 7 ; 12.5714286 + Moduli32 8392, 21, 10, 8 ; 8.4000000 + + Moduli32 36000, 9, 4, 2 + + Moduli32 8800, 11, 5, 8 ; 8.8000000 + Moduli32 17600, 11, 4, 5 ; 17.6000000 + Moduli32 35200, 11, 5, 2 ; 35.3000000 + ] +; +; Updated by TMD 28-Jan-94 to use new VCO range 55-110MHz +; +; Values suitable for any machine with rclk=24MHz (eg Medussa) +; + Moduli 24000, 2, 2, 1 + Moduli 16000, 8, 2, 6 + Moduli 12000, 2, 2, 2 + Moduli 8000, 2, 2, 3 + Moduli 6000, 2, 2, 4 + + Moduli 25175, 21, 5, 4 ; 25.2000000 + Moduli 16783, 7, 2, 5 ; 16.8000000 + Moduli 12587, 21, 5, 8 ; 12.6000000 + Moduli 8392, 14, 5, 8 ; 8.4000000 + + Moduli 36000, 6, 2, 2 + + Moduli 8800, 44, 15, 8 ; 8.8 + Moduli 17600, 11, 3, 5 ; 17.6 + Moduli 35200, 22, 5, 3 ; 35.2 + + + | +CRPix_24000 * 3 :OR: (0 :SHL: ClockControlShift) +CRPix_16783 * 2 :OR: (1 :SHL: ClockControlShift) +CRPix_16000 * 2 :OR: (0 :SHL: ClockControlShift) +CRPix_12587 * 1 :OR: (1 :SHL: ClockControlShift) +CRPix_12000 * 1 :OR: (0 :SHL: ClockControlShift) +CRPix_8392 * 0 :OR: (1 :SHL: ClockControlShift) +CRPix_8000 * 0 :OR: (0 :SHL: ClockControlShift) +CRPix_25175 * 3 :OR: (1 :SHL: ClockControlShift) +CRPix_36000 * 3 :OR: (2 :SHL: ClockControlShift) + ] + + MACRO +$label VIDC_List $lbpp,$hsync,$hbpch,$hlbdr,$hdisp,$hrbdr,$hfpch, $vsync,$vbpch,$vlbdr,$vdisp,$vrbdr,$vfpch,$pixrate,$sp + [ VIDC_Type = "VIDC20" +$label VIDC_List20 $lbpp,$hsync,$hbpch,$hlbdr,$hdisp,$hrbdr,$hfpch, $vsync,$vbpch,$vlbdr,$vdisp,$vrbdr,$vfpch,$pixrate,$sp + | +$label VIDC_List10 $lbpp,$hsync,$hbpch,$hlbdr,$hdisp,$hrbdr,$hfpch, $vsync,$vbpch,$vlbdr,$vdisp,$vrbdr,$vfpch,$pixrate,$sp + ] + MEND + +; VIDC1 format VIDC list + + MACRO +$label VIDC_List10 $lbpp,$hsync,$hbpch,$hlbdr,$hdisp,$hrbdr,$hfpch, $vsync,$vbpch,$vlbdr,$vdisp,$vrbdr,$vfpch,$pixrate,$sp + +$label + LCLA sub + LCLA sp + LCLA syncpol + LCLA hbpch + LCLA hfpch + [ :LNOT: AssemblingArthur + & 0 ; VIDC list type (default) + & 0 ; base mode (irrelevant, all entries overwritten) + ] + [ $lbpp = 3 +sub SETA 5 + ] + [ $lbpp = 2 +sub SETA 7 + ] + [ $lbpp = 1 +sub SETA 11 + ] + [ $lbpp = 0 +sub SETA 19 + ] + + [ "$sp"="" +syncpol SETA 0 :SHL: SyncControlShift ; normal sync polarity + | + ASSERT $sp<=3 +syncpol SETA $sp :SHL: SyncControlShift + ] + +; Note that on VIDC1, hbpch and hfpch must be odd, and on VIDC20 they must be even +; The macro now specifies them as even. +; So increase back porch and reduce front porch by 1 + + ASSERT ($hsync :AND: 1)=0 + ASSERT ($hbpch :AND: 1)=0 +hbpch SETA ($hbpch) + 1 + ASSERT ($hlbdr :AND: 1)=0 + ASSERT ($hdisp :AND: 1)=0 + ASSERT ($hrbdr :AND: 1)=0 + ASSERT ($hfpch :AND: 1)=0 +hfpch SETA ($hfpch) - 1 + [ (($hsync+hbpch+$hlbdr+$hdisp+$hrbdr+hfpch) :AND: 3)<>0 + ! 0, "Warning: mode unsuitable for interlaced use" + ] +; Horizontal + & (&80:SHL:24) :OR: ((($hsync+hbpch+$hlbdr+$hdisp+$hrbdr+hfpch -2 )/2) :SHL: 14) ; HCR + & (&84:SHL:24) :OR: ((($hsync -2 )/2) :SHL: 14) ; HSWR + & (&88:SHL:24) :OR: ((($hsync+hbpch -1 )/2) :SHL: 14) ; HBSR + & (&8C:SHL:24) :OR: ((($hsync+hbpch+$hlbdr -sub)/2) :SHL: 14) ; HDSR + & (&90:SHL:24) :OR: ((($hsync+hbpch+$hlbdr+$hdisp -sub)/2) :SHL: 14) ; HDER + & (&94:SHL:24) :OR: ((($hsync+hbpch+$hlbdr+$hdisp+$hrbdr -1 )/2) :SHL: 14) ; HBER + & (&9C:SHL:24) :OR: (((($hsync+hbpch+$hlbdr+$hdisp+$hrbdr+hfpch-2)/2+1)/2):SHL:14); HIR +; Vertical + & (&A0:SHL:24) :OR: (($vsync+$vbpch+$vlbdr+$vdisp+$vrbdr+$vfpch -1) :SHL: 14) ; VCR + & (&A4:SHL:24) :OR: (($vsync -1) :SHL: 14) ; VSWR + & (&A8:SHL:24) :OR: (($vsync+$vbpch -1) :SHL: 14) ; VBSR + & (&AC:SHL:24) :OR: (($vsync+$vbpch+$vlbdr -1) :SHL: 14) ; VDSR + & (&B0:SHL:24) :OR: (($vsync+$vbpch+$vlbdr+$vdisp -1) :SHL: 14) ; VDER + & (&B4:SHL:24) :OR: (($vsync+$vbpch+$vlbdr+$vdisp+$vrbdr -1) :SHL: 14) ; VBER +; Control Register + & (&E0:SHL:24) :OR: (CRPix_$pixrate) :OR: ($lbpp :SHL: 2) :OR: syncpol + & -1 + MEND + + MACRO +$label VIDC_List20 $lbpp,$hsync,$hbpch,$hlbdr,$hdisp,$hrbdr,$hfpch, $vsync,$vbpch,$vlbdr,$vdisp,$vrbdr,$vfpch,$pixrate,$sp + +$label + LCLA sp + LCLA syncpol + LCLA dwidth + GBLA framerate + LCLA framepixels + [ :LNOT: AssemblingArthur + & 0 ; VIDC list type (default) + & 0 ; base mode (irrelevant, all entries overwritten) + ] + [ "$sp"="" +sp SETA 0 ; normal sync polarity + | + ASSERT $sp<=3 +sp SETA $sp + ] +syncpol SETA 0 + [ (sp :AND: 1) <> 0 +syncpol SETA syncpol :OR: Ext_InvertHSYNC + ] + [ (sp :AND: 2) <> 0 +syncpol SETA syncpol :OR: Ext_InvertVSYNC + ] + + ASSERT ($hsync :AND: 1)=0 + ASSERT ($hbpch :AND: 1)=0 + ASSERT ($hlbdr :AND: 1)=0 + ASSERT ($hdisp :AND: 1)=0 + ASSERT ($hrbdr :AND: 1)=0 + ASSERT ($hfpch :AND: 1)=0 + + ASSERT (($hsync+$hbpch+$hlbdr+$hdisp+$hrbdr+$hfpch) :AND: 3)=0 + +dwidth SETA $hdisp :SHL: $lbpp + ASSERT (dwidth :AND: 31) = 0 +dwidth SETA dwidth / 32 + +framepixels SETA ($hsync+$hbpch+$hlbdr+$hdisp+$hrbdr+$hfpch)*($vsync+$vbpch+$vlbdr+$vdisp+$vrbdr+$vfpch) +framerate SETA ($pixrate*1000+framepixels/2)/framepixels + +F_$label * framerate ; set up frame rate symbol + +; Horizontal + & (&80:SHL:24) :OR: ($hsync+$hbpch+$hlbdr+$hdisp+$hrbdr+$hfpch-8) ; HCR + & (&81:SHL:24) :OR: ($hsync -8) ; HSWR + & (&82:SHL:24) :OR: ($hsync+$hbpch -12) ; HBSR + & (&83:SHL:24) :OR: ($hsync+$hbpch+$hlbdr -18) ; HDSR + & (&84:SHL:24) :OR: ($hsync+$hbpch+$hlbdr+$hdisp -18) ; HDER + & (&85:SHL:24) :OR: ($hsync+$hbpch+$hlbdr+$hdisp+$hrbdr -12) ; HBER + & (&87:SHL:24) :OR: ($hsync+$hbpch+$hlbdr+$hdisp+$hrbdr+$hfpch )/2 ; HIR +; Vertical + & (&90:SHL:24) :OR: ($vsync+$vbpch+$vlbdr+$vdisp+$vrbdr+$vfpch -2) ; VCR + & (&91:SHL:24) :OR: ($vsync -2) ; VSWR + & (&92:SHL:24) :OR: ($vsync+$vbpch -2) ; VBSR + & (&93:SHL:24) :OR: ($vsync+$vbpch+$vlbdr -2) ; VDSR + & (&94:SHL:24) :OR: ($vsync+$vbpch+$vlbdr+$vdisp -2) ; VDER + & (&95:SHL:24) :OR: ($vsync+$vbpch+$vlbdr+$vdisp+$vrbdr -2) ; VBER +; Data Control Register + [ MEMC_Type = "IOMD" +; Note: the bus bits get overwritten by the mode change code, to set it up correctly for 1 or 2 MBytes of VRAM + & VIDCDataControl :OR: DCR_VRAMOff :OR: DCR_Bus31_0 :OR: (dwidth :SHL: DCR_HDWRShift) :OR: DCR_Sync + | + & VIDCDataControl :OR: DCR_VRAMOff :OR: DCR_Bus31_0 :OR: (dwidth :SHL: DCR_HDWRShift) + ] +; External Register + & VIDCExternal :OR: Ext_DACsOn :OR: Ext_ERegExt :OR: syncpol +; Frequency Synthesizer Register (rclk=24MHz) + & VIDCFSyn :OR: (FSyn_$pixrate) +; Control Register (rclk=24MHz) + & VIDCControl :OR: (4 :SHL: CR_FIFOLoadShift) :OR: (CR_LBPP$lbpp) :OR: (CRPix_$pixrate) + & -1 + [ MorrisSupport +; Frequency Synthesizer Register (32MHz) + & VIDCFSyn :OR: (FSyn32_$pixrate) +; Control Register (32MHz) + & VIDCControl :OR: (4 :SHL: CR_FIFOLoadShift) :OR: (CR_LBPP$lbpp) :OR: (CRPix32_$pixrate) + & -1 + ] + MEND + +NumMonitorTypes * 5 +NumModes * 50 +maxmode * NumModes-1 +minmode * 0 + +; These macro are used by various routines in the kernel to check for a valid mode number +; MUST be kept up-to-date with the list of invalid modes between 0 and maxmode + + MACRO + BranchIfKnownMode $reg, $address + [ VIDC_Type = "VIDC20" + CMP $reg, #NumModes + | + CMP $reg, #32 ; if not 32 (EQ => CS) + CMPNE $reg, #NumModes ; and less than ?? + ] + BCC $address ; then branch + MEND + + MACRO + BranchIfNotKnownMode $reg, $address + [ VIDC_Type = "VIDC20" + CMP $reg, #NumModes + | + CMP $reg, #32 ; if not 32 (EQ => CS) + CMPNE $reg, #NumModes ; and less than ?? + ] + BCS $address ; branch if *NOT* known + MEND + +BigVIDCTable + & VLN_0 - BigVIDCTable ; 0 + & VLN_1 - BigVIDCTable ; 1 + & VLN_2 - BigVIDCTable ; 2 + & VLN_3 - BigVIDCTable ; 3 + & VLN_4 - BigVIDCTable ; 4 + & VLN_5 - BigVIDCTable ; 5 + & VLN_6 - BigVIDCTable ; 6 + & VLN_7 - BigVIDCTable ; 7 + & VLN_8 - BigVIDCTable ; 8 + & VLN_9 - BigVIDCTable ; 9 + & VLN_10 - BigVIDCTable ; 10 + & VLN_11 - BigVIDCTable ; 11 + & VLN_12 - BigVIDCTable ; 12 + & VLN_13 - BigVIDCTable ; 13 + & VLN_14 - BigVIDCTable ; 14 + & VLN_15 - BigVIDCTable ; 15 + & VLN_16 - BigVIDCTable ; 16 + & VLN_17 - BigVIDCTable ; 17 + & -1 ; 18 + & -1 ; 19 + & -1 ; 20 + & -1 ; 21 + & VLN_22 - BigVIDCTable ; 22 + & -1 ; 23 + & VLN_24 - BigVIDCTable ; 24 + & -1 ; 25 + & -1 ; 26 + & -1 ; 27 + & -1 ; 28 + & -1 ; 29 + & -1 ; 30 + & -1 ; 31 + & -1 ; 32 + & VLN_33 - BigVIDCTable ; 33 + & VLN_34 - BigVIDCTable ; 34 + & VLN_35 - BigVIDCTable ; 35 + & VLN_36 - BigVIDCTable ; 36 + & -1 ; 37 + & -1 ; 38 + & -1 ; 39 + & -1 ; 40 + & -1 ; 41 + & -1 ; 42 + & -1 ; 43 + & -1 ; 44 + & -1 ; 45 + & -1 ; 46 + & -1 ; 47 + & -1 ; 48 + & -1 ; 49 + + ASSERT (.-BigVIDCTable)=((NumModes*1):SHL:2) + + & VLM_0 - BigVIDCTable ; 0 + & VLM_1 - BigVIDCTable ; 1 + & VLM_2 - BigVIDCTable ; 2 + & VLM_3 - BigVIDCTable ; 3 + & VLM_4 - BigVIDCTable ; 4 + & VLM_5 - BigVIDCTable ; 5 + & VLM_6 - BigVIDCTable ; 6 + & VLM_7 - BigVIDCTable ; 7 + & VLM_8 - BigVIDCTable ; 8 + & VLM_9 - BigVIDCTable ; 9 + & VLM_10 - BigVIDCTable ; 10 + & VLM_11 - BigVIDCTable ; 11 + & VLM_12 - BigVIDCTable ; 12 + & VLM_13 - BigVIDCTable ; 13 + & VLM_14 - BigVIDCTable ; 14 + & VLM_15 - BigVIDCTable ; 15 + & VLM_16 - BigVIDCTable ; 16 + & VLM_17 - BigVIDCTable ; 17 + & VLM_18 - BigVIDCTable ; 18 + & VLM_19 - BigVIDCTable ; 19 + & VLM_20 - BigVIDCTable ; 20 + & VLM_21 - BigVIDCTable ; 21 + & VLM_22 - BigVIDCTable ; 22 + & -1 ; 23 + & VLM_24 - BigVIDCTable ; 24 + & VLM_25 - BigVIDCTable ; 25 + & VLM_26 - BigVIDCTable ; 26 + & VLM_27 - BigVIDCTable ; 27 + & VLM_28 - BigVIDCTable ; 28 + & VLM_29 - BigVIDCTable ; 29 + & VLM_30 - BigVIDCTable ; 30 + & VLM_31 - BigVIDCTable ; 31 + [ VIDC_Type = "VIDC20" + & VLM_32 - BigVIDCTable ; 32 + | + & -1 ; 32 + ] + & VLM_33 - BigVIDCTable ; 33 Ovscn + & VLM_34 - BigVIDCTable ; 34 + & VLM_35 - BigVIDCTable ; 35 + & VLM_36 - BigVIDCTable ; 36 + & VLM_37 - BigVIDCTable ; 37 dtp + & VLM_38 - BigVIDCTable ; 38 + & VLM_39 - BigVIDCTable ; 39 + & VLM_40 - BigVIDCTable ; 40 + & VLM_41 - BigVIDCTable ; 41 EGA + & VLM_42 - BigVIDCTable ; 42 + & VLM_43 - BigVIDCTable ; 43 + & VLM_44 - BigVIDCTable ; 44 CGA + & VLM_45 - BigVIDCTable ; 45 + & VLM_46 - BigVIDCTable ; 46 + & VLM_47 - BigVIDCTable ; 47 PCSoft + & VLM_48 - BigVIDCTable ; 48 Games mode + & VLM_49 - BigVIDCTable ; 49 Games mode + + ASSERT (.-BigVIDCTable)=((NumModes*2):SHL:2) + + & -1 ; 0 + & -1 ; 1 + & -1 ; 2 + & -1 ; 3 + & -1 ; 4 + & -1 ; 5 + & -1 ; 6 + & -1 ; 7 + & -1 ; 8 + & -1 ; 9 + & -1 ; 10 + & -1 ; 11 + & -1 ; 12 + & -1 ; 13 + & -1 ; 14 + & -1 ; 15 + & -1 ; 16 + & -1 ; 17 + & -1 ; 18 + & -1 ; 19 + & -1 ; 20 + & -1 ; 21 + & -1 ; 22 + & VLH_23 - BigVIDCTable ; 23 + & -1 ; 24 + & -1 ; 25 + & -1 ; 26 + & -1 ; 27 + & -1 ; 28 + & -1 ; 29 + & -1 ; 30 + & -1 ; 31 + & -1 ; 32 + & -1 ; 33 + & -1 ; 34 + & -1 ; 35 + & -1 ; 36 + & -1 ; 37 + & -1 ; 38 + & -1 ; 39 + & -1 ; 40 + & -1 ; 41 + & -1 ; 42 + & -1 ; 43 + & -1 ; 44 + & -1 ; 45 + & -1 ; 46 + & -1 ; 47 + & -1 ; 48 + & -1 ; 49 + + ASSERT (.-BigVIDCTable)=((NumModes*3):SHL:2) + + & VgaX_0 - BigVIDCTable ; 0 + & VgaX_1 - BigVIDCTable ; 1 + & VgaX_2 - BigVIDCTable ; 2 + & VgaX_3 - BigVIDCTable ; 3 + & VgaX_4 - BigVIDCTable ; 4 + & VgaX_5 - BigVIDCTable ; 5 + & VgaX_6 - BigVIDCTable ; 6 + & VgaX_7 - BigVIDCTable ; 7 + & VgaX_8 - BigVIDCTable ; 8 + & VgaX_9 - BigVIDCTable ; 9 + & VgaX_10 - BigVIDCTable ; 10 + & VgaX_11 - BigVIDCTable ; 11 + & VgaX_12 - BigVIDCTable ; 12 + & VgaX_13 - BigVIDCTable ; 13 + & VgaX_14 - BigVIDCTable ; 14 + & VgaX_15 - BigVIDCTable ; 15 + & -1 ; 16 + & -1 ; 17 + & -1 ; 18 + & -1 ; 19 + & -1 ; 20 + & -1 ; 21 + & -1 ; 22 + & -1 ; 23 + & -1 ; 24 + & VLM_25 - BigVIDCTable ; 25 + & VLM_26 - BigVIDCTable ; 26 + & VLM_27 - BigVIDCTable ; 27 + & VLM_28 - BigVIDCTable ; 28 + & -1 ; 29 + & -1 ; 30 + & -1 ; 31 + & -1 ; 32 + & -1 ; 33 + & -1 ; 34 + & -1 ; 35 + & -1 ; 36 + & -1 ; 37 + & -1 ; 38 + & -1 ; 39 + & -1 ; 40 + & VgaX_41 - BigVIDCTable ; 41 EGA + & VgaX_42 - BigVIDCTable ; 42 + & VgaX_43 - BigVIDCTable ; 43 + & VgaX_44 - BigVIDCTable ; 44 CGA + & VgaX_45 - BigVIDCTable ; 45 + & VgaX_46 - BigVIDCTable ; 46 + & VLM_47 - BigVIDCTable ; 47 PCSoft + & VLM_48 - BigVIDCTable ; 48 Games mode + & VLM_49 - BigVIDCTable ; 49 Games mode + + ASSERT (.-BigVIDCTable)=((NumModes*4):SHL:2) + + & VgaX_0 - BigVIDCTable ; 0 + & VgaX_1 - BigVIDCTable ; 1 + & VgaX_2 - BigVIDCTable ; 2 + & VgaX_3 - BigVIDCTable ; 3 + & VgaX_4 - BigVIDCTable ; 4 + & VgaX_5 - BigVIDCTable ; 5 + & VgaX_6 - BigVIDCTable ; 6 + & VgaX_7 - BigVIDCTable ; 7 + & VgaX_8 - BigVIDCTable ; 8 + & VgaX_9 - BigVIDCTable ; 9 + & VgaX_10 - BigVIDCTable ; 10 + & VgaX_11 - BigVIDCTable ; 11 + & VgaX_12 - BigVIDCTable ; 12 + & VgaX_13 - BigVIDCTable ; 13 + & VgaX_14 - BigVIDCTable ; 14 + & VgaX_15 - BigVIDCTable ; 15 + & -1 ; 16 + & -1 ; 17 + & -1 ; 18 + & -1 ; 19 + & -1 ; 20 + & -1 ; 21 + & -1 ; 22 + & -1 ; 23 + & -1 ; 24 + & VLM_25 - BigVIDCTable ; 25 + & VLM_26 - BigVIDCTable ; 26 + & VLM_27 - BigVIDCTable ; 27 + & VLM_28 - BigVIDCTable ; 28 + & VLM_29 - BigVIDCTable ; 29 + & VLM_30 - BigVIDCTable ; 30 + & VLM_31 - BigVIDCTable ; 31 + [ VIDC_Type = "VIDC20" + & VLM_32 - BigVIDCTable ; 32 + | + & -1 ; 32 + ] + & -1 ; 33 + & -1 ; 34 + & -1 ; 35 + & -1 ; 36 + & -1 ; 37 + & -1 ; 38 + & -1 ; 39 + & -1 ; 40 + & VgaX_41 - BigVIDCTable ; 41 EGA + & VgaX_42 - BigVIDCTable ; 42 + & VgaX_43 - BigVIDCTable ; 43 + & VgaX_44 - BigVIDCTable ; 44 CGA + & VgaX_45 - BigVIDCTable ; 45 + & VgaX_46 - BigVIDCTable ; 46 + & VLM_47 - BigVIDCTable ; 47 PCSoft + & VLM_48 - BigVIDCTable ; 48 Games mode + & VLM_49 - BigVIDCTable ; 49 Games mode + + ASSERT (.-BigVIDCTable)=((NumModes*5):SHL:2) + +VLN_0 VIDC_List 0, 76, 88, 96, 640, 96, 28, 3,19,16,256,16, 2,16000,0 ; MODE 0 +VLN_1 VIDC_List 1, 38, 44, 48, 320, 48, 14, 3,19,16,256,16, 2, 8000,0 ; MODE 1 +VLN_2 VIDC_List 2, 38, 44, 48, 320, 48, 14, 3,19,16,256,16, 2, 8000,0 ; MODE 2 +VLN_3 VIDC_List 1, 76, 88, 96, 640, 96, 28, 3,19,19,250,19, 2,16000,0 ; MODE 3 +VLN_4 VIDC_List 0, 76, 88, 96, 640, 96, 28, 3,19,16,256,16, 2,16000,0 ; MODE 4 +VLN_5 VIDC_List 1, 38, 44, 48, 320, 48, 14, 3,19,16,256,16, 2, 8000,0 ; MODE 5 +VLN_6 VIDC_List 1, 38, 44, 48, 320, 48, 14, 3,19,19,250,19, 2, 8000,0 ; MODE 6 +VLN_7 VIDC_List 2, 38, 44, 48, 320, 48, 14, 3,19,19,250,19, 2, 8000,0 ; MODE 7 +VLN_8 VIDC_List 1, 76, 88, 96, 640, 96, 28, 3,19,16,256,16, 2,16000,0 ; MODE 8 +VLN_9 VIDC_List 2, 38, 44, 48, 320, 48, 14, 3,19,16,256,16, 2, 8000,0 ; MODE 9 +VLN_10 VIDC_List 3, 38, 44, 48, 320, 48, 14, 3,19,16,256,16, 2, 8000,0 ; MODE 10 +VLN_11 VIDC_List 1, 76, 88, 96, 640, 96, 28, 3,19,19,250,19, 2,16000,0 ; MODE 11 +VLN_12 VIDC_List 2, 76, 88, 96, 640, 96, 28, 3,19,16,256,16, 2,16000,0 ; MODE 12 +VLN_13 VIDC_List 3, 38, 44, 48, 320, 48, 14, 3,19,16,256,16, 2, 8000,0 ; MODE 13 +VLN_14 VIDC_List 2, 76, 88, 96, 640, 96, 28, 3,19,19,250,19, 2,16000,0 ; MODE 14 +VLN_15 VIDC_List 3, 76, 88, 96, 640, 96, 28, 3,19,16,256,16, 2,16000,0 ; MODE 15 +VLN_16 VIDC_List 2,114,132, 96,1056, 96, 42, 3,19,16,256,16, 2,24000,0 ; MODE 16 +VLN_17 VIDC_List 2,114,132, 96,1056, 96, 42, 3,19,19,250,19, 2,24000,0 ; MODE 17 +VLN_22 VIDC_List 2, 76,120, 0, 768, 0, 60, 3,19, 0,288, 0, 2,16000,0 ; MODE 22 +VLN_24 VIDC_List 3,114,132, 96,1056, 96, 42, 3,19,16,256,16, 2,24000,0 ; MODE 24 +VLN_33 VIDC_List 0, 76,120, 0, 768, 0, 60, 3,19, 0,288, 0, 2,16000,0 ; MODE 33 +VLN_34 VIDC_List 1, 76,120, 0, 768, 0, 60, 3,19, 0,288, 0, 2,16000,0 ; MODE 34 +VLN_35 VIDC_List 2, 76,120, 0, 768, 0, 60, 3,19, 0,288, 0, 2,16000,0 ; MODE 35 +VLN_36 VIDC_List 3, 76,120, 0, 768, 0, 60, 3,19, 0,288, 0, 2,16000,0 ; MODE 36 + +VLM_0 VIDC_List 0, 72, 62, 88, 640, 88, 74, 3,16,17,256,17, 3,16000,0 ; MODE 0 +VLM_1 VIDC_List 1, 36, 30, 44, 320, 44, 38, 3,16,17,256,17, 3, 8000,0 ; MODE 1 +VLM_2 VIDC_List 2, 36, 30, 44, 320, 44, 38, 3,16,17,256,17, 3, 8000,0 ; MODE 2 +VLM_3 VIDC_List 1, 72, 62, 88, 640, 88, 74, 3,16,20,250,20, 3,16000,0 ; MODE 3 +VLM_4 VIDC_List 0, 72, 62, 88, 640, 88, 74, 3,16,17,256,17, 3,16000,0 ; MODE 4 +VLM_5 VIDC_List 1, 36, 30, 44, 320, 44, 38, 3,16,17,256,17, 3, 8000,0 ; MODE 5 +VLM_6 VIDC_List 1, 36, 30, 44, 320, 44, 38, 3,16,20,250,20, 3, 8000,0 ; MODE 6 +VLM_7 VIDC_List 2, 36, 30, 44, 320, 44, 38, 3,16,20,250,20, 3, 8000,0 ; MODE 7 +VLM_8 VIDC_List 1, 72, 62, 88, 640, 88, 74, 3,16,17,256,17, 3,16000,0 ; MODE 8 +VLM_9 VIDC_List 2, 36, 30, 44, 320, 44, 38, 3,16,17,256,17, 3, 8000,0 ; MODE 9 +VLM_10 VIDC_List 3, 36, 30, 44, 320, 44, 38, 3,16,17,256,17, 3, 8000,0 ; MODE 10 +VLM_11 VIDC_List 1, 72, 62, 88, 640, 88, 74, 3,16,20,250,20, 3,16000,0 ; MODE 11 +VLM_12 VIDC_List 2, 72, 62, 88, 640, 88, 74, 3,16,17,256,17, 3,16000,0 ; MODE 12 +VLM_13 VIDC_List 3, 36, 30, 44, 320, 44, 38, 3,16,17,256,17, 3, 8000,0 ; MODE 13 +VLM_14 VIDC_List 2, 72, 62, 88, 640, 88, 74, 3,16,20,250,20, 3,16000,0 ; MODE 14 +VLM_15 VIDC_List 3, 72, 62, 88, 640, 88, 74, 3,16,17,256,17, 3,16000,0 ; MODE 15 +VLM_16 VIDC_List 2,108, 72,106,1056,106, 88, 3,16,17,256,17, 3,24000,0 ; MODE 16 +VLM_17 VIDC_List 2,108, 72,106,1056,106, 88, 3,16,20,250,20, 3,24000,0 ; MODE 17 +VLM_18 VIDC_List 0, 56,112, 0, 640, 0, 88, 3,18, 0,512, 0, 1,24000,0 ; MODE 18 +VLM_19 VIDC_List 1, 56,112, 0, 640, 0, 88, 3,18, 0,512, 0, 1,24000,0 ; MODE 19 +VLM_20 VIDC_List 2, 56,112, 0, 640, 0, 88, 3,18, 0,512, 0, 1,24000,0 ; MODE 20 +VLM_21 VIDC_List 3, 56,112, 0, 640, 0, 88, 3,18, 0,512, 0, 1,24000,0 ; MODE 21 +VLM_22 VIDC_List 2, 76, 82, 0, 768, 0, 98, 3,19, 0,288, 0, 2,16000,0 ; MODE 22 +VLM_24 VIDC_List 3,108, 72,106,1056,106, 88, 3,16,17,256,17, 3,24000,0 ; MODE 24 +VLM_25 VIDC_List 0, 96, 46, 0, 640, 0, 18, 2,32, 0,480, 0,11,25175,3 ; MODE 25 +VLM_26 VIDC_List 1, 96, 46, 0, 640, 0, 18, 2,32, 0,480, 0,11,25175,3 ; MODE 26 +VLM_27 VIDC_List 2, 96, 46, 0, 640, 0, 18, 2,32, 0,480, 0,11,25175,3 ; MODE 27 +VLM_28 VIDC_List 3, 96, 46, 0, 640, 0, 18, 2,32, 0,480, 0,11,25175,3 ; MODE 28 +VLM_29 VIDC_List 0, 72,128, 0, 800, 0, 24, 2,22, 0,600, 0, 1,36000,0 ; MODE 29 +VLM_30 VIDC_List 1, 72,128, 0, 800, 0, 24, 2,22, 0,600, 0, 1,36000,0 ; MODE 30 +VLM_31 VIDC_List 2, 72,128, 0, 800, 0, 24, 2,22, 0,600, 0, 1,36000,0 ; MODE 31 + +VLM_33 VIDC_List 0, 76,82, 0, 768, 0, 98, 3,19, 0,288, 0, 2,16000,0 ; MODE 33 +VLM_34 VIDC_List 1, 76,82, 0, 768, 0, 98, 3,19, 0,288, 0, 2,16000,0 ; MODE 34 +VLM_35 VIDC_List 2, 76,82, 0, 768, 0, 98, 3,19, 0,288, 0, 2,16000,0 ; MODE 35 +VLM_36 VIDC_List 3, 76,82, 0, 768, 0, 98, 3,19, 0,288, 0, 2,16000,0 ; MODE 36 + +VLM_37 VIDC_List 0,118, 58, 0, 896, 0, 28, 3, 9, 0,352, 0, 0,24000,2 ; DTP 896x352 +VLM_38 VIDC_List 1,118, 58, 0, 896, 0, 28, 3, 9, 0,352, 0, 0,24000,2 ; EGA std +VLM_39 VIDC_List 2,118, 58, 0, 896, 0, 28, 3, 9, 0,352, 0, 0,24000,2 +VLM_40 VIDC_List 3,118, 58, 0, 896, 0, 28, 3, 9, 0,352, 0, 0,24000,2 + +VLM_41 VIDC_List 0, 76, 36, 0, 640, 0, 16, 3, 9, 0,352, 0, 0,16783,2 ; EGA +VLM_42 VIDC_List 1, 76, 36, 0, 640, 0, 16, 3, 9, 0,352, 0, 0,16783,2 +VLM_43 VIDC_List 2, 76, 36, 0, 640, 0, 16, 3, 9, 0,352, 0, 0,16783,2 + +VLM_44 VIDC_List 0, 72,162, 0, 640, 0,146, 3,34, 0,200, 0,25,16000,0 ; CGA +VLM_45 VIDC_List 1, 72,162, 0, 640, 0,146, 3,34, 0,200, 0,25,16000,0 +VLM_46 VIDC_List 2, 72,162, 0, 640, 0,146, 3,34, 0,200, 0,25,16000,0 + +VLM_47 VIDC_List 3, 64, 62, 0, 360, 0, 46, 2,32, 0,480, 0,11,16783,3 ; PC Soft + +VLM_48 VIDC_List 2, 48, 22, 0, 320, 0, 10, 2,32, 0,480, 0,11,12587,3 ; Games mode +VLM_49 VIDC_List 3, 48, 22, 0, 320, 0, 10, 2,32, 0,480, 0,11,12587,3 ; Games mode + +; New modes for VIDC20 + + [ VIDC_Type = "VIDC20" +VLM_32 VIDC_List 3, 72,128, 0, 800, 0, 24, 2,22, 0,600, 0, 1,36000,0 ; MODE 32 (800 x 600 x 8bpp) + ] + + +VLH_23 VIDC_List 2, 52, 46, 2, 288, 2, 2, 3,43, 4,896, 4, 0,24000,0 ; MODE 23 + +VgaX_0 VIDC_List 0, 96, 46, 0, 640, 0,18, 2,106,0,256, 0,85,25175,2 ; TV modes in VGA_350) +VgaX_1 VIDC_List 1, 48, 22, 0, 320, 0,10, 2,106,0,256, 0,85,12587,2 +VgaX_2 VIDC_List 2, 48, 22, 0, 320, 0,10, 2,106,0,256, 0,85,12587,2 +VgaX_3 VIDC_List 1, 96, 46, 0, 640, 0,18, 2,109,0,250, 0,88,25175,2 +VgaX_4 VIDC_List 0, 96, 46, 0, 640, 0,18, 2,106,0,256, 0,85,25175,2 +VgaX_5 VIDC_List 1, 48, 22, 0, 320, 0,10, 2,106,0,256, 0,85,12587,2 +VgaX_6 VIDC_List 1, 48, 22, 0, 320, 0,10, 2,109,0,250, 0,88,12587,2 +VgaX_7 VIDC_List 2, 48, 22, 0, 320, 0,10, 2,109,0,250, 0,88,12587,2 +VgaX_8 VIDC_List 1, 96, 46, 0, 640, 0,18, 2,106,0,256, 0,85,25175,2 +VgaX_9 VIDC_List 2, 48, 22, 0, 320, 0,10, 2,106,0,256, 0,85,12587,2 +VgaX_10 VIDC_List 3, 48, 22, 0, 320, 0,10, 2,106,0,256, 0,85,12587,2 +VgaX_11 VIDC_List 1, 96, 46, 0, 640, 0,18, 2,109,0,250, 0,88,25175,2 +VgaX_12 VIDC_List 2, 96, 46, 0, 640, 0,18, 2,106,0,256, 0,85,25175,2 +VgaX_13 VIDC_List 3, 48, 22, 0, 320, 0,10, 2,106,0,256, 0,85,12587,2 +VgaX_14 VIDC_List 2, 96, 46, 0, 640, 0,18, 2,109,0,250, 0,88,25175,2 +VgaX_15 VIDC_List 3, 96, 46, 0, 640, 0,18, 2,106,0,256, 0,85,25175,2 + +VgaX_41 VIDC_List 0, 96, 46, 0, 640, 0,18, 2,58, 0,352, 0,37,25175,2 ; EGA +VgaX_42 VIDC_List 1, 96, 46, 0, 640, 0,18, 2,58, 0,352, 0,37,25175,2 +VgaX_43 VIDC_List 2, 96, 46, 0, 640, 0,18, 2,58, 0,352, 0,37,25175,2 + +VgaX_44 VIDC_List 0, 96, 46, 0, 640, 0,18,2,134, 0,200,0,113,25175,2 ; CGA +VgaX_45 VIDC_List 1, 96, 46, 0, 640, 0,18,2,134, 0,200,0,113,25175,2 +VgaX_46 VIDC_List 2, 96, 46, 0, 640, 0,18,2,134, 0,200,0,113,25175,2 + + [ ModeSelectors + +; Table of ideal frame rate for each numbered mode, to put in dummy mode selector +; if numbered mode number is not directly available on this monitortype + + [ VIDC_Type <> "VIDC20" +F_VLM_32 * 0 + ] + +FrameRateTable + = F_VLN_0, F_VLN_1, F_VLN_2, F_VLN_3, F_VLN_4, F_VLN_5, F_VLN_6, F_VLN_7 + = F_VLN_8, F_VLN_9, F_VLN_10, F_VLN_11, F_VLN_12, F_VLN_13, F_VLN_14, F_VLN_15 + = F_VLN_16, F_VLN_17, F_VLM_18, F_VLM_19, F_VLM_20, F_VLM_21, F_VLN_22, F_VLH_23 + = F_VLN_24, F_VLM_25, F_VLM_26, F_VLM_27, F_VLM_28, F_VLM_29, F_VLM_30, F_VLM_31 + = F_VLM_32, F_VLN_33, F_VLN_34, F_VLN_35, F_VLN_36, F_VLM_37, F_VLM_38, F_VLM_39 + = F_VLM_40, F_VLM_41, F_VLM_42, F_VLM_43, F_VLM_44, F_VLM_45, F_VLM_46, F_VLM_47 + = F_VLM_48, F_VLM_49 + ASSERT . - FrameRateTable = NumModes + ALIGN + + ] + +Vwstab + & VW_0 - Vwstab ; MODE 0 + & VW_1 - Vwstab ; MODE 1 + & VW_2 - Vwstab ; MODE 2 + & VW_3 - Vwstab ; MODE 3 + & VW_4 - Vwstab ; MODE 4 + & VW_5 - Vwstab ; MODE 5 + & VW_6 - Vwstab ; MODE 6 + & VW_7 - Vwstab ; MODE 7 + & VW_8 - Vwstab ; MODE 8 + & VW_9 - Vwstab ; MODE 9 + & VW_10 - Vwstab ; MODE 10 + & VW_11 - Vwstab ; MODE 11 + & VW_12 - Vwstab ; MODE 12 + & VW_13 - Vwstab ; MODE 13 + & VW_14 - Vwstab ; MODE 14 + & VW_15 - Vwstab ; MODE 15 + & VW_16 - Vwstab ; MODE 16 + & VW_17 - Vwstab ; MODE 17 + & VW_18 - Vwstab ; MODE 18 + & VW_19 - Vwstab ; MODE 19 + & VW_20 - Vwstab ; MODE 20 + & VW_21 - Vwstab ; MODE 21 + & VW_22 - Vwstab ; MODE 22 (new mode for visually handicapped) + & VW_23 - Vwstab ; MODE 23 + & VW_24 - Vwstab ; MODE 24 + & VW_25 - Vwstab ; MODE 25 + & VW_26 - Vwstab ; MODE 26 + & VW_27 - Vwstab ; MODE 27 + & VW_28 - Vwstab ; MODE 28 + & VW_29 - Vwstab ; MODE 29 exp + & VW_30 - Vwstab ; MODE 30 exp + & VW_31 - Vwstab ; MODE 31 + & VW_32 - Vwstab ; MODE 32 + & VW_33 - Vwstab ; MODE 33 + & VW_34 - Vwstab ; MODE 34 + & VW_35 - Vwstab ; MODE 35 + & VW_36 - Vwstab ; MODE 36 + & VW_37 - Vwstab ; MODE 37 + & VW_38 - Vwstab ; MODE 38 + & VW_39 - Vwstab ; MODE 39 + & VW_40 - Vwstab ; MODE 40 + & VW_41 - Vwstab ; MODE 41 + & VW_42 - Vwstab ; MODE 42 + & VW_43 - Vwstab ; MODE 43 + & VW_44 - Vwstab ; MODE 44 + & VW_45 - Vwstab ; MODE 45 + & VW_46 - Vwstab ; MODE 46 + & VW_47 - Vwstab ; MODE 47 + & VW_48 - Vwstab ; MODE 48 + & VW_49 - Vwstab ; MODE 49 + +; To change the order of mode variables, change the following:- +; a) The order of the 'wk' labels below +; b) The order of the output variables in macro VWSTAB below +; c) The order of the variables in '$.Hdr.Workspace' and '$.Hdr.NewSpace' + + ^ 0 +wkstart # 0 +wkScreenSize # 4 +wkXWindLimit # 4 +wkYWindLimit # 4 +wkLineLength # 4 +wkNColour # 4 ; DDV; defined to be a word (17-Sep-92) +wkmiddle # 0 +wkYShftFactor # 4 +wkModeFlags # 4 +wkXEigFactor # 4 +wkYEigFactor # 4 +wkLog2BPC # 4 +wkLog2BPP # 4 +wkECFIndex # 4 +wkmidend # 0 +wkScrRCol # 4 +wkScrBRow # 4 +wkdispstart # 0 +wkPalIndex # 4 +wkend # 0 +wksize * wkend-wkstart +wkwordsize * (wksize + 3) :AND: :NOT: 3 +wklim * wksize-(wkmiddle-wkstart) + + [ VIDC_Type = "VIDC20" +VIDCParmsSize * (128*4) ; 128 words from 80xxxxxx to FFxxxxxx step 01000000 + | +VIDCParmsSize * (32*4) ; 32 words from 80xxxxxx to FCxxxxxx step 04000000 + ] + +PushedInfoSize * wkwordsize + VIDCParmsSize + +M22S * 1280*976/8 ; screen size +M23S * 1152*896/8 +M25S * 640*480/8 +M31S * 800*600/8 +M37S * 896*352/8 +M41S * 640*352/8 +M44S * 640*200/8 +M47S * 360*480/8 + + MACRO +$label VWSTAB1 $BaseMode, $ScreenSize,$LineLength,$XWindLimit,$YWindLimit,$YShftFactor, $XEigFactor,$YEigFactor,$NColour,$ScrRCol,$ScrBRow,$Log2BPC,$Log2BPP,$PalIndex, $ECFIndex,$ModeFlags +$label + LCLS ScrSize + LCLA xres + LCLA yres + LCLA pixdepth + LCLA yeig + LCLA scrsz + [ ("$ScreenSize" :RIGHT: 1) = "K" +ScrSize SETS ("$ScreenSize" :LEFT: ((:LEN: "$ScreenSize")-1)) +scrsz SETA $ScrSize * 1024 + | +scrsz SETA $ScreenSize + ] + & scrsz + & $XWindLimit, $YWindLimit, $LineLength, $NColour + & $YShftFactor, $ModeFlags, $XEigFactor, $YEigFactor + & $Log2BPC, $Log2BPP, $ECFIndex + & $ScrRCol, $ScrBRow, $PalIndex + ALIGN + [ MakeModeSelectorsForModeNumbers +xres SETA (($XWindLimit+1):SHL:($Log2BPC)):SHR:($Log2BPP) +yres SETA ($YWindLimit)+1 +pixdepth SETA $Log2BPP + [ yres < xres/2 +yeig SETA 2 + | +yeig SETA 1 + ] + +ModeSelector_$label + & 1, xres, yres, pixdepth + & -1 ; frame rate (is this going to be OK?) + [ {FALSE} ; don't need any of this stuff - we're only getting the VIDC stuff via this mechanism + [ ($ModeFlags)<>0 + & VduExt_ModeFlags, $ModeFlags + ] + [ ($ScrRCol) <> (xres :SHR: 3)-1 + & VduExt_ScrRCol, $ScrRCol + ] + [ ($ScrBRow) <> (yres :SHR: 3)-1 + & VduExt_ScrBRow, $ScrBRow + ] + [ ($NColour) <> NColour_$Log2BPP + & VduExt_NColour, $NColour + ] + [ ($XEigFactor) <> 1 + & VduExt_XEigFactor, $XEigFactor + ] + [ ($YEigFactor) <> yeig + & VduExt_YEigFactor, $YEigFactor + ] + [ ($LineLength) <> (xres :SHL: pixdepth) :SHR: 3 + & VduExt_LineLength, $LineLength + ] + [ scrsz <> ((xres * yres) :SHL: pixdepth) :SHR: 3 + & VduExt_ScreenSize, scrsz + ] + [ ($Log2BPC) <> pixdepth + & VduExt_Log2BPC, $Log2BPC + ] + ] + & -1 ; terminator + ] + MEND + + MACRO +$label VWSTAB2 $BaseMode, $ScreenSize,$LineLength,$XWindLimit,$YWindLimit,$YShftFactor, $XEigFactor,$YEigFactor,$NColour,$ScrRCol,$ScrBRow,$Log2BPC,$Log2BPP,$PalIndex, $ECFIndex,$ModeFlags +$label + LCLS ScrSize + & 0 ; wslist type (default) + & $BaseMode + [ ("$ScreenSize" :RIGHT: 1) = "K" +ScrSize SETS ("$ScreenSize" :LEFT: ((:LEN: "$ScreenSize")-1)) + & VduExt_ScreenSize, $ScrSize * 1024 + | + & VduExt_ScreenSize, $ScreenSize + ] + & VduExt_LineLength, $LineLength + & VduExt_XWindLimit, $XWindLimit + & VduExt_YWindLimit, $YWindLimit + & VduExt_YShftFactor, $YShftFactor + & VduExt_XEigFactor, $XEigFactor + & VduExt_YEigFactor, $YEigFactor + & VduExt_NColour, $NColour + & VduExt_ScrRCol, $ScrRCol + & VduExt_ScrBRow, $ScrBRow + & VduExt_Log2BPC, $Log2BPC + & VduExt_Log2BPP, $Log2BPP + & VduExt_ModeFlags, $ModeFlags + & -1 + MEND + + MACRO +$label VWSTAB $BaseMode, $ScreenSize,$LineLength,$XWindLimit,$YWindLimit,$YShftFactor, $XEigFactor,$YEigFactor,$NColour,$ScrRCol,$ScrBRow,$Log2BPC,$Log2BPP,$PalIndex, $ECFIndex,$ModeFlags + [ AssemblingArthur +$label VWSTAB1 $BaseMode, $ScreenSize,$LineLength,$XWindLimit,$YWindLimit,$YShftFactor, $XEigFactor,$YEigFactor,$NColour,$ScrRCol,$ScrBRow,$Log2BPC,$Log2BPP,$PalIndex, $ECFIndex,$ModeFlags + | +$label VWSTAB2 $BaseMode, $ScreenSize,$LineLength,$XWindLimit,$YWindLimit,$YShftFactor, $XEigFactor,$YEigFactor,$NColour,$ScrRCol,$ScrBRow,$Log2BPC,$Log2BPP,$PalIndex, $ECFIndex,$ModeFlags + ] + MEND + +VW_0 VWSTAB 0, 20K, 80, 639,255,4,1,2, 1, 79, 31,0,0,0,1,0 ; MODE 0 +VW_1 VWSTAB 1, 20K, 80, 319,255,4,2,2, 3, 39, 31,1,1,1,2,0 ; MODE 1 +VW_2 VWSTAB 2, 40K,160, 159,255,5,3,2,15, 19, 31,3,2,2,3,0 ; MODE 2 +VW_3 VWSTAB 3, 40K,160, 639,249,5,1,2, 1, 79, 24,1,1,0,0,Flag_NonGraphic+Flag_GapMode+Flag_BBCGapMode ; MODE 3 +VW_4 VWSTAB 4, 20K, 80, 319,255,4,2,2, 1, 39, 31,1,0,0,4,0 ; MODE 4 +VW_5 VWSTAB 5, 20K, 80, 159,255,4,3,2, 3, 19, 31,2,1,1,2,0 ; MODE 5 +VW_6 VWSTAB 6, 20K, 80, 319,249,4,2,2, 1, 39, 24,1,1,0,0,Flag_NonGraphic+Flag_GapMode+Flag_BBCGapMode ; MODE 6 +VW_7 VWSTAB 7, 80K,160, 319,249,5,2,2,15, 39, 24,2,2,4,0,Flag_NonGraphic+Flag_GapMode+Flag_Teletext ; MODE 7 +VW_8 VWSTAB 8, 40K,160, 639,255,5,1,2, 3, 79, 31,1,1,1,2,0 ; MODE 8 +VW_9 VWSTAB 9, 40K,160, 319,255,5,2,2,15, 39, 31,2,2,2,3,0 ; MODE 9 +VW_10 VWSTAB 10, 80K,320, 159,255,6,3,2,63, 19, 31,4,3,3,5,0 ; MODE 10 +VW_11 VWSTAB 11, 40K,160, 639,249,5,1,2, 3, 79, 24,1,1,1,2,Flag_GapMode ; MODE 11 +VW_12 VWSTAB 12, 80K,320, 639,255,6,1,2,15, 79, 31,2,2,2,3,0 ; MODE 12 +VW_13 VWSTAB 13, 80K,320, 319,255,6,2,2,63, 39, 31,3,3,3,5,0 ; MODE 13 +VW_14 VWSTAB 14, 80K,320, 639,249,6,1,2,15, 79, 24,2,2,2,3,Flag_GapMode ; MODE 14 +VW_15 VWSTAB 15,160K,640, 639,255,7,1,2,63, 79, 31,3,3,3,5,0 ; MODE 15 +VW_16 VWSTAB 16,132K,528,1055,255,0,1,2,15,131, 31,2,2,2,3,0 ; MODE 16 +VW_17 VWSTAB 17,132K,528,1055,249,0,1,2,15,131, 24,2,2,2,3,Flag_GapMode ; MODE 17 +VW_18 VWSTAB 18, 40K, 80, 639,511,4,1,1, 1, 79, 63,0,0,0,4,0 ; MODE 18 +VW_19 VWSTAB 19, 80K,160, 639,511,5,1,1, 3, 79, 63,1,1,1,2,0 ; MODE 19 +VW_20 VWSTAB 20,160K,320, 639,511,6,1,1,15, 79, 63,2,2,2,3,0 ; MODE 20 +VW_21 VWSTAB 21,320K,640, 639,511,7,1,1,63, 79, 63,3,3,3,5,0 ; MODE 21 +VW_22 VWSTAB 22,108K,384, 767,287,0,0,1,15, 95, 35,2,2,2,3,0 ; MODE 22 +VW_23 VWSTAB 23,M23S,144,1151,895,0,1,1, 1,143, 55,0,0,5,4,Flag_HiResMono+Flag_DoubleVertical ; MODE 23 +VW_24 VWSTAB 24,264K,1056,1055,255,0,1,2,63,131,31,3,3,3,5,0 ; MODE 24 +VW_25 VWSTAB 25,M25S , 80, 639,479,4,1,1, 1, 79, 59,0,0,0,4,0 ; MODE 25 +VW_26 VWSTAB 26,M25S*2,160, 639,479,5,1,1, 3, 79, 59,1,1,1,2,0 ; MODE 26 +VW_27 VWSTAB 27,M25S*4,320, 639,479,6,1,1,15, 79, 59,2,2,2,3,0 ; MODE 27 +VW_28 VWSTAB 28,M25S*8,640, 639,479,7,1,1,63, 79, 59,3,3,3,5,0 ; MODE 28 + +VW_29 VWSTAB 29,M31S ,100, 799,599,0,1,1, 1, 99, 74,0,0,0,4,0 ; MODE 29 +VW_30 VWSTAB 30,M31S*2,200, 799,599,0,1,1, 3, 99, 74,1,1,1,2,0 ; MODE 30 +VW_31 VWSTAB 31,M31S*4,400, 799,599,0,1,1,15, 99, 74,2,2,2,3,0 ; MODE 31 + [ VIDC_Type = "VIDC20" +VW_32 VWSTAB 32,M31S*8,800, 799,599,0,1,1,63, 99, 74,3,3,3,5,0 ; MODE 32 + | +VW_32 * VW_31 + ] + +VW_33 VWSTAB 33, 27K, 96, 767,287,0,1,2, 1, 95, 35,0,0,0,4,0 ; MODE 33 +VW_34 VWSTAB 34, 54K,192, 767,287,0,1,2, 3, 95, 35,1,1,1,2,0 ; MODE 34 +VW_35 VWSTAB 35,108K,384, 767,287,0,1,2,15, 95, 35,2,2,2,3,0 ; MODE 35 +VW_36 VWSTAB 36,216K,768, 767,287,0,1,2,63, 95, 35,3,3,3,5,0 ; MODE 36 + +VW_37 VWSTAB 37,M37S ,112, 895,351,0,1,2, 1,111, 43,0,0,0,4,0 ; MODE 37 +VW_38 VWSTAB 38,M37S*2,224, 895,351,0,1,2, 3,111, 43,1,1,1,2,0 ; MODE 38 +VW_39 VWSTAB 39,M37S*4,448, 895,351,0,1,2,15,111, 43,2,2,2,3,0 ; MODE 39 +VW_40 VWSTAB 40,M37S*8,896, 895,351,0,1,2,63,111, 43,3,3,3,5,0 ; MODE 40 + +VW_41 VWSTAB 41,M41S , 80, 639,351,0,1,2, 1, 79, 43,0,0,0,4,0 ; EGA 1,2,4bpp +VW_42 VWSTAB 42,M41S*2,160, 639,351,0,1,2, 3, 79, 43,1,1,1,2,0 ; +VW_43 VWSTAB 43,M41S*4,320, 639,351,0,1,2,15, 79, 43,2,2,2,3,0 ; 640x352 + +VW_44 VWSTAB 44,M44S , 80, 639,199,0,1,2, 1, 79, 24,0,0,0,4,0 ; CGA 1,2,4bpp +VW_45 VWSTAB 45,M44S*2,160, 639,199,0,1,2, 3, 79, 24,1,1,1,2,0 ; +VW_46 VWSTAB 46,M44S*4,320, 639,199,0,1,2,15, 79, 24,2,2,2,3,0 ; 640x200 + +VW_47 VWSTAB 47,M47S*8,360, 359,479,0,2,2,63, 89, 59,3,3,3,5,0 ; PCSoft 360 x 480 x 8bpp +VW_48 VWSTAB 48, 75K,160, 319,479,0,2,1,15, 39, 59,2,2,2,3,0 ; Games 320 x 480 x 4bpp +VW_49 VWSTAB 49, 150K,320, 319,479,0,2,1,63, 39, 59,3,3,3,5,0 ; Games 320 x 480 x 8bpp + +; $BaseMode $YShftFactor $ScrBRow $ModeFlags +; $ScreenSize $XEigFactor $Log2BPC +; $LineLength $YEigFactor $Log2BPP +; $XWindLimit $NColour $PalIndex +; $YWindLimit $ScrRCol $ECFIndex + + [ MakeModeSelectorsForModeNumbers +ModeSelectorTable + GBLA modecount + GBLS h + GBLS l +modecount SETA 0 + ASSERT NumModes <= 100 + WHILE modecount < NumModes + [ modecount >= 10 +h SETS :CHR:(&30 + modecount/10) + | +h SETS "" + ] +l SETS :CHR:(&30 + modecount :MOD: 10) + & ModeSelector_VW_$h$l-ModeSelectorTable +modecount SETA modecount + 1 + WEND + + ! 0, "Mode selector table at ":CC: :STR: ModeSelectorTable + ] + + END diff --git a/s/vdu/vdupal10 b/s/vdu/vdupal10 new file mode 100644 index 0000000000000000000000000000000000000000..02bfdf8a4818f679b3bb40c0fe60045526ca3030 --- /dev/null +++ b/s/vdu/vdupal10 @@ -0,0 +1,595 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > VduPal10 + +; Palette programming for VIDC10 (ie VIDC1 or VIDC1a) + +; ***************************************************************************** + +; PaletteV handler +; ---------------- + +; ***************************************************************************** +; +; MOSPaletteV - Default owner of PaletteV +; + + ASSERT paletteV_Complete = 0 + ASSERT paletteV_Read = 1 + ASSERT paletteV_Set = 2 + ASSERT paletteV_1stFlashState = 3 + ASSERT paletteV_2ndFlashState = 4 + ASSERT paletteV_SetDefaultPalette = 5 + ASSERT paletteV_BlankScreen = 6 + +MOSPaletteV ROUT + CMP r4, #1 + MOVCCS pc, lr + BEQ PV_ReadPalette + CMP r4, #3 + BCC PV_SetPalette + BEQ PV_1stFlashState + CMP r4, #5 + BCC PV_2ndFlashState + BEQ PV_SetDefaultPalette + CMP r4, #7 + BCC PV_BlankScreen + MOVS pc, lr ; reason code not known, so pass it on + +; ***************************************************************************** + +PV_SetDefaultPalette ROUT + Push "r0-r3,r5-r9" + LDR r0, [WsPtr, #PalIndex] ; the new index 0-5 + ADR r1, paldptab + LDR r2, [r1, r0, LSL #2] ; offset from r1 to start of table + ADD r0, r0, #1 ; point to next item + LDR r5, [r1, r0, LSL #2] ; offset from r1 to end of table +1 + ADD r2, r2, r1 ; r2 -> start of table + ADD r5, r5, r1 ; r5 -> end of table + MOV r0, #0 ; start at palette index 0 + MOV r1, #3 ; set both halves +10 + LDR r6, [r2], #4 + MOVS r3, r6, LSL #17 ; get 1st half word and set carry if flashing + MOV r3, r3, LSR #17 + MOVCC r4, #0 + LDRCS r4, =&FFF ; flashing so invert 2nd half RGB + BL UpdateSettingStraightRGB + ADD r0, r0, #1 + MOVS r3, r6, LSL #1 ; get 2nd half word and set carry if flashing + MOV r3, r3, LSR #17 + MOVCC r4, #0 + LDRCS r4, =&FFF + BL UpdateSettingStraightRGB + ADD r0, r0, #1 + TEQ r2, r5 + BNE %BT10 + +; now ensure all palette entries from 0..15 are initialised + + MOV r3, #0 ; set unused (and border) to black + MOV r4, #0 ; no flashing +20 + CMP r0, #16 + BLCC UpdateSettingStraightRGB + ADDCC r0, r0, #1 + BCC %BT20 + + MOV r2, #0 ; Set border to black (sup 0) + BL BorderInitEntry + + MOV r4, #0 ; indicate PaletteV operation complete + Pull "r0-r3,r5-r9,pc" ; restore registers and claim vector + + LTORG + +; ***************************************************************************** + +; Table of offsets from paldata_pointer to palette data + +paldptab + & paldat1-paldptab ; 2 Colour Modes + & paldat2-paldptab ; 4 + & paldat4-paldptab ; 16 + & paldat8-paldptab ; 256 + & paldatT-paldptab ; teletext mode + & paldatHR-paldptab ; Hi-res mono mode + & paldatend-paldptab ; end of table marker + +paldat1 ; Data for 1 bit modes - only necessary to program registers 0 and 1 + +; FSBGR + + DCW &0000 ; 0 Black + DCW &0FFF ; 1 White + +paldat2 ; Data for 2 bit modes - only necessary to program registers 0..3 + +; FSBGR + + DCW &0000 ; 0 Black + DCW &000F ; 1 Red + DCW &00FF ; 2 Yellow + DCW &0FFF ; 3 White + +paldat4 ; Data for 4 bit modes - program all registers + ; Flashing Colours will be needed here + +; FSBGR + + DCW &0000 ; 0 Black + DCW &000F ; 1 Red + DCW &00F0 ; 2 Green + DCW &00FF ; 3 Yellow + DCW &0F00 ; 4 Blue + DCW &0F0F ; 5 Magenta + DCW &0FF0 ; 6 Cyan + DCW &0FFF ; 7 White + DCW &8000 ; 8 Flashing Black + DCW &800F ; 9 Flashing Red + DCW &80F0 ; 10 Flashing Green + DCW &80FF ; 11 Flashing Yellow + DCW &8F00 ; 12 Flashing Blue + DCW &8F0F ; 13 Flashing Magenta + DCW &8FF0 ; 14 Flashing Cyan + DCW &8FFF ; 15 Flashing White + +paldat8 ; Data for 8 bit modes - Program all registers + ; PP field is 16 for all these, cos not true BBC colours + +; FSBGR + + DCW &0000 ; 0 + DCW &0111 ; 1 + DCW &0222 ; 2 + DCW &0333 ; 3 + DCW &0004 ; 4 + DCW &0115 ; 5 + DCW &0226 ; 6 + DCW &0337 ; 7 + DCW &0400 ; 8 + DCW &0511 ; 9 + DCW &0622 ; A + DCW &0733 ; B + DCW &0404 ; C + DCW &0515 ; D + DCW &0626 ; E + DCW &0737 ; F + +paldatT ; Data for teletext mode + + DCW &0000 ; 0 Black + DCW &000F ; 1 Red + DCW &00F0 ; 2 Green + DCW &00FF ; 3 Yellow + DCW &0F00 ; 4 Blue + DCW &0F0F ; 5 Magenta + DCW &0FF0 ; 6 Cyan + DCW &0FFF ; 7 White + +; Colours 8 to 15 have supremacy bit set + + DCW &1000 ; 8 Supremacy+ Black + DCW &100F ; 9 Red + DCW &10F0 ; 10 Green + DCW &10FF ; 11 Yellow + DCW &1F00 ; 12 Blue + DCW &1F0F ; 13 Magenta + DCW &1FF0 ; 14 Cyan + DCW &1FFF ; 15 White + +paldatHR ; data for Hi-res mono mode + DCW &0000 ; Only red gun necessary + DCW &0111 ; but setting all three makes + DCW &0222 ; reading it more natural + DCW &0333 + DCW &0444 + DCW &0555 + DCW &0666 + DCW &0777 + DCW &0888 + DCW &0999 + DCW &0AAA + DCW &0BBB + DCW &0CCC + DCW &0DDD + DCW &0EEE + DCW &0FFF + + DCW &0000 ; border black + DCW &0010 ; fixed pointer colours + DCW &0020 + DCW &0030 +paldatend + + +; ***************************************************************************** + +; PaletteV call to set palette +; in: R0 = logical colour +; R1 = colour type (16,17,18,24,25) +; R2 = BBGGRRS0 +; R4 = PaletteV reason code +; +; out: R4 = 0, claim vector if recognised +; otherwise preserve R4 and pass on +; + +PV_SetPalette ROUT + Push "r0-r3" + TEQ r1, #16 ; if 16 then set both colours + MOVEQ r1, #3 + BEQ UpdateNormalColour + + TEQ r1, #17 ; elif 17 then set 1st colour + MOVEQ r1, #1 + BEQ UpdateNormalColour + + TEQ r1, #18 ; elif 18 then set 2nd colour + MOVEQ r1, #2 + BEQ UpdateNormalColour + + TEQ r1, #24 ; elif 24 then border colour + BEQ BorderColour + + TEQ r1, #25 ; elif 25 then pointer colour + BEQ PointerColour + + Pull "r0-r3" + MOVS pc, lr ; else not defined + +; ***************************************************************************** + +UpdateNormalColour ROUT + LDR lr, [WsPtr, #DisplayNColour] ; get the mask + AND r0, r0, lr ; and mask it off + AND r0, r0, #15 ; maximum 15 + BL UpdateSettingAndVIDC + MOV r4, #0 ; indicate successful PaletteV op + Pull "r0-r3, pc" + +BorderInitEntry ENTRY "r0-r3" ; entry used in default palette setting +BorderColour ROUT + LDR r0, [WsPtr, #PalIndex] ; if hi res mono + TEQ r0, #5 + BICEQ r2, r2, #&00300000 ; then knock out bits 0,1 of green palette + + MOV r0, #16 ; palette index for border colour + MOV r1, #3 ; both colours + BL UpdateSettingAndVIDC + +; Now test for BBC gap mode (ie 3 or 6) +; if so then set colour 2 to same as border, and colour 3 to inverse + + LDR lr, [WsPtr, #DisplayModeFlags] + TST lr, #Flag_BBCGapMode + BEQ %FT10 + + MOV r0, #2 ; make colour 2 (gap) same as border + BL UpdateSettingAndVIDC + + MOV r0, #3 ; make colour 3 inverse gap + MVN r2, r2 ; invert R, G and B + EOR r2, r2, #&FF ; but use same supremacy + BL UpdateSettingAndVIDC +10 + MOV r4, #0 ; indicate successful PaletteV op + Pull "r0-r3, pc" + + +PointerColour ROUT + LDR r1, [WsPtr, #PalIndex] ; if hi res mono, then don't allow + TEQ r1, #5 ; pointer palette changes + ANDNES r0, r0, #3 ; force pointer colour number in range 1..3 + BEQ %FT10 ; zero is invalid + ADD r0, r0, #16 ; form palette index 17..19 + MOV r1, #3 + BL UpdateSettingAndVIDC +10 + MOV r4, #0 ; indicate successful PaletteV op + Pull "r0-r3,pc" + +UpdateSettingAndVIDC ROUT + AND r4, r2, #&F0000000 + MOV r3, r4, LSR #(28-8) ; move blue to bits 8..11 + AND r4, r2, #&00F00000 + ORR r3, r3, r4, LSR #(20-4) ; move green to bits 4..7 + AND r4, r2, #&0000F000 + ORR r3, r3, r4, LSR #(12-0) ; move red to bits 0..3 + AND r4, r2, #&00000080 + ORR r3, r3, r4, LSL #(12-7) ; move sup to bit 12 + + CMP r0, #16 ; if not normal colour + BCS %FT10 ; then OK for hi-res-mono + LDR r4, [WsPtr, #PalIndex] + TEQ r4, #5 + BEQ UpdateHiResRGB +10 + MOV r4, #0 ; indicate no EORing between parts + +; and drop thru to ... + +UpdateSettingStraightRGB ENTRY "r2,r5,r6" + PHPSEI ; protect against IRQs + ORR r3, r3, r0, LSL #26 ; form VIDC register number at top + LDRB r5, [WsPtr, #ScreenBlankFlag] + TEQ r5, #0 + MOVNE r5, #&00FFFFFF ; bits to knock out if blanked + + LDROSB r2, FlashState ; 0 => second, 1 => first + CMP r2, #1 ; C=0 => second, C=1 => first + + TST r1, #1 + BEQ %FT10 ; skip if not setting 1st colour + ADD r2, WsPtr, #FirPalSetting + STR r3, [r2, r0, LSL #2] + MOVCS r2, #VIDC + BICCS r6, r3, r5 ; knock out bits for blanking + STRCS r6, [r2] ; poke VIDC if setting 1st colour and in 1st state +10 + TST r1, #2 + BEQ %FT20 ; skip if not setting 2nd colour + ADD r2, WsPtr, #SecPalSetting + EOR r3, r3, r4 ; toggle requested bits for 2nd half + STR r3, [r2, r0, LSL #2] + MOVCC r2, #VIDC + BICCC r6, r3, r5 ; knock out bits for blanking + STRCC r6, [r2] ; poke VIDC if setting 2nd colour and in 2nd state +20 + PLP + EXITS ; restore registers, claim vector + +; ***************************************************************************** +; +; UpdateHiResRGB - Routine to program normal palette for Hi-Res-Mono display +; +; in: r0 = logical colour +; r1 = mask of which states to update (bit 0 = 1st flash state, bit 1 = 2nd) +; r3 = &0000SBGR +; +; out: r3, r4 may be corrupted +; + +UpdateHiResRGB ENTRY "r5" + PHPSEI + Push "lr" + LDROSB r5, FlashState + TEQ r5, #0 ; 0 => 2nd state, 1 => 1st state + MOVNE r5, #VIDC ; 1st state => r5 = VIDC, else = 0 + + TST r1, #1 + ADDNE r4, WsPtr, #FirPalSetting + BLNE UpdateOneHiResSetting + + EOR r5, r5, #VIDC ; 2nd state => r5 = VIDC, else = 0 + TST r1, #2 + ADDNE r4, WsPtr, #SecPalSetting + BLNE UpdateOneHiResSetting + Pull "lr" + PLP + EXITS + +UpdateOneHiResSetting ENTRY "r1,r2,r6-r9" + LDRB lr, [WsPtr, #ScreenBlankFlag] + TEQ lr, #0 + MOVNE lr, #&00FFFFFF ; if blanked, mask off these bits + + LDR r2, =&FFF + TEQ r0, #0 + MOVEQ r1, r3 ; if programming colour 0 then 1st colour is r3 + LDREQ r6, [r4, #15*4] ; and 2nd colour is what's in colour 15 + LDRNE r1, [r4, #0*4] ; else 1st colour is what's in colour 0 + MOVNE r6, r3 ; and 2nd colour is r3 + + EOR r6, r6, #&008 ; invert bit R3 of colour 15 + EOR r6, r6, r1 ; inverted EOR of colours 0 and 15 + ANDS r6, r6, #&008 ; just use R3 for black/white + MOVNE r6, r2 ; if non-zero make BIC mask full RGB else 0 + ANDS r1, r1, #&008 ; if colour 0 = white then make EOR mask full RGB else 0 + MOVNE r1, r2 + + ADD r7, r4, #16*4 ; end of table + MOV r8, #0 ; start + LDR r2, =&04000111 ; amount to add on each time round + +10 + BIC r9, r8, r6 ; take value and knock out BIC mask + EOR r9, r9, r1 ; then toggle EOR mask + STR r9, [r4], #4 ; store in soft copy + TEQ r5, #0 ; if updating VIDC + BICNE r9, r9, lr ; knock out bits (for blanking) + STRNE r9, [r5] ; then do it + ADD r8, r8, r2 ; move on to next value + TEQ r4, r7 ; if not done all 16 entries + BNE %BT10 ; then loop + + EXITS + + LTORG + +; ***************************************************************************** +; +; PV_ReadPalette - PaletteV read palette handler +; +; in: R0 = logical colour +; R1 = 16 (read normal colour) +; 24 (read border colour) +; 25 (read cursor colour) +; +; out: R2 = first flash setting (BBGGRRS0), supremacy bit 7 +; R3 = second flash setting (BBGGRRS0), supremacy bit 7 +; + +PV_ReadPalette ROUT + Push "r10,r11" + LDR r10, [WsPtr, #DisplayNColour] ; logical colours in this mode -1 + TEQ r1, #24 ; is it reading border palette + MOVEQ r11, #16 ; then set up border index + BEQ %FT10 ; and go + + TEQ r1, #25 ; is it reading pointer palette + BEQ %FT05 + AND r11, r0, r10 ; no, then force into suitable range + AND r11, r11, #15 ; only allow 0..15 + LDR r2, [WsPtr, #PalIndex] + TEQ r2, #5 ; if hi res mono + TEQEQ r11, #1 ; and reading colour 1 + MOVEQ r11, #15 ; then read colour 15 instead + B %FT10 ; always skip +05 + ANDS r11, r0, #3 ; else force logical colour 0..3 + BEQ %FT99 ; and 0 is illegal, so do nothing + ADD r11, r11, #16 ; set up correct index +10 + CMP r11, #16 ; is it normal one (not border/cursor) + MOVCSS r3, #0 ; no, then don't fudge colours; Z=1 + ; (carry preserved from CMP) + ANDCCS r3, r10, #&F0 ; yes, then fudge if 256 colour mode + + ADD r10, WsPtr, #FirPalSetting + + LDR r11, [r10, r11, LSL #2]! ; r11 := 1st XX00SBGR + BLNE FudgeRGB + + AND lr, r11, #&F00 ; lr := 1st 00000B00 + MOV r2, lr, LSL #20 ; r2 := 1st B0000000 + AND lr, r11, #&0F0 ; lr := 1st 000000G0 + ORR r2, r2, lr, LSL #16 ; r2 := 1st B0G00000 + AND lr, r11, #&00F ; lr := 1st 0000000R + ORR r2, r2, lr, LSL #12 ; r2 := 1st B0G0R000 + ORR r2, r2, r2, LSR #4 ; r2 := 1st BBGGRR00 + AND lr, r11, #&1000 + ORR r2, r2, lr, LSR #5 ; r2 := 1st BBGGRRS0 + + LDR r11, [r10, #SecPalSetting-FirPalSetting] + BLNE FudgeRGB + + AND lr, r11, #&F00 ; lr := 2nd 00000B00 + MOV r3, lr, LSL #20 ; r3 := 2nd B0000000 + AND lr, r11, #&0F0 ; lr := 2nd 000000G0 + ORR r3, r3, lr, LSL #16 ; r3 := 2nd B0G00000 + AND lr, r11, #&00F ; lr := 2nd 0000000R + ORR r3, r3, lr, LSL #12 ; r3 := 2nd B0G0R000 + ORR r3, r3, r3, LSR #4 ; r3 := 2nd BBGGRR00 + AND lr, r11, #&1000 + ORR r3, r3, lr, LSR #5 ; r3 := 2nd BBGGRRS0 +99 + MOV r4, #0 + Pull "r10, r11, pc" + +FudgeRGB ROUT + BIC r11, r11, #&C8 ; knock out top bit R, top 2 bits G + BIC r11, r11, #&800 ; knock out top bit B + + TST r0, #&10 ; override top bit of red + ORRNE r11, r11, #&8 + TST r0, #&20 ; override next to top bit of green + ORRNE r11, r11, #&40 + TST r0, #&40 ; override top bit of green + ORRNE r11, r11, #&80 + TST r0, #&80 ; override top bit of blue + ORRNE r11, r11, #&800 + MOVS pc, lr + +; ***************************************************************************** +; +; PV_1stFlashState - PaletteV routine to set first flash state +; + +PV_1stFlashState ROUT + Push "r0-r3" + ADD r0, WsPtr, #FirPalSetting +DoR0Flash + MOV r1, #15 ; logical colour +DoAllUpdate + LDRB lr, [WsPtr, #ScreenBlankFlag] + TEQ lr, #0 + MOVEQ lr, #&FF000000 ; unblanked, just knock off top 8 bits + MOVNE lr, #&FFFFFFFF ; blanked, knock off all bits! + MOV r2, #VIDC +10 + LDR r3, [r0, r1, LSL #2] + BIC r3, r3, lr ; get rid of top bits, or all if blanked + ORR r3, r3, r1, LSL #26 ; OR in register number + STR r3, [r2] ; program VidC + SUBS r1, r1, #1 + BPL %BT10 + + MOV r4, #0 + Pull "r0-r3, pc" + +; ***************************************************************************** +; +; PV_2ndFlashState - PaletteV routine to set second flash state +; + +PV_2ndFlashState ROUT + Push "r0-r3" + ADD r0, WsPtr, #SecPalSetting + B DoR0Flash + +; ***************************************************************************** +; +; UpdateAllPalette - Update all VIDC palette entries +; + +UpdateAllPalette ENTRY "r0-r3" ; "r0-r3,lr" stacked ready to branch to code + LDROSB r0, FlashState + CMP r0, #1 + ADDCS r0, WsPtr, #FirPalSetting ; FlashState = 1 => 1st state, 0 => 2nd state + ADDCC r0, WsPtr, #SecPalSetting + MOV r1, #19 ; do 0-15 and border + 3 pointer + B DoAllUpdate + +; ***************************************************************************** +; +; PV_BlankScreen - Blank/unblank screen +; +; in: R0 = -1 => read blank state +; R0 = 0 => unblank screen +; R0 = 1 => blank screen +; +; out: R0 = old state (0=unblanked, 1=blanked) +; R4 = 0 + +PV_BlankScreen ROUT + Push "r1-r3" + LDRB r3, [WsPtr, #ScreenBlankFlag] + CMP r0, #1 + BHI %FT99 + + TEQ r0, r3 ; changing to same state? (carry preserved) + BEQ %FT99 ; if so, do nothing + + STRB r0, [WsPtr, #ScreenBlankFlag] ; update new state + + MOVCC r0, #(1 :SHL: 10) :OR: (0 :SHL: 8) ; unblank: video DMA on, no refresh + MOVCS r0, #(0 :SHL: 10) :OR: (3 :SHL: 8) ; blank: video DMA off, continuous refresh + MOV r1, #(1 :SHL: 10) :OR: (3 :SHL: 8) ; bits to modify + SWI XOS_UpdateMEMC + + MOV r0, pc + ORR lr, r0, #I_bit ; disable IRQs so we don't get a flash in the middle + TEQP lr, #0 + BL UpdateAllPalette ; update all palette, including border + pointer + TEQP r0, #0 ; restore old IRQ state +99 + MOV r0, r3 + MOV r4, #0 + Pull "r1-r3, pc" + + + END diff --git a/s/vdu/vdupal20 b/s/vdu/vdupal20 new file mode 100644 index 0000000000000000000000000000000000000000..1e8d48285b060d8818dcb56d1a2ea14e44083a55 --- /dev/null +++ b/s/vdu/vdupal20 @@ -0,0 +1,1013 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > VduPal20 + +; Palette programming for VIDC20 + +; ***************************************************************************** + +; PaletteV handler +; ---------------- + +; ***************************************************************************** +; +; MOSPaletteV - Default owner of PaletteV +; + + ASSERT paletteV_Complete = 0 + ASSERT paletteV_Read = 1 + ASSERT paletteV_Set = 2 + ASSERT paletteV_1stFlashState = 3 + ASSERT paletteV_2ndFlashState = 4 + ASSERT paletteV_SetDefaultPalette = 5 + ASSERT paletteV_BlankScreen = 6 + ASSERT paletteV_BulkRead = 7 + ASSERT paletteV_BulkWrite = 8 + [ GammaCorrection + ASSERT paletteV_GammaCorrection = 9 + ] + +MOSPaletteV ROUT + CMP r4, #1 + MOVCCS pc, lr + BEQ PV_ReadPalette + CMP r4, #3 + BCC PV_SetPalette + BEQ PV_1stFlashState + CMP r4, #5 + BCC PV_2ndFlashState + BEQ PV_SetDefaultPalette + CMP r4, #7 + BCC PV_BlankScreen + BEQ PV_BulkRead + CMP r4, #9 + BCC PV_BulkWrite + + [ GammaCorrection + BEQ PV_GammaCorrect + ] + MOVS pc, lr ; reason code not known, so pass it on + +; ***************************************************************************** + +PV_SetDefaultPalette ROUT + Push "r0-r3,r5-r9" + LDR r0, [WsPtr, #PalIndex] ; the new index 0-7 + ADR r1, paldptab + LDR r2, [r1, r0, LSL #2] ; offset from r1 to start of table + ADD r0, r0, #1 ; point to next item + LDR r5, [r1, r0, LSL #2] ; offset from r1 to end of table +1 + ADDS r2, r2, r1 ; r2 -> start of table + BICMI pc, r2, #&80000000 ; if negative then it's a routine + ADD r5, r5, r1 ; r5 -> end of table + BIC r5, r5, #&80000000 + MOV r0, #0 ; start at palette index 0 + MOV r1, #3 ; set both halves +10 + LDR r6, [r2], #4 + MOVS r3, r6, LSL #17 ; get 1st half word and set carry if flashing + MOV r3, r3, LSR #17 + MOVCC r4, #0 + LDRCS r4, =&FFF ; flashing so invert 2nd half RGB + BL UpdateSettingStraightRGB + ADD r0, r0, #1 + MOVS r3, r6, LSL #1 ; get 2nd half word and set carry if flashing + MOV r3, r3, LSR #17 + MOVCC r4, #0 + LDRCS r4, =&FFF + BL UpdateSettingStraightRGB + ADD r0, r0, #1 + TEQ r2, r5 + BNE %BT10 + +; now ensure all palette entries from 0..255 are initialised + + MOV r3, #0 ; set unused (and border) to black + MOV r4, #0 ; no flashing +20 + CMP r0, #256 + BLCC UpdateSettingStraightRGB + ADDCC r0, r0, #1 + BCC %BT20 + +FinishDefault + MOV r2, #0 ; set border to black (and setup colours 2,3 in BBC gap modes) + BL BorderInitEntry + + MOV r4, #0 ; indicate PaletteV operation complete + Pull "r0-r3,r5-r9,pc" ; restore registers and claim vector + + LTORG + +; ***************************************************************************** + +; Table of offsets from paldata_pointer to palette data + +paldptab + & paldat1-paldptab ; 2 Colour Modes + & paldat2-paldptab ; 4 + & paldat4-paldptab ; 16 + & (paldat8-paldptab) :OR: &80000000 ; 256 (VIDC10 compatible) - use routine + & paldatT-paldptab ; teletext mode + & paldatHR-paldptab ; Hi-res mono mode + & (paldat16-paldptab) :OR: &80000000 ; 16 bpp - use routine + & (paldat32-paldptab) :OR: &80000000 ; 32 bpp (or 256 greys - they're identical!) - use routine + & paldatend-paldptab ; end of table marker + +paldat1 ; Data for 1 bit modes - only necessary to program registers 0 and 1 + +; FSBGR + + DCW &0000 ; 0 Black + DCW &0FFF ; 1 White + +paldat2 ; Data for 2 bit modes - only necessary to program registers 0..3 + +; FSBGR + + DCW &0000 ; 0 Black + DCW &000F ; 1 Red + DCW &00FF ; 2 Yellow + DCW &0FFF ; 3 White + +paldat4 ; Data for 4 bit modes - program all registers + ; Flashing Colours will be needed here + +; FSBGR + + DCW &0000 ; 0 Black + DCW &000F ; 1 Red + DCW &00F0 ; 2 Green + DCW &00FF ; 3 Yellow + DCW &0F00 ; 4 Blue + DCW &0F0F ; 5 Magenta + DCW &0FF0 ; 6 Cyan + DCW &0FFF ; 7 White + DCW &8000 ; 8 Flashing Black + DCW &800F ; 9 Flashing Red + DCW &80F0 ; 10 Flashing Green + DCW &80FF ; 11 Flashing Yellow + DCW &8F00 ; 12 Flashing Blue + DCW &8F0F ; 13 Flashing Magenta + DCW &8FF0 ; 14 Flashing Cyan + DCW &8FFF ; 15 Flashing White + +; Routine to initialise palette for VIDC10-compatible 8bpp modes +; Note this must still be in between paldat4 and paldatT + +paldat8 ROUT + MOV r1, #3 ; set both halves of palette + MOV r0, #0 ; starting index +10 + AND r2, r0, #3 ; get tint bits + ORR r2, r2, r2, LSL #4 ; and duplicate into bits 8,9,12,13,16,17,20,21,24,25,28,29 + ORR r2, r2, r2, LSL #8 + ORR r2, r2, r2, LSL #16 + BIC r2, r2, #&FF + TST r0, #4 + ORRNE r2, r2, #&00004400 + TST r0, #8 + ORRNE r2, r2, #&44000000 + TST r0, #&10 + ORRNE r2, r2, #&00008800 + TST r0, #&20 + ORRNE r2, r2, #&00440000 + TST r0, #&40 + ORRNE r2, r2, #&00880000 + TST r0, #&80 + ORRNE r2, r2, #&88000000 + BL UpdateSettingAndVIDC + ADD r0, r0, #1 + TEQ r0, #&100 + BNE %BT10 + B FinishDefault + +paldatT ; Data for teletext mode + + DCW &0000 ; 0 Black + DCW &000F ; 1 Red + DCW &00F0 ; 2 Green + DCW &00FF ; 3 Yellow + DCW &0F00 ; 4 Blue + DCW &0F0F ; 5 Magenta + DCW &0FF0 ; 6 Cyan + DCW &0FFF ; 7 White + +; Colours 8 to 15 have supremacy bit set + + DCW &1000 ; 8 Supremacy+ Black + DCW &100F ; 9 Red + DCW &10F0 ; 10 Green + DCW &10FF ; 11 Yellow + DCW &1F00 ; 12 Blue + DCW &1F0F ; 13 Magenta + DCW &1FF0 ; 14 Cyan + DCW &1FFF ; 15 White + +paldatHR ; data for Hi-res mono mode + DCW &0000 ; Only red gun necessary + DCW &0111 ; but setting all three makes + DCW &0222 ; reading it more natural + DCW &0333 + DCW &0444 + DCW &0555 + DCW &0666 + DCW &0777 + DCW &0888 + DCW &0999 + DCW &0AAA + DCW &0BBB + DCW &0CCC + DCW &0DDD + DCW &0EEE + DCW &0FFF + + DCW &0000 ; border black + DCW &0010 ; fixed pointer colours + DCW &0020 + DCW &0030 + +paldat16 ROUT + ADR r5, paldat16tab +palmetatab + MOV r1, #3 ; set both halves of palette + MOV r0, #0 ; starting index +10 + MOV r8, r5 + MOV r2, #0 + MOV r6, r0 +20 + LDR r7, [r8], #4 + MOVS r6, r6, LSR #1 + ORRCS r2, r2, r7 + BNE %BT20 + BL UpdateSettingAndVIDC + ADD r0, r0, #1 + TEQ r0, #&100 + BNE %BT10 + B FinishDefault + +paldat16tab + & &00000800 ; palette bit 0 + & &00081000 ; 1 + & &08102100 ; 2 + & &10214200 ; 3 + & &21428400 ; 4 + & &42840000 ; 5 + & &84000000 ; 6 + & &00000000 ; 7 + +paldat32 ROUT + ADR r5, paldat32tab + B palmetatab + +paldat32tab + & &01010100 ; palette bit 0 + & &02020200 ; 1 + & &04040400 ; 2 + & &08080800 ; 3 + & &10101000 ; 4 + & &20202000 ; 5 + & &40404000 ; 6 + & &80808000 ; 7 + +paldatend + +; ***************************************************************************** + +; PaletteV call to set palette in bulk +; in: R0 => list of colours, or 0 +; R1 = colour type (16,17,18,24,25) in b24-31 & number to do in b23-b00 +; R2 => list of palette entries (both flash states if 16, one if 17/18) +; R4 = PaletteV reason code +; +; out: R4 = 0, claim vector if recognised +; otherwise preserve R4 and pass on + +PV_BulkWrite ROUT + Push "R0-R3,R5-R11" ; pc already stacked + + ;register usage: + ;[R6] colour list + ;R7 colour type + ;R8 max number + ;[R9] palette entries + ;R10 loop counter + ;R11 colour number + + MOV R7,R1,LSR #24 + BIC R8,R1,#&FF000000 + MOV R6,R0 + MOV R9,R2 + + MOV R10,#0 +10 + TEQ R6,#0 + MOVEQ R11,R10 + LDRNE R11,[R6],#4 + + TEQ R7,#16 + TEQNE R7,#17 + + MOVEQ R0,R11 + MOVEQ R1,#1 + LDREQ R2,[R9],#4 + BLEQ UpdateNormalColour + + TEQ R7,#16 + TEQNE R7,#18 + + MOVEQ R0,R11 + MOVEQ R1,#2 + LDREQ R2,[R9],#4 + BLEQ UpdateNormalColour + + TEQ R7,#24 + + MOVEQ R0,R11 + LDREQ R2,[R9],#4 + BLEQ BorderColour + + TEQ R7,#25 + + MOVEQ R0,R11 + LDREQ R2,[R9],#4 + BLEQ PointerColour + + ADD R10,R10,#1 + CMP R10,R8 + BCC %BT10 + + MOV R4,#0 + Pull "R0-R3,R5-R11,PC" + +; ***************************************************************************** + +; PaletteV call to set palette +; in: R0 = logical colour +; R1 = colour type (16,17,18,24,25) +; R2 = BBGGRRS0 +; R4 = PaletteV reason code +; +; out: R4 = 0, claim vector if recognised +; otherwise preserve R4 and pass on +; + +;amg 19/4/93 - change this routine to make all the calls subroutines rather +; than branches. Although it will slow this down a bit, it makes the bulk +; write a lot simpler and involves less duplication of mungeing code. + +PV_SetPalette ROUT + Push "r0-r3" + TEQ r1, #16 ; if 16 then set both colours + MOVEQ r1, #3 + BEQ Call_UpdateNormalColour + + TEQ r1, #17 ; elif 17 then set 1st colour + MOVEQ r1, #1 + BEQ Call_UpdateNormalColour + + TEQ r1, #18 ; elif 18 then set 2nd colour + MOVEQ r1, #2 + BEQ Call_UpdateNormalColour + + TEQ r1, #24 ; elif 24 then border colour + BEQ Call_BorderColour + + TEQ r1, #25 ; elif 25 then pointer colour + BEQ Call_PointerColour +10 + Pull "r0-r3" + MOVS pc, lr ; else not defined + +Call_UpdateNormalColour + BL UpdateNormalColour + Pull "r0-r3,pc" + +BorderInitEntry Push "r0-r3,lr" ; entry used in default palette setting +Call_BorderColour + BL BorderColour + Pull "r0-r3,pc" + +Call_PointerColour + BL PointerColour + Pull "r0-r3,pc" + +; ***************************************************************************** + +UpdateNormalColour ROUT + Push "LR" + LDR lr, [WsPtr, #DisplayNColour] ; get the mask + TEQ lr, #63 ; is it brain-damaged VIDC10-compatible 256 colour mode? + BEQ %FT10 + AND r0, r0, lr ; and mask it off + AND r0, r0, #255 ; definitely no more than 256 palette entries + BL UpdateSettingAndVIDC +05 + MOV r4, #0 ; indicate successful PaletteV op + Pull "pc" + +10 + AND r0, r0, #15 ; starting palette entry +20 + LDR r3, =&88CC8800 ; r3 = bits controlled by bits 4..7 of pixel value + BIC r2, r2, r3 + TST r0, #&10 ; test bit 4 (r3,7) + ORRNE r2, r2, #&00008800 + TST r0, #&20 ; test bit 5 (g2,6) + ORRNE r2, r2, #&00440000 + TST r0, #&40 ; test bit 6 (g3,7) + ORRNE r2, r2, #&00880000 + TST r0, #&80 ; test bit 7 (b3,7) + ORRNE r2, r2, #&88000000 + BL UpdateSettingAndVIDC + ADD r0, r0, #&10 + CMP r0, #&100 + BCC %BT20 + B %BT05 + +BorderColour ROUT + Push "LR" + MOV r0, #&40000000 ; pseudo-palette-index for border colour + MOV r1, #3 ; both colours + BL UpdateSettingAndVIDC + +; Now test for BBC gap mode (ie 3 or 6) +; if so then set colour 2 to same as border, and colour 3 to inverse + + LDR lr, [WsPtr, #DisplayModeFlags] + TST lr, #Flag_BBCGapMode + BEQ %FT10 + + MOV r0, #2 ; make colour 2 (gap) same as border + BL UpdateSettingAndVIDC + + MOV r0, #3 ; make colour 3 inverse gap + MVN r2, r2 ; invert R, G and B + EOR r2, r2, #&FF ; but use same supremacy + BL UpdateSettingAndVIDC +10 + MOV r4, #0 ; indicate successful PaletteV op + Pull "pc" + + +PointerColour ROUT + Push "LR" + ANDS r0, r0, #3 ; force pointer colour number in range 1..3 + BEQ %FT10 ; zero is invalid + MOV r0, r0, LSL #28 ; move up to top nybble + ORR r0, r0, #&40000000 ; form pseudo-palette-index + MOV r1, #3 + BL UpdateSettingAndVIDC +10 + MOV r4, #0 ; indicate successful PaletteV op + Pull "pc" + +; UpdateSettingStraightRGB +; +; in: r0 = logical colour (border = 4 << 28, pointer colours = 5,6,7 << 28) +; r1 = bit mask of which flash states to update (bit 0 set => 1st, bit 1 set => 2nd) +; r3 = SBGR +; r4 = SBGR to EOR with to go from 1st to 2nd flash state + +; out: r0,r1,r2,r4 preserved +; r3 corrupted + +UpdateSettingStraightRGB ENTRY "r2,r5,r6,r7" + ANDS r5, r3, #1 :SHL: 12 ; get supremacy bit in 1st colour + MOVNE r5, #1 :SHL: 27 ; put in r5 in new position + AND r6, r3, #&FF0 ; r6 = 00000BG0 + ORR r5, r5, r6, LSL #8 ; r5 = 0s0BG000 + AND r6, r3, #&0FF ; r6 = 000000GR + ORR r5, r5, r6, LSL #4 ; r5 = 0s0BGGR0 + AND r6, r3, #&00F ; r6 = 0000000R + ORR r5, r5, r6 ; r5 = 0s0BGGRR + AND r6, r3, #&F00 ; r6 = 00000B00 + ORR r3, r5, r6, LSL #12 ; r3 = 0sBBGGRR + + ANDS r5, r4, #1 :SHL: 12 ; get supremacy bit in EOR mask + MOVNE r5, #1 :SHL: 27 ; put in r5 in new position + AND r6, r4, #&FF0 ; r6 = 00000BG0 + ORR r5, r5, r6, LSL #8 ; r5 = 0s0BG000 + AND r6, r4, #&0FF ; r6 = 000000GR + ORR r5, r5, r6, LSL #4 ; r5 = 0s0BGGR0 + AND r6, r4, #&00F ; r6 = 0000000R + ORR r5, r5, r6 ; r5 = 0s0BGGRR + AND r6, r4, #&F00 ; r6 = 00000B00 + ORR r4, r5, r6, LSL #12 ; r5 = 0sBBGGRR + B UpdateSettingCommon + + +; UpdateSettingAndVIDC +; +; in: r0 = logical colour (border = 4 << 28, pointer colours = 5,6,7 << 28) +; r1 = bit mask of which flash states to update (bit 0 set => 1st, bit 1 set => 2nd) +; r2 = BBGGRRS0 +; +; out: r0, r1, r2 preserved +; r3, r4 corrupted +; + +UpdateSettingAndVIDC ALTENTRY + + ;amg: changed to handle 4 bits of supremacy + + MOV r3, r2, LSR #8 ; r3 = 00bbggrr + ANDS r2, r2, #&F0 ; r2 = 000000s0 + ORRNE r3, r3, r2, LSL #20 ; r3 = 0sbbggrr + + MOV r4, #0 ; indicate no EORing between parts + +; ... and drop thru to + +; UpdateSettingCommon +; +; in: r0 = logical colour (border = 4 << 28, pointer colours = 5,6,7 << 28) +; r1 = bit mask of which flash states to update (bit 0 set => 1st, bit 1 set => 2nd) +; r3 = 0sBBGGRR (s in bits 24-27) +; r2, r5, r6, r7, lr stacked +; +; out: r0, r1, r2, r4 preserved +; r3 corrupted +; + [ GammaCorrection +UpdateSettingCommon ROUT + PHPSEI ; protect against IRQs + + Push "r0, r8, r9" + MOV r7, #VIDC + + TST r0, #&40000000 ; if border or pointer + ORRNE r3, r3, r0 ; then merge with RGB + MOVNE r0, r0, LSR #28 ; and make r0 into index for soft copy + ADDNE r0, r0, #(256-4) ; ie 256, 257, 258 or 259 + + ORREQ r5, r0, #VIDCPalAddress ; else set up palette index register + STREQ r5, [r7] + + LDRB r5, [WsPtr, #ScreenBlankFlag] + TEQ r5, #0 + MOVNE r5, #&0FFFFFFF ; bits to knock out if blanked (EBBGGRR) + + LDROSB r2, FlashState ; 0 => second, 1 => first + CMP r2, #1 ; C=0 => second, C=1 => first + + TST r1, #1 + BEQ %FT10 ; skip if not setting 1st colour + LDR r2, [WsPtr, #FirPalAddr] + ADD r8, r2, #(256+1+3)*4*4 ; r8 -> rgb transfer tables + STR r3, [r2, r0, LSL #2]! ; store in logical colour and write back pointer + AND r6, r3, #&FF ; r6 = red + LDRB r6, [r8, r6] ; r6 = gamma(red) + ADD r8, r8, #&100 ; r8 -> green transfer + AND r9, r3, #&FF00 ; r9 = green << 8 + LDRB r9, [r8, r9, LSR #8] ; r9 = gamma(green) + ORR r6, r6, r9, LSL #8 ; r6 = gamma(red) + (gamma(green)<<8) + ADD r8, r8, #&100 ; r8 -> blue transfer + AND r9, r3, #&FF0000 ; r9 = blue << 16 + LDRB r9, [r8, r9, LSR #16] ; r9 = gamma(blue) + ORR r6, r6, r9, LSL #16 ; r6 = gamma(red) + (gamma(green)<<8) + (gamma(blue)<<16) + AND r9, r3, #&FF000000 ; knock out rgb from original + ORR r6, r6, r9 ; and or in new bits + STR r6, [r2, #(256+1+3)*4*2] ; store in physical copy + + BICCS r6, r6, r5 ; knock out bits for blanking + STRCS r6, [r7] ; poke VIDC if setting 1st colour and in 1st state +10 + EOR r3, r3, r4 ; toggle requested bits for 2nd half + TST r1, #2 + BEQ %FT20 ; skip if not setting 2nd colour + LDR r2, [WsPtr, #SecPalAddr] + ADD r8, r2, #(256+1+3)*4*3 ; r8 -> rgb transfer tables + STR r3, [r2, r0, LSL #2]! ; store in logical copy and write back + + AND r6, r3, #&FF ; r6 = red + LDRB r6, [r8, r6] ; r6 = gamma(red) + ADD r8, r8, #&100 ; r8 -> green transfer + AND r9, r3, #&FF00 ; r9 = green << 8 + LDRB r9, [r8, r9, LSR #8] ; r9 = gamma(green) + ORR r6, r6, r9, LSL #8 ; r6 = gamma(red) + (gamma(green)<<8) + ADD r8, r8, #&100 ; r8 -> blue transfer + AND r9, r3, #&FF0000 ; r9 = blue << 16 + LDRB r9, [r8, r9, LSR #16] ; r9 = gamma(blue) + ORR r6, r6, r9, LSL #16 ; r6 = gamma(red) + (gamma(green)<<8) + (gamma(blue)<<16) + AND r9, r3, #&FF000000 ; knock out rgb from original + ORR r6, r6, r9 ; and or in new bits + STR r6, [r2, #(256+1+3)*4*2] ; store in physical copy + + BICCC r6, r6, r5 ; knock out bits for blanking + STRCC r6, [r7] ; poke VIDC if setting 2nd colour and in 2nd state +20 + PLP + Pull "r0, r8, r9" + EXITS ; restore registers, claim vector + | +UpdateSettingCommon ROUT + PHPSEI ; protect against IRQs + + Push "r0" + MOV r7, #VIDC + + TST r0, #&40000000 ; if border or pointer + ORRNE r3, r3, r0 ; then merge with RGB + MOVNE r0, r0, LSR #28 ; and make r0 into index for soft copy + ADDNE r0, r0, #(256-4) ; ie 256, 257, 258 or 259 + + ORREQ r5, r0, #VIDCPalAddress ; else set up palette index register + STREQ r5, [r7] + + LDRB r5, [WsPtr, #ScreenBlankFlag] + TEQ r5, #0 + MOVNE r5, #&0FFFFFFF ; bits to knock out if blanked (EBBGGRR) + + LDROSB r2, FlashState ; 0 => second, 1 => first + CMP r2, #1 ; C=0 => second, C=1 => first + + TST r1, #1 + BEQ %FT10 ; skip if not setting 1st colour + LDR r2, [WsPtr, #FirPalAddr] + STR r3, [r2, r0, LSL #2] + BICCS r6, r3, r5 ; knock out bits for blanking + STRCS r6, [r7] ; poke VIDC if setting 1st colour and in 1st state +10 + EOR r3, r3, r4 ; toggle requested bits for 2nd half + TST r1, #2 + BEQ %FT20 ; skip if not setting 2nd colour + LDR r2, [WsPtr, #SecPalAddr] + STR r3, [r2, r0, LSL #2] + BICCC r6, r3, r5 ; knock out bits for blanking + STRCC r6, [r7] ; poke VIDC if setting 2nd colour and in 2nd state +20 + PLP + Pull "r0" + EXITS ; restore registers, claim vector + ] + +; ***************************************************************************** +; +; PV_BulkRead - Read multiple palette entries with one call +; +; in: R0 => list of colours wanted, or 0 to start with first and increment +; R1 = b24-b31 - colour type: 16/17/18/24/25 +; b00-b23 - number of colours to do +; +; R2 => memory for first flash state colours (and second if R3=0) +; R3 => memory for second flash state colours (if 0, intermingle with R2 instead) +; +; out: all preserved (R4 set to 0 to show call handled) + +; flags used to control routine + +PV_BR_WantFirst * 1 ; doing 16 or 17 +PV_BR_WantSecond * 2 ; doing 16 or 18 +PV_BR_HaveList * 4 ; we have a list of colours +PV_BR_TwoLists * 8 ; we have two output areas (R2 & R3 valid) +PV_BR_Border * 16 ; doing 24 +PV_BR_Mouse * 32 ; doing 25 + +PV_BulkRead ROUT + Push "R0-R3,R6-R11" ; return addr already stacked + + MOV R6,R1,LSR #24 ; isolate the colour type + + MOV R7,#(PV_BR_WantFirst + PV_BR_WantSecond) + + CMP R6,#17 ; do we want both flash states ? + BICEQ R7,R7,#PV_BR_WantSecond ; if 17 only want first flash state + + CMP R6,#18 + BICEQ R7,R7,#PV_BR_WantFirst ; if 18 only want second flash state + + CMP R6,#24 + ORREQ R7,R7,#PV_BR_Border + ORRGT R7,R7,#PV_BR_Mouse + + ;now set up other control flags + CMP R0,#0 + ORRNE R7,R7,#PV_BR_HaveList ; we have a list of colours + + CMP R3,#0 + ORRNE R7,R7,#PV_BR_TwoLists ; we have two output areas + + ;set up a mask for the number of colours + LDR R8,[WsPtr,#DisplayNColour] + TEQ R8,#63 + MOVEQ R8,#255 ; deal with braindamaged 8BPP case + + ;take the colour type off the top of R1, leaving #colours wanted + BIC R1,R1,#&FF000000 + + ; register usage: + ; [R0]: colour list + ; R1: number of colours + ; [R2]: first flash state list + ; [R3]: second flash state list + ; R7: control flags + ; R8: mask for colour number + ; R9: loop counter + ; R10: misc + ; LR: misc + + MOV R9,#0 +30 + TST R7,#PV_BR_HaveList + LDRNE LR,[R0],#4 + MOVEQ LR,R9 ; LR = wanted colour number + + AND LR,LR,R8 ; ensure it is sensible + + TST R7,#PV_BR_Border + MOVNE LR,#256 ; border is stored as colour 256 + + TST R7,#PV_BR_Mouse + BEQ %FT40 + + ANDS LR,LR,#3 + TEQ LR,#0 + BEQ %FT50 ;colour 0 is invalid + ADD LR,LR,#256 ;bring into range (257-259) + +40 + TST R7,#PV_BR_WantFirst + + LDRNE R10,[WsPtr,#FirPalAddr] + + LDRNE R10,[R10,LR,LSL#2] ; xsbbggrr - could be 4 sup. bits + MOVNE R11,R10,LSL #8 ; bbggrr00 + ANDNE R10,R10,#&0F000000 ; 0s000000 + ORRNE R11,R11,R10,LSR #20 ; bbggrrs0 + STRNE R11,[R2],#4 + + TST R7,#PV_BR_WantSecond + BEQ %FT60 ; have to use a branch here - another TST coming up + + LDR R10,[WsPtr,#SecPalAddr] + + LDR R10,[R10,LR,LSL#2] ; xsbbggrr + MOV R11,R10,LSL #8 ; bbggrr00 + ANDNE R10,R10,#&0F000000 ; 0s000000 + ORR R11,R11,R10,LSR #20 ; bbggrrs0 + + TST R7,#PV_BR_TwoLists + + STREQ R11,[R2],#4 + STRNE R11,[R3],#4 + +60 ADD R9,R9,#1 + CMP R9,R1 + BCC %BT30 +50 + MOV R4,#0 + Pull "R0-R3,R6-R11,PC" ; return addr already stacked + + +; ***************************************************************************** +; +; PV_ReadPalette - PaletteV read palette handler +; +; in: R0 = logical colour +; R1 = 16 (read normal colour) +; 24 (read border colour) +; 25 (read cursor colour) +; +; out: R2 = first flash setting (BBGGRRS0), supremacy bit 7 +; R3 = second flash setting (BBGGRRS0), supremacy bit 7 +; + +PV_ReadPalette ROUT + Push "r10,r11" + LDR r10, [WsPtr, #DisplayNColour] ; logical colours in this mode -1 + TEQ r10, #63 ; if bodgy 256 colour mode + MOVEQ r10, #255 ; then use AND mask of 255 + + TEQ r1, #24 ; is it reading border palette + MOVEQ r11, #&100 ; then set up border index + BEQ %FT10 ; and go + + TEQ r1, #25 ; is it reading pointer palette + BEQ %FT05 + AND r11, r0, r10 ; no, then force into suitable range + B %FT10 ; always skip +05 + ANDS r11, r0, #3 ; else force logical colour 0..3 + BEQ %FT99 ; and 0 is illegal, so do nothing + ADD r11, r11, #&100 ; set up correct index +10 + +; note no need to fudge 256-colour modes, since we have the correct full 256 entry palette + + LDR r10, [WsPtr, #FirPalAddr] + LDR r10, [r10, r11, LSL #2] ; r10 := 1st XSBBGGRR + MOV r2, r10, LSL #8 ; r2 := 1st BBGGRR00 + TST r10, #1 :SHL: 27 + ORRNE r2, r2, #&80 ; r2 := 1st BBGGRRS0 + + LDR r10, [WsPtr, #SecPalAddr] + LDR r10, [r10, r11, LSL #2] ; r10 := 2nd XSBBGGRR + MOV r3, r10, LSL #8 ; r3 := 2nd BBGGRR00 + TST r10, #1 :SHL: 27 + ORRNE r3, r3, #&80 ; r3 := 2nd BBGGRRS0 +99 + MOV r4, #0 + Pull "r10, r11, pc" + +; ***************************************************************************** +; +; PV_1stFlashState - PaletteV routine to set first flash state +; + +PV_1stFlashState ROUT + Push "r0-r3" + LDR r0, [WsPtr, #FirPalAddr] +DoR0Flash + MOV r1, #256 ; just update normal palette +DoAllUpdate + [ GammaCorrection + ADD r0, r0, #(256+1+3)*4*2 ; move pointer to physical palette copy + ] + ADD r1, r0, r1, LSL #2 + MOV r2, #VIDC + MOV r3, #VIDCPalAddress + 0 ; initialise palette address to 0 + PHPSEI ; disable IRQs round this bit + STR r3, [r2] + + LDRB r4, [WsPtr, #ScreenBlankFlag] + TEQ r4, #0 ; if unblanked, leave all bits alone + MOVNE r4, #&0FFFFFFF ; blanked, knock off all bits, except register bits +10 + LDR r3, [r0], #4 + BIC r3, r3, r4 + STR r3, [r2] + TEQ r0, r1 + BNE %BT10 + + PLP + MOV r4, #0 + Pull "r0-r3, pc" + +; ***************************************************************************** +; +; PV_2ndFlashState - PaletteV routine to set second flash state +; + +PV_2ndFlashState ROUT + Push "r0-r3" + LDR r0, [WsPtr, #SecPalAddr] + B DoR0Flash + +; ***************************************************************************** +; +; UpdateAllPalette - Update all VIDC palette entries +; + +UpdateAllPalette ENTRY "r0-r3" ; "r0-r3,lr" stacked ready to branch to code + LDROSB r0, FlashState + CMP r0, #1 + LDRCS r0, [WsPtr, #FirPalAddr] ; FlashState = 1 => 1st state, 0 => 2nd state + LDRCC r0, [WsPtr, #SecPalAddr] + MOV r1, #260 ; update normal palette and border/pointer + B DoAllUpdate + +; ***************************************************************************** +; +; PV_BlankScreen - Blank/unblank screen +; +; in: R0 = -1 => read blank state +; R0 = 0 => unblank screen +; R0 = 1 => blank screen +; +; out: R0 = old state (0=unblanked, 1=blanked) +; R4 = 0 + +PV_BlankScreen ROUT + Push "r1-r3" + LDRB r3, [WsPtr, #ScreenBlankFlag] + CMP r0, #1 + BHI %FT99 + + TEQ r0, r3 ; changing to same state? (carry preserved) + BEQ %FT99 ; if so, do nothing + + STRB r0, [WsPtr, #ScreenBlankFlag] ; update new state + MOV r4, #VIDC + LDRB r0, [WsPtr, #ScreenBlankDPMSState] + BCC %FT50 + +; blanking + + TST r0, #1 ; if hsyncs should be off, + LDRNE r1, =HorizSyncWidth + ((1:SHL:14) -1) ; maximum value in h.sync width register + STRNE r1, [r4] + TST r0, #2 ; if vsyncs should be off, + LDRNE r1, =VertiSyncWidth + ((1:SHL:13) -1) ; maximum value in v.sync width register + STRNE r1, [r4] + + MOV r0, #(0 :SHL: 10) :OR: (3 :SHL: 8) ; blank: video DMA off, continuous refresh + B %FT60 + +50 + +; unblanking + + TST r0, #1 ; if hsyncs were turned off, + LDRNE r1, [WsPtr, #HSWRSoftCopy] ; then restore from soft copy + STRNE r1, [r4] + TST r0, #2 ; if vsyncs were turned off, + LDRNE r1, [WsPtr, #VSWRSoftCopy] ; then restore from soft copy + STRNE r1, [r4] + + MOV r0, #(1 :SHL: 10) :OR: (0 :SHL: 8) ; unblank: video DMA on, no refresh +60 + MOV r1, #(1 :SHL: 10) :OR: (3 :SHL: 8) ; bits to modify + SWI XOS_UpdateMEMC + + MOV r0, pc + ORR lr, r0, #I_bit ; disable IRQs so we don't get a flash in the middle + TEQP lr, #0 + BL UpdateAllPalette ; update all palette, including border + pointer + TEQP r0, #0 ; restore old IRQ state +99 + MOV r0, r3 + MOV r4, #0 + Pull "r1-r3, pc" + + [ GammaCorrection + +; ***************************************************************************** +; +; PV_GammaCorrect - Update gamma correction tables +; +; in: r0 -> red table +; r1 -> green table +; r2 -> blue table +; +; out: r4 = 0 + +PV_GammaCorrect ROUT + Push "r0-r3,r5-r8" + LDR r4, [WsPtr, #FirPalAddr] + ADD r4, r4, #(256+1+3)*4*4 ; point to gamma tables + ADD r3, r4, #256 +10 + LDR lr, [r0], #4 + STR lr, [r4], #4 + TEQ r4, r3 + BNE %BT10 + + ADD r3, r4, #256 +20 + LDR lr, [r1], #4 + STR lr, [r4], #4 + TEQ r4, r3 + BNE %BT20 + + ADD r3, r4, #256 +30 + LDR lr, [r2], #4 + STR lr, [r4], #4 + TEQ r4, r3 + BNE %BT30 + +; now go through the logical palette, recomputing the physical from it using the new tables + + SUB r0, r4, #3*256 ; r0 -> red table + SUB r1, r4, #2*256 ; r1 -> green table + SUB r2, r4, #1*256 ; r2 -> blue table + + LDR r4, [WsPtr, #FirPalAddr] ; r4 -> start of logical palette + ADD r5, r4, #260*4*2 ; r5 -> start of physical palette + MOV r6, r5 ; r6 = r5 = end of logical palette +40 + LDR r7, [r4], #4 ; get word + AND r8, r7, #&FF ; r8 = red + LDRB r8, [r0, r8] ; r8 = gamma(red) + AND lr, r7, #&FF00 ; lr = green << 8 + LDRB lr, [r1, lr, LSR #8] ; lr = gamma(green) + ORR r8, r8, lr, LSL #8 ; r8 = gamma(red) + (gamma(green)<<8) + AND lr, r7, #&FF0000 ; lr = blue << 16 + LDRB lr, [r2, lr, LSR #16] ; lr = gamma(blue) + ORR r8, r8, lr, LSL #16 ; r8 = gamma(red) + (gamma(green)<<8) + (gamma(blue)<<16) + AND lr, r7, #&FF000000 ; lr = other bits + ORR r8, r8, lr ; r8 = gamma-corrected combined value + STR r8, [r5], #4 ; store word + TEQ r4, r6 + BNE %BT40 + + BL UpdateAllPalette + + MOV r4, #0 + Pull "r0-r3,r5-r8, pc" + ] + END diff --git a/s/vdu/vdupalette b/s/vdu/vdupalette new file mode 100644 index 0000000000000000000000000000000000000000..303db429a42195333ecfe81b5379f8c55c6be6e9 --- /dev/null +++ b/s/vdu/vdupalette @@ -0,0 +1,227 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > VduPalette +; +; ARTHUR OPERATING SYSTEM - Vdu Drivers +; ======================= +; +; Vdu driver code - Palette setting (VIDC independent parts) +; +; ***************************************************************************** + +; Routines above PaletteV +; ----------------------- + +; ***************************************************************************** +; +; PalInit - Restore default palette for the displayed mode +; +; out: R6 is preserved (may contain CursorFlags) +; + +PalInit ROUT + MOV r4, #paletteV_SetDefaultPalette + B CallPaletteV + +; ***************************************************************************** +; +; UnblankScreen - Unblank screen (called on mode change) +; + +UnblankScreen ROUT + MOV r0, #0 + MOV r4, #paletteV_BlankScreen + B CallPaletteV + +; ***************************************************************************** +; +; DoSetPalette - Entry point for OSWORD 12 (program palette) +; +; in: R1 -> Control block +; [R1, #0] = logical colour +; [R1, #1] = physical colour or action +; [R1, #2] = red +; [R1, #3] = green +; [R1, #4] = blue +; +; R12 -> VDUWS +; +; R0-R4, R11, R12 may be corrupted +; +; +DoSetPalette + Push "R5-R10,R14" + BL SetPal + Pull "R5-R10,PC" + +; ***************************************************************************** +; +; DC3 - Entry point for VDU 19 (program palette) +; +; in: QQ+0..QQ+4 contain the parameters in the same format as OSWORD +; + +DC3 ROUT + ADD R1, WsPtr, #QQ ; Point R1 at the queued data + ; and drop thru to Palette OSWORD code +SetPal ENTRY + LDR R6, [WsPtr, #DisplayModeFlags] + TST R6, #Flag_Teletext ; if teletext mode + EXITS NE ; then ignore VDU 19 + +; Now we must check for BBC style colours (VDU 19,n,0..15,...) and map these onto +; 16 or (17 and 18) + + MOV lr, r1 + LDRB r0, [lr, #0] ; r0 = logical colour + LDRB r1, [lr, #1] + AND r2, r1, #&80 ; r2 = sup bit + BIC r1, r1, #&80 ; r1 = type of colour + CMP r1, #16 ; r1 < 16 => BBC style colour + BCS %FT10 + + TST r1, #1 ; bit 0 set => red full on + ORRNE r2, r2, #&0000FF00 + TST r1, #2 ; bit 1 set => green full on + ORRNE r2, r2, #&00FF0000 + TST r1, #4 ; bit 2 set => blue full on + ORRNE r2, r2, #&FF000000 + + LDRB lr, [WsPtr, #PalIndex] + CMP lr, #3 ; only flash colours if PalIndex = 0, 1 or 2 + BICCS r1, r1, #8 + + TST r1, #8 + MOVEQ r1, #16 + BEQ %FT20 ; not a flashing colour, so just set it once + + MOV r1, #17 ; set first flash colour + BL CallSetPalette + MVN r2, r2 ; then toggle all bits of R, G and B + EOR r2, r2, #&FF ; (don't toggle supremacy) + MOV r1, #18 ; set second flash colour + B %FT20 + +10 + LDRB r3, [lr, #2] ; r3 = red + ORR r2, r2, r3, LSL #8 ; r2 = &0000RRS0 + LDRB r3, [lr, #3] ; r3 = green + ORR r2, r2, r3, LSL #16 ; r2 = &00GGRRS0 + LDRB r3, [lr, #4] ; r3 = blue + ORR r2, r2, r3, LSL #24 ; r2 = &BBGGRRS0 +20 + BL CallSetPalette + EXITS + + +CallSetPalette + MOV r4, #paletteV_Set +CallPaletteV + Push "r9,lr" + MOV r9, #PaletteV + SWI XOS_CallAVector + Pull "r9,pc",,^ + +; ***************************************************************************** +; +; SWIReadPalette - SWI ReadPalette handler +; +; in: R0 = logical colour +; R1 = 16 (read normal colour) +; 24 (read border colour) +; 25 (read cursor colour) +; +; out: R2 = first flash setting (B0G0R0PP), supremacy bit 7 +; R3 = second flash setting (B0G0R0PP), supremacy bit 7 +; R10-R12 corrupted (preserved by Sam), all others preserved +; + +SWIReadPalette ENTRY "r4" + VDWS WsPtr + MOV r4, #paletteV_Read + BL CallPaletteV + BIC r2, r2, #&7F ; knock out any weird bits + BIC r3, r3, #&7F + ORR r2, r2, r1 ; put in nominal PP field + ORR r3, r3, r1 + TEQ r1, #16 ; if reading normal colour + BNE %FT10 + TEQ r2, r3 ; and colours different + ORRNE r2, r2, #1 ; then make 1st PP field 17 + ORRNE r3, r3, #2 ; and 2nd PP field 18 +10 + PullEnv + ExitSWIHandler + +; ***************************************************************************** +; +; DoReadPalette - Entry point from OSWORD 11 (read palette) +; +; in: R1 -> control block +; [R1, #0] = logical colour to read +; +; out: [R1, #1] (bits 0..6) = physical colour 0..15 or 16; (bit 7) = supremacy +; [R1, #2] = red (in bits 4..7) +; [R1, #3] = green (-----""-----) +; [R1, #4] = blue (-----""-----) +; R0-R4, R11, R12 can be corrupted +; + +DoReadPalette ENTRY + MOV r4, r1 ; save pointer to block + LDRB r0, [r4] ; r0 = logical colour + MOV r1, #16 + SWI XOS_ReadPalette + LDROSB r0, FlashState + CMP r0, #1 ; CS => 1st state, CC => 2nd state + MOVCC r2, r3 ; r2 = current state + MOV r1, #4 +10 + STRB r2, [r4, #1]! ; store 4 bytes of data in block, starting R1+1 + MOV r2, r2, LSR #8 + SUBS r1, r1, #1 + BNE %BT10 + EXIT + +; ***************************************************************************** +; +; DoFirstFlash - Set palette to first palette setting +; Called in either SVC or IRQ mode +; + +DoFirstFlash ENTRY "r0,r4" + MOV r4, #paletteV_1stFlashState +SetFlashState + MOV r0, pc + TEQP pc, #SVC_mode + I_bit + NOP + Push "lr" + BL CallPaletteV + Pull "lr" + TEQP r0, #0 + NOP + EXITS + +; ***************************************************************************** +; +; DoSecondFlash - Set palette to second palette setting +; Called in either SVC or IRQ mode +; + +DoSecondFlash ALTENTRY + MOV r4, #paletteV_2ndFlashState + B SetFlashState + + END diff --git a/s/vdu/vduplot b/s/vdu/vduplot new file mode 100644 index 0000000000000000000000000000000000000000..1a765a322fd7945868f173fae317cf2278c65577 --- /dev/null +++ b/s/vdu/vduplot @@ -0,0 +1,1506 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.VduPlot +; +; ARTHUR OPERATING SYSTEM - Vdu Drivers +; ======================= +; +; Vdu graphics code - Entry point for plotting & low level primitives +; & Ecf pattern setting +; Author R C Manby +; Date 5.9.86 +; + +; ***************************************************************************** +; +; EM +; PLOT - Graphics operation, eg triangle, line etc. +; ==== +; +; The plot operation, and the co-ordinate to plot at given by bytes +; in the vdu queue, as follows +; QQ+0 - plot number +; QQ+1 - xLo +; QQ+2 - xHi +; QQ+3 - yLo +; QQ+4 - yHi +; +; The co-ordinate is in external 16 bit form. +; If 2 or 3 are required, they are taken from ICursor & OldCs +; +; Also, both PLOT and EntryFromSWIPlot are entered with R6 = CursorFlags +; +EM +PLOT ROUT + [ {TRUE} + GraphicsMode R0 ; Quit if not a graphics mode + MOVNE PC, Link + | + LDR R0, [WsPtr, #NPix] + CMP R0, #0 ; Quit if not a graphics mode + MOVEQ PC, Link + ] + + ASSERT ((QQ+1):AND:3)=0 + LDR R2, [WsPtr, #QQ+1] ; R2 = xlo,xhi,ylo,yhi + MOV R0, R2, LSL #16 ; R0 = 0 ,0 ,xlo,xhi + MOV R0, R0, ASR #16 ; R0 = xlo,xhi,sgn,sgn + MOV R1, R2, ASR #16 ; R1 = ylo,yhi,sgn,sgn + + LDRB R2, [WsPtr, #QQ+0] ; plot mode + MOV R9, #0 ; indicate coming from VDU Plot + +EntryFromSWIPlot + SaveRetAdr + +; now convert to internal coords (modified EIG code) + + ASSERT OrgY = OrgX +4 + ASSERT GCsX = OrgX +8 + ASSERT GCsY = OrgX +12 + ASSERT YEigFactor = XEigFactor +4 + + ADD R3, WsPtr, #OrgX + + LDMIA R3!, {R4-R5} ; R4 = OrgX: R5 = OrgY + TST R2, #4 ; If bit2 is clear, then relative + LDMEQIA R3, {R7-R8} ; so load old cursor position + ADDEQ R0, R0, R7 ; and add + ADDEQ R1, R1, R8 + STMIA R3, {R0-R1} ; store new coords in GCsX,GCsY + + ADD R3, WsPtr, #XEigFactor + LDMIA R3, {R7-R8} ; R7 = XEigFactor: R8 = YEigFactor + ADD R0, R0, R4 ; add on origin + ADD R1, R1, R5 + MOV R0, R0, ASR R7 ; and shift down + MOV R1, R1, ASR R8 + + ADD R3, WsPtr, #NewPtX + STMIA R3, {R0-R1} + +; +; The 2 LSBits of the plot code specify fg/bg colour and action as :- +; 0 No effect eqv. of Gcol(5,c) +; 1 Foreground colour using foreground Gcol action +; 2 Invert eqv. of Gcol(4,c) +; 3 Background colour using background Gcol action +; + +; *****Change made by DJS +; Original code was: +; MOV R3, R2, LSL #30 ; put bottom 2 bits into top 2 bits +; CMP R3, #&40000000 ; set lots of flags +; +; ADDMI R4, WsPtr, #BgEcfOraEor ; if 0 or 3 +; ADRCC R4, NoEffect ; if 0 +; ADDEQ R4, WsPtr, #FgEcfOraEor ; if 1 +; ADRVS R4, Invert ; if 2 + + MOVS R3, R2, LSL #31 ;Put bit 1 in C, NOT(bit 0) in Z + ADR R4, NoEffect ; if 0, 1, 2 or 3 + ADDNE R4, WsPtr, #FgEcfOraEor ; if 1 or 3 + ADRCS R4, Invert ; if 2 or 3 + ADDHI R4, WsPtr, #BgEcfOraEor ; if CS & NE - i.e. 3 + +; *****End of change made by DJS + + STR R4, [WsPtr, #GColAdr] ; save address of Ecf to plot with + + TST R6, #ClipBoxEnableBit + BLNE DoPlotClipBox + + ADR R14, CTidy + SVC_mode ; set up return address + ; R0=X, R1=Y, R2=plot code + ADD PC, PC, R2, LSR #1 ; jump to branch (bottom 2 bits of the + ; result are ignored!) + & 0 ; dummy word + + B LineDrawSolid ; 0 - Solid line + B LineDrawSolid ; 8 - Solid line, endpoint omitted + B LineDrawDotted ; 16 - Dot-dash line, restart pattern + B LineDrawDotted ; 24 - Dot-dash line, restart pattern, + ; endpoint omitted + B LineDrawSolid ; 32 - Solid extension line + B LineDrawSolid ; 40 - Solid extension line, endpoint omitted + B LineDrawDotted ; 48 - Dot-dash extension line, continue pattern + B LineDrawDotted ; 56 - Dot-dash extension line, continue pattern, + ; endpoint omitted + B PlotPoint ; 64 - Point plot + B FillLRnonBg ; 72 - Line fill L&R, upto non-background + B TriangleFill ; 80 - Triangle fill + B FillLRtoBg ; 88 - Fill right, upto background + B RectangleFill ; 96 - Rectangle fill + B FillLRtoFg ; 104 - Line fill L&R, upto foreground + B ParallelogramFill ; 112 - Parallelogram Fill + B FillLRnonFg ; 120 - Fill right, upto non-foreground + B FloodNonBg ; 128 - Flood to non-bg (ie over bg) + B FloodToFg ; 136 - Flood to fg (ie over non-fg) + B CircleOutline ; 144 - Circle outline + B CircleFill ; 152 - Circle fill + B CircleArc ; 160 - Circular arc outline + B SegmentFill ; 168 - Segment fill + B SectorFill ; 176 - Sector (pie) fill + B BlockCopyMove ; 184 - Block copy/move + B EllipseOutline ; 192 - Ellipse outline + B EllipseFill ; 200 - Ellipse fill + B NYA ; 208 - Unassigned + B NYA ; 216 - Unassigned + B NYA ; 224 - Unassigned + B SpritePlot ; 232 - Sprite plot + B NYA ; 240 - Assigned to applications + B NYA ; 248 - Assigned to applications + +CTidy ; The "normal" return point after a plot + ; operation, any call that does not want + ; the cursors moving should pull return + ; address off the stack + + ; Shuffle the cursors along + ; NewPt -> ICursor -> OldCs -> OlderCs + ; + ; ECursor was set earlier by EIG + + ADD R0, WsPtr, #OldCsX + LDMIA R0, {R1,R2, R3,R4, R5,R6} ; OldCs(X,Y) ICursor(X,Y) NewPt(X,Y) + ADD R0, WsPtr, #OlderCsX + STMIA R0, {R1,R2, R3,R4, R5,R6} + Return + +NYA + MOV R0, R2 ; R0 := plot code + MOV R10, #UKPLOTV + Push "R9, WsPtr, R14" ; save SWIPlot indicator, WsPtr + link + BL VduQQVec + Pull "R9, WsPtr, PC", VC ; return to CTidy if no error + +; error in UKPLOTV + + Pull "R9, WsPtr" ; restore SWIPlot indicator and WsPtr + ADD R13, R13, #8 ; throw away return to CTidy + ; and return address stacked by PLOT + TEQ R9, #0 ; called from Wrch ? + BEQ VduBadExit ; yes, then go to error exit code + B SWIPlotBadExit ; no, then go to SWIPlot error exit + +VduQQVec + ADD R1, WsPtr, #QQ +VduGoVec + CallAVector + + + +; +; Words for forming ZGORA & ZGEOR for colour actions 0 to 7, where +; 0=Store, 1=OR, 2=AND, 3=EOR, 4=Inverse, 5=No change, +; 6=And Not(colour) ie BIC, 7=Or Not(colour) +; +; +; The values correspond to TBzgoo etc on the 6502 and are stored +; in the following order zgoo,zgeo,zgoe,zgee to allow LDM to be used +; +; Action +; 0 1 2 3 4 5 6 7 +; TBzgoo OR the OR :- F,0,0,F,F,F,0,0 +; TBzgeo EOR the OR :- 0,0,F,F,F,F,0,F +; TBzgoe OR the EOR :- 0,F,0,0,F,F,0,F +; TBzgee EOR the EOR :- F,F,F,0,0,F,0,F +; + +TBscrmasks * 2_10010111000011111110110001010011 + + [ {FALSE} +TBscrmask + & &FFFFFFFF ;Store colour to screen ( OR the OR) + & &00000000 ; (EOR the OR) + & &00000000 ; ( OR the EOR) + & &FFFFFFFF ; (EOR the EOR) + + & &00000000 ;OR colour to screen + & &00000000 + & &FFFFFFFF + & &FFFFFFFF + + & &00000000 ;AND + & &FFFFFFFF + & &00000000 + & &FFFFFFFF + + & &FFFFFFFF ;EOR + & &FFFFFFFF + & &00000000 + & &00000000 + + & &FFFFFFFF ;Invert + & &FFFFFFFF + & &FFFFFFFF + & &00000000 + + & &FFFFFFFF ;No change + & &FFFFFFFF + & &FFFFFFFF + & &FFFFFFFF + + & &00000000 ;BIC (ie AND NOTcol) + & &00000000 + & &00000000 + & &00000000 + + & &00000000 ;OR NOTcol + & &FFFFFFFF + & &FFFFFFFF + & &FFFFFFFF + ] + + MALIGN 64 ; Invert and NoEffect must be aligned to a multiple + ; of 64 for line drawing routines (TMD) + + ;Interleaved zgora & zgeor values to give invert + ; and no effect plotting, used when plot code +Invert ; overrides Fg/Bg Gcol colour and action. + & &00000000 + & &FFFFFFFF + & &00000000 + & &FFFFFFFF + & &00000000 + & &FFFFFFFF + & &00000000 + & &FFFFFFFF + & &00000000 + & &FFFFFFFF + & &00000000 + & &FFFFFFFF + & &00000000 + & &FFFFFFFF + & &00000000 + & &FFFFFFFF +NoEffect + & &00000000 + & &00000000 + & &00000000 + & &00000000 + & &00000000 + & &00000000 + & &00000000 + & &00000000 + & &00000000 + & &00000000 + & &00000000 + & &00000000 + & &00000000 + & &00000000 + & &00000000 + & &00000000 + +; ***************************************************************************** +; +; EIG - External to internal graphic coordinate conversion +; === +; +; Convert external coordinates (either relative or absolute) into +; internal ones. No windowing is done. +; +; +; On entry, R0 (X), R1 (Y) hold coordinate (external co-ords) +; R2 holds plot mode, where bit2 = 0 for relative (add ECursor) +; = 1 for absolute (add origin) +; +; On exit, R0 (X), R1 (Y) hold internal representation +; R2 preserved +; +; R3 corrupt +; +; The external cursor (GCsX,GCsY) is updated to the new point, +; hence in triangle relative mode, the points are relative to +; the last point specified, not the original. +; +EIG + ;Do Ycoord first + TST R2,#4 ;If bit2 is clear + LDREQ R3,[WsPtr,#GCsY] ;then co-ord is relative + ADDEQ R1,R1,R3 ; so add previous cursor (ext. rep.) + + STR R1,[WsPtr,#GCsY] ;Update previous cursor + LDR R3,[WsPtr,#OrgY] ;Add origin + ADD R1,R1,R3 + + LDR R3, [WsPtr, #YEigFactor] + MOV R1,R1,ASR R3 ;Transform 0-1023 to 0-255 or 0-511 + + ;Do Xcoord + LDREQ R3,[WsPtr,#GCsX] ;If relative then + ADDEQ R0,R0,R3 ; add previous cursor (ext. rep.) + + STR R0,[WsPtr,#GCsX] ;Update previous cursor + LDR R3,[WsPtr,#OrgX] ;Add origin + ADD R0,R0,R3 + + LDR R3,[WsPtr,#XEigFactor] + MOV R0,R0,ASR R3 ;Transform 0-1279 to 0-639/0-319/0-159 + + MOVS PC,R14 + +; ***************************************************************************** +; +; IEG - Inverse of EIG. Convert ICursor to ECursor +; === +; +; On exit, R0 (X), R1 (Y) holds ECursor, ECursor updated +; R2, R3 hold XEigFactor, YEigFactor +; R4, R5 corrupt +; + ASSERT GCsIY = GCsIX +4 + ASSERT YEigFactor = XEigFactor +4 + ASSERT OrgY = OrgX +4 + ASSERT GCsY = GCsX +4 +IEG + ADD R0, WsPtr, #GCsIX + LDMIA R0, {R0,R1} ; load graphics cursor (internal) +IEGB + ADD R2, WsPtr, #XEigFactor + LDMIA R2, {R2, R3} ; R2 = XEigFactor; R3 = YEigFactor + ADD R4, WsPtr, #OrgX + LDMIA R4, {R4, R5} ; R4 = OrgX; R5 = OrgY + RSB R0, R4, R0, LSL R2 ; R0 = (X << XEigFactor)-OrgX + RSB R1, R5, R1, LSL R3 ; R1 = (Y << YEigFactor)-OrgY + ADD R4, WsPtr, #GCsX + STMIA R4, {R0,R1} ; write graphics cursor (external) + + MOVS PC,R14 + + [ {FALSE} +; ***************************************************************************** +; +; Window - Check a coordinate against the graphics window +; ====== +; +; On entry, R0 (X), R1 (Y) holds coordinate to window +; On exit, R0,R1 preserved, +; R3 corrupt +; R2 holds result, as follows: +; +; | | +; 1001 | 1000 | 1010 +; | | +; -----+------+----- +; | | +; 0001 | 0000 | 0010 +; | | +; -----+------+----- +; | | +; 0101 | 0100 | 0110 +; | | +; +; +; +Window + MOV R2,#0 + LDR R3,[WsPtr,#GWBRow] ;Test ycoord against window + CMP R1,R3 + ORRLT R2,R2,#4 ;Set bit 2 if Y < window + + LDR R3,[WsPtr,#GWTRow] + CMP R3,R1 + ORRLT R2,R2,#8 ;Set bit 3 if Y > window + + LDR R3,[WsPtr,#GWLCol] ;Test xcoord against window + CMP R0,R3 + ORRLT R2,R2,#1 ;Set bit 0 if X < window + + LDR R3,[WsPtr,#GWRCol] + CMP R3,R0 + ORRLT R2,R2,#2 ;Set bit 1 if X > window + + MOVS PC,R14 ;Return to whence we came + + ] +; ***************************************************************************** +; +; ScreenAddr - Generate screen address of coordinate +; ========== +; +; On entry, R0 (X), R1 (Y) holds coordinate - must be within graphics window +; On exit, R0,R1 preserved, +; R2 holds word address +; R3 holds pixel mask +; +; R7,R8 corrupt +ScreenAddr + ASSERT LineLength = YWindLimit +4 + + ADD R7, WsPtr, #YWindLimit + LDMIA R7, {R7,R8} ; R7=YWindLimit,R8=LineLength + SUB R2, R7, R1 ; flip ycoord into R2 + + LDR R7, [WsPtr, #ScreenStart] ; add the screen start + MLA R2, R8, R2, R7 ; to Ycoord * bytes per row + + LDR R3, [WsPtr, #XShftFactor] ; R7 := 2,3,4 or 5 + MOV R8, R0, ASR R3 ; R8 := word offset + ADD R2, R2, R8, LSL #2 ; add on to screen address + + EOR R7, R0, R8, LSL R3 ; R7 := pixel offset + ADD R3, WsPtr, #RAMMaskTb + LDR R3, [R3, R7, LSL #2] ; R3 := mask for this pixel + + MOVS PC, R14 ; and return + +; ***************************************************************************** +; +; PlotPoint - Plot a point in the current colour +; ========= +; +; On entry, R0 (X), R1 (Y) holds coordinate of point +; On exit, R0,R1 preserved +; R2-R8 corrupt +; R9-R11 preserved +; + +PlotPoint + WINDow R0,R1, R2,R3,R4,R5 + MOVLTS PC, R14 ; If outside window, give up + + ASSERT LineLength = YWindLimit +4 + + ADD R7, WsPtr, #YWindLimit + LDMIA R7, {R7,R8} ; R7=YWindLimit; R8=LineLength + SUB R2, R7, R1 ; flip ycoord into R2 + +; *****Change made by DJS +; Original code was: +; ASSERT GColAdr = XShftFactor +4 +; ASSERT ScreenStart = XShftFactor +8 +; +; ADD R4, WsPtr, #XShftFactor ; R4=XShftFactor; R5=GColAdr +; LDMIA R4, {R4, R5, R7} ; R7=ScreenStart +; +; MLA R2, R8, R2, R7 ; R2=ScreenStart+Y*LineLength +; MOV R8, R0, ASR R4 ; R8 := XCoord DIV 4,8,16 +; ; or 32 +; EOR R7, R0, R8, LSL R4 ; R7 := pixel offset in word +; ADD R3, WsPtr, #RAMMaskTb +; LDR R3, [R3, R7, LSL #2] ; R3 := mask for this pixel +; +; EOR R6, R1, #7 ; flip Ycoord +; AND R6, R6, #7 ; line within ecf +; This does not calculate the ecf line correctly, resulting in bugs if (e.g.) +; a destination sprite is not a multiple of 8 pixels high. + + AND R6, R2, #7 ; R6 := line with ecf + + ASSERT GColAdr = XShftFactor +4 + ASSERT ScreenStart = XShftFactor +8 + + ADD R4, WsPtr, #XShftFactor ; R4=XShftFactor; R5=GColAdr + LDMIA R4, {R4, R5, R7} ; R7=ScreenStart + + MLA R2, R8, R2, R7 ; R2=ScreenStart+Y*LineLength + MOV R8, R0, ASR R4 ; R8 := XCoord DIV 4,8,16 or 32 + EOR R7, R0, R8, LSL R4 ; R7 := pixel offset in word + ADD R3, WsPtr, #RAMMaskTb + LDR R3, [R3, R7, LSL #2] ; R3 := mask for this pixel + +; *****End of change made by DJS + + ADD R5, R5, R6, LSL #3 + LDMIA R5, {R5, R6} ; get zgora,zgeor + + AND R5, R5, R3 ; mask zgora + AND R6, R6, R3 ; & zgeor for this pixel + LDR R7, [R2, R8, LSL #2]! ; + ORR R7, R7, R5 ; and hit the screen + EOR R7, R7, R6 + STR R7, [R2] + MOV PC, R14 + +; ***************************************************************************** +; +; ComplexEcfPattern +; ================= +; +; On entry, R0 holds pattern number, where 2..6 means Ecf1..4 +; +; Vdu queue holds +; +; QQ+0 pattern number +; QQ+1 pattern bytes 0 +; | | +; QQ+8 7 +; +; ComplexEcfPat10 is an entry point from simple Ecf setting for 8 bpp modes +; ie simple=complex in 8 bpp modes +; R1 points to Ecf(n) to be programmed. +; +; Corrupts R0..R3 +; + +ComplexEcfPattern ROUT ; R0 holds 2,3,4,5 for Ecfs 1,2,3,4 + ADD R1, WsPtr, #(Ecf1-2*8) + ADD R1, R1, R0, LSL #3 ; point R1 at Ecf(n) +ComplexEcfPat10 + ADD R0, WsPtr, #(QQ+1) + LDR R2, [WsPtr, #BBCcompatibleECFs] ; if in BBC mode + CMP R2, #0 + BEQ ComplexEcfPat20 ; then unmangle the interleaved + ; pixels + LDMIA R0, {R2,R3} ; else (native) use as given + STMIA R1, {R2,R3} + B SetColour ; update FgEcf & BgEcf incase they use this Ecf + +; R1 points at Ecf(n) +; R0 points at QQ+1 +; +; Uses R2 - pointer into InterleaveTB(BitsPerPix) +; R3 - byte to process 7..0 +; R4 - #1 +; R5 - bit within byte to process 7..0 +; R6 - result byte +; R7 - byte from queue +; R8 - bit mask from InterleaveTB(BitsPerPix,R5) + +ComplexEcfPat20 + ADR R2, InterleaveTB + LDR R3, [WsPtr, #Log2BPP] ; 0,1,2,3 means 1,2,4,8 bits per pixel + ADD R2, R2, R3, LSL #3 ; point R2 at entry in interleave table + MOV R3, #7 ; 7..0 bytes to process + MOV R4, #1 +ComplexEcfPat30 + MOV R5, #7 ; 7..0 bits per byte + MOV R6, #0 ; clear result byte + LDRB R7, [R0, R3] ; byte from queue +ComplexEcfPat40 + LDRB R8, [R2, R5] + TST R8, R7 + ORRNE R6, R6, R4, LSL R5 ; set bit in result byte + SUBS R5, R5, #1 + BGE ComplexEcfPat40 ; process next bit + + STRB R6, [R1, R3] ; write de-interleaved byte to Ecf(n) + SUBS R3, R3, #1 + BGE ComplexEcfPat30 ; process next byte from queue + + B SetColour ; update FgEcf & BgEcf incase they use this Ecf + +; +; InterleaveTB - Values used to unpack BBC style interleaved pixels +; +InterleaveTB +; 1 bit per pixel eg Mode 0 & 4 - Log2BPP is 0 + = &80, &40, &20, &10, &08, &04, &02, &01 +; 2 bits per pixel eg Mode 1 & 5 - Log2BPP is 1 + = &08, &80, &04, &40, &02, &20, &01, &10 +; 4 bits per pixel eg Mode 2 - Log2BPP is 2 + = &02, &08, &20, &80, &01, &04, &10, &40 +; 8 bits per pixel - no effect - Log2BPP is 3 + = &01, &02, &04, &08, &10, &20, &40, &80 + + ALIGN + +; ***************************************************************************** +; +; LineStyle - Setup dotted line style (does not affect repeat length) +; ========= +; +; Corrupts R0..R3 +; + +LineStyle ROUT + MOV R3, #8 ; Copy 8 bytes in reverse order + ADD R1, WsPtr, #QQ+9 + ADD R2, WsPtr, #DotLineStyle ; from Queue into DotLineStyle +LineSty10 + LDRB R0, [R1, #-1]! + STRB R0, [R2], #1 + SUBS R3, R3, #1 + BNE LineSty10 + MOVS PC, R14 + + LTORG ;limited offsets + +; ***************************************************************************** +; +; DefaultLineStyle - Setup default line style and length +; +; Internal routine, called by mode change, SwitchOutputToSprite and +; FX163,242,n code +; +; out: Can corrupt R0-R3, +; PSR preserved +; + +DefaultLineStyle ROUT + MOV R0, #8 ; dot pattern repeats after 8 pixels + STR R0, [WsPtr, #DotLineLength] + LDR R0, =&AAAAAAAA ; on-off pattern + STR R0, [WsPtr, #DotLineStyle+0] ; 64 bits of pattern + STR R0, [WsPtr, #DotLineStyle+4] + MOV R0, #0 ; force a restart of the pattern + STR R0, [WsPtr, #LineDotCnt] ; if the user does a "continue" + MOVS PC, R14 + +; ***************************************************************************** +; +; SetPatLength - Set dotted line repeat length +; +; Internal routine, called by DoOsbyte163_242 +; +; in: R2 = 1..64 => set pattern length to this +; 0 => set default length and pattern +; +; out: Can corrupt R0-R3, +; PSR preserved +; + +SetPatLength ROUT + CMP R2, #0 + BEQ DefaultLineStyle + STR R2, [WsPtr, #DotLineLength] ; 1..64 + MOV R2, #0 ; force restart of the pattern + STR R2, [WsPtr, #LineDotCnt] ; if the user does a "continue" + MOVS PC, R14 + +; ***************************************************************************** +; +; DefaultEcfPattern - Setup all 4 ecf patterns for this mode +; (does not affect line style) +; +; Internal routine, called by mode change, SwitchOutputToSprite and +; VDU 23_11 +; + +DefaultEcfPattern ROUT + MOV R0, #0 + STR R0, [WsPtr, #BBCcompatibleECFs] ;Select BBC compatible ECF mode + + LDR R0, [WsPtr, #ECFIndex] + ADR R1, DefEcfTb + ADD R0, R1, R0, LSL #4 ; 16 bytes per entry + ADD R1, WsPtr, #Ecf1 + + LDMIA R0, {R2,R4,R6,R8} ; Get all four patterns for each mode + LDMIA R0, {R3,R5,R7,R9} ; duplicate top half into bottom half + STMIA R1, {R2-R9} ; Write all 4 Ecfs + B SetColour ; update FgEcf & BgEcf in case they are Ecfs + + +DefEcfTb ; Table of default ECFs, indexed by ECFIndex (a mode variable) + +; Modes 3,6,7 + & 0 + & 0 + & 0 + & 0 + +; Mode 0 + & &00330033 ;Dark grey (3 black, 1 white) + & &CC33CC33 ;Grey (2 black, 2 white) + & &CCFFCCFF ;Light grey (1 black, 3 white) + & &030C30C0 ;Hatching + +; Modes 1,5,8,11,19 + & &55665566 ;Red orange (3 red, 1 yellow) + & &99669966 ;Orange (2 red, 2 yellow) + & &99AA99AA ;Yellow orange (1 red, 3 yellow) + & &BBEEBBEE ;Cream (2 white, 2 yellow) + +; Modes 2,9,12,14,16,17,20(,21) + & &31133113 ;Orange (2 red, 2 yellow) + & &51155115 ;Pink (2 red, 2 magenta) + & &32233223 ;Yellow green (2 green, 2 yellow) + & &37733773 ;Cream (2 white, 2 yellow) + +; Modes 4,18,22,23 + & &00550055 ;Dark grey (3 black, 1 white) + & &AA55AA55 ;Grey (2 black, 2 white) + & &AAFFAAFF ;Light grey (1 black, 3 white) + & &11224488 ;Hatching + +; Modes 10,13,15 + & &FFFEFDFC ;Its runnier than yoy'll lik itt + & &00010203 + & &20212223 + & &DFDEDDDC + +; ***************************************************************************** +; +; SimpleEcfPattern - Setup simple ecf pattern +; +; Internal routine, called by VDU23_12..15 +; +; in: R0 = 12..15 for ecfs 1..4 +; Vdu queue holds +; QQ+0 pattern number +; QQ+1 pattern bytes 0 +; | | +; QQ+8 7 +; + +SimpleEcfPattern ROUT + ADD R1, WsPtr, #(Ecf1-12*8) + ADD R1, R1, R0, LSL #3 ; Point R1 at ECF(n) + ADD R2, WsPtr, #(QQ+1) ; Point R2 at first colour in queue + ADR R3, SimpEcfTb + LDR R4, [WsPtr, #ECFIndex] + LDRB R10, [R3, R4] ; Mask for this mode + CMP R10, #&FF + BEQ SimplEc20 ; 256 colour modes are different + LDR R5, [WsPtr, #NColour] + ADRL R4, TBFullCol ; Base of full colour table (of bytes) + ADD R4, R4, R5 ; Access to table is always + ; TBFullCol(NColour+(byte AND NColour)) + ; so add NColour in now ! + MOV R7, #4 ; There are 4 pairs of bytes in queue +SimplEc10 + LDRB R6, [R2], #1 ; Get first colour of pair from queue + AND R6, R6, R5 ; (byte AND NColour) + LDRB R6, [R4, R6] ; The full byte for this colour + AND R6, R6, R10 ; Extract required pixels + LDRB R9, [R2], #1 ; Get next colour of pair from queue + AND R9, R9, R5 ; (byte AND Ncolour) + LDRB R9, [R4, R9] + BIC R9, R9, R10 ; Extract required pixels and + ORR R6, R6, R9 ; build into final pattern + STRB R6, [R1, #4] ; Replicate pattern in both halves + STRB R6, [R1], #1 ; of ECF + SUBS R7, R7, #1 + BNE SimplEc10 + B SetColour ; update FgEcf & BgEcf in case they use this + +; R1 -> ECF(n) +; R2 -> first colour in queue + +SimplEc20 + Push R14 + MOV R5, #8 +SimplEc30 + LDRB R0, [R2], #1 ; Get byte from queue + AND R3, R0, #&C0 ; Extract Tint + AND R0, R0, #&3F ; Colour + + BL AddTintToColour ; Recombine in our funny fashion + STRB R0, [R1], #1 ; And store in the Ecf + SUBS R5, R5, #1 + BNE SimplEc30 + Pull R14 + B SetColour ; Update FgEcf & BgEcf incase they use this Ecf + +SimpEcfTb ; Table of masks for simple ECFs, indexed by ECFIndex + ; (bit set => use left pixel, bit clear => use right pixel) + + = &00 ; Modes 3,6,7 + = &33 ; Mode 0 + = &33 ; Modes 1,5,8,11,19 + = &0F ; Modes 2,9,12,14,16,17,20 + = &55 ; Modes 4,18,21,22 + = &FF ; Modes 10,13,15 + + ALIGN + +; ***************************************************************************** +; +; ExportedHLine - Routine exported via VDU variable HLineAddr +; +; in: R0,R2 = X coords in some order (internal coords) +; R1 = Y coord (internal coord) +; R3 = 0 => no effect +; R3 = 1 => foreground colour/action +; R3 = 2 => invert +; R3 = 3 => background colour/action +; R3 >= 4 => R3 -> eight word pairs +; + +ExportedHLine ROUT + Push "R0,R2,R4-R10,WsPtr,R14" + VDWS WsPtr + CMP R3, #4 + BCS %FT10 + +; *****Change made by DJS +; Original code was: +; MOV R3, R3, LSL #30 ; put bottom 2 bits into top 2 bits +; CMP R3, #&40000000 ; set lots of flags +; +; ADDMI R3, WsPtr, #BgEcfOraEor ; if 0 or 3 +; ADRCC R3, NoEffect ; if 0 +; ADDEQ R3, WsPtr, #FgEcfOraEor ; if 1 +; ADRVS R3, Invert ; if 2 + + MOVS R3, R3, LSL #31 ;Put bit 1 in C, NOT(bit 0) in Z + ADR R3, NoEffect ; if 0, 1, 2 or 3 + ADDNE R3, WsPtr, #FgEcfOraEor ; if 1 or 3 + ADRCS R3, Invert ; if 2 or 3 + ADDHI R3, WsPtr, #BgEcfOraEor ; if CS & NE - i.e. 3 + +; *****End of change made by DJS + +10 + STR R3, [WsPtr, #GColAdr] ; save address of Ecf to plot with + BL HLine + CLRV + Pull "R0,R2,R4-R10,WsPtr,PC" + +; ***************************************************************************** +; +; NewHLine - Horizontal line draw an even newer version what does 8 words +; ======== at a time if it can +; +; On entry, R0 (X), R1 (Y) holds coordinate of point +; R2 holds right hand XCoord +; On exit, R3 preserved +; R4..R10 corrupt +; PSR preserved +; +; N.B. R11 WILL BE PRESERVED - This is assumed by rectangle fill and all circle +; operations +; + +HLine + SortT R0, R2, R4 ; Sort the Xcoord into order R0<=R2 + +NewHLine ROUT ; Entry point for sorted Xcoords + + ADD R4, WsPtr, #GWLCol + LDMIA R4, {R4-R7} ; GWLCol,GWBRow,GWRCol,GWTRow + + CMP R7, R1 ; Test ycoord against window + CMPGE R1, R5 + + CMPGE R6, R0 ; Test xcoords against window + CMPGE R2, R4 + MOVLTS PC, R14 ; Quit if above,below,left or right + ; of window + + Greatest R0, R0, R4 ; If start of line to left of window + ; pull to window edge + Least R2, R2, R6 ; If end of line to right of window + ; pull to window edge + + Push "R0-R3,R11,Link" + +; +; Now, R0 holds Start (leftX), R1 holds Y and R2 holds End (rightX) +; +; Now pick up ecf word and form the ZGORA & ZGEOR masks +; + + ASSERT LineLength = YWindLimit +4 + ASSERT GColAdr = XShftFactor +4 + ASSERT ScreenStart = XShftFactor +8 + + ADD R11, WsPtr, #YWindLimit + LDMIA R11, {R10-R11} ; R10 = YWindLimit; R11 = LineLength + + ADD R9, WsPtr, #XShftFactor + LDMIA R9, {R7-R9} ; R7 = XShftFactor; R8 = GColAdr + ; R9 = ScreenStart + + SUB R1, R10, R1 ; flip ycoord into R1 + AND R6, R1, #7 ; R6 = line within ecf + ADD R8, R8, R6, LSL #3 ; R8 -> zgora, zgeor + LDMIA R8, {R8, R10} ; R8 = zgora; R10 = zgeor + + MLA R9, R11, R1, R9 ; R9 -> start of this scan line + + MOV R6, R0, LSR R7 ; R6 = X1Coord word offset + MOV R11, R2, LSR R7 ; R11 = X2Coord word offset + ADD R9, R9, R6, LSL #2 ; R9 = address of lefthand word + +; *****Change made by DJS +; Original code was: +; +; EOR R4, R0, R6, LSL R7 ; R4 = X1 pixel offset +; EOR R5, R2, R11, LSL R7 ; R5 = X2 pixel offset +; +; SUBS R11, R11, R6 ; R11 = number of words -1 +; ; and set Z on it +; +; ADD R7, WsPtr, #RAMMaskTb ; R7 -> MaskTb for this mode +; LDR R6, [R7, R4, LSL #2] ; R6 = left mask +; LDR R14, [R7, R5, LSL #2] ; R14 = right mask +; +; SUB R7, R14, #1 ; in right mask set all bits lower +; ORR R14, R14, R7 ; by RM = RM OR (RM-1) +; +; RSB R7, R6, #0 ; in left mask, set all bits higher +; ORR R6, R6, R7 ; by LM = LM OR (-LM) +; +; The following code is shorter and faster. + + SUBS R11, R11, R6 ; R11 = number of words -1 + ; and set Z on it + + RSB R7, R7, #5 ; R7 = Log2BPC (quicker than loading!) + MOV R14, #31 ; constant to extract bit offsets + AND R4, R14, R0, LSL R7 ; R4 = start of X1 pixel offset + AND R5, R14, R2, LSL R7 ; R5 = start of X2 pixel offset + MOV R14, #-1 ; Useful both as -1 and as &FFFFFFFF + SUB R5, R5, R14, LSL R7 ; R5 = end of X2 pixel offset + MOV R6, R14, LSL R4 ; R6 = left mask + MVN R14, R14, LSL R5 ; R14 = right mask + +; *****End of change made by DJS + + ANDEQ R14, R14, R6 ; if start word = end word + BEQ %FT40 ; then combine masks + + LDR R0, [R9] ; do left hand word of line + AND R1, R8, R6 ; zgora AND left mask + AND R2, R10, R6 ; zgeor AND left mask + ORR R0, R0, R1 ; screen OR or mask + EOR R0, R0, R2 ; EOR eor mask + STR R0, [R9], #4 ; store to screen + + SUBS R11, R11, #1 ; decrement word count, if =0 + BEQ %FT40 ; then plot RH partial word + + CMP R8, #-1 ; if R8 = -1 then store action + BNE %FT05 ; else do it the slow way + + MVN R0, R10 ; R0 = word of colour to plot + MOV R1, R0 + MOV R2, R0 + MOV R3, R0 + ADDS R8, R8, R11, LSR #3 ; R8 = (no. of words DIV 8)-1 + BCC %FT60 ; must be fewer than 8 + MOV R4, R0 + MOV R5, R0 + MOV R6, R0 + MOV R7, R0 + +; *****Additional message inserted by DJS + + [ (. :AND: 15) = 12 + ! 0, "HLine critical loop has bad alignment for running in RAM" + ] + +; *****End of message inserted by DJS + +50 + STMCSIA R9!, {R0-R7} ; write 8 words to screen if >=0 + STMHIIA R9!, {R0-R7} ; write 8 words to screen if > 0 + SUBS R8, R8, #2 ; try for another 16 + BCS %BT50 +60 + TST R11, #4 ; can we do 4 words ? + STMNEIA R9!, {R0-R3} ; write 4 words to screen + TST R11, #2 ; can we do 2 words ? + STMNEIA R9!, {R0-R1} ; write 2 words to screen + TST R11, #1 ; can we do 1 word ? + STMNEIA R9!, {R0} ; write 1 word to screen + AND R10, R10, R14 ; do partial word at end + LDR R0, [R9] + OrrEor R0,R0, R14,R10 + STR R0, [R9],#4 + + Pull "R0-R3,R11,PC",,^ + +; code for when not store action + +05 + SUBS R11, R11, #8 ; else try for 8 words at a time + BMI %FT20 ; failed, so try for 4 at a time +10 + LDMIA R9, {R0-R7} + OrrEor R0,R0, R8,R10 ; Write 8 words to screen + OrrEor R1,R1, R8,R10 + OrrEor R2,R2, R8,R10 + OrrEor R3,R3, R8,R10 + OrrEor R4,R4, R8,R10 + OrrEor R5,R5, R8,R10 + OrrEor R6,R6, R8,R10 + OrrEor R7,R7, R8,R10 + STMIA R9!, {R0-R7} + SUBS R11, R11, #8 ; try for another 8 + BPL %BT10 + +20 + ADDS R11, R11, #4 ; can we do 4 words ? + BMI %FT30 ; no, then do 1 word at a time + + LDMIA R9, {R0-R3} + OrrEor R0,R0, R8,R10 ; Write 4 words to screen + OrrEor R1,R1, R8,R10 + OrrEor R2,R2, R8,R10 + OrrEor R3,R3, R8,R10 + STMIA R9!, {R0-R3} + + SUB R11, R11, #4 +30 + ADDS R11, R11, #4 ; Correct for earlier SUB #4 + +40 ; Plot single words + ANDEQ R8, R8, R14 ; If EQ, this is RH word, + ANDEQ R10, R10, R14 ; so mask down to required pixels + LDR R0, [R9] + OrrEor R0,R0, R8,R10 + STR R0, [R9],#4 + + SUBS R11,R11,#1 + BPL %BT40 + + Pull "R0-R3,R11,PC",,^ + +; ***************************************************************************** +; +; NewVLine - Vertical line draw for non-dotted solid pattern lines +; +; in: R0 = R2 = X coord +; R1 = bottom Y coord +; R3 = top Y coord +; +; out: R4-R10 corrupt +; PSR preserved +; + +NewVLine ROUT ; Entry point for sorted Ycoords + + ADD R4, WsPtr, #GWLCol + LDMIA R4, {R4-R7} ; GWLCol,GWBRow,GWRCol,GWTRow + + CMP R7, R1 ; Test ycoord against window + CMPGE R3, R5 + + CMPGE R6, R0 ; Test xcoords against window + CMPGE R2, R4 + MOVLTS PC, R14 ; Quit if above,below,left or right + ; of window + + Greatest R1, R1, R5 ; If bottom of line below window + ; pull to window edge + Least R3, R3, R7 ; If top of line above window + ; pull to window edge + + + Push "R0-R3,R11,Link" + +; Now, R0 holds X, R1 holds bottom Y and R3 holds top Y +; +; Now pick up ecf word and form the ZGORA & ZGEOR masks +; + + ASSERT LineLength = YWindLimit +4 + ASSERT GColAdr = XShftFactor +4 + ASSERT ScreenStart = XShftFactor +8 + + ADD R11, WsPtr, #YWindLimit + LDMIA R11, {R10-R11} ; R10 = YWindLimit; R11 = LineLength + + ADD R9, WsPtr, #XShftFactor + LDMIA R9, {R7-R9} ; R7 = XShftFactor; R8 = GColAdr + ; R9 = ScreenStart + SUB R1, R3, R1 ; R1 = number of dots to do -1 + + SUB R3, R10, R3 ; R3 = flipped top ycoord + MLA R9, R11, R3, R9 ; R9 -> start of this scan line + + LDMIA R8, {R8, R10} ; R8 = zgora; R10 = zgeor + ; (no need to index with Y cos we + ; know there's no ECF pattern) + + MOV R6, R0, LSR R7 ; R6 = X coord word offset + ADD R9, R9, R6, LSL #2 ; R9 = address of top word + + EOR R4, R0, R6, LSL R7 ; R4 = X pixel offset + + ADD R7, WsPtr, #RAMMaskTb ; R7 -> MaskTb for this mode + LDR R6, [R7, R4, LSL #2] ; R6 = pixel mask + AND R8, R8, R6 ; zgora = zgora AND pixelmask + AND R10, R10, R6 ; zgeor = zgeor AND pixelmask + +; now do the plotting + +10 + LDR R6, [R9] + ORR R6, R6, R8 + EOR R6, R6, R10 + STR R6, [R9], R11 + SUBS R1, R1, #1 + BPL %BT10 + + Pull "R0-R3,R11,PC",,^ + + + +; ***************************************************************************** +; +; DoubleHLine - Draw 2 horizontal lines +; =========== +; +; On entry, R0 (X) - Left most point +; R1 (Y) - y ordinate of line +; R2 (X) - Right most point +; R3 (X) - end of left most line +; R4 (X) - start of right most line +; +; On exit, R0..R10 preserved } subject +; R11 corrupt } to change +; +DoubleHLine + Push "R0-R10, R14" + MOV R2, R3 ; draw left line, R0->R3 inc. + BL HLine + LDMIB R13, {R1-R4} + MOV R0, R4 ; draw right line, R4->R2 inc. + BL HLine + Pull "R0-R10, PC" + +; ***************************************************************************** +; +; ExtractTintAndColour - Convert 256-colour mode byte value into +; colour and tint +; +; Internal routine, called by ReadPixelColour, SwiReadPoint +; +; in: R0 = single screen pixel (ie 'half' user pixel in double modes) +; +; out: R0 corrupt +; R2 = colour value (GCOL a,colour) +; R3 = tint Vdu 23,17 etc +; + +ExtractTintAndColour ROUT + ; R0 := B3 G3 G2 R3 B2 R2 T1 T0 + MOV R3, R0, LSL #6 ; R3 := T1 T0 0 0 0 0 0 0 + AND R3, R3, #&C0 + AND R2, R0, #&84 ; R2 := B3 0 0 0 0 R2 0 0 + TST R0, #8 + ORRNE R2, R2, #&40 ; R2 := B3 B2 0 0 0 R2 0 0 + AND R0, R0, #&70 ; R0 := 0 G3 G2 R3 0 0 0 0 + ORR R2, R2, R0, LSR #1 ; R2 := B3 B2 G3 G2 R3 R2 0 0 + MOV R2, R2, LSR #2 ; R2 := 0 0 B3 B2 G3 G2 R3 R2 + MOVS PC, R14 + +; ***************************************************************************** +; +; SwiReadPoint - Read colour of screen pixel +; +; External routine - entry point for SWI OS_ReadPoint +; +; in: R0, R1 = X, Y coordinate of point +; +; out: R2 = colour (as in GCOL a,colour) } -1 if off screen +; R3 = tint value (as in VDU 23,17 etc) } 0 if off screen +; R4 = 0/-1 for On/Off screen +; R0,R1, R5-R9 preserved (R10-R12 preserved by MOS) +; + +SwiReadPoint ROUT + TEQP PC, #SVC_mode ; re-enable interrupts + VDWS WsPtr ; point R12 at vdu driver workspace + + [ {TRUE} + GraphicsMode R10 ; if not a graphics mode then give up now! + BNE %FT20 + | + LDR R10, [WsPtr, #NPix] ; if not a graphics mode then + CMP R10, #0 ; indicate off screen + BEQ %FT20 + ] + + Push "R0-R9, R14" ; save registers + + ADD R7, WsPtr, #GCsX + LDMIA R7, {R8,R9} ; preserve GCsX,GCsY around EIG + MOV R2, #4 ; absolute coord + BL EIG + STMIA R7, {R8,R9} ; restore GcsX,GCsY + + WINDow R0,R1, R2,R3,R4,R5 + BLT %FT10 ; outside window + + Push "R0,R1" ; save internal coords + BL PreWrchCursor ; remove any split cursors etc + Pull "R0,R1" + ; R0,R1,R2 ,R3 ,R4 ,R5 ,R6 ,R7 ,R8 + BL ScreenAddr ; in :X ,Y + ; out:X ,Y ,Adr,Msk, , , ,crp,crp + LDR R8, [WsPtr, #NColour] + +;amg - changes here to cope with 16/32bpp which will also return an NCOL with b4-b7 set + +; TST R8, #&F0 ; if NColour=63 +; MOVNE R8, #&FF ; then use 255 + + CMP R8,#63 + MOVEQ R8,#255 + + LDR R9, [WsPtr, #XShftFactor] + LDR R10, [WsPtr, #NPix] + LDR R11, [WsPtr, #Log2BPC] + + BitLOffset R7,R0, R9,R10,R11 ; R7 := bit position to align to + + LDR R0, [R2] + AND R0, R8, R0, LSR R7 ; extract one pixel + + TEQ R8,#255 + MOVNE R2,R0 + MOVNE R3,#0 + BLEQ ExtractTintAndColour + +; TST R8, #&F0 ; if not a 256 colour mode +; MOVEQ R2, R0 ; colour = pixel +; MOVEQ R3, #0 ; tint = 0 +; BLNE ExtractTintAndColour ; else extract colour & tint from pixel + + MOV R4, #0 ; indicate on screen + + ADD R0, R13, #2*4 ; point to stacked R2 + STMIA R0, {R2-R4} + + BL PostWrchCursor + + Pull "R0-R9, R14" ; restore R0-R9 & return address + BIC R14, R14, #V_bit + ExitSWIHandler + +10 + Pull "R0-R9, R14" ; restore R0-R9 & return address +20 + MOV R2, #-1 + MOV R3, #0 + MOV R4, #-1 + + BIC R14, R14, #V_bit + ExitSWIHandler + +; ***************************************************************************** +; +; GenCircleParm - Generate a control block for a circle +; +; Internal routine, called by CircleOutline, CircleFill, GenArcParmBlk +; +; in: R0 (X), R1(Y) centre of circle +; R2 (X), R3(Y) point on circumference +; +; out: R0-R7 hold the following control block +; R0 - xPnt (CurrentX - relative to centre) +; R1 - yPnt (CurrentY - relative to centre) +; R2 - sum (Bres) +; R3 - upcnt +; R4 - downcnt +; R5 - CentreX +; R6 - CentreY +; R7 - Aspect (pixel shape : 0 square, 1 horz rect, 2 vert rect) +; R8-R11 undefined +; +GenCircleParm + Push R14 + LDR R11, [WsPtr, #AspectRatio] + SUB R7, R2, R0 + TST R11, #1 ; if pixels are horz rects, adjust + MOVNE R7, R7, LSL #1 ; x distance + MUL R2, R7, R7 ; R2 = (x-cx)^2 + + SUB R7, R3, R1 + TST R11, #2 ; if pixels are vert rects, adjust + MOVNE R7, R7, LSL #1 ; y distance + + MLA R2, R7, R7, R2 ; rawradsqr=(x-cx)^2 + (y-cy)^2 + MOV R7, R2 + BL SquareRoot + + ADD R2, R2, R8 ; radsqr=rawradsqr+rawrad + STR R2, [WsPtr, #CircleRadSquare] ; needed in seg. line calc + + MOV R7, R2 + BL SquareRoot + MOV R4, R8 ; R4=rad, R2=radsqr + +; +; Now build the parameter block proper +; +; R0 = CentreX, R1 = CentreY, R2 = radsqr, R4 = rad +; + MUL R9, R4, R4 ; R9=rad*rad + SUB R2, R2, R9 ; Sum=radsqu-rad*rad + + MOV R5, R0 ; CentreX + MOV R6, R1 ; CentreY + + MOV R0, R4 ; xPnt starts at rad + + ADD R4, R4, R4 + SUB R4, R4, #1 ; downcnt = 2*rad-1 + + MOV R1, #0 ; yPnt starts at 0 + MOV R3, #1 ; upcnt = 1 + + LDR R7, [WsPtr,#AspectRatio] ; taking account of pixel shape + LDR R11, [WsPtr, #CursorFlags] + TST R11, #ClipBoxEnableBit + BLNE ClipCircle + + CMP R7, #1 + + MOVEQ R0, R0, ASR #1 ; if horz pixel (ie like mode2) + ADDEQ R2, R2, R4 + SUBEQ R4, R4, #2 + + SUBGT R2, R2, R3 ; if vert pixel (ie like mode0) + ADDGT R3, R3, #2 + + Pull PC + +; ***************************************************************************** +; +; AdvCircleParm - Advance a set of circle parameters +; +; Internal routine, called by CircleOutline, CircleFill, CircleArc, +; SegmentFill, SectorFill +; +; in: R0..R7 hold a circle parameter block +; +; out: R0 (X), R1 (Y) updated +; C=1 <=> R1 (Y) has changed +; Z preserved +; +; Format of a control block +; R0 - xPnt (CurrentX - relative to centre) +; R1 - yPnt (CurrentY - relative to centre) +; R2 - sum (Bres) +; R3 - upcnt +; R4 - downcnt +; R5 - CentreX +; R6 - CentreY +; R7 - Aspect (pixel shape : 0 square, 1 horz rect, 2 vert rect) +; + +AdvCircleParm ROUT + CMP R2, R3 ; if sum >= upcnt advance Y only + BGE %FT10 + + SUB R0, R0, #1 ; else step xPnt inward one point + + ADD R2, R2, R4 ; Sum := Sum + DownCnt + SUB R4, R4, #2 ; DownCnt = next lower odd number + + TST R7, #1 ; if pixels are horizontal rectangles + ADDNE R2, R2, R4 ; modify sum again, so x steps at + SUBNE R4, R4, #2 ; half normal rate + + CMP R2, R3 + BICLTS PC, R14, #C_bit ; if not doing Y, indicate with C=0 +10 + ; if sum >= upcnt then advance Y + ADD R1, R1, #1 ; step yPnt up a line + + SUB R2, R2, R3 ; Sum := Sum - UpCnt + ADD R3, R3, #2 ; UpCnt = next higher odd number + + TST R7, #2 ; if pixels are vertical rectangles + SUBNE R2, R2, R3 ; modify sum again, so y steps + ADDNE R3, R3, #2 ; at half normal rate + + ORRS PC, R14, #C_bit ; Y modified, so return C=1 + +; ***************************************************************************** +; +; SquareRoot - Calculate the square root of a 32-bit number +; +; Internal routine, called by GenSegParmBlk, GenCircleParm +; +; SquareRootAlt is a alternative routine which specifies the precision +; of the result in R11 (SquareRoot produces a 16-bit result) +; +; in: R7 = number to squareroot +; +; out: R8 = result +; R9-R11 corrupted +; R9 temp +; R10 sqdiff +; R11 counter +; + +SquareRoot ROUT + MOV R11, #16 ; 16 bit result +SquareRootAlt + MOV R8, #0 ; result=0 + MOV R10, #0 ; sqdiff=0 +10 + +; *****Change made by DJS +; Original code was: +; ADDS R7, R7, R7 ; (sqdiff,number) = (sqdiff,number)*4 +; ADC R10, R10, R10 +; ADDS R7, R7, R7 +; ADCS R10, R10, R10 ; (C:=0 we hope!) + + MOVS R10, R10, LSL #2 ; C:=0 (we hope!) while doing (sqdiff, + ORR R10, R10, R7, LSR #30 ; number) := (sqdiff, number) * 4 + MOV R7, R7, LSL #2 + +; *****End of change made by DJS + + SBCS R9, R10, R8, LSL #2 ; C=0 here, so try to subtract + ; result*4 +1 from sqdiff + MOVCS R10, R9 ; if successful then shift in a "1" bit + ADC R8, R8, R8 ; else shift in a "0" bit + SUBS R11, R11, #1 ; decrement loop counter + BNE %BT10 + + MOVS PC, R14 + +; ***************************************************************************** +; +; DoOsWord13 - Read graphics cursors (in external coords) +; +; in: R1 -> control block +; +; out: [R1+0..1] = old cursor X +; [R1+2..3] = old cursor Y +; [R1+4..5] = current cursor X +; [R1+6..7] = current cursor Y +; + ASSERT OldCsY = OldCsX +4 + ASSERT YEigFactor = XEigFactor +4 + ASSERT OrgY = OrgX +4 + ASSERT GCsY = GCsX +4 + +DoOsWord13 ROUT + Push "R0-R6" + MOV R6, R1 ; pointer to control block + + ADD R0, WsPtr, #OldCsX + LDMIA R0, {R0, R1} + ADD R2, WsPtr, #XEigFactor + LDMIA R2, {R2, R3} ; R2 = XEigFactor; R3 = YEigFactor + ADD R4, WsPtr, #OrgX + LDMIA R4, {R4, R5} ; R4 = OrgX; R5 = OrgY + RSB R0, R4, R0, LSL R2 ; R0 = (X << XEigFactor)-OrgX + RSB R1, R5, R1, LSL R3 ; R1 = (Y << YEigFactor)-OrgY + + STRB R0, [R6], #1 + MOV R0, R0, LSR #8 + STRB R0, [R6], #1 + STRB R1, [R6], #1 + MOV R1, R1, LSR #8 + STRB R1, [R6], #1 + + ADD R0, WsPtr, #GCsX + LDMIA R0, {R0, R1} ; get current cursor + + STRB R0, [R6], #1 + MOV R0, R0, LSR #8 + STRB R0, [R6], #1 + STRB R1, [R6], #1 + MOV R1, R1, LSR #8 + STRB R1, [R6], #1 + + Pull "R0-R6" + MOV PC, R14 + + LTORG + END diff --git a/s/vdu/vdupointer b/s/vdu/vdupointer new file mode 100644 index 0000000000000000000000000000000000000000..bc7b20d0fe40b0d085a6fb61a7679453c329f23a --- /dev/null +++ b/s/vdu/vdupointer @@ -0,0 +1,657 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.VduPointer + +; ***************************************************************************** +; +; DoPointerStuff - Entry point for OSWORD nn +; +; in: R1 -> control block +; [R1, #0] : Reason code +; +; Reason code 0 - Define pointer size, shape and active point +; +; [R1, #1] : Shape number (1..4) +; [R1, #2] : Width (w) in bytes (0..8) +; [R1, #3] : Height (h) in pixels (0..32) +; [R1, #4] : ActiveX in pixels from left (0..w*4-1) +; [R1, #5] : ActiveY in pixels from top (0..h-1) +; [R1, #6..9] : Pointer (P) to data +; [P, #0..w*h-1] : Data bytes in rows from top to bottom, +; left to right in each row. +; +; Reason code 1 - Define mouse coordinate bounding box +; +; [R1, #1..2] : left ; all treated as +; [R1, #3..4] : bottom ; signed 16-bit values, +; [R1, #5..6] : right ; relative to screen origin at the time +; [R1, #7..8] : top ; the command is issued +; +; If (left > right) or (bottom > top) then the command is ignored +; An infinite box can be obtained by setting +; left=&8000, right=&7FFF, bottom=&8000, top=&7FFF +; +; If the current mouse position is outside the box, it is moved to +; the nearest point inside the box +; +; The mouse buffer is NOT flushed - any buffered coords will be moved +; inside the bounding box when they are read. +; +; Reason code 2 - Define mouse multipliers +; +; [R1, #1] : X multiplier ; both treated as +; [R1, #2] : Y multiplier ; signed 8-bit values +; +; Reason code 3 - Set mouse position +; +; [R1, #1..2] : X position ; both treated as +; [R1, #3..4] : Y position ; signed 16-bit values +; The mouse buffer is flushed +; +; Reason code 4 - Read mouse position (not buffered) +; +; out: [R1, #1..2] : X position ; both treated as +; [R1, #3..4] : Y position ; signed 16-bit values +; +; Reason code 5 - Set pointer position +; +; [R1, #1..2] : X position ; both treated as +; [R1, #3..4] : Y position ; signed 16-bit values +; +; Reason code 6 - Read pointer position +; +; out: [R1, #1..2] : X position ; both treated as +; [R1, #3..4] : Y position ; signed 16-bit values +; + +DoPointerStuff ROUT + LDRB R0, [R1, #0] + +; *****Change made by DJS & SKS +; Original code was: +; CMP R0, #1 +; BCC DoDefinePointer +; BEQ DoMouseBox +; CMP R0, #3 +; BCC SetMouseMult +; BEQ SetMousePosn +; CMP R0, #5 +; BCC ReadMousePosn +; BEQ SetPointerPosn +; CMP R0, #7 +; BCC ReadPointerPosn +; MOV PC, R14 + + CMP R0, #7 + + [ Module + + ADDCC PC, PC, R0, LSL #2 + MOV PC, R14 ; ***** WHY NO ERROR???????? + B DoDefinePointer + B DoMouseBox + B SetMouseMult + B SetMousePosn + B ReadMousePosn + B SetPointerPosn + B ReadPointerPosn + + | + + LDRCC PC, [PC, R0, LSL #2] + MOV PC, R14 ; ***** WHY NO ERROR???????? + DCD DoDefinePointer + DCD DoMouseBox + DCD SetMouseMult + DCD SetMousePosn + DCD ReadMousePosn + DCD SetPointerPosn + DCD ReadPointerPosn + + ] + +; *****End of change made by DJS & SKS + +; ***************************************************************************** + +DoDefinePointer + Push "R1-R6, R14" + [ Fix8 + CLRPSR I_bit, R0 ; could take some time + ] + MOV R0, #19 ; wait for vsync, so we change + SWI XOS_Byte ; cleanly (ignore errors) + + LDMFD R13, {R1} ; get back pointer to block + + LDRB R6, [R1, #1] ; shape number + SUB R6, R6, #1 + CMP R6, #4 ; now in range 0..3 ? + BCS %FT10 ; bad shape number + + ADD WsPtr, WsPtr, R6 ; point to table entries + + LDRB R0, [R1, #2] ; R0 = width + LDRB R2, [R1, #3] ; R2 = height + LDRB R3, [R1, #4] ; R3 = ActiveX + LDRB R4, [R1, #5] ; R4 = ActiveY + + CMP R2, #0 ; C=1 if EQ + STREQB R2, [WsPtr, #PointerHeights] + BEQ %FT10 + + CMP R0, #0 ; C=1 if EQ + STREQB R0, [WsPtr, #PointerHeights] + CMPNE R0, #8+1 + BCS %FT10 ; bad width + + CMP R2, #32+1 ; C=1 => bad height + CMPCC R3, R0, LSL #2 ; ActiveX >= (width * 4) ? + CMPCC R4, R2 ; ActiveY >= height + + BCS %FT10 ; bad definition + + STRB R2, [WsPtr, #PointerHeights] + STRB R3, [WsPtr, #PointerActiveXs] + STRB R4, [WsPtr, #PointerActiveYs] + + ADD R4, R1, #6 + LDW R1, R4, R3, R5 ; load word from + ; unknown alignment +; Now R1 -> user's data + + LDR R3, =CursorData ; &200 per shape, so + ADD R3, R3, R6, LSL #9 ; R3 -> first copy + ADD R6, R3, #&F8 ; R6 -> second copy +20 + ADD R4, R3, R0 ; terminating R3 for this row +30 + LDRB R5, [R1], #1 +40 + STRB R5, [R3], #1 ; store to 1st copy + STRB R5, [R6], #1 ; store to 2nd copy + CMP R3, R4 ; still within user data + BCC %BT30 ; for this row ? + +; now fill up rest of row + + MOV R5, #0 + TST R3, #7 ; are we on a multiple of 8 + BNE %BT40 ; no, then store 0 + + SUBS R2, R2, #1 ; done all rows ? + BNE %BT20 ; no, then loop + +10 + Pull "R1-R6,PC" + +; ***************************************************************************** +; +; SetMouseRectangle - Called on mode change to set appropriate mouse +; rectangle and mouse position +; +; in: WsPtr -> VDWS +; + +SetMouseRectangle ROUT + Push R14 + + ASSERT DisplayYWindLimit = DisplayXWindLimit +4 + ASSERT DisplayXEigFactor = DisplayXWindLimit +8 + ASSERT DisplayYEigFactor = DisplayXWindLimit +12 + + ADD R2, WsPtr, #DisplayXWindLimit + LDMIA R2, {R2-R5} + + ADD R2, R2, #1 ; XWindLimit+1 + MOV R2, R2, LSL R4 ; (XWindLimit+1) << XEigFactor + SUB R4, R2, #1 ; ((XWindLimit+1) << XEigFactor)-1 + MOV R2, R2, LSR #1 ; centre x of window + + ADD R3, R3, #1 ; YWindLimit+1 + MOV R3, R3, LSL R5 ; (YWindLimit+1) << YEigFactor + SUB R5, R3, #1 ; ((YWindLimit+1) << YEigFactor)-1 + MOV R3, R3, LSR #1 ; centre y of window + + BL SetMousePosnRegs + + MOV R2, #0 ; left = 0 + MOV R3, #0 ; bottom = 0 + + Push "R1-R6" + B DoMouseBoxRegs + + +DoMouseBox ROUT + Push "R1-R6, R14" + + LDRB R2, [R1, #1] ; R2 = left + LDRB R0, [R1, #2] + ORR R2, R2, R0, LSL #8 + + LDRB R3, [R1, #3] ; R3 = bottom + LDRB R0, [R1, #4] + ORR R3, R3, R0, LSL #8 + + LDRB R4, [R1, #5] ; R4 = right + LDRB R0, [R1, #6] + ORR R4, R4, R0, LSL #8 + + LDRB R5, [R1, #7] ; R5 = top + LDRB R0, [R1, #8] + ORR R5, R5, R0, LSL #8 + +DoMouseBoxRegs + +; now add on graphics origin + + LDR R0, [WsPtr, #OrgX] + ADD R2, R2, R0 + ADD R4, R4, R0 + LDR R0, [WsPtr, #OrgY] + ADD R3, R3, R0 + ADD R5, R5, R0 + +; now sign extend all coords + + MOV R2, R2, LSL #16 + MOV R2, R2, ASR #16 + MOV R3, R3, LSL #16 + MOV R3, R3, ASR #16 + MOV R4, R4, LSL #16 + MOV R4, R4, ASR #16 + MOV R5, R5, LSL #16 + MOV R5, R5, ASR #16 + +; now check right >= left and top >= bottom + + CMP R4, R2 + CMPGE R5, R3 + BLT %FT10 ; bad definition + +; everything seems OK, so disable IRQs while we update vars + + MOV R14, PC + ORR R0, R14, #I_bit + TEQP R0, #0 + + Push R11 + MOV R11, #KeyWorkSpace + + ADR R0, MouseBounds + STMIA R0, {R2-R5} + +; check mouse position is within box + + LDR R0, MouseX + CMP R0, R2 ; if X < left + STRLT R2, MouseX ; then X := left + CMP R4, R0 ; if right < X + STRLT R4, MouseX ; then X := right + + LDR R0, MouseY + CMP R0, R3 ; if Y < bottom + STRLT R3, MouseY ; then Y := bottom + CMP R5, R0 ; if top < Y + STRLT R5, MouseY ; then Y := top + + Pull R11 + +; BL FlushMouse ; flush mouse buffer no longer done + +; *****Change made by DJS and SKS +; Bug fix. Original code was: +; TEQP R14, #0 ; restore old IRQ state +;10 +; Pull "R1-R6, PC" +; This is making use of a nonsense value of R14. It also looks as if this +; can be made shorter: + +10 + Pull "R1-R6, PC",,^ ;Return, restoring old IRQ state + +; ***************************************************************************** +; +; UpdatePointer - Called on vsync to update pointer position +; +; in: WsPtr (R12) -> VduDriverWorkSpace +; + +UpdatePointer ROUT + MOV R11, #KeyWorkSpace + MOV R10, #VIDC + + LDRB R5, [WsPtr, #PointerShapeNumber] + TST R5, #&80 ; pointer unlinked if bit 7 set + + LDREQ R6, MouseX + STREQ R6, [WsPtr, #PointerX] + LDREQ R6, MouseY + STREQ R6, [WsPtr, #PointerY] + + ANDS R5, R5, #&7F ; clear bit 7 and set Z if 0 ie off + SUBNE R5, R5, #1 + ADDNE R6, WsPtr, R5 ; R6 is WsPtr + index + + LDRNEB R0, [R6, #PointerHeights] + TEQNE R0, #0 ; if shape 0 or height 0 + BNE %FT07 +05 + +; don't display pointer + + MOV R1, #0 ; Y := 0 + MOV R2, #0 ; height := 0 + MOV R4, #0 ; LAG offset := 0 + B %FT10 + +07 + [ VIDC_Type = "VIDC20" + + LDR R2, [WsPtr, #PointerXEigFactor] + LDR R3, [WsPtr, #PointerX] + MOV R3, R3, ASR R2 + + LDRB R2, [R6, #PointerActiveXs] + SUB R3, R3, R2 ; subtract off active point coord + + CMP R3, #-31 ; if LHS < -31, ie RHS < 0 + BLT %BT05 ; then remove pointer completely (fixes MED-00523) + + LDR R1, [WsPtr, #CursorFudgeFactor] + ADDS R3, R3, R1 ; X := X + CursFudgeFactor + MOVLT R3, #0 ; if < 0 then make =0 + + CMP R3, #16*1024 ; if >= limit then make =limit-1 + MOVGE R3, #16*1024 + SUBGE R3, R3, #1 + + ORR R3, R3, #HorizCursorStart + | + LDR R1, [WsPtr, #CursorFudgeFactor] + LDRB R2, [R6, #PointerActiveXs] + SUB R1, R1, R2 + + LDR R2, [WsPtr, #PointerXEigFactor] + LDR R3, [WsPtr, #PointerX] + MOV R3, R3, ASR R2 + + LDR R4, [WsPtr, #DisplayModeFlags] + TST R4, #Flag_HiResMono ; if not hi-res-mono + MOVEQ R3, R3, LSL #2 ; then multiply by 4 + + ADD R3, R3, R1, LSL #2 ; X := X + (CursFudgeFactor-ActiveX)<<2 + + CMP R3, #0 ; if < 0 then make =0 + MOVLT R3, #0 + + CMP R3, #8*1024 ; if >= limit then make =limit-1 + MOVGE R3, #8*1024 + SUBGE R3, R3, #1 + + MOV R3, R3, LSL #11 + ORR R3, R3, #HorizCursorStart + ] + + [ {FALSE} ; debug horiz pointer programming + Push "r0,lr" + MOV r0, r3 + BL TubeDumpR0 + BL TubeNewl + Pull "r0,lr" + ] + + STR R3, [R10] + +; now process Y + + LDR R1, [WsPtr, #PointerY] + LDR R2, [WsPtr, #DisplayYEigFactor] + + LDR R3, [WsPtr, #DisplayYWindLimit] + ; Total height of screen in pixels-1 + SUB R1, R3, R1, ASR R2 ; convert Y to pixels and invert + + LDRB R2, [R6, #PointerActiveYs] + SUB R1, R1, R2 + + MOV R2, #0 ; height + MOV R4, R5, LSL #9 ; LAG offset from CursorData + + ADD R5, R3, #1 ; Total vertical pixels + + ADDS R3, R1, R0 ; R3 = Y + PointerHeight(shape) + MOVLE R1, #0 ; if <= 0 then off, ie Y=0, height=0 + BLE %FT10 + + CMP R1, R5 ; Y >= TotalHeight + MOVGE R1, #0 ; then off + BGE %FT10 + + CMP R3, R5 ; Y + PointerHeight > TotalHeight + RSBGT R2, R1, R5 ; then height=TotalHeight-Y + BGT %FT10 + + CMP R1, #0 ; Y >=0 + MOVGE R2, R0 ; then height=PointerHeight + BGE %FT10 + + TST R1, #1 ; Y odd ? + ADDNE R4, R4, #&100 ; then use 2nd copy + + ADD R2, R1, R0 ; height = PointerHeight+Y + + RSB R1, R1, #0 ; Y := -Y + BIC R1, R1, #1 ; Y := (-Y AND NOT 1) + ADD R4, R4, R1, LSL #3 ; add on offset into shape + MOV R1, #0 ; Y := 0 +10 + Push "r1, r14" + [ MEMC_Type = "IOMD" + MOV r0, #0 + LDR r0, [r0, #DRAMPhysAddrA] + LDR r1, =DRAMOffset_CursorChunk + (CursorData - CursorChunkAddress) + ADD r0, r0, r1 + | + LDR r0, =PhysCursorStartAdr + ] + ADD r0, r0, r4 + MOV r1, #MEMCDAG_CInit + BL SetDAG + Pull "r1, r14" + + [ VIDC_Type <> "VIDC20" + MOV R1, R1, LSL #14 ; shift up + ] + LDR R3, [WsPtr, #VertAdjust] ; get display start value + ADD R1, R1, R3 ; and add on + + ORR R3, R1, #VertiCursorStart + STR R3, [R10] + + [ VIDC_Type = "VIDC20" + ADD R1, R1, R2 ; add height + | + ADD R1, R1, R2, LSL #14 ; add height + ] + ORR R3, R1, #VertiCursorEnd + STR R3, [R10] + + MOV PC, R14 + + LTORG + +; ***************************************************************************** + +SetMouseMult ROUT + Push "R11,R14" + MOV R11, #KeyWorkSpace + + LDRB R0, [R1, #1] + MOV R0, R0, LSL #24 ; sign extend to 32 bits + MOV R0, R0, ASR #24 + STR R0, MouseXMult + + LDRB R0, [R1, #2] + MOV R0, R0, LSL #24 ; sign extend to 32 bits + MOV R0, R0, ASR #24 + STR R0, MouseYMult + + Pull "R11,PC" + +; ***************************************************************************** +; +; GetCoordPair - get pair of 2-byte coords from R1+1..R1+4 +; adds on graphics origin and sign extends to 32 bits +; and puts X into R2, Y into R3 +; + +GetCoordPair ROUT + LDRB R0, [R1, #1] ; get X coordinate + LDRB R2, [R1, #2] + ORR R0, R0, R2, LSL #8 + + LDR R2, [WsPtr, #OrgX] ; add on origin + ADD R0, R0, R2 + + MOV R0, R0, LSL #16 ; sign extend 16 to 32 + MOV R2, R0, ASR #16 + + LDRB R0, [R1, #3] ; get Y coordinate + LDRB R3, [R1, #4] + ORR R0, R0, R3, LSL #8 + + LDR R3, [WsPtr, #OrgY] ; add on origin + ADD R0, R0, R3 + + MOV R0, R0, LSL #16 ; sign extend 16 to 32 + MOV R3, R0, ASR #16 + + MOV PC, R14 + +; ***************************************************************************** + +SetMousePosn ROUT + Push "R2, R3, R11, R14" + MOV R11, #KeyWorkSpace + + BL GetCoordPair + +; now check point is within bounding box + + LDR R0, MouseBoundLCol + CMP R2, R0 + LDRGE R0, MouseBoundRCol + CMPGE R0, R2 + LDRGE R0, MouseBoundBRow + CMPGE R3, R0 + LDRGE R0, MouseBoundTRow + CMPGE R0, R3 + + BLGE SetMousePosnRegs + + Pull "R2, R3, R11, PC" + +SetMousePosnRegs + MOV R11, #KeyWorkSpace + STR R2, MouseX + STR R3, MouseY + B FlushMouse + +; ***************************************************************************** +; +; StoreCoordPair - Stores X,Y coords in R2,R3 in R1+1..R1+4 +; subtracts graphics origin + +StoreCoordPair ROUT + + LDR R0, [WsPtr, #OrgX] ; subtract off origin + SUB R2, R2, R0 + + STRB R2, [R1, #1] ; store lo-byte of X + MOV R2, R2, LSR #8 + STRB R2, [R1, #2] ; store hi-byte of X + + LDR R0, [WsPtr, #OrgY] ; subtract off origin + SUB R3, R3, R0 + + STRB R3, [R1, #3] ; store lo-byte of Y + MOV R3, R3, LSR #8 + STRB R3, [R1, #4] ; store hi-byte of Y + + MOV PC, R14 + +; ***************************************************************************** + +ReadMousePosn ROUT + [ AssemblePointerV :LAND: {TRUE} + Push "r0-r3, r9-r11, lr" + BL PollPointer ; update mouse position on a read + LDR r1, [sp, #1*4] ; reload pointer to buffer + MOV R11, #KeyWorkSpace + + LDR R2, MouseX ; get mouse X + LDR R3, MouseY ; get mouse Y + BL StoreCoordPair + Pull "r0-r3, r9-r11, pc" + + | + Push "R2, R3, R11, R14" + MOV R11, #KeyWorkSpace + + LDR R2, MouseX ; get mouse X + LDR R3, MouseY ; get mouse Y + BL StoreCoordPair + + Pull "R2, R3, R11, PC" + ] + +; ***************************************************************************** + +SetPointerPosn ROUT + Push "R2, R3, R14" + + BL GetCoordPair + + STR R2, [WsPtr, #PointerX] + STR R3, [WsPtr, #PointerY] + + Pull "R2, R3, PC" + +; ***************************************************************************** + +ReadPointerPosn ROUT + Push "R2, R3, R14" + + LDR R2, [WsPtr, #PointerX] + LDR R3, [WsPtr, #PointerY] + BL StoreCoordPair + + Pull "R2, R3, PC" + +; ***************************************************************************** +; +; FlushMouse - Flush mouse buffer +; +; out: All registers preserved + +FlushMouse ROUT + Push "R0-R2, R14" + MOV R0, #21 + MOV R1, #Buff_Mouse + SWI XOS_Byte + Pull "R0-R2, PC" + + END diff --git a/s/vdu/vduswis b/s/vdu/vduswis new file mode 100644 index 0000000000000000000000000000000000000000..131efe1e9e49268ed86e4c7776a49ef1b8c37a27 --- /dev/null +++ b/s/vdu/vduswis @@ -0,0 +1,2001 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.VduSWIs + + GBLL FixRemovePages +FixRemovePages SETL {TRUE} + + MACRO + BranchNotJustUs $label, $vector, $tmp1, $tmp2 + MOV R11, #0 + [ AssemblingArthur + [ $tmp1=R11 + LDR R12, [R11, #VecPtrTab+$vector*4]! ; load vector node + | + LDR R12, [R11, #VecPtrTab+$vector*4] ; load vector, leave R11=0 + ] + CMP R12, #&03800000 + BCC $label + | + [ Module + LDR $tmp1, [R11, #VecPtrTab+$vector*4] ; load vector node + LDR R12, [$tmp1] ; get first address on chain + EOR $tmp2, R12, #&01000000 + CMP $tmp2, #&00020000 + BCS $label + | + LDR $tmp1, [R11, #VecPtrTab+$vector*4] ; load vector node + LDR R12, [$tmp1] ; get first address on chain + [ $vector=SpriteV + EOR $tmp2, R12, #&01600000 + | + RSB $tmp2, R12, #&01E00000 + ] + CMP $tmp2, #&10000 + BCS $label + ] + ] + MEND + + MACRO + BranchNotJustUsWrch $label + BranchNotJustUs $label, WrchV, R11, R14 + MEND + + MACRO + SWIEntry $swiname + & OS_$swiname + & SWI$swiname-(.+4) + MEND + + [ :LNOT: AssemblingArthur +SetUpSWIs ROUT + LDR R1, =SvcTable + ADR R2, SWITable +10 + LDMIA R2!, {R3, R4} ; R3 = SWI number; R4 = address offset + CMP R3, #-1 ; end of table ? + ADDNE R4, R4, R2 ; no, then R4 = address + STRNE R4, [R1, R3, LSL #2] + BNE %BT10 + MOV PC, R14 + +SWITable + SWIEntry ReadVduVariables + SWIEntry ReadPalette + SWIEntry ReadModeVariable + SWIEntry RemoveCursors + SWIEntry RestoreCursors + SWIEntry CheckModeValid + SWIEntry ClaimScreenMemory + SWIEntry Plot + SWIEntry WriteN + SWIEntry Write0 + SWIEntry WriteS + SWIEntry SetECFOrigin + SWIEntry ChangedBox + & -1 + ] + +; ***************************************************************************** +; +; SWIRVV - SWI ReadVduVariables handler +; +; in: R0 -> input block +; R1 -> output block +; +; out: All registers preserved +; +; The input block consists of a string of words, terminated by -1 +; Each word indicates which VDU variable to read. +; The (word) values of these variables are put in sequence into the +; output block (no terminator is put in this block). Invalid variables +; are returned as zero. + +SWIRVV ROUT +SWIReadVduVariables ; alternative symbol used for init'ing + TST R0, #3 ; input block not aligned + TSTEQ R1, #3 ; or output block not aligned + ExitSWIHandler NE ; then exit + Push R9 + VDWS WsPtr + MOV R10, #0 ; offset into both blocks +10 + LDR R11, [R0, R10] + CMP R11, #-1 ; end of block ? + Pull R9, EQ + ExitSWIHandler EQ + + CMP R11, #&100 ; is it fudged "code" variable + BCS %FT30 ; yes, then use special code + + CMP R11, #(SWIRVVTabModeEnd-SWIRVVTab) ; a mode variable + ADRCC R9, SWIRVVTab ; if so then point to them + BCC %FT20 + SUB R11, R11, #&80 ; base for non-mode variables + CMP R11, #(SWIRVVTabEnd-SWIRVVTabModeEnd) + ADRCCL R9, SWIRVVTabModeEnd +20 + LDRCCB R11, [R9, R11] ; yes, then load offset + LDRCC R11, [WsPtr, R11, LSL #2] ; and then load variable + MOVCS R11, #0 ; no, then put zero in it +25 + STR R11, [R1, R10] + ADD R10, R10, #4 + B %BT10 + +; Special code to read window width for Bruce et al. + +30 + SUB R11, R11, #&100 + CMP R11, #2 ; 0 => WindowWidth, 1 => WindowHeight + BCS %BT20 ; not one of those, so illegal + + Push "R0-R7" + LDR R6, [WsPtr, #CursorFlags] + TST R6, #Vdu5Bit + ADDEQ R4, WsPtr, #TWLCol ; if VDU 4 mode, use text window + ADDNE R4, WsPtr, #GWLCol ; else use graphics window + LDMIA R4, {R0-R3} + SUB R0, R2, R0 ; R0 = horizontal width -1 + SUB R1, R1, R3 ; R1 = vertical height -1 + + BEQ %FT32 + + ADD R2, WsPtr, #GCharSizes ; R2=GCharSizeX; R3=GCharSizeY + LDMIA R2, {R2-R5} ; R4=GCharSpaceX; R5=GCharSpaceY + + TST R6, #2 ; if going from right to left + SUBNE R2, R2, #1 ; then width reduction = sizex-1 + MOVEQ R2, #0 ; else 0 + + TST R6, #4 ; if going from bottom to top + RSBNE R3, R3, #1 ; then -height reduction = 1-sizey + MOVEQ R3, #0 ; else 0 + + SUB R7, R0, R2 ; R7 = width-1-(width reduction) + DivRem R0, R7, R4, R2 ; R0 = (width-(1 or sizex))DIV spacex + + SUB R7, R3, R1 ; R7 = height-(1-height reduction) + DivRem R1, R7, R5, R3 ; R1 = (height-(1 or sizey))DIV spacey +32 + TST R6, #8 ; are X and Y reversed ? + EORNE R0, R0, R1 ; yes, then swap + EORNE R1, R0, R1 + EORNE R0, R0, R1 + + TST R6, #Vdu5Bit + BNE %FT35 + TST R6, #1 ; is it "81 column mode ?" and VDU 4 + ADDNE R0, R0, #1 ; yes, then extra column +35 + TEQ R11, #0 ; reading width ? + MOVEQ R11, R0 ; yes, then use X + MOVNE R11, R1 ; no, use Y + + Pull "R0-R7" ; restore registers + B %BT25 ; and store result away + + +SWIRVVTab + +; Note these first variables should be the same as in SWI ReadModeVariable + + RVVT ModeFlags + RVVT ScrRCol + RVVT ScrBRow + RVVT NColour + RVVT XEigFactor + RVVT YEigFactor + RVVT LineLength + RVVT ScreenSize + RVVT YShftFactor + RVVT Log2BPP + RVVT Log2BPC + RVVT XWindLimit + RVVT YWindLimit +SWIRVVTabModeEnd + + RVVT GWLCol + RVVT GWBRow + RVVT GWRCol + RVVT GWTRow + RVVT TWLCol + RVVT TWBRow + RVVT TWRCol + RVVT TWTRow + RVVT OrgX + RVVT OrgY + RVVT GCsX + RVVT GCsY + RVVT OlderCsX + RVVT OlderCsY + RVVT OldCsX + RVVT OldCsY + RVVT GCsIX + RVVT GCsIY + RVVT NewPtX + RVVT NewPtY + RVVT ScreenStart + RVVT DisplayStart + RVVT TotalScreenSize + RVVT GPLFMD + RVVT GPLBMD + RVVT GFCOL + RVVT GBCOL + RVVT TForeCol + RVVT TBackCol + RVVT GFTint + RVVT GBTint + RVVT TFTint + RVVT TBTint + RVVT MaxMode + RVVT GCharSizeX + RVVT GCharSizeY + RVVT GCharSpaceX + RVVT GCharSpaceY + RVVT HLineAddr + RVVT TCharSizeX + RVVT TCharSizeY + RVVT TCharSpaceX + RVVT TCharSpaceY + RVVT GcolOraEorAddr + RVVT VIDCClockSpeed +SWIRVVTabEnd + + ALIGN + + [ {FALSE} + +; ***************************************************************************** +; +; SWISetVduVariables - SWI OS_SetVduVariables handler +; +; in: R0 -> block of variable numbers (word aligned) +; R1 -> block of variable values (word aligned) +; +; out: All registers preserved +; +; The block pointed to by R0 consists of a string of words, terminated +; by -1. Each word indicates which variable to write. The corresponding +; value in the R1 block is written to this variable. Invalid variables +; are ignored. +; + +SWISetVduVariables ROUT + TST R0, #3 ; index block not aligned + TSTEQ R1, #3 ; or value block not aligned + ExitSWIHandler NE ; then exit + Push R9 + VDWS WsPtr + MOV R10, #0 ; offset into both blocks +10 + LDR R11, [R0, R10] + CMP R11, #-1 ; end of block ? + Pull R9, EQ + ExitSWIHandler EQ + + TEQ R11, #VduExt_XEigFactor + TEQNE R11, #VduExt_YEigFactor + BNE %FT25 + + CMP R11, #(SWIRVVTabModeEnd-SWIRVVTab) ; a mode variable + ADRCC R9, SWIRVVTab ; if so then point to them + SUBCS R11, R11, #&80 ; base for non-mode variables + ADRCS R9, SWIRVVTabModeEnd +20 + LDRB R11, [R9, R11] ; yes, then load offset + LDR R9, [R1, R10] ; load value + STR R9, [WsPtr, R11, LSL #2] ; store in variable + Push "R0-R5,R14" + BL IEG ; update ext. cursor + ; on exit, R2=XEigFactor, R3=YEigFactor + SUBS R0, R2, R3 ; XEigFactor-YEigFactor + MOVLT R0, #2 ; X<Y => 2 (vert rect) + MOVGT R0, #1 ; X>Y => 1 (horz rect) else 0 (square) + STR R0, [WsPtr, #AspectRatio] + +; mouse bounding box, mouse position ??? + + Pull "R0-R5,R14" +25 + ADD R10, R10, #4 + B %BT10 + + ] + +; ***************************************************************************** +; +; SWIReadModeVar - Handler for SWI OS_ReadModeVariable +; +; in: R0 = screen mode you want the information for, -1 => current mode +; R1 = number of variable to read +; +; out: R2 = value of variable +; + +; Note: the algorithms used to derive the variables for mode selectors +; are duplicated in source.vdudriver, in GenerateModeSelectorVars + +SWIReadModeVar ROUT +SWIReadModeVariable ; alternative symbol used for init'ing + Push "R0,R1,R14" + + CMP R1, #(RMVTabEnd-RMVTab) ; valid variable number ? + BCS BadReadModeVar ; no, then exit + + ; AMG - note that the new sprite mode word code assumes that this + ; test has been done! + + VDWS WsPtr + +; AMG - add readmodevariable returns for new format sprite mode words. Much of +; this is munging the word passed in. A new sprite mode word can be +; distinguished from a pointer to a mode selector structure because +; b0 will be set in the new sprite mode word. 11/3/93 + +; TMD - serious optimisation introduced 17-Feb-93 +; TMD - additional optimisation for current mode added 16-Mar-93 + +; AMG - Fix bug MED-00414 ... need to support eig=0 modes here 26-Oct-93 + + LDR r11, [WsPtr, #ModeNo] ; get current mode + + CMP r0, #-1 ; if explicitly asking for current mode + BEQ RMVForCurrentMode ; then use optimised code + + CMP r0, #&100 + BCC %FT11 ; an old style mode number, branch past + ; the new code below + TST r0, #&01 + BNE NewSpriteModeWord ; b0 set, so it is a NewSpriteModeWord + ; rather than a pointer to a mode selector + + [ ModeSelectors + +; it's a mode selector, so check if valid first + + BL ValidateModeSelector + BVS BadReadModeVar + +; check if variable is in workspace list + + ADD r10, r0, #ModeSelector_ModeVars ; point at list + BL CheckWorkspaceList ; check list + BCC GoodReadModeVar ; [it was in list, so exit] + +; not in list, so deduce from other parms +; (we know the variable number is in range) + + LDR pc, [pc, r1, LSL #2] + NOP + & RMVMS_ModeFlags + & RMVMS_ScrRCol + & RMVMS_ScrBRow + & RMVMS_NColour + & RMVMS_XEigFactor + & RMVMS_YEigFactor + & RMVMS_LineLength + & RMVMS_ScreenSize + & RMVMS_YShftFactor + & RMVMS_Log2BPP + & RMVMS_Log2BPC + & RMVMS_XWindLimit + & RMVMS_YWindLimit + +RMVMS_ModeFlags +RMVMS_YShftFactor + MOV r2, #0 ; default modeflags, yshftfactor = 0 + B GoodReadModeVar + +RMVMS_ScrRCol + LDR r2, [r0, #ModeSelector_XRes] ; default scrcol = (xres>>3)-1 + MOV r2, r2, LSR #3 + SUB r2, r2, #1 + B GoodReadModeVar + +RMVMS_ScrBRow + LDR r2, [r0, #ModeSelector_YRes] ; default scrbrow = (yres>>3)-1 + MOV r2, r2, LSR #3 + SUB r2, r2, #1 + B GoodReadModeVar + +RMVMS_NColour + LDR r2, [r0, #ModeSelector_PixelDepth] + CMP r2, #6 ; if pixel depth is sensible + ADRCCL r11, NColourTable ; then lookup in table + LDRCC r2, [r11, r2, LSL #2] + MOVCS r2, #1 ; else return 1 + B GoodReadModeVar + +; TMD 09-Dec-93 +; New algorithms for xeig, yeig from Roger: +; xeig = 1: yeig = 1 +; if yres<xres/2 OR yres<400 then yeig = 2 +; if (xres<<xeig)<(yres<<yeig) then xeig = 2 + + [ RogerEXEY +RMVMS_XEigFactor + LDR r2, [r0, #ModeSelector_XRes] + LDR r11, [r0, #ModeSelector_YRes] + CMP r11, r2, LSR #1 ; if yres < xres/2 + CMPCS r11, #400 ; or yres < 400 + MOVCC r11, r11, LSL #2 ; then yeig = 2 + MOVCS r11, r11, LSL #1 ; else yeig = 1 + CMP r11, r2, LSL #1 ; if (xres<<1) < (yres<<yeig) + MOVHI r2, #2 ; then xeig = 2 + MOVLS r2, #1 ; else xeig = 1 + B GoodReadModeVar + +RMVMS_YEigFactor + LDR r2, [r0, #ModeSelector_XRes] + LDR r11, [r0, #ModeSelector_YRes] + CMP r11, r2, LSR #1 ; if yres < xres/2 + CMPCS r11, #400 ; or yres < 400 + MOVCC r2, #2 ; then yeig = 2 + MOVCS r2, #1 ; else yeig = 1 + B GoodReadModeVar + | +RMVMS_XEigFactor + MOV r2, #1 ; default xeig = 1 + B GoodReadModeVar + +RMVMS_YEigFactor + LDR r2, [r0, #ModeSelector_XRes] + LDR r11, [r0, #ModeSelector_YRes] + CMP r11, r2, LSR #1 ; if yres < xres/2 + MOVCC r2, #2 ; then yeig = 2 + MOVCS r2, #1 ; else yeig = 1 + B GoodReadModeVar + ] + +RMVMS_LineLength + LDR r2, [r0, #ModeSelector_XRes] +RMVMS_ShiftByPixDepthMinus3 + LDR r11, [r0, #ModeSelector_PixelDepth] + CMP r11, #6 ; if out of range + MOVCS r11, #0 ; use log2bpp=0 + MOV r2, r2, LSL r11 + MOV r2, r2, LSR #3 ; ll = (xres << pixdepth) >> 3 + B GoodReadModeVar + +RMVMS_ScreenSize + LDR r2, [r0, #ModeSelector_XRes] + LDR r11, [r0, #ModeSelector_YRes] + MUL r2, r11, r2 ; xres * yres + B RMVMS_ShiftByPixDepthMinus3 + +RMVMS_Log2BPP +RMVMS_Log2BPC + LDR r2, [r0, #ModeSelector_PixelDepth] + CMP r2, #6 ; range check + MOVCS r2, #0 + B GoodReadModeVar + +RMVMS_XWindLimit + LDR r2, [r0, #ModeSelector_XRes] ; default xwindlimit = xres-1 + SUB r2, r2, #1 + B GoodReadModeVar + +RMVMS_YWindLimit + LDR r2, [r0, #ModeSelector_YRes] ; default ywindlimit = yres-1 + SUB r2, r2, #1 + B GoodReadModeVar + | + +; else drop thru into ... + + ] + +11 + CMP r0, r11 ; if implicitly asking for current mode (and mode <> mode selector) + BEQ RMVForCurrentMode ; then use optimised code + + BIC r11, r0, #&80 ; clear shadow bit + + BranchIfKnownMode r11, %FA50 + +; not known mode, so look + + Push "r2-r4" + MOV r2, r11 + BL OfferModeExtensionAnyMonitor + MOVEQ r11, r4 ; if service responded to, save pointer to workspace list + Pull "r2-r4" + BNE BadReadModeVar ; exit if mode not known about + +; now search down list checking for variable number + + ADD r10, r11, #8 ; skip list type and base mode + BL CheckWorkspaceList ; look up variable in list + BCC GoodReadModeVar ; if there then exit + +; not in workspace list provided, so use base mode to look up in MOS's table + + LDR r11, [r11, #4] ; load workspace list base mode + BranchIfKnownMode r11, %FA50 + +; panic - base mode unrecognised +; existing code simply loads off end of table! - instead of that, return value zero +; alternatively we could return carry set, but that might cause backward compatibility problems (maybe) + + MOV r2, #0 + B GoodReadModeVar + +50 + ADR r10, RMVTab + LDRB r10, [r10, r1] ; R10 = offset in each mode table * 2 + ; if bit 0 set, then word value + ADRL r14, Vwstab + LDR r11, [r14, r11, LSL #2] ; get offset to table for this mode + ADD r11, r11, r14 ; convert to pointer + MOVS r10, r10, LSR #1 ; put byte/word flag into carry + LDRCCB r2, [r11, r10] ; load either a byte + LDRCS r2, [r11, r10] ; or a word out of table + +; and drop thru to GoodModeVar + +GoodReadModeVar + Pull "R0,R1,R14" + BIC R14, R14, #C_bit ; indicate successful read + ExitSWIHandler + +BadReadModeVar + Pull "R0,R1,R14" + ORR R14, R14, #C_bit ; indicate bad read + ExitSWIHandler + +; CheckWorkspaceList - Check a mode variable (index, value) list for a match +; in: r1 = variable number +; r10 -> list +; +; out: If match found, then +; r2 = value +; C=0 +; else +; C=1 +; endif +; r10 corrupted in both cases + +CheckWorkspaceList ENTRY +10 + LDR r14, [r10], #8 ; load next index (and skip index+value) + CMP r14, #-1 ; if end of list + EXIT EQ ; then not in workspace list, so exit (C=1 from CMP) + TEQ r14, r1 + BNE %BT10 + + LDR r2, [r10, #-4] ; load value of variable + CLC ; clear carry + EXIT + +RMVForCurrentMode + ADR r10, MVToVVTable + LDR r10, [r10, r1, LSL #2] + LDR r2, [WsPtr, r10] + B GoodReadModeVar + +MVToVVTable + & ModeFlags + & ScrRCol + & ScrBRow + & NColour + & XEigFactor + & YEigFactor + & LineLength + & ScreenSize + & YShftFactor + & Log2BPP + & Log2BPC + & XWindLimit + & YWindLimit + +; Note these should be the same as the first few in SWI ReadVduVariables + +RMVTab + RMVT ModeFlags, W ; was B + RMVT ScrRCol, W ; was B + RMVT ScrBRow, W ; was B + RMVT NColour, W + RMVT XEigFactor, W ; was B + RMVT YEigFactor, W ; was B + RMVT LineLength, W + RMVT ScreenSize, W + RMVT YShftFactor, W ; was B + RMVT Log2BPP, W ; was B + RMVT Log2BPC, W ; was B + RMVT XWindLimit, W + RMVT YWindLimit, W +RMVTabEnd + ALIGN + +; ***************************************************************************** +; +; NewSpriteModeWord, called from ReadModeVariable +; +; in: R0 = new sprite mode word +; R1 = number of variable to read +; (R0,R1,R14 stacked) +; +; out: R2 = value of variable +; +; Return parameters as follows: + +; (Unknown types will return an error. Invalid mode variable numbers will already +; have been weeded out at the entry to ReadModeVariable) + +; 0 ModeFlags Error +; 1 ScrRCol Error +; 2 ScrBRow Error +; 3 NColour derived from bpp passed in (255 for 8bpp) +; 4 XEigFactor returns 0,1,2 for 180,90,45 dpi, error otherwise +; 5 YEigFactor as XEigFactor +; 6 LineLength Error +; 7 ScreenSize Error +; 8 YShftFactor Error +; 9 Log2BPP returns 0,1,2,3,4,5 for T=1-6, error otherwise +; 10 Log2BPC as Log2BPP +; 11 XWindLimit Error +; 12 YWindLimit Error + +NewSpriteModeWord ROUT + +; validate the sprite type. Types 1-6 only at present. Type 0 is a +; mode number, but if it comes this way, it's bad, since mode >= 256 + + MOVS r14, r0, LSR #27 ; shift type word into b4-b0 + BEQ BadReadModeVar ; zero is bad cos mode >= 256 + ;if it's an unknown one, apply a substitute + CMP r14, #SpriteType_MAX + MOVCS r14, #SpriteType_Substitute + +; it's a valid type, now branch by the mode variable number + + ADR r2, NewSpriteModeWordRoutines + ADD pc, r2, r1, LSL #2 ; and despatch it + +NewSpriteModeWordRoutines + B NSM_modeflags ; 0 ModeFlags (zero) + B BadReadModeVar ; 1 ScrRCol Error + B BadReadModeVar ; 2 ScrBRow Error + B NSM_ncol ; 3 NColour + B NSM_xeig ; 4 XEigFactor + B NSM_yeig ; 5 YEigFactor + B BadReadModeVar ; 6 LineLength Error + B BadReadModeVar ; 7 ScreenSize Error + B NSM_yshftfactor ; 8 YShftFactor (zero) + B NSM_bpp ; 9 Log2BPP + B NSM_bpp ; 10 Log2BPC as Log2BPP + B BadReadModeVar ; 11 XWindLimit Error + B BadReadModeVar ; 12 YWindLimit Error + +; entry conditions here +; r14 - sprite type in b0-b6 for a word offset +; r0 - mode word +; r1 - mode variable (no longer needed at this point) + +NSM_ncol ; r14 is already the type bits shifted down to b0-b6, ie a word offset + ADRL r2, NColourTable -4 ; results table (adjust for T=0 never occurring here) + LDR r2, [r2, r14, LSL #2] ; pull the correct value + CMP r2, #63 + MOVEQ r2, #255 ; make sure we return 255 not 63 + B GoodReadModeVar ; and return happily + +NSM_bpp + ADR r2, NSM_bpptable-4 ; (adjusted for T=0 never occurring here) + LDR r2, [r2, r14, LSL #2] + B GoodReadModeVar + +NSM_bpptable + ; note, yes - I know this could be type-1, but at some point some new type + ; will break the relationship so it's a table from day 1 to cope with this + & 0, 1, 2, 3, 4, 5 + +NSM_eig_mask + & &00001FFF + +NSM_yeig + MOV r0, r0, LSR #14 ; move ydpi into b0-b12 + B %FT10 + +NSM_xeig + MOV r0, r0, LSR #1 ; move xdpi into b0-b12 +10 + LDR r14, =&00001FFF ; mask for dpi bits + AND r0, r0, r14 + + CMP r0, #180 + MOVEQ r2, #0 + BEQ GoodReadModeVar + + CMP r0, #22 + CMPNE r0, #23 + MOVEQ r2, #3 + BEQ GoodReadModeVar + + TEQ r0, #(45 :SHL: 2), 2 ; check if 45 (EQ,CC if so) + CMPNE r0, #90 ; or 90 (EQ,CS if so) + BNE BadReadModeVar + MOVCC r2, #2 ; 45 => xeig=2 + MOVCS r2, #1 ; 90 => xeig=1 + B GoodReadModeVar + +NSM_modeflags +NSM_yshftfactor + MOV r2, #0 ; both these return zero + B GoodReadModeVar + +; ***************************************************************************** +; +; SWICheckModeValid - The 'Can I get into this mode?' call +; +; in: r0 = mode you want to get into (may be pointer to mode selector) +; out: C=0 => yes you can, r0 preserved +; C=1 => no you can't ... +; r0 = -1 => ... because the mode doesn't exist +; r1 = substitute mode +; r1 = -2 => not enough memory for even the substitute mode ! +; r0 = -2 => ... because not enough memory +; + +SWICheckModeValid ROUT + VDWS WsPtr + Push "r1,r9,lr" + BL FindOKMode ; out: r1 = substitute mode + BVS %FT90 + + [ ModeSelectors + CMP r1, #&100 ; if it's a mode number + BICCC r10, r1, #&80 ; then knock off shadow bit + MOVCS r10, r1 ; else don't + | + BIC r10, r1, #&80 ; only use substitute mode (11/8/88) + ] + MOV r11, r10 + BL PushModeInfo + BVS %FT90 + + LDR r11, [r13, #wkScreenSize] ; get screen size for this mode + ADD r13, r13, #PushedInfoSize ; junk stacked mode table + VIDC info + + MOV r10, r1, LSR #7 ; 'shadow' bit (NB will be 0 or 1) + [ ModeSelectors + CMP r10, #2 ; except if its a mode selector + MOVCS r10, #0 ; in which case no shadow + ] + LDROSB r9, Shadow + TEQ r0, r1 ; if substitute different from original + MOV r0, r1 ; (always set r0 to be substitute mode) + MOVNE r14, #-1 ; then indicate original is silly + MOVEQ r14, #0 ; else indicate sensible + TEQEQ r9, #0 ; and if shadow 0 + MOVEQ r10, #1 ; then force shadow mode + + LDR r9, [WsPtr, #TotalScreenSize] ; maximum allowed amount + CMP r9, r11, LSL r10 ; compare with this (*2 if shadow) + ; C=0 => No room + TEQ r14, #0 ; NZ => silly, CC => no room + + MOV r1, #-2 ; for if silly mode and bad space + Pull r1, EQ ; if not silly, restore old R1 + ADDNE r13, r13, #4 ; else junk stacked R1 + MOVHI r1, r0 ; silly mode, ok space, R1=subst. mode + + MOVCC r0, #-2 ; if no room, indicate it + MOVNE r0, #-1 ; but silly overrides this + + Pull "r9, r14" + CMP r0, #-2 ; C=1 => bad exit + BICCC r14, r14, #C_bit + ORRCS r14, r14, #C_bit + ExitSWIHandler + +; exit point in case of error from FindOKMode or PushModeInfo + +90 + Pull "r1, r9, r14" + MOV r0, #-1 ; indicate no such mode + MOV r1, #-2 ; and no substitute mode + ORR r14, r14, #C_bit + ExitSWIHandler + +; ***************************************************************************** +; +; FindOKMode - Convert mode number into an appropriate one for +; this monitor type +; +; in: r0 = original mode specifier +; +; out: If no error, then +; r0 preserved +; r1 = appropriate mode specifier +; V = 0 +; else +; r0 -> error +; r1 corrupted +; V = 1 +; endif +; All other registers preserved +; + +FindOKMode ROUT + Push "r0,r2-r4,r10,r11,lr" + BL ReadMonitorType + [ ModeSelectors + CMP r0, #&100 ; if it's a mode number + BICCC r2, r0, #&80 ; then knock off shadow bit + MOVCS r2, r0 ; else don't + | + BIC r2, r0, #&80 + ] + BL OfferModeExtension + BNE %FT05 + +; service claimed, so return with this number + + MOV r1, r0 + CLRV + Pull "r0,r2-r4,r10,r11,pc" + +05 + +; not claimed, so r2 (=mode without shadow) and r3 (=monitortype) are preserved + + Pull "r0" + [ ModeSelectors + CMP r0, #&100 ; if a mode selector and not responded to + BCS %FT30 ; then return error + ] + + MOV r10, r2 ; mode without shadow bits + MOV r1, r0 ; start from existing mode + + CMP r3, #NumMonitorTypes ; monitor type must be in range + BCS %FT10 ; if not then must issue service + CMPCC r10, #NumModes ; and mode must be in range + MOVCC r11, #NumModes + MLACC r11, r3, r11, r10 ; then form monitortype*numberofmodes + modenumber + ADRCCL r14, BigVIDCTable ; point to big table + LDRCC r11, [r14, r11, LSL #2] ; and load offset + CMPCC r11, #-1 ; CS if mode number or monitor type out of range, or if not known in table + BCC %FT20 ; else it's known about, so OK + +; known monitor type, but unknown mode, so find substitute + + ADR r14, SubstModeTable + LDR r11, [r14, r3, LSL #2] + ADD r1, r11, r14 +05 + BL FindSubstitute + Pull "r2-r4,r10,r11, pc" ; exit VC or VS + +; unknown monitor type, so offer service + +10 + MOV r2, r10 + MOV r1, #Service_ModeTranslation + IssueService + TEQ r1, #0 + MOVEQ r1, r2 ; if claimed, then use module's mode + BEQ %FT20 + +; unknown monitor type +; if monitor type 7 (file), use substitution table for VGA (reasonable assumption) + + TEQ r3, #7 + ADREQ r1, SubstType3 + BEQ %BT05 + + MOV r1, #0 ; else panic and use mode 0 + +20 + CLRV + Pull "r2-r4,r10,r11, pc" + +30 + ADRL r0, ErrorBlock_ModeNotAvailable ; then return error + [ International + BL TranslateError + ] + SETV ; error exit + Pull "r2-r4,r10,r11, pc" + +SubstModeTable + & SubstType01-SubstModeTable + & SubstType01-SubstModeTable + & SubstType2-SubstModeTable + & SubstType3-SubstModeTable + & SubstType4-SubstModeTable + +SubstType01 + = 0, 8, 12, 15 +SubstType2 + = 23, 23, 23, 23 +SubstType3 + = 25, 26, 27, 28 +SubstType4 + = 29, 30, 31, 32 + +; ***************************************************************************** +; +; FindSubstitute - Find substitute mode with right no. of bpp +; +; in: r1 -> table of 4 bytes; subst. modes for 1, 2, 4, 8 bpp respectively +; r10 = mode specifier to be tested (shadow bit clear) +; +; out: If no error, then +; r0 preserved +; r1 = substitute mode +; V=0 +; else +; r0 -> error +; r1 preserved +; endif +; r11 corrupted, all other registers preserved +; + +FindSubstitute ENTRY + MOV r11, #0 + BL PushModeInfoAnyMonitor + EXIT VS ; if error, then exit now + LDR r11, [r13, #wkLog2BPP] + ADD r13, r13, #PushedInfoSize + CMP r11, #4 + MOVCS r11, #0 + LDRB r1, [r1, r11] + CLRV + EXIT + +; ***************************************************************************** +; +; ReadMonitorType - Read monitor type +; +; out: R3 = monitor type +; All other registers preserved +; + +ReadMonitorType ENTRY "r0-r2" + MOV r0, #1 + SWI XOS_ReadSysInfo ; out: r0 = mode, r1 = monitortype, r2 = sync + MOV r3, r1 ; move into r3 + EXIT + +; ***************************************************************************** +; +; ReadSyncType - Read sync type +; +; out: R4 = sync type (0 or 1) +; Z set/clear on R4 +; All other registers preserved +; + +ReadSyncType ENTRY "r0-r2" + MOV r0, #1 + SWI XOS_ReadSysInfo ; out: r0 = mode, r1 = monitortype, r2 = sync + MOVS r4, r2 ; move into r4 + EXIT + +; ***************************************************************************** +; +; SWIClaimScreenMemory - Claim unused screen memory (for ADFS etc.) +; +; in: R0 = 0 => release, 1 => claim +; R1 = length you require +; +; out: (for claim) +; C=0 => success +; R1 = actual length +; R2 = address +; +; C=1 => failure +; R1 = length you could have +; + +SWIClaimScreenMemory ROUT + MOV R11, PC ; disable IRQs, so can be called from + TST R11, #I_bit ; an IRQ routine + TEQEQP R11, #I_bit + + VDWS WsPtr + TEQ R0, #0 ; 0 => release + STREQB R0, [WsPtr, #ScreenMemoryClaimed] ; indicate free again + ExitSWIHandler EQ + +; is claim + + LDRB R10, [WsPtr, #ScreenMemoryClaimed] + TEQ R10, #0 ; already claimed (NZ) + MOVNE R1, #0 ; indicate you could have zero bytes + BNE %FT10 ; failure exit + + LDR R10, [WsPtr, #TotalScreenSize] + LDR R11, [WsPtr, #ScreenSize] + SUB R10, R10, R11 ; amount available + CMP R1, R10 ; is this enough + MOV R1, R10 ; tell him how much he could have + BHI %FT10 ; if not enough, then exit + + MOV R10, #1 ; indicate now claimed + STRB R10, [WsPtr, #ScreenMemoryClaimed] + + LDR R2, [WsPtr, #DisplayStart] + ADD R2, R2, R11 ; R2 -> start of usable area + + BIC R14, R14, #C_bit + ExitSWIHandler + +10 + ORR R14, R14, #C_bit + ExitSWIHandler + +; ***************************************************************************** +; +; SWIPlot - PLOT R0,R1,R2 +; +; in: R0 = plot code +; R1 = X coordinate +; R2 = Y coordinate +; +; out: - +; + +SWIPlot ROUT + CMP R0, #256 ; is plot code >= 256 ? + ExitSWIHandler CS ; yes, then do nothing + ; (for future expansion) + BranchNotJustUs %F10, WrchV, R12, R12 + + LDRB R12, [R11, #OsbyteVars + :INDEX: WrchDest] + LDRB R10, [R11, #OsbyteVars + :INDEX: SpoolFileH] + ORRS R10, R10, R12 + LDREQB R10, [R11, #OsbyteVars + :INDEX: VDUqueueItems] + TEQEQ R10, #0 + + VDWS WsPtr + LDREQ R10, [WsPtr, #CursorFlags] + TSTEQ R10, #VduDisabled ; if VDU disabled, go thru normal stuff + LDREQ R10, [WsPtr, #ModeFlags] ; if non-graphic, then send + TSTEQ R10, #Flag_NonGraphic ; thru normal chans + BNE %FT10 + + Push "R0-R9,R14" + ADR R14, %FT05 + SVC_mode ; R14 will have I_bit clear + +; TMD 16-May-89: Next instruction used to be B PreWrchCursor2, a secondary +; entry point that didn't disable IRQs as they were assumed to be already +; off. However this caused a bug in RISC OS 2.00, since SWIs are now entered +; with the IRQ state of the caller, so this has now been changed back to +; use the primary entry point (PreWrchCursor) which does disable them. + + B PreWrchCursor ; this exits by MOVS PC, R14 so it + ; clears the I_bit for us +; PreWrchCursor also exits with R6 = CursorFlags, needed for the +; EntryFromSWIPlot routine to do clip window calculations if necessary + +05 + LDMFD R13, {R0-R2} + MOV R3, R0 ; save plot code + MOV R0, R1, LSL #16 + MOV R0, R0, ASR #16 ; R0 := sign extended X coord + MOV R1, R2, LSL #16 + MOV R1, R1, ASR #16 ; R1 := sign extended Y coord + MOV R2, R3 + MOV R9, #1 ; indicate entry from SWI Plot + BL EntryFromSWIPlot + BL PostWrchCursor + Pull "R0-R9,R14" + ExitSWIHandler + +SWIPlotBadExit + STR R0, [R13] ; save error block pointer in saved R0 + BL PostWrchCursor + Pull "R0-R9,R14" + ORR R14, R14, #V_bit + ExitSWIHandler + +10 + Push "R0,R14" + SWI XOS_WriteI+25 ; send 25 + SWIVC XOS_WriteC ; send plot code + ANDVC R0, R1, #&FF + SWIVC XOS_WriteC ; send X (lo) + MOVVC R0, R1, LSR #8 + SWIVC XOS_WriteC ; send X (hi) + ANDVC R0, R2, #&FF + SWIVC XOS_WriteC ; send Y (lo) + MOVVC R0, R2, LSR #8 + SWIVC XOS_WriteC ; send Y (hi) + + Pull "R0,R14", VC ; if no error, pull stacked R0 and R14 + ExitSWIHandler VC + + ADD R13, R13, #4 ; if error, junk stacked R0 + Pull "R14" + ORR R14, R14, #V_bit ; and set V bit in link + ExitSWIHandler + +; ***************************************************************************** +; +; SWIRemoveCursors - Remove input and output cursors for screen bashing +; +; out: All registers preserved (R10-R12 preserved by Sam) +; + +SWIRemoveCursors + Push "R0-R4,R6,R8-R9,R14" + VDWS WsPtr + BL PreWrchCursor + Pull "R0-R4,R6,R8-R9,R14" + ExitSWIHandler + +; ***************************************************************************** +; +; SWIRestoreCursors - Restore input and output cursors after screen bash +; +; out: All registers preserved (R10-R12 preserved by Sam) +; + +SWIRestoreCursors + Push "R0-R4,R6,R8-R9,R14" + VDWS WsPtr + BL PostWrchCursor + Pull "R0-R4,R6,R8-R9,R14" + ExitSWIHandler + +; ***************************************************************************** +; +; SWIWriteN - Write R1 bytes from address R0 to wrch +; +; in: R0 -> string +; R1 -> number of chars to print +; +; out: - +; + +SWIWriteN ROUT + Push "R0,R1,R14" + TEQP PC, #SVC_mode ; enable interrupts + + BranchNotJustUsWrch %F70 + +; R11 now points to either vector node or 1st address on chain, as appropriate +; R12 holds current value of this location, to be checked each time + + MOV R10, R0 +10 + SUBS R1, R1, #1 + BCC %FT90 ; count has expired (V=0) + Push PC ; push address of %FT20 + LDRB R0, [R10], #1 + [ AssemblingArthur + B PMFWrchDirect + | + LDR PC, =(MOSDriver + MOSPMFWrch) + ] +20 + BVS %FT90 + LDR R0, [R11] + TEQ R0, R12 ; vector still the same ? + BEQ %BT10 ; yes, then loop + B %FT75 ; no, do rest with wrch + +70 + ADDS R10, R0, #0 ; R10 := R0 and V := 0 +75 + ADD R11, R10, R1 + TEQ R10, R11 +80 + LDRNEB R0, [R10], #1 + SWINE XOS_WriteC + MOVVS R10, R11 + TEQ R10, R11 + BNE %BT80 +90 + Pull "R0,R1,R14", VC ; if no error, pull stacked R0,R1 & R14 + ExitSWIHandler VC + + ADD R13, R13, #4 ; if error, junk stacked R0 + Pull "R1,R14" + ORR R14, R14, #V_bit ; and set V bit in link + ExitSWIHandler + + +; ***************************************************************************** +; +; SWIWrite0 - Write a zero-terminated string pointed to by R0 +; +; in: R0 -> string +; +; out: R0 -> char after the zero +; + +SWIWrite0 ROUT + Push "R14" + TEQP PC, #SVC_mode ; enable interrupts + + MOV R10, R0 ; R10 -> string + + BranchNotJustUsWrch %F70 + +; R11 now points to either vector node or 1st address on chain, as appropriate +; R12 holds current value of this location, to be checked each time + +10 + LDRB R0, [R10], #1 + CMP R0, #0 + Push PC, NE ; push address of %FT20 + [ AssemblingArthur + BNE PMFWrchDirect + | + LDRNE PC, =(MOSDriver + MOSPMFWrch) + ] + B %FT80 ; no more characters +20 + BVS %FT80 + LDR R0, [R11] + TEQ R0, R12 ; vector still the same ? + BEQ %BT10 ; yes, then loop + ; no, then drop thru + ; and do rest with Wrch +70 + LDRB R0, [R10], #1 + CMP R0, #0 ; (V:=0) + SWINE XOS_WriteC + BGT %BT70 ; branch if no error and not terminated +80 + MOVVC R0, R10 ; if no error, R0 -> char after zero + + Pull "R14" + ORRVS R14, R14, #V_bit + ExitSWIHandler + +; ***************************************************************************** +; +; SWIWriteS - Write a zero-terminated in-line string +; +; in: R14 -> first char of string (but has PSR bits in it) +; +; out: - +; + +SWIWriteS ROUT + Push "R0, R14" + TEQP PC, #SVC_mode ; enable interrupts + + BIC R10, R14, #ARM_CC_Mask ; R10 -> string + + BranchNotJustUsWrch %F70 + +; R11 now points to either vector node or 1st address on chain, as appropriate +; R12 holds current value of this location, to be checked each time + +10 + LDRB R0, [R10], #1 + CMP R0, #0 + Push PC, NE ; push address of %FT20 + [ AssemblingArthur + BNE PMFWrchDirect + | + LDRNE PC, =(MOSDriver + MOSPMFWrch) + ] + B %FT80 ; no more characters +20 + BVS %FT80 + LDR R0, [R11] + TEQ R0, R12 ; vector still the same ? + BEQ %BT10 ; yes, then loop + ; no, then drop thru + ; and do rest with Wrch +70 + LDRB R0, [R10], #1 + CMP R0, #0 ; (V:=0) + SWINE XOS_WriteC + BGT %BT70 ; branch if no error and not terminated +80 + BVS %FT90 + Pull "R0, R14" +85 + ADD R10, R10, #3 + BIC R10, R10, #3 ; round up to next word boundary + AND R14, R14, #ARM_CC_Mask ; R14 = user PSR + ORR R14, R14, R10 + ExitSWIHandler + +90 + Pull "R11, R14" ; junk the stacked R0 + ORR R14, R14, #V_bit +95 + LDRB R11, [R10], #1 ; skip to the zero terminator + TEQ R11, #0 + BNE %BT95 + B %BT85 + + [ AssemblingArthur + +; ***************************************************************************** +; +; RemovePages - Called by MOS when ChangeDynamicArea reduces the +; amount of screen memory +; +; in: R0 = - number of bytes being removed +; +; out: All registers preserved +; + +RemovePages ROUT + Push "R0-R8,R12,R14" + BL InsertRemovePagesCommon + ADD R2, R0, #ScreenEndAdr ; end of remaining screen memory + [ :LNOT: FixRemovePages + CMP R3, R2 + BCS %FT50 ; display starts in disappearing pages + ] + +; display starts in pages that remain + + SUB R5, R3, R0 ; new DisplayStart + + [ FixRemovePages +05 + CMP R5, #ScreenEndAdr ; if off end of 1st copy + SUBCS R5, R5, R4 ; then repeatedly subtract off new size + BCS %BT05 ; until in range + + Push "R0-R2" + MOV R0, R5 ; put new display start in r0 + BL SetVinit ; this updates DisplayStart + Pull "R0-R2" + + | + STR R5, [WsPtr, #DisplayStart] + ] + ADD R3, R3, R4 ; end of area to copy +1 + CMP R3, R2 + BLS %FT20 ; nothing to copy + + SUB R4, R3, R0 ; destination end +10 + LDMDB R3!, {R5-R8} ; load 4 words (minimum amount) + STMDB R4!, {R5-R8} ; store 4 words + TEQ R3, R2 + BNE %BT10 + +20 +InsertRemovePagesExit + LDR R4, [WsPtr, #DisplayScreenStart] + SUB R0, R4, R0 + [ FixRemovePages + LDR R3, [WsPtr, #TotalScreenSize] +25 + CMP R0, #ScreenEndAdr ; ensure displayscreenstart in range too + SUBCS R0, R0, R3 + BCS %BT25 + ] + BL NewScreenStart +30 + BL SetVendDefault + + Pull "R0-R8,R12,PC",,^ + + [ :LNOT: FixRemovePages + +; display starts in disappearing pages + +50 + ADD R4, R3, R0 ; destination start + MOV R0, R3 + BL SetVinit ; set vinit and DisplayStart +60 + LDMIA R3!, {R5-R8} + STMIA R4!, {R5-R8} + TEQ R3, #ScreenEndAdr + BNE %BT60 + B %BT30 + ] + +; ***************************************************************************** +; +; InsertPages - Called by MOS when ChangeDynamicArea increases the +; amount of screen memory +; +; in: R0 = number of bytes being added +; + +InsertPages ROUT + Push "R0-R8,R12,R14" + BL InsertRemovePagesCommon + SUB R5, R3, R0 ; new DisplayStart + STR R5, [WsPtr, #DisplayStart] + ADD R2, R3, R1 ; end of block to copy + + MOV R3, #ScreenEndAdr + SUB R4, R3, R0 +10 + TEQ R3, R2 + LDMNEIA R3!, {R5-R8} + STMNEIA R4!, {R5-R8} + BNE %BT10 + B InsertRemovePagesExit + +; ***************************************************************************** + +InsertRemovePagesCommon ROUT + VDWS WsPtr + LDR R1, [WsPtr, #TotalScreenSize] ; old size + + MOV R4, #0 + STRB R4, [R4, #OsbyteVars + :INDEX:MemDriver] ; indicate default + STRB R4, [R4, #OsbyteVars + :INDEX:MemDisplay] ; for both of these + + LDR R4, [WsPtr, #VduStatus] ; not shadowing any more + BIC R4, R4, #Shadowing + STR R4, [WsPtr, #VduStatus] + + ADD R4, R1, R0 ; length of remaining screen memory + STR R4, [WsPtr, #TotalScreenSize] ; new size + RSB R5, R4, #ScreenEndAdr ; start of remaining screen memory + STR R5, [WsPtr, #DriverBankAddr] + STR R5, [WsPtr, #DisplayBankAddr] + + LDR R3, [WsPtr, #DisplayStart] + MOV PC, R14 + + ] + +; ***************************************************************************** +; +; SWIChangedBox - Entry point for SWI OS_ChangedBox +; +; in: R0 = 0 => disable clip box calculations +; 1 => enable clip box calculations +; 2 => reset clip box to null +; -1 => do nothing +; +; out: R0 = old enable state (0 => disabled, 1 => enabled) +; R1 -> clipbox info, consisting of 5 words +; [R1, #0] = disable/enable flag (in bit 0) +; [R1, #4] = internal X-coord of left edge of box +; [R1, #8] = internal Y-coord of bottom edge of box +; [R1, #12] = internal X-coord of right edge of box +; [R1, #16] = internal Y-coord of top edge of box +; + +SWIChangedBox ROUT + VDWS WsPtr + MOV R1, WsPtr + LDR R10, [R1, #ClipBoxEnable]! ; R10 = old state, R1 -> state + CMP R0, #2 ; known reason ? + BHI %FT10 ; no, then just read state + BEQ %FT20 ; reset rectangle to null + + STR R0, [R1] ; then store R0 in ClipBoxEnable + TEQP PC, #SVC_mode + I_bit ; disable IRQs to update CursorFlags + TST R0, #1 + LDR R0, [WsPtr, #CursorFlags] + BICEQ R0, R0, #ClipBoxEnableBit + ORRNE R0, R0, #ClipBoxEnableBit + STR R0, [WsPtr, #CursorFlags] +10 + MOV R0, R10 ; R0 = old state + ExitSWIHandler + +20 + Push "R4-R7" + ADR R0, NullRectangle + LDMIA R0, {R4-R7} + STMIB R1, {R4-R7} ; store over coordinates + Pull "R4-R7" + B %BT10 + +NullRectangle + & &7FFFFFFF, &7FFFFFFF, &80000000, &80000000 + +; ***************************************************************************** +; +; SetClipBoxToFullScreen - Called by FF +; +; in: WsPtr -> VduDriverWorkSpace +; +; out: R0-R4 corrupted +; PSR preserved +; + + ASSERT YWindLimit = XWindLimit +4 + +SetClipBoxToFullScreen ROUT + ADD R4, WsPtr, #XWindLimit + LDMIA R4, {R2, R3} + MOV R0, #0 + MOV R1, #0 + ADD R4, WsPtr, #ClipBoxCoords + STMIA R4, {R0-R3} + MOV PC, R14 + +; ***************************************************************************** +; +; MergeClipBox - Merge a given rectangle into clip box +; +; in: R0..R3 = Left, bottom, right, top of rectangle to merge +; WsPtr -> VduDriverWorkSpace +; +; out: All registers preserved +; + +MergeClipBox ROUT + Push "R4-R8, R14" + ADD R8, WsPtr, #ClipBoxCoords + LDMIA R8, {R4-R7} + BL MergeClipBoxes + STMIA R8, {R4-R7} + Pull "R4-R8, PC" + +MergeClipBoxes ROUT + CMP R0, R4 + MOVLT R4, R0 + CMP R1, R5 + MOVLT R5, R1 + CMP R2, R6 + MOVGT R6, R2 + CMP R3, R7 + MOVGT R7, R3 + MOV PC, R14 + +; ***************************************************************************** +; +; DoPlotClipBox - Compute clip box for a PLOT command +; +; in: R2 = plot code +; +; out: R0-R2 preserved +; + +DoPlotClipBox ROUT + TST R2, #3 ; (R2 AND 3)=0 => move operation + ADRNE R11, ClipBoxPlotTable + LDRNEB R11, [R11, R2, LSR #3] ; get 'type' of this plot + TEQNE R11, #0 ; 0 => don't change clip window + MOVEQ PC, R14 + Push "R0-R2, R14" + CMP R11, #3 ; if 1..3 + BLS ClipLastR11Points ; then use last R11 points + CMP R11, #ClipIndex_Ellipse + BCC ClipFullWindow ; flood fill => merge graphics window + BEQ ClipEllipse + CMP R11, #ClipIndex_LineFill + BCC ClipParallelogram + BEQ ClipLineFill + Pull "R0-R2, PC" + +ClipIndex_FloodFill * 4 +ClipIndex_Ellipse * 5 +ClipIndex_Parallelogram * 6 +ClipIndex_LineFill * 7 + +ClipBoxPlotTable + = 2,2,2,2,2,2,2,2 ; 00..38 line drawing + = 1 ; 40 point plot + = ClipIndex_LineFill ; 48 line fill + = 3 ; 50 triangle + = ClipIndex_LineFill ; 58 line fill + = 2 ; 60 rectangle fill + = ClipIndex_LineFill ; 68 line fill + = ClipIndex_Parallelogram ; 70 parallelogram + = ClipIndex_LineFill ; 78 line fill + = ClipIndex_FloodFill ; 80 flood fill + = ClipIndex_FloodFill ; 88 flood fill + = 0,0,0,0,0 ; 90..B0 circle things + ; (done in GenCircleParm) + = 0 ; B8 block copy/move (done in code) + = ClipIndex_Ellipse ; C0 ellipse outline + = ClipIndex_Ellipse ; C8 ellipse fill + = 0, 0, 0 ; D0..E0 do nothing + = 0 ; E8 sprite plot (done in SWI SpriteOp) + = 0, 0 ; F0,F8 do nothing + ALIGN + +ClipLastR11Points ROUT + ADD R10, WsPtr, #NewPtX + BL MergeR11PointsFromR10 + Pull "R0-R2, PC" + +MergeR11PointsFromR10 ROUT + Push R14 + LDMIA R10, {R4,R5} ; get last point + MOV R6, R4 ; right=left + MOV R7, R5 ; top=bottom + SUBS R11, R11, #1 + BEQ %FT10 +05 + LDMDB R10!, {R0,R1} ; get another point (X,Y) + MOV R2, R0 + MOV R3, R1 + BL MergeClipBoxes + SUBS R11, R11, #1 ; one less point to do + BNE %BT05 +10 + +; now clip this to graphics window + + ADD R10, WsPtr, #GWLCol + LDMIA R10, {R0-R3} + CMP R4, R0 + MOVGE R0, R4 + CMP R5, R1 + MOVGE R1, R5 + CMP R6, R2 + MOVLE R2, R6 + CMP R7, R3 + MOVLE R3, R7 + CMP R2, R0 + CMPGE R3, R1 + BLGE MergeClipBox ; if R>=L and T>=B then merge + Pull PC + + +ClipLineFill ROUT + ADD R10, WsPtr, #GWLCol + LDMIA R10, {R0-R3} + ADD R10, WsPtr, #NewPtX + LDMIA R10, {R4-R5} + CMP R4, R0 ; if point is inside window + CMPGE R2, R4 + CMPGE R5, R1 + CMPGE R3, R5 + MOVGE R1, R5 ; then top=bottom=Y + MOVGE R3, R5 ; and left=GWLCol, right=GWRCol + BLGE MergeClipBox + Pull "R0-R2, PC" + +ClipParallelogram ROUT + ADD R10, WsPtr, #OldCsX + LDMIA R10, {R0-R5} ; load up last 3 points +ClipParallelRegs + ADD R6, R0, R4 ; 4th point = 1st + 3rd - 2nd + SUB R6, R6, R2 + ADD R7, R1, R5 + SUB R7, R7, R3 + Push "R0-R7" ; stack all four points + ADD R10, R13, #6*4 ; point R10 at last point + MOV R11, #4 ; 4 points to merge + BL MergeR11PointsFromR10 + ADD R13, R13, #8*4 ; junk stacked points + Pull "R0-R2, PC" + +ClipEllipse ROUT + ADD R10, WsPtr, #OldCsX + LDMIA R10, {R0-R5} ; last 3 points (AX,AY,BX,BY,CX,CY) + SUB R6, R2, R0 ; R6 = BX-AX + ADD R0, R0, R2 ; R0 = AX+BX + SUB R0, R0, R4 ; R0 = AX+BX-CX + ADD R2, R4, R6 ; R2 = CX+BX-AX + SUB R4, R4, R6 ; R4 = CX-(BX-AX) = CX+AX-BX + RSB R1, R5, R1, LSL #1 ; R1 = 2*AY-CY + MOV R3, R5 ; R3 = CY + B ClipParallelRegs + +ClipFullWindow ROUT + ADD R10, WsPtr, #GWLCol ; merge graphics window with + LDMIA R10, {R0-R3} ; clip rectangle (which can be larger) + BL MergeClipBox + Pull "R0-R2, PC" + +; ***************************************************************************** +; +; ClipBlockCopyMove - Calculate clip box for block copy/move +; +; in: R0-R7 = SrcL, SrcB, SrcR, SrcT, DestL, DestB, DestR, DestT +; R8 = 0 => move, 2 => copy +; +; out: R0-R7 preserved +; R8-R11 undefined +; + +ClipBlockCopyMove ROUT + Push "R0-R7, R14" + ADD R10, R13, #6*4 ; R10 -> last point (DestR,DestT) + RSB R11, R8, #4 ; R11 = 4 if move, 2 if copy + ; (number of points to merge) + BL MergeR11PointsFromR10 + Pull "R0-R7, PC" + +; ***************************************************************************** +; +; ClipCircle - Add circle bounding box to clip box +; +; in: R0 = radius of circle in square pixels +; R5, R6 = CentreX, CentreY +; R7 = AspectRatio (0 => square, 1 => flat rect, 2 => tall rect) +; +; out: R0-R7 preserved +; R8-R11 undefined +; + +ClipCircle ROUT + Push "R0-R7,R14" + CMP R7, #1 + MOVEQ R8, R0, LSR #1 ; if flat then dX = rad/2 + MOVNE R8, R0 ; else dX = rad + MOVHI R9, R0, LSR #1 ; if tall then dY = rad/2 + MOVLS R9, R0 ; else dY = rad + SUB R0, R5, R8 ; left + SUB R1, R6, R9 ; bottom + ADD R2, R5, R8 ; right + ADD R3, R6, R9 ; top + Push "R0-R3" + ADD R10, R13, #2*4 ; point R10 at last point + MOV R11, #2 ; 2 points to merge + BL MergeR11PointsFromR10 + ADD R13, R13, #4*4 ; junk stacked points + Pull "R0-R7,PC" + +; ***************************************************************************** +; +; ClipCursorCell - Add current cursor cell to clip box +; +; in: - +; +; out: All registers preserved +; + +ClipCursorCell ROUT + ASSERT CursorY = CursorX +4 + Push "R0-R3, R14" + ADD R0, WsPtr, #CursorX + LDMIA R0, {R0, R1} + MOV R2, R0 ; RCol = LCol + MOV R3, R1 ; TRow = BRow + BL ClipTextArea + Pull "R0-R3, PC" + +; ***************************************************************************** +; +; ClipTextArea - Add a text area to the clip box +; +; in: R0 = LCol of area +; R1 = BRow of area +; R2 = RCol of area +; R3 = TRow of area +; +; out: All registers preserved +; + +ClipTextArea ROUT + Push "R0-R3, R14" + MOV R0, R0, LSL #3 ; left = LCol*8 + MOV R2, R2, LSL #3 + ADD R2, R2, #7 ; right = RCol*8 + 7 + LDR R14, [WsPtr, #RowMult] + MUL R3, R14, R3 ; TRow * RowMult + MLA R1, R14, R1, R14 ; (BRow+1) * RowMult + LDR R14, [WsPtr, #YWindLimit] + SUB R3, R14, R3 ; top = YWindLimit-TRow*RowMult + SUB R1, R14, R1 + ADD R1, R1, #1 ; bot = YWindLimit-(BRow+1)*Mult+1 + BL MergeClipBox + Pull "R0-R3, PC" + +; ***************************************************************************** +; +; ClipScroll - Add clip box when scrolling +; +; in: R0 = 0 => add text window +; R0 <> 0 => set to full screen +; +; out: All registers preserved +; + +ClipScroll ROUT + Push "R0-R4, R14" + CMP R0, #1 ; if scrolling screen + BLCS SetClipBoxToFullScreen ; set to full screen + + ADDCC R4, WsPtr, #TWLCol ; else add text window + LDMCCIA R4, {R0-R3} + BLCC ClipTextArea + + Pull "R0-R4, PC" + +; ***************************************************************************** +; +; ClipSpritePlot - Compute and merge sprite plot bounding box +; +; in: R0 = unclipped X-coord (internal) +; R1 = clipped topY (internal) +; R2 = width of sprite in words +; R3 = height of sprite -1 +; R4 = GWLCol +; R5 = height reduction +; R6 = GWRCol +; R8 -> sprite +; +; out: All registers preserved +; + +ClipSpritePlot ROUT + Push "R0-R11, R14" + ADD R9, R8, #spLBit + LDMIA R9, {R9, R10} ; R9 = spLBit; R10 = spRBit + ADD R2, R9, R2, LSL #5 ; R2 = width*32+spLBit + RSB R10, R10, #32 ; R10 = 32-spRBit + SUB R2, R2, R10 ; R2 = width in bits-1 + LDR R9, [WsPtr, #Log2BPC] + ADD R2, R0, R2, LSR R9 ; R2 = unclipped rightX + CMP R0, R4 + MOVLT R0, R4 ; R0 = clipped leftX + CMP R2, R6 + MOVGT R2, R6 ; R2 = clipped rightX + SUB R3, R3, R5 ; R3 = no. of lines on screen -1 + SUB R1, R1, R3 ; R1 = clipped botY + ADD R3, R1, R3 ; R3 = clipped topY + + CMP R2, R0 ; if right>=left + CMPGE R3, R1 ; and top>=bot + BLGE MergeClipBox ; then add rectangle + Pull "R0-R11, PC" + + [ ModeSelectors + +; ***************************************************************************** +; +; ScreenModeSWI - Entry point for SWI OS_ScreenMode +; +; in: r0 = reason code +; Other registers depend on reason code +; +; out: Depends on reason code +; + +ScreenModeSWI ENTRY + BL ScreenModeSub + PullEnv + ORRVS lr, lr, #V_bit + ExitSWIHandler + + ASSERT ScreenModeReason_SelectMode = 0 + ASSERT ScreenModeReason_ReturnMode = 1 + ASSERT ScreenModeReason_EnumerateModes = 2 + ASSERT ScreenModeReason_SelectMonitorType = 3 + ASSERT ScreenModeReason_Limit = 4 + +ScreenModeSub + CMP r0, #ScreenModeReason_Limit + ADDCC pc, pc, r0, LSL #2 + B ScreenMode_Unknown + B ScreenMode_SelectMode + B ScreenMode_ReturnMode + B ScreenMode_EnumerateModes + B ScreenMode_SelectMonitorType + +; unknown OS_ScreenMode reason code + +ScreenMode_Unknown + ADR r0, ErrorBlock_ScreenModeBadReason +ScreenMode_TranslateAndReturnError + [ International + Push lr + BL TranslateError + Pull lr + ] +ScreenMode_ReturnError + SETV + MOV pc, lr + +; Temporary error blocks, so we don't have to claim Hdr:NewErrors every 5 mins. + +ErrorBlock_ScreenModeBadReason + & 0 + = "Zonk:Unknown OS_ScreenMode reason code", 0 + ALIGN + +;************************************************************************** +; +; ScreenMode_SelectMode - Select a screen mode +; +; Internal routine called by ScreenModeSWI +; +; in: r0 = reason code (0) +; r1 = mode specifier +; +; out: r10-r12 may be corrupted +; All other registers preserved +; + +ScreenMode_SelectMode ENTRY "r0-r9" + TEQP pc, #SVC_mode ; enable IRQs + VDWS WsPtr + BL PreWrchCursor ; remove cursor + LDR r2, [sp, #1*4] ; reload mode specifier + BL ModeChangeSub ; perform mode change + BVS %FT90 + BL PostWrchCursor ; if no error, then restore cursor + CLRV ; indicate no error + EXIT ; and exit + +90 + STR r0, [sp] ; overwrite stacked r0 with error ptr + BL PostWrchCursor ; restore cursor + SETV ; indicate error + EXIT ; and exit + +;************************************************************************** +; +; ScreenMode_ReturnMode - Return current screen mode specifier +; +; Internal routine called by ScreenModeSWI +; +; in: r0 = reason code (1) +; +; out: r1 = mode specifier +; r10-r12 may be corrupted +; All other registers preserved +; + +ScreenMode_ReturnMode ROUT + VDWS WsPtr + LDR r1, [WsPtr, #ModeNo] + CLRV + MOV pc, lr + +;************************************************************************** +; +; ScreenMode_EnumerateModes - Enumerate screen modes +; +; Internal routine called by ScreenModeSWI +; +; in: r0 = reason code (2) +; r2 = enumeration index (0 to start from beginning) +; r6 -> block to return data into, or 0 to just count entries +; r7 = size of block if r6<>0, or zero if r6=0 +; +; out: r1 = 0 if service claimed, otherwise r1<>0 +; r2 = updated enumeration index +; r6 = updated block pointer +; r7 = size of remaining free area in block +; r10-r12 may be corrupted +; All other registers are preserved +; + +ScreenMode_EnumerateModes ENTRY "r3-r5" + MOV r1, #Service_EnumerateScreenModes + BL ReadMonitorType + GetBandwidthAndSize r4, r5 + BL Issue_Service + EXIT + +;************************************************************************** +; +; ScreenMode_SelectMonitorType - Select current monitor type +; +; Internal routine called by ScreenModeSWI +; +; in: r0 = reason code (3) +; r1 = monitor type to set, or -1 to restore from configured value +; +; out: r10-r12 may be corrupted +; All other registers preserved +; + +ScreenMode_SelectMonitorType ENTRY "r0" + VDWS WsPtr + CMP r1, #-1 ; if not restoring configured value + BNE %FT10 ; then skip + BL Read_Configd_MonitorType ; else read CMOS value (returns in r0) + MOV r1, r0 +10 + STR r1, [WsPtr, #CurrentMonitorType] ; update current value + EXIT + + ] + END diff --git a/s/vdu/vduttx b/s/vdu/vduttx new file mode 100644 index 0000000000000000000000000000000000000000..b930183fdfcc11c957cb70361fb07045775c1187 --- /dev/null +++ b/s/vdu/vduttx @@ -0,0 +1,1235 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.VduTTX + +; Teletext (MODE 7) emulation +; --------------------------- + +; Author Tim Dobson +; Started 24-Feb-87 + +; ***************************************************************************** + +; Teletext control codes + +TTX_AlphaRed * &01 +TTX_AlphaGreen * &02 +TTX_AlphaYellow * &03 +TTX_AlphaBlue * &04 +TTX_AlphaMagenta * &05 +TTX_AlphaCyan * &06 +TTX_AlphaWhite * &07 +TTX_Flash * &08 +TTX_Steady * &09 +TTX_EndBox * &0A +TTX_StartBox * &0B +TTX_NormalHeight * &0C +TTX_DoubleHeight * &0D + +TTX_GraphRed * &11 +TTX_GraphGreen * &12 +TTX_GraphYellow * &13 +TTX_GraphBlue * &14 +TTX_GraphMagenta * &15 +TTX_GraphCyan * &16 +TTX_GraphWhite * &17 +TTX_Conceal * &18 +TTX_Contiguous * &19 +TTX_Separated * &1A +TTX_BlackBackgd * &1C +TTX_NewBackgd * &1D +TTX_HoldGraph * &1E +TTX_RelGraph * &1F + +TTXGraphContFontA * TTXSoftFonts +0 ; Contiguous graphics font (&20-&3F) +TTXGraphSepaFontA * TTXSoftFonts +&140 ; Separated graphics font (&20-&3F) +TTXGraphContFontB * TTXSoftFonts +&280 ; Contiguous graphics font (&60-&7F) +TTXGraphSepaFontB * TTXSoftFonts +&3C0 ; Separated graphics font (&60-&7F) + +; Bits in the map + +; Bits 0-7 8 bit character +; Bit 8 0 => Alpha, 1 => Graphics +; Bit 9 0 => Contiguous, 1 => Separated +; Bit 10 0 => Steady, 1 => Flash +; Bit 11 0 => Release, 1 => Hold +; Bit 12 0 => Reveal, 1 => Conceal +; Bits 13-14 Bit 13 Bit 14 +; 0 0 Single Height +; 1 0 Undefined +; 0 1 Double Height Top +; 1 1 Double Height Bottom +; Bit 15 1 => Pending Start Box +; Bit 16 1 => Pending End Box +; Bits 17-19 Foreground colour +; Bit 20 0 => Unboxed, 1 => Boxed +; Bits 21-23 Background colour +; Bit 24 0 => Unboxed, 1 => Boxed +; Bits 25-29,31 Held graphic +; Bit 30 0 => Held graphic contiguous, 1 => separated + +MapBit_Char * 1 :SHL: 0 +MapBit_Graph * 1 :SHL: 8 +MapBit_Separated * 1 :SHL: 9 +MapBit_Flash * 1 :SHL: 10 +MapBit_Hold * 1 :SHL: 11 +MapBit_Conceal * 1 :SHL: 12 +MapBit_Bottom * 1 :SHL: 13 +MapBit_Double * 1 :SHL: 14 +MapBit_PendingStart * 1 :SHL: 15 + +MapBit_PendingEnd * 1 :SHL: 16 +MapBit_ForeMask * 7 :SHL: 17 +MapBit_BackMask * 7 :SHL: 21 +MapBits_Boxed * (1 :SHL: 20) :OR: (1 :SHL: 24) +MapBit_HeldMask * &7F :SHL: 25 +MapBit_HeldSeparated * 1 :SHL: 30 + +MapForeShift * 17 +MapBackShift * 21 +MapHeldShift * 25 + +MapBit_Default * (7 :SHL: MapForeShift)+32 ; default at start of line + +; ***************************************************************************** +; +; TeletextInit - Initialise teletext workspace +; Called when MODE 7 (or 135) is selected +; + +TeletextInit ROUT + MOV R0, #1 ; set to flash immediately + STR R0, [WsPtr, #TeletextCount] + +; compute the graphics fonts + + ADD R0, WsPtr, #TTXSoftFonts ; R0 -> contiguous font + MOV R2, #&20 ; R2 = character number + MOV R3, #0 ; R3 = byte to store +10 + ADD R1, R0, #&140 ; R1 -> separated font +20 + TST R2, #1 ; top left + ORRNE R3, R3, #&F0 + TST R2, #2 ; top right + ORRNE R3, R3, #&0F + STRB R3, [R0], #1 ; 3 pixel rows for top + STRB R3, [R0], #1 + STRB R3, [R0], #1 + AND R3, R3, #&77 ; do separated + STRB R3, [R1], #1 + STRB R3, [R1], #1 + MOV R3, #0 + STRB R3, [R1], #1 + + TST R2, #4 ; middle left + ORRNE R3, R3, #&F0 + TST R2, #8 ; middle right + ORRNE R3, R3, #&0F + STRB R3, [R0], #1 ; 4 pixel rows for middle + STRB R3, [R0], #1 + STRB R3, [R0], #1 + STRB R3, [R0], #1 + AND R3, R3, #&77 ; do separated + STRB R3, [R1], #1 + STRB R3, [R1], #1 + STRB R3, [R1], #1 + MOV R3, #0 + STRB R3, [R1], #1 + + TST R2, #&10 ; bottom left + ORRNE R3, R3, #&F0 + TST R2, #&40 ; bottom right + ORRNE R3, R3, #&0F + STRB R3, [R0], #1 ; 3 pixel rows for bottom + STRB R3, [R0], #1 + STRB R3, [R0], #1 + AND R3, R3, #&77 ; do separated + STRB R3, [R1], #1 + STRB R3, [R1], #1 + MOV R3, #0 + STRB R3, [R1], #1 + + ADD R2, R2, #1 + TEQ R2, #&40 ; if at end of 1st part + MOVEQ R2, #&60 ; then start 2nd + ADDEQ R0, R0, #&140 ; skipping separated already done + BEQ %BT10 ; and resetting R1 too + + TEQ R2, #&80 ; finished + BNE %BT20 + + MOV PC, R14 + +; ***************************************************************************** +; +; TTXFastCLS - Called when clearing whole screen +; Clears the teletext map to default +; + +TTXFastCLS ROUT + ADD R0, WsPtr, #TTXMap ; R0 -> map + ADD R1, R0, #TTXMapSize-4 ; R1 -> last word of map + LDR R2, =MapBit_Default ; R2 = default status at start of line +10 + STR R2, [R0], #4 + CMP R0, R1 + BLS %BT10 + + ADD R0, WsPtr, #TTXDoubleCounts ; zero double counts on each line + ADD R1, R0, #25 + MOV R2, #0 +20 + STRB R2, [R0], #1 + TEQ R0, R1 + BNE %BT20 + + MOV PC, R14 + +; ***************************************************************************** +; +; TTXUpdateColours - Update colour table for new colours +; +; in: R5 = new foregd colour +; R6 = new backgd colour +; +; out: R0, R2 preserved +; + +TTXUpdateColours ROUT + Push "R0,R2,R14" + ADD R14, WsPtr, #TForeCol + STMIA R14, {R5,R6} + MOV fore, R5 + MOV back, R6 + LDR bpp, [WsPtr, #BitsPerPix] + BL SetColours + Pull "R0,R2,PC" + +; ***************************************************************************** +; +; PrintDoubleHeight - Process font for double height +; +; in: R0 = char + attributes +; tophalf contains bytes 0123 +; bottomhalf contains bytes 4567 +; R10 contains bytes xx89 +; We know that at least one of MapBit_Bottom or MapBit_Double is set +; + +PrintDoubleHeight ROUT + TST R0, #MapBit_Double ; if not double height, + MOVEQ tophalf, #0 ; then must be single height + MOVEQ bottomhalf, #0 ; part on line below double, + MOVEQ R10, #0 ; so make it invisible + MOVEQ PC, R14 + + TST R0, #MapBit_Bottom + BNE %FT10 ; [bottom half of double] + + [ 1=1 ; 0 1 2 3 4 +; do top half, we want tophalf=0112, bottomhalf=2334, R10=xx45 + MOV R10, bottomhalf, LSL #16 ; R10 := o o 4 5 + ORR R10, R10, R10, LSL #8 ; R10 := o o 4 4/5 + AND R3, tophalf, #&FF000000 ; R3 := o o o 3 + ORR bottomhalf, R3, bottomhalf, LSL #24 ; bot := o o o 3/4 + MOV R3, tophalf, LSR #16 ; R3 := 2 3 o o + ORR R3, R3, R3, LSL #8 ; R3 := 2 2/3 3 o + ORR bottomhalf, bottomhalf, R3 ; bot := 2 2/3 3 3/4 + MOV tophalf, tophalf, LSL #16 ; top := o o 0 1 + ORR tophalf, tophalf, tophalf, LSR #8 ; top := o 0 0/1 1 + MOV tophalf, tophalf, LSR #8 ; top := 0 0/1 1 o + ORR tophalf, tophalf, bottomhalf, LSL #24 ; top := 0 0/1 1 2 + AND R3, tophalf, #&00FF0000 ; R3 := o o 1 o + ORR tophalf, tophalf, R3, LSL #8 ; top := 0 0/1 1 1/2 + MOV PC, R14 + +10 ; 5 6 7 8 9 +; do bottom half, we want tophalf=5667, bottomhalf=7889, R10=xx9o + AND tophalf, bottomhalf, #&FF000000 ; top := o o o 7 + MOV R3, bottomhalf, LSL #8 ; R3 := o 4 5 6 + MOV R3, R3, LSR #16 ; R3 := 5 6 o o + ORR tophalf, tophalf, R3 ; top := 5 6 o 7 + ORR tophalf, tophalf, R3, LSL #8 ; top := 5 5/6 6 7 + AND R3, R3, #&0000FF00 ; R3 := o 6 o o + ORR tophalf, tophalf, R3, LSL #16 ; top := 5 5/6 6 6/7 + MOV bottomhalf, bottomhalf, LSR #24 ; bot := 7 o o o + AND R3, R10, #&00FF0000 ; R3 := o o 8 o + ORR bottomhalf, bottomhalf, R3, LSR #8 ; bot := 7 8 o o + ORR bottomhalf, bottomhalf, bottomhalf, LSL #8 ; bot := 7 7/8 8 o + ORR R3, R10, R10, LSL #8 ; R3 := x x x 8/9 + AND R3, R3, #&FF000000 ; R3 := o o o 8/9 + ORR bottomhalf, bottomhalf, R3 ; bot := 7 7/8 8 8/9 + MOV R10, R10, LSR #24 ; R10 := 9 o o o + ORR R10, R10, R10, LSL #8 ; R10 := 9 9 o o + MOV R10, R10, LSL #16 ; R10 := o o 9 9 + MOV PC, R14 + | +; do top half, we want tophalf=0011, bottomhalf=2233, R10=xx44 + + MOV R10, bottomhalf, LSL #24 ; R10 := ooo4 + ORR R10, R10, R10, LSR #8 ; R10 := oo44 + AND bottomhalf, tophalf, #&00FF0000 ; bottom := oo2o + ORR bottomhalf, bottomhalf, tophalf, LSR #24 ; bottom := 3o2o + ORR bottomhalf, bottomhalf, bottomhalf, LSL #8 ; bottom := 3322 + MOV bottomhalf, bottomhalf, ROR #16 ; bottom := 2233 + AND R3, tophalf, #&0000FF00 ; R3 := o1oo + AND tophalf, tophalf, #&FF ; top := 0ooo + ORR tophalf, tophalf, R3, LSL #8 ; top := 0o1o + ORR tophalf, tophalf, tophalf, LSL #8 ; top := 0011 + MOV PC, R14 + +; do bottom half, we want tophalf=5566, bottomhalf=7788, R10=xx99 + +10 + AND tophalf, bottomhalf, #&0000FF00 ; top := o5oo + MOV bottomhalf, bottomhalf, LSR #16 ; bot := 67oo + ORR tophalf, tophalf, bottomhalf, LSL #24 ; top := o5o6 + ORR tophalf, tophalf, tophalf, LSR #8 ; top := 5566 + MOV bottomhalf, bottomhalf, LSR #8 ; bot := 7ooo + MOV R10, R10, LSR #16 ; R10 := 89oo + ORR bottomhalf, bottomhalf, R10, LSL #16 ; bot := 7o89 + BIC bottomhalf, bottomhalf, #&FF000000 ; bot := 7o8o + ORR bottomhalf, bottomhalf, bottomhalf, LSL #8 ; bot := 7788 + BIC R10, R10, #&FF ; R10 := o9oo + ORR R10, R10, R10, LSR #8 ; R10 := 99oo + MOV R10, R10, LSL #16 ; R10 := oo99 + MOV PC, R14 + ] + +; ***************************************************************************** +; +; TTXWrch - Print a character in the range &20-&FF +; +; in: R0 = character +; out: cursor has been moved on if appropriate +; + +TTXWrch ROUT + Push R14 + BL TTXDoChar + Pull R14 + B PostCharMove + +; ***************************************************************************** +; +; TTXDoChar - Print a character (don't move cursor) +; +; in: R0 = character +; + +TTXDoChar ROUT + Push R14 + + MOV R3, R0 + TEQ R3, #"#" ; swap around the three + MOVEQ R0, #"_" ; old favourites + TEQ R3, #"_" + MOVEQ R0, #"`" + TEQ R3, #"`" + MOVEQ R0, #"#" + + LDR R11, [WsPtr, #CursorY] ; R11 = current Y position + LDR R3, [WsPtr, #CursorX] ; R3=start X posn on this line + LDR R2, [WsPtr, #CursorAddr] ; screen address +TTXScanFromHere + MOV R4, #0 ; Xmin and + MOV R5, #0 ; Xmax are irrelevant + MOV R10, #0 ; Ymax always <= Y so no zap +TTXScanZap + ADRL R1, TTXLineStarts ; R1 -> table of line starts + LDR R8, [R1, R11, LSL #2] ; R8 -> map entry at st.of line + ADD R7, R8, #40*4 ; R7 -> end of this line + LDR R1, [R8, R3, LSL #2]! ; R1 = prev. char+attr +08 + ADD R3, WsPtr, #TTXDoubleCounts + LDRB R9, [R3, R11] ; R9 = no. of dbls on this line +10 + BIC R1, R1, #&FF ; clear char bits + ORR R0, R1, R0 ; store new char + AND R1, R0, #&7F ; just look at char bits + + Push R14 + CMP R1, #&20 ; is it a control char + BLCC DoPreControl ; [do pre-control things] + + Push "R1,R4-R11" + BL TTXPaintChar + Pull "R1,R4-R11" + + BIC R0, R0, #(MapBit_PendingStart :OR: MapBit_PendingEnd) + + CMP R1, #&20 + BLCC DoPostControl ; [do post-control things] + Pull R14 ; restore zap flag + + LDR R1, [R8, #4]! ; get old character + STR R0, [R8] ; store character away + + AND R3, R1, #&7F ; if overwriting double height + TEQ R3, #TTX_DoubleHeight + SUBEQ R9, R9, #1 ; then one less + + EOR R1, R0, R1 ; get difference + BIC R3, R1, #&FF ; difference in attributes + MOV R1, R0 ; R1 = prev char + new attr + + CMP R11, R10 ; if Y >= Ymax + BCS %FT20 ; then load from map + CMPCC R8, R5 ; else if X <= Xmax + MOVLS R3, #1 ; then pretend attr different + CMPCC R4, R8 ; if Xmin < X < Xmax + CMPCC R14, #1 ; and we're zapping (not scan) + MOVCC R0, #32 ; then zap to space +20 + LDRCSB R0, [R8, #4] ; else load from map + + TEQ R3, #0 ; if attributes different + TEQNE R8, R7 ; and not at end of line + ADDNE R2, R2, #4 ; then move to next char + BNE %BT10 ; and loop + + ADD R3, WsPtr, #TTXDoubleCounts + STRB R9, [R3, R11] ; update no. of doubles + + ADD R11, R11, #1 ; go to next line + TEQ R11, #25 ; if off bottom of screen + Pull PC, EQ ; then finished + + MOVS R3, R9 ; if no doubles + ; then next line is top line + EORNE R3, R1, #MapBit_Bottom ; else next line is opposite + ; to this line + + LDR R1, [R7, #4] ; get dummy word on next line + EOR R3, R1, R3 ; difference + ANDS R3, R3, #MapBit_Bottom ; difference in 'bottom' bit + EORNE R1, R1, #MapBit_Bottom ; if different then toggle bit + STR R1, [R7, #4]! ; always store back + BNE %FT30 ; and do another row + + CMP R11, R10 ; else if finished zap + Pull PC, CS ; then exit +30 + +; now compute new R2 + + SUB R3, R7, R8 ; no. of chars before eol + RSB R3, R3, #160 ; current char number + SUB R2, R2, R3 ; back to start of old line + LDR R3, [WsPtr, #RowLength] + ADD R2, R2, R3 ; move down a row + + MOV R8, R7 ; R8 -> dummy char on new line + ADD R7, R7, #40*4 ; R7 -> last char on new line + + ADD R4, R4, #41*4 ; move Xmin to next line + ADD R5, R5, #41*4 ; move Xmax to next line + + CMP R11, R10 ; if Y < Ymax + CMPCC R8, R5 ; and X < Xmax + CMPCC R4, R8 ; if also Xmin < X + CMPCC R14, #1 ; & we're zapping not scanning + MOVCC R0, #32 ; then zap to space + LDRCSB R0, [R8, #4] ; else load from map + B %BT08 + +; ***************************************************************************** +; +; TTXClearBox - Fill a rectangle with spaces, and update screen +; +; in: R0 = left column +; R1 = bottom row +; R2 = right column +; R3 = top row +; Return address already stacked +; + +TTXClearBox + ADD R10, R1, #1 ; R10 := bottom +1 + MOV R11, R3 ; R11 := top + ADD R5, R2, #1 ; R5 := right + 1 + + MOV R1, R3 + BL AddressR0R1 ; R2 := address(topleft) + ; R1, R3, R4 corrupted + MOV R3, R0 ; R3 := left + + ADRL R4, TTXLineStarts + LDR R0, [R4, R11, LSL #2] ; R0 -> dummy(top) + ADD R5, R0, R5, LSL #2 ; R5 := map(topright) + ADD R4, R0, R3, LSL #2 ; R4 := map(topleft)-4 + SUB R4, R4, #4 ; R4 := map(topleft)-8 + MOV R0, #32 ; start with a space + MOV R14, #0 ; indicate zapping + B TTXScanZap ; go and do it + +; ***************************************************************************** +; +; TTXHardScrollUp - Scroll teletext screen upwards +; + +TTXHardScrollUp ROUT + +; first scroll map up + + LDR R0, [WsPtr, #RowLength] ; save real RowLength + Push "R0, R6, R14" ; and save CursorFlags + + MOV R0, #1 ; pretend rowmult = 1 + LDR R2, TTXLineStarts ; R2 -> TTXMap + MOV R5, #41*4 ; R5 = no. of bytes horiz + STR R5, [WsPtr, #RowLength] ; pretend rowlength + MOV R6, #25 ; no. of 'pixel' rows + MOV R7, R5 ; linelength + BL SoftScrollUp2 + + Pull "R0, R6" + STR R0, [WsPtr, #RowLength] ; restore RowLength + +; now 'scroll' DoubleCounts + + ADD R0, WsPtr, #TTXDoubleCounts + ADD R1, R0, #24 +10 + LDRB R2, [R0, #1] + STRB R2, [R0], #1 + TEQ R0, R1 + BNE %BT10 + +; now see if top line was a 'bottom' row +; if so, we need to rescan from the top + + LDR R8, TTXLineStarts ; R8 -> top left map + LDR R1, [R8] ; R1 = dummy word + TST R1, #MapBit_Bottom ; if not bottom + BEQ %FT20 ; then OK + + BIC R1, R1, #MapBit_Bottom ; make into a 'top' line + STR R1, [R8] ; store back + LDRB R0, [R8, #4] ; R0 = first char + MOV R3, #0 ; X = 0 + MOV R11, #0 ; Y = 0 + LDR R2, [WsPtr, #ScreenStart] ; screen address for top-left + + ADR R14, %FT20 + Push R14 + B TTXScanFromHere + +20 + +; now see if new bottom line should be a 'bottom' or a 'top' line + + ADRL R0, TTXLineStarts + LDR R0, [R0, #23*4] ; R0 -> dummy word on line 23 + LDRB R1, [WsPtr, #TTXDoubleCounts+23] ; no. of dbls on line 23 + TEQ R1, #0 ; if R1=0 then line 24 is 'top' + LDRNE R1, [R0] ; else line 24 is opposite + EORNE R1, R1, #MapBit_Bottom ; of line 23 + ANDNE R1, R1, #MapBit_Bottom + LDR R2, [R0, #41*4] ; R2 = dummy word on line 24 + BIC R2, R2, #MapBit_Bottom ; clear that bit + ORR R2, R2, R1 ; OR in new bit + STR R2, [R0, #41*4] ; and store back + + Pull PC + +; ***************************************************************************** +; +; TTXSoftScrollUp - Scroll screen up by software in teletext mode +; + +TTXSoftScrollUp ROUT + +; first scroll map up + + LDR R0, [WsPtr, #RowLength] ; save real RowLength + LDR R1, [WsPtr, #TWTRow] ; top row + LDR R3, [WsPtr, #TWBRow] ; bottom row + + ADRL R2, TTXLineStarts + LDR R2, [R2, R1, LSL #2] ; R2 -> dummy char top row + ADD R2, R2, #4 ; R2 -> 0th char top row + LDR R4, [WsPtr, #TWLCol] + LDR R5, [WsPtr, #TWRCol] + + Push "R0-R6,R14" ; and save CursorFlags + + ADD R2, R2, R4, LSL #2 ; R2 -> top left char + + SUB R5, R5, R4 + ADD R5, R5, #1 ; R5 = no. of chars wide + MOV R5, R5, LSL #2 ; R5 = no. of bytes / line + + SUB R6, R3, R1 + ADD R6, R6, #1 ; R6 = no. of 'pixel' rows + + MOV R7, #41*4 ; R7 = line length + STR R7, [WsPtr, #RowLength] ; pretend row length + MOV R0, #1 ; pretend rowmult =1 + + BL SoftScrollUp2 + + Pull "R0-R6" + STR R0, [WsPtr, #RowLength] ; restore RowLength + +; now R1=top row, R2 -> char 0 on row R1, R3=bottom row, R4=left, R5=right + +; now clear bottom row + + ADR R7, TTXLineStarts + LDR R7, [R7, R3, LSL #2] ; R7 -> dummy word(bottom) + ADD R8, R7, R5, LSL #2 ; R8 -> char before bottom rt + ADD R7, R7, R4, LSL #2 ; R7 -> char before bottom left + MOV R0, #32 +30 + STRB R0, [R7, #4]! ; zap to space + CMP R7, R8 ; if <= char before bottom rt + BLS %BT30 ; then loop + + MOV R9, R2 +CountAndRescan + BL CountDoubles + +; now rescan from top of window + + ADD R10, R3, #1 ; R10 = bottom + 1 + MOV R11, R1 ; R11 = top + ADD R7, R2, R4, LSL #2 ; R7 = map(left,top) + ADD R5, R2, R5, LSL #2 ; R5 = map(right,top) + MOV R0, R4 ; R0 = left +TTXScanZap2 + BL AddressR0R1 ; R2 = screen(left,top) + ; (R1,R3,R4 corrupted) + SUB R4, R7, #8 ; R4 = map(left,top)-8 + MOV R3, R0 ; R3 = left + LDRB R0, [R4, #8] ; R0 = first char + MOV R14, #1 ; scan not zap + B TTXScanZap + +; ***************************************************************************** +; +; CountDoubles - Count double height characters in a range of rows +; +; in: R1 = top row to count +; R3 = bottom row to count +; R9 -> map(0,top) +; +; out: R1-R6 preserved +; + +CountDoubles ROUT + ADD R7, WsPtr, #TTXDoubleCounts + ADD R7, R7, R1 ; R7 -> current double count + MOV R11, R1 +10 + ADD R8, R9, #40*4 ; R8 -> dummy char next row + MOV R10, #0 ; count so far +20 + LDR R0, [R9], #4 ; load char word + AND R0, R0, #&7F ; only look at bottom 7 bits + TEQ R0, #TTX_DoubleHeight ; if double height + ADDEQ R10, R10, #1 ; then increment count + TEQ R9, R8 ; if not at end of row + BNE %BT20 ; then loop + + STRB R10, [R7], #1 ; store double count + ADD R9, R9, #4 ; skip dummy char + ADD R11, R11, #1 ; goto next row + CMP R11, R3 ; if <= bottom + BLS %BT10 ; then loop + + MOV PC, R14 + +; ***************************************************************************** +; +; TTXHardScrollDown - Scroll teletext screen downwards +; + +TTXHardScrollDown ROUT + +; first scroll map down + + LDR R0, [WsPtr, #RowLength] ; save real RowLength + Push "R0, R6, R14" ; and save CursorFlags + + MOV R0, #1 ; pretend rowmult = 1 + LDR R2, TTXLineStarts+24*4 ; R2 -> dummy char on bottom + MOV R5, #41*4 ; R5 = no. of bytes horiz + STR R5, [WsPtr, #RowLength] ; pretend rowlength + MOV R6, #25 ; no. of 'pixel' rows + MOV R7, R5 ; linelength + BL SoftScrollDown2 + + Pull "R0, R6" + STR R0, [WsPtr, #RowLength] ; restore RowLength + +; now 'scroll' DoubleCounts + + ADD R0, WsPtr, #TTXDoubleCounts + ADD R1, R0, #24 +10 + LDRB R2, [R1, #-1] + STRB R2, [R1], #-1 + TEQ R1, R0 + BNE %BT10 + +; now make top row a 'top' row + + LDR R0, TTXLineStarts ; R0 -> top line dummy word + LDR R1, [R0] ; R1 = dummy word + BIC R1, R1, #MapBit_Bottom ; clear 'bottom' bit + STR R1, [R0] ; and store back + + Pull PC + +; ***************************************************************************** +; +; TTXSoftScrollDown - Scroll screen down by software in teletext mode +; + +TTXSoftScrollDown ROUT + +; first scroll map down + + LDR R0, [WsPtr, #RowLength] ; save real RowLength + LDR R1, [WsPtr, #TWTRow] ; top row + LDR R3, [WsPtr, #TWBRow] ; bottom row + + ADR R2, TTXLineStarts + LDR R2, [R2, R3, LSL #2] ; R2 -> dummy char bottom row + ADD R2, R2, #4 ; R2 -> 0th char bottom row + LDR R4, [WsPtr, #TWLCol] + LDR R5, [WsPtr, #TWRCol] + + Push "R0-R6,R14" ; and save CursorFlags + + ADD R2, R2, R4, LSL #2 ; R2 -> bottom left char + + SUB R5, R5, R4 + ADD R5, R5, #1 ; R5 = no. of chars wide + MOV R5, R5, LSL #2 ; R5 = no. of bytes / line + + SUB R6, R3, R1 + ADD R6, R6, #1 ; R6 = no. of 'pixel' rows + + MOV R7, #41*4 ; R7 = line length + STR R7, [WsPtr, #RowLength] ; pretend row length + MOV R0, #1 ; pretend rowmult =1 + + BL SoftScrollDown2 + + Pull "R0-R6" + STR R0, [WsPtr, #RowLength] ; restore RowLength + +; now R1=top row, R2 -> char 0 on row R3, R3=bottom row, R4=left, R5=right + +; now clear top row + + ADR R7, TTXLineStarts + LDR R7, [R7, R1, LSL #2] ; R7 -> dummy word(top) + ADD R8, R7, R5, LSL #2 ; R8 -> char before top rt + ADD R7, R7, R4, LSL #2 ; R7 -> char before top left + MOV R0, #32 +30 + STRB R0, [R7, #4]! ; zap to space + CMP R7, R8 ; if <= char before bottom rt + BLS %BT30 ; then loop + + SUB R9, R8, R5, LSL #2 ; R9 -> dummy word(top) + ADD R9, R9, #4 ; R9 -> map(0,top) + MOV R2, R9 + B CountAndRescan ; count doubles and rescan + ; from top of window + +; ***************************************************************************** +; +; TTXScrollLeft - Scroll left (by software) in Teletext mode +; +; in: R0 bit0=0 => scroll window +; 1 => scroll screen +; + +TTXScrollLeft ROUT + Push R14 + BL TTXSideScroll1 + MOV R5, R0 ; R5 = left = column to check + ; for double height chars + BL TTXSideScroll2 ; do second part + BL ScrollLeft2 + +; now store spaces in right hand column + + Pull "R0-R3, R6, R9" + ADD R4, R9, R2, LSL #2 ; R4 -> map(right,top) +TTXSideScroll3 + MOV R7, R3 ; R7 = current row + MOV R8, #32 ; poke spaces +20 + STRB R8, [R4], #41*4 ; store space and move down + ADD R7, R7, #1 ; next row + CMP R7, R1 ; if row <= bottom + BLS %BT20 ; then loop + +; now rescan from top of window/screen + + ADD R10, R1, #1 ; R10 = bottom+1 + MOV R11, R3 ; R11 = top + ADD R7, R9, R0, LSL #2 ; R7 -> map(left,top) + ADD R5, R9, R2, LSL #2 ; R5 -> map(right,top) + MOV R1, R3 ; R1 = top + B TTXScanZap2 + +; ***************************************************************************** +; +; TTXScrollRight - Scroll right (by software) in Teletext mode +; +; in: R0 bit0=0 => scroll window +; 1 => scroll screen +; + +TTXScrollRight ROUT + Push R14 + BL TTXSideScroll1 + MOV R5, R2 ; R5 = right = column to check + ; for double height chars + BL TTXSideScroll2 + BL ScrollRight2 + +; now store spaces in left hand column + + Pull "R0-R3, R6, R9" + ADD R4, R9, R0, LSL #2 ; R4 -> map(left,top) + B TTXSideScroll3 + +; ***************************************************************************** +; +; TTXSideScroll1 - Do first part of sideways scroll +; + +TTXSideScroll1 ROUT + MOVS R0, R0, LSR #1 + +; C=0 => scroll window + + ADDCC R0, WsPtr, #TWLCol ; R0 = left, R1 = bottom + LDMCCIA R0, {R0-R3} ; R2 = right, R3 = top + +; C=1 => scroll screen + + MOVCS R0, #0 ; left + LDRCS R1, [WsPtr, #ScrBRow] ; bottom + LDRCS R2, [WsPtr, #ScrRCol] ; right + MOVCS R3, #0 ; top + + MOV PC, R14 + +; ***************************************************************************** +; +; TTXSideScroll2 - Do second part of sideways scroll +; +; in: R5 = left or right hand column for left or right scroll respectively +; + +TTXSideScroll2 ROUT + +; first check char R5 on each line and decrement double count if a double + + ADR R4, TTXLineStarts + LDR R4, [R4, R3, LSL #2] ; R4 -> map(dummy,top) + ADD R9, R4, #4 ; R9 -> map(0,top) + ADD R4, R9, R5, LSL #2 ; R4 -> map(left or right,top) + + ADD R5, WsPtr, #TTXDoubleCounts + MOV R7, R3 ; R7 = current row +10 + LDR R8, [R4], #41*4 ; get char+attr + AND R8, R8, #&7F + TEQ R8, #TTX_DoubleHeight ; test if double height char + + LDREQB R8, [R5, R7] ; if so then load double count + SUBEQ R8, R8, #1 ; decrement it + STREQB R8, [R5, R7] ; and store back + + ADD R7, R7, #1 ; next row + CMP R7, R1 ; if row <= bottom + BLS %BT10 ; then loop + +; now scroll map + + Push "R0-R3, R6, R9" + SUB R5, R2, R0 ; R5 = right-left + ADD R5, R5, #1 ; R5 = right-left+1 + MOV R5, R5, LSL #2 ; R5 = (right-left+1)*4 + ADD R2, R9, R0, LSL #2 ; R2 -> map(left,top) + SUB R6, R1, R3 ; R6 = bottom-top + ADD R6, R6, #1 ; R6 = bottom-top+1 + MOV R7, #41*4 ; linelength + MOV R9, #4 ; no. of bytes to scroll by + + MOV PC, R14 + +; ***************************************************************************** +; +; TTXPaintChar - Paint char according to attributes +; +; in: R0 = character + attributes word +; R2 -> screen (for the time being) +; +; out: R2 preserved +; R0 largely preserved, but held graphic bits may have been changed +; + +TTXPaintChar ROUT + Push R14 + VDWS WsPtr ; for now + +; first set up the colours + + ADD R1, WsPtr, #TForeCol + LDMIA R1, {R1, R3} ; R1 = TForeCol; R3 = TBackCol + MOV R4, #&0F + AND R5, R4, R0, LSR #MapForeShift ; R5 = new foregd colour + AND R6, R4, R0, LSR #MapBackShift ; R6 = new backgd colour + + TEQ R1, R5 ; if foregd different + TEQEQ R3, R6 ; or backgd different + BLNE TTXUpdateColours ; then update colour table + + ADR R1, TTXHardFont-32*10 ; R1 -> base for font + MOVS R3, R0, LSL #26 ; C := bit6, N := bit5 + AND R3, R0, #&7F ; R3 = char + BMI %FT10 ; [&20-&3F or &60-&7F] + BCS %FT20 ; [&40-&5F (definitely Alpha)] + +; control code, so display as space or held graphic + + TST R0, #MapBit_Hold ; zero if not holding + MOVEQ R3, #&20 ; pretend to be space + BICEQ R0, R0, #MapBit_HeldMask ; and cancel held graphic + BEQ %FT20 ; [display as space] + +; next instruction assumes no valid bits above held graphic bits + + MOV R3, R0, LSR #MapHeldShift ; R3 = char to display + B %FT30 ; [display as held graphic] + +; char in range &20-&3F or &60-&7F, so check for alpha/graphics + +10 + TST R0, #MapBit_Graph ; in graphics mode + BEQ %FT20 ; [no, so definitely Alpha] + TST R0, #MapBit_Separated ; separated graphics ? + BICEQ R3, R3, #&20 ; no, then make &00-&1F,&40-&5F + BIC R0, R0, #MapBit_HeldMask ; cancel current held graphic + ORR R0, R0, R3, LSL #MapHeldShift ; and put new one in +30 + ADD R1, WsPtr, #TTXSoftFonts +20 + ADD R1, R1, R3, LSL #3 ; add 8*char + ADD R1, R1, R3, LSL #1 ; add 2*char + + TST R0, #MapBit_Conceal ; concealing ? + ADRNE R1, TTXHardFont ; yes, then display as space + +; now load font bytes +; 0..3 into tophalf +; 4..7 into bottomhalf +; 8..9 into R10 (top 2 bytes) + + TST R1, #2 ; starting on a word bdy ? + + SUBNE R1, R1, #2 ; if not, move back + LDMIA R1, {tophalf, bottomhalf, R10} ; yes, so load all 3 up + MOVEQ R10, R10, LSL #16 + MOVNE tophalf, tophalf, LSR #16 + ORRNE tophalf, tophalf, bottomhalf, LSL #16 + MOVNE bottomhalf, bottomhalf, LSR #16 + ORRNE bottomhalf, bottomhalf, R10, LSL #16 + + TST R0, #(MapBit_Bottom :OR: MapBit_Double) + BLNE PrintDoubleHeight + + [ VIDC_Type = "VIDC20" + LDR bigfont, [WsPtr, #TextExpandArea] + | + ADD bigfont, WsPtr, #TextExpand + ] + MOV mask, #&FF000000 + LDR linelen, [WsPtr, #LineLength] + Push "R0, screen" + MOV R0, #0 ; indicate 10 rows + BL Wrch4bitTTX ; do 1st bank + + LDMFD R13, {R0, screen} ; restore char + scr. addr + ADD screen, screen, #40*1024 + TST R0, #MapBit_Flash + MOVNE mask, #0 ; flash => 2nd bank is space + MOV R0, #0 + BL Wrch4bitTTX + Pull "R0, screen, PC" + +; ***************************************************************************** + +TTXLineStarts + GBLA lineno +lineno SETA 0 + WHILE lineno < 25 + & VduDriverWorkSpace+TTXMap+4*41*lineno +lineno SETA lineno +1 + WEND + + LTORG + +; ***************************************************************************** +; +; DoPreControl - Process 'at' action of control char +; DoPostControl - Process 'after' action of control char +; +; in: R0 = new char + attributes of current previous char +; R1 = new char AND &7F +; (0 <= R1 <= 31) +; + +DoPreControl ROUT + ADD PC, PC, R1, LSL #3 +DoPostControl ROUT + ADD PC, PC, R1, LSL #3 + MOV PC, R14 ; &00 Pre + MOV PC, R14 ; &00 Post + MOV PC, R14 ; &01 Pre + B DoAlphaColour ; &01 Post + MOV PC, R14 ; &02 Pre + B DoAlphaColour ; &02 Post + MOV PC, R14 ; &03 Pre + B DoAlphaColour ; &03 Post + MOV PC, R14 ; &04 Pre + B DoAlphaColour ; &04 Post + MOV PC, R14 ; &05 Pre + B DoAlphaColour ; &05 Post + MOV PC, R14 ; &06 Pre + B DoAlphaColour ; &06 Post + MOV PC, R14 ; &07 Pre + B DoAlphaColour ; &07 Post + MOV PC, R14 ; &08 Pre + B DoFlash ; &08 Post + BIC R0, R0, #MapBit_Flash ; &09 Pre ; clear flash mode + MOV PC, R14 ; &09 Post + B DoPreEndBox ; &0A Pre + B DoPostEndBox ; &0A Post + B DoPreStartBox ; &0B Pre + B DoPostStartBox ; &0B Post + B DoSingleHeight ; &0C Pre + MOV PC, R14 ; &0C Post + B DoDoubleHeight ; &0D Pre + MOV PC, R14 ; &0D Post + MOV PC, R14 ; &0E Pre + MOV PC, R14 ; &0E Post + MOV PC, R14 ; &0F Pre + MOV PC, R14 ; &0F Post + MOV PC, R14 ; &10 Pre + MOV PC, R14 ; &10 Post + MOV PC, R14 ; &11 Pre + B DoGraphColour ; &11 Post + MOV PC, R14 ; &12 Pre + B DoGraphColour ; &12 Post + MOV PC, R14 ; &13 Pre + B DoGraphColour ; &13 Post + MOV PC, R14 ; &14 Pre + B DoGraphColour ; &14 Post + MOV PC, R14 ; &15 Pre + B DoGraphColour ; &15 Post + MOV PC, R14 ; &16 Pre + B DoGraphColour ; &16 Post + MOV PC, R14 ; &17 Pre + B DoGraphColour ; &17 Post + ORR R0, R0, #MapBit_Conceal ; &18 Pre ; set conceal mode + MOV PC, R14 ; &18 Post + MOV PC, R14 ; &19 Pre + BIC R0, R0, #MapBit_Separated ; &19 Post ; clear separated + MOV PC, R14 ; &1A Pre + ORR R0, R0, #MapBit_Separated ; &1A Post ; set separated + MOV PC, R14 ; &1B Pre + MOV PC, R14 ; &1B Post + BIC R0, R0, #MapBit_BackMask ; &1C Pre ; clear backgd colour + MOV PC, R14 ; &1C Post + B DoNewBackgd ; &1D Pre + MOV PC, R14 ; &1D Post + ORR R0, R0, #MapBit_Hold ; &1E Pre ; set hold graph mode + MOV PC, R14 ; &1E Post + MOV PC, R14 ; &1F Pre + BIC R0, R0, #MapBit_Hold ; &1F Post ; clear hold graph mode + MOV PC, R14 + +; ***************************************************************************** + +DoAlphaColour + BIC R0, R0, #MapBit_HeldMask ; clear held graphic + BIC R0, R0, #(MapBit_ForeMask :OR: MapBit_Conceal) + ; clear colour + conceal + ORR R0, R0, R1, LSL #MapForeShift ; put in new colour + BIC R0, R0, #MapBit_Graph ; set alpha mode + MOV PC, R14 + +DoGraphColour + BIC R0, R0, #(MapBit_ForeMask :OR: MapBit_Conceal) + ; clear colour + conceal + AND R3, R1, #&07 ; ensure only colour bits + ORR R0, R0, R3, LSL #MapForeShift ; put in new colour + ORR R0, R0, #MapBit_Graph ; set graph mode + MOV PC, R14 + +DoFlash + ORR R0, R0, #MapBit_Flash ; set flash mode + MOV PC, R14 + +DoNewBackgd + AND R3, R0, #MapBit_ForeMask ; R5 = fore colour + BIC R0, R0, #MapBit_BackMask ; clear old backgd + ORR R0, R0, R3, LSL #(MapBackShift-MapForeShift) ; new backgd + MOV PC, R14 + +DoDoubleHeight + TST R0, #MapBit_Double ; if currently single height + BICEQ R0, R0, #MapBit_HeldMask ; then cancel held graphic + ORR R0, R0, #MapBit_Double ; set double height mode + ADD R9, R9, #1 ; one more double char + MOV PC, R14 + +DoSingleHeight + TST R0, #MapBit_Double ; if currently double height + BICNE R0, R0, #MapBit_HeldMask ; then cancel held graphic + BIC R0, R0, #MapBit_Double ; set single height mode + MOV PC, R14 + +DoPreStartBox + TST R0, #MapBit_PendingStart ; if prev char was start box + ORRNE R0, R0, #MapBits_Boxed ; then start boxed area + MOV PC, R14 + +DoPostStartBox + ORR R0, R0, #MapBit_PendingStart ; "Previous char is Start Box" + MOV PC, R14 + +DoPreEndBox + TST R0, #MapBit_PendingEnd ; if prev char was end box + BICNE R0, R0, #MapBits_Boxed ; then end boxed area + MOV PC, R14 + +DoPostEndBox + ORR R0, R0, #MapBit_PendingEnd ; "Previous char is End Box" + MOV PC, R14 + +; ***************************************************************************** + +TTXHardFont + = &00,&00,&00,&00,&00,&00,&00,&00,&00,&00 ; space + = &00,&08,&08,&08,&08,&08,&00,&08,&00,&00 ; ! + = &00,&14,&14,&14,&00,&00,&00,&00,&00,&00 ; " + = &00,&0C,&12,&10,&38,&10,&10,&3E,&00,&00 ; ` + = &00,&1C,&2A,&28,&1C,&0A,&2A,&1C,&00,&00 ; $ + = &00,&30,&32,&04,&08,&10,&26,&06,&00,&00 ; % + = &00,&10,&28,&28,&10,&2A,&24,&1A,&00,&00 ; & + = &00,&08,&08,&08,&00,&00,&00,&00,&00,&00 ; ' + = &00,&04,&08,&10,&10,&10,&08,&04,&00,&00 ; ( + = &00,&10,&08,&04,&04,&04,&08,&10,&00,&00 ; ) + = &00,&08,&2A,&1C,&08,&1C,&2A,&08,&00,&00 ; * + = &00,&00,&08,&08,&3E,&08,&08,&00,&00,&00 ; + + = &00,&00,&00,&00,&00,&00,&08,&08,&10,&00 ; , + = &00,&00,&00,&00,&1C,&00,&00,&00,&00,&00 ; - + = &00,&00,&00,&00,&00,&00,&00,&08,&00,&00 ; . + = &00,&00,&02,&04,&08,&10,&20,&00,&00,&00 ; / + = &00,&08,&14,&22,&22,&22,&14,&08,&00,&00 ; 0 + = &00,&08,&18,&08,&08,&08,&08,&1C,&00,&00 ; 1 + = &00,&1C,&22,&02,&0C,&10,&20,&3E,&00,&00 ; 2 + = &00,&3E,&02,&04,&0C,&02,&22,&1C,&00,&00 ; 3 + = &00,&04,&0C,&14,&24,&3E,&04,&04,&00,&00 ; 4 + = &00,&3E,&20,&3C,&02,&02,&22,&1C,&00,&00 ; 5 + = &00,&0C,&10,&20,&3C,&22,&22,&1C,&00,&00 ; 6 + = &00,&3E,&02,&04,&08,&10,&10,&10,&00,&00 ; 7 + = &00,&1C,&22,&22,&1C,&22,&22,&1C,&00,&00 ; 8 + = &00,&1C,&22,&22,&1E,&02,&04,&18,&00,&00 ; 9 + = &00,&00,&00,&08,&00,&00,&08,&00,&00,&00 ; : + = &00,&00,&00,&08,&00,&00,&08,&08,&10,&00 ; ; + = &00,&04,&08,&10,&20,&10,&08,&04,&00,&00 ; < + = &00,&00,&00,&3E,&00,&3E,&00,&00,&00,&00 ; = + = &00,&10,&08,&04,&02,&04,&08,&10,&00,&00 ; > + = &00,&1C,&22,&04,&08,&08,&00,&08,&00,&00 ; ? + = &00,&1C,&22,&2E,&2A,&2E,&20,&1C,&00,&00 ; @ + = &00,&08,&14,&22,&22,&3E,&22,&22,&00,&00 ; A + = &00,&3C,&22,&22,&3C,&22,&22,&3C,&00,&00 ; B + = &00,&1C,&22,&20,&20,&20,&22,&1C,&00,&00 ; C + = &00,&3C,&22,&22,&22,&22,&22,&3C,&00,&00 ; D + = &00,&3E,&20,&20,&3C,&20,&20,&3E,&00,&00 ; E + = &00,&3E,&20,&20,&3C,&20,&20,&20,&00,&00 ; F + = &00,&1C,&22,&20,&20,&26,&22,&1E,&00,&00 ; G + = &00,&22,&22,&22,&3E,&22,&22,&22,&00,&00 ; H + = &00,&1C,&08,&08,&08,&08,&08,&1C,&00,&00 ; I + = &00,&02,&02,&02,&02,&02,&22,&1C,&00,&00 ; J + = &00,&22,&24,&28,&30,&28,&24,&22,&00,&00 ; K + = &00,&20,&20,&20,&20,&20,&20,&3E,&00,&00 ; L + = &00,&22,&36,&2A,&22,&22,&22,&22,&00,&00 ; M + = &00,&22,&22,&32,&2A,&26,&22,&22,&00,&00 ; N + = &00,&1C,&22,&22,&22,&22,&22,&1C,&00,&00 ; O + = &00,&3C,&22,&22,&3C,&20,&20,&20,&00,&00 ; P + = &00,&1C,&22,&22,&22,&2A,&24,&1A,&00,&00 ; Q + = &00,&3C,&22,&22,&3C,&28,&24,&22,&00,&00 ; R + = &00,&1C,&22,&20,&1C,&02,&22,&1C,&00,&00 ; S + = &00,&3E,&08,&08,&08,&08,&08,&08,&00,&00 ; T + = &00,&22,&22,&22,&22,&22,&22,&1C,&00,&00 ; U + = &00,&22,&22,&22,&14,&14,&08,&08,&00,&00 ; V + = &00,&22,&22,&22,&2A,&2A,&2A,&14,&00,&00 ; W + = &00,&22,&22,&14,&08,&14,&22,&22,&00,&00 ; X + = &00,&22,&22,&14,&08,&08,&08,&08,&00,&00 ; Y + = &00,&3E,&02,&04,&08,&10,&20,&3E,&00,&00 ; Z + = &00,&00,&08,&10,&3E,&10,&08,&00,&00,&00 ; [ + = &00,&20,&20,&20,&20,&2C,&02,&04,&08,&0E ; \ + = &00,&00,&08,&04,&3E,&04,&08,&00,&00,&00 ; ] + = &00,&00,&08,&1C,&2A,&08,&08,&00,&00,&00 ; ^ + = &00,&14,&14,&3E,&14,&3E,&14,&14,&00,&00 ; # + = &00,&00,&00,&00,&3E,&00,&00,&00,&00,&00 ; _ + = &00,&00,&00,&1C,&02,&1E,&22,&1E,&00,&00 ; a + = &00,&20,&20,&3C,&22,&22,&22,&3C,&00,&00 ; b + = &00,&00,&00,&1E,&20,&20,&20,&1E,&00,&00 ; c + = &00,&02,&02,&1E,&22,&22,&22,&1E,&00,&00 ; d + = &00,&00,&00,&1C,&22,&3E,&20,&1C,&00,&00 ; e + = &00,&04,&08,&08,&1C,&08,&08,&08,&00,&00 ; f + = &00,&00,&00,&1E,&22,&22,&22,&1E,&02,&1C ; g + = &00,&20,&20,&3C,&22,&22,&22,&22,&00,&00 ; h + = &00,&08,&00,&18,&08,&08,&08,&1C,&00,&00 ; i + = &00,&08,&00,&08,&08,&08,&08,&08,&08,&10 ; j + = &00,&10,&10,&12,&14,&18,&14,&12,&00,&00 ; k + = &00,&18,&08,&08,&08,&08,&08,&1C,&00,&00 ; l + = &00,&00,&00,&34,&2A,&2A,&2A,&2A,&00,&00 ; m + = &00,&00,&00,&3C,&22,&22,&22,&22,&00,&00 ; n + = &00,&00,&00,&1C,&22,&22,&22,&1C,&00,&00 ; o + = &00,&00,&00,&3C,&22,&22,&22,&3C,&20,&20 ; p + = &00,&00,&00,&1E,&22,&22,&22,&1E,&02,&02 ; q + = &00,&00,&00,&16,&18,&10,&10,&10,&00,&00 ; r + = &00,&00,&00,&1E,&20,&1C,&02,&3C,&00,&00 ; s + = &00,&08,&08,&1C,&08,&08,&08,&04,&00,&00 ; t + = &00,&00,&00,&22,&22,&22,&22,&1E,&00,&00 ; u + = &00,&00,&00,&22,&22,&14,&14,&08,&00,&00 ; v + = &00,&00,&00,&22,&22,&2A,&2A,&14,&00,&00 ; w + = &00,&00,&00,&22,&14,&08,&14,&22,&00,&00 ; x + = &00,&00,&00,&22,&22,&22,&22,&1E,&02,&1C ; y + = &00,&00,&00,&3E,&04,&08,&10,&3E,&00,&00 ; z + = &00,&10,&10,&10,&10,&12,&06,&0A,&0E,&02 ; { + = &00,&14,&14,&14,&14,&14,&14,&14,&00,&00 ; | + = &00,&30,&08,&30,&08,&32,&06,&0A,&0E,&02 ; } + = &00,&00,&08,&00,&3E,&00,&08,&00,&00,&00 ; ~ + = &00,&3E,&3E,&3E,&3E,&3E,&3E,&3E,&00,&00 ; &FF + + END diff --git a/s/vdu/vduwrch b/s/vdu/vduwrch new file mode 100644 index 0000000000000000000000000000000000000000..5ffecd2de6cadc79f057145f35f54745d6ac95a2 --- /dev/null +++ b/s/vdu/vduwrch @@ -0,0 +1,3119 @@ +; Copyright 1996 Acorn Computers Ltd +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +; +; > $.Source.VduWrch + +; Text printing etc. +; ------------------ + +; Author Tim Dobson +; Started 01-Sep-86 +; Status Mostly Arm-less + +; ***************************************************************************** + +; CursorFlags bits + +; Bit 0 '81 column' mode +; Bits 1-3 Cursor movement directions +; Bit 4 Wrap instead of scroll in VDU4 mode +; Bit 5 Don't move cursor after printing character +; Bit 6 Don't wrap in VDU 5 mode +; Bit 7 Unused but could be set by user +; Bit 8 When in Wrch or screen update operation, set to 1 and forms +; part of mask for ROR #10. +; Otherwise is set to 0. +; Tested by cursor code to see if it can update CursorFlags. +; Bits 9-17 Set to 101111000 so we can TST CursorFlags with itself ROR #10 +; to test for OR of C81Bit, Vdu5Bit, silly movement bits in 1 go +; in order to optimise the case when none of these are present +; Bit 18 Set when cursors are split - since bit 8 is set this triggers +; Bit 19 Set when in teletext mode +; Bit 20 Set when in page mode +; Bit 21 Set when clip box calculations are enabled - this triggers +; Bits 22-24 Unused, but probably have to be zero because of ROR #10 +; Bit 25 Actual cursor state (1 => cursor is on screen) +; Bit 26 Set if VDU disabled +; Bits 27-28 Unused, but probably have to be zero because of ROR #10 +; Bit 29 TextExpand not up-to-date +; Bit 30 VDU 5 mode +; Bit 31 In the '81st' column + +InWrchBitPosn * 8 +InWrchBit * 1 :SHL: InWrchBitPosn +CursorsSplit * 1 :SHL: 18 +TeletextMode * 1 :SHL: 19 +PageMode * 1 :SHL: 20 +ClipBoxEnableBit * 1 :SHL: 21 +ActualState * 1 :SHL: 25 +VduDisabled * 1 :SHL: 26 +TEUpdate * 1 :SHL: 29 +Vdu5Bit * 1 :SHL: 30 +C81Bit * 1 :SHL: 31 +InitialCursorFlags * (&1E :SHL: 10) :OR: (C81Bit :SHR: (32-10)) + +; The TST R6, R6, ROR #10 returns non-zero if +; +; C81Bit OR Vdu5 OR (any of bits 1-4) OR CursorsSplit +; OR ClipBoxEnableBit OR (TEUpdate AND bit7) OR Teletext +; +; The last two of these are slightly undesirable, but fairly harmless since: +; (a) bit 7 is not normally set, and TEUpdate is only set when a colour +; change happens. +; (b) Teletext mode takes quite a long time anyway. +; NB We don't believe that the TST needs to detect Teletext mode, but if you +; want to stop it doing so, it's on your own head. Check everything carefully! + +; ***************************************************************************** +; +; Set default logical and physical colours + +bpp RN 0 +fore RN 1 +back RN 2 +tabaddr RN 3 +index RN 4 +source RN 5 +dest RN 6 +col RN 7 +orrbits RN 8 +addbits RN 9 +bit0 RN 10 + +hiaddr RN 4 +loaddr RN 5 +; dest 6 +hiword RN 7 ; must be higher number than dest (for Colour16Bit) +loword RN 8 +cbyte RN 9 +spare1 RN 10 +spare2 RN 11 + +; ***************************************************************************** +; +; VDU 20 - Set default colours (if output mode not teletext) +; and palette (if display mode not teletext) +; +; External routine, and DefaultColours called by mode change +; and SwitchOutputToSprite +; +; in: R6 = CursorFlags (for output mode) +; + +VDU20 ROUT + LDR R0, [WsPtr, #DisplayModeFlags] ; if display mode is + TST R0, #Flag_Teletext ; not teletext, then restore + BNE %FT10 ; default palette + + Push R14 + BL PalInit ; R6 is preserved over the call + Pull R14 +10 + TST R6, #TeletextMode ; if output mode is teletext + MOVNE PC, R14 ; then don't reset colours + +; else drop thru to ... + +DefaultColours ROUT + Push R14 + + ASSERT GPLBMD = GPLFMD +4 + ASSERT GFCOL = GPLFMD +8 + ASSERT GBCOL = GPLFMD +12 + + ASSERT TBTint = TFTint +4 + ASSERT GFTint = TFTint +8 + ASSERT GBTint = TFTint +12 + + ASSERT TBackCol = TForeCol +4 + ASSERT back > fore + + MOV R0, #0 ; foreground action := store + MOV R1, #0 ; background action := store + LDR R2, [WsPtr, #NColour] ; GCOL(0,(NColour AND 7)) except + TST R2, #&F0 ; for 256 colour modes + ANDEQ R2, R2, #7 ; when we use colour 63 (=NColour) + MOV R3, #0 ; background colour := black + ADD R4, WsPtr, #GPLFMD ; store GPLFMD, GPLBMD, GFCOL, GBCOL + STMIA R4, {R0-R3} + + MOV R0, #&FF ; R0 = TFTint := &FF; R1 = TBTint := 0 + MOV R2, #&FF ; R2 = GFTint := &FF; R3 = GBTint := 0 + ADD R4, WsPtr, #TFTint + STMIA R4, {R0-R3} + + BL SetColour ; Update FgEcf & BgEcf + + LDR bpp, [WsPtr, #BitsPerPix] + LDR fore, [WsPtr, #NColour] ; Number of colours allowed -1 + TEQ fore, #63 ; are we in bodgy 256 colour mode? + MOVEQ fore, #255 ; then use colour 255 (cringe!) + TEQ fore, #15 ; 16 colour mode + MOVEQ fore, #7 ; Default is 7 for this depth of mode + + [ {TRUE} ; TMD 25-Jun-93 - change default text colour in 16bpp to &7FFF, and 32bpp to &00FFFFFF + LDR r14, =&FFFF + CMP fore, r14 + BICEQ fore, fore, #&8000 ; &FFFF -> &7FFF + BICHI fore, fore, #&FF000000 ; &FFFFFFFF -> &00FFFFFF + ] + MOV back, #0 + ADD R14, WsPtr, #TForeCol + STMIA R14, {fore, back} ; save fgd + bgd text colours + Pull R14 + +; and drop thru to ... + +SetColours ROUT + Push R14 + + MOV R8, back, ROR bpp ; move bits to top of word + MOV R9, fore, ROR bpp + + LDR bpp, [WsPtr, #BytesPerChar] ; fudge some more bits + ORR back, R8, back, ROR bpp + ORR fore, R9, fore, ROR bpp + + MOV LR, bpp +10 + TEQ LR, #32 ; have we finished replicating through word yet? + ORRNE back, back, back, LSR LR ; if not then expand again through the word + ORRNE fore, fore, fore, LSR LR + MOVNE LR, LR, LSL #1 ; double the shift ready for the next pass + BNE %BT10 ; and loop again! + + STR fore, [WsPtr, #TextFgColour] + STR back, [WsPtr, #TextBgColour] ; store bit expanded fore / background colour + +; New colour change code +; entered with fore, back expanded to <bytes_per_char> bits +; and bpp set to be <bytes_per_char> + + TEQ bpp, #16 + BEQ Colour16Bit ; can't optimise + + [ VIDC_Type = "VIDC20" + TEQ bpp, #32 + BEQ Colour32Bit ; cannie optimise captin! + ] + + EOR fore, fore, back ; so we can AND and EOR + [ VIDC_Type = "VIDC20" + LDR loaddr, [WsPtr, #TextExpandArea] + | + ADD loaddr, WsPtr, #TextExpand + ] + ADD dest, loaddr, bpp, LSL #8 ; end+1 destination addr + MOV hiaddr, dest ; TextPlain now moves around, + ; depending on bytes-per-char +10 + LDR cbyte, [hiaddr], #4 + AND cbyte, cbyte, fore + EOR cbyte, cbyte, back + STR cbyte, [loaddr], #4 + TEQ loaddr, dest + BNE %BT10 + + Pull PC + LTORG + +; ***************************************************************************** +; +; Colour16Bit - Set up colour table for MODE 10 +; Entered with R14 already pushed +; + +Colour16Bit + [ VIDC_Type = "VIDC20" + LDR tabaddr, [WsPtr, #TextExpandArea] + | + ADD tabaddr, WsPtr, #TextExpandArea + ] + + ADR hiaddr, C16BTab + ADD R10, hiaddr, #128 +C16B20 + ADR loaddr, C16BTab +C16B30 + LDMIA hiaddr, {dest, hiword} + BL OutputColour + MOV dest, hiword + BL OutputColour + + LDMIA loaddr!, {dest, loword} + BL OutputColour + MOV dest, loword + BL OutputColour + + TEQ loaddr, R10 + BNE C16B30 + + ADD hiaddr, hiaddr, #8 + TEQ hiaddr, R10 + BNE C16B20 + + Pull PC + +C16BTab + & &00000000, &00000000 + & &00000000, &FFFF0000 + & &00000000, &0000FFFF + & &00000000, &FFFFFFFF + + & &FFFF0000, &00000000 + & &FFFF0000, &FFFF0000 + & &FFFF0000, &0000FFFF + & &FFFF0000, &FFFFFFFF + + & &0000FFFF, &00000000 + & &0000FFFF, &FFFF0000 + & &0000FFFF, &0000FFFF + & &0000FFFF, &FFFFFFFF + + & &FFFFFFFF, &00000000 + & &FFFFFFFF, &FFFF0000 + & &FFFFFFFF, &0000FFFF + & &FFFFFFFF, &FFFFFFFF + + [ VIDC_Type = "VIDC20" + +; ***************************************************************************** +; +; Colour32Bit - Set up colour table for MODE 48 (32 bit per pixel) +; Entered with R14 already pushed +; + +Colour32Bit + LDR tabaddr, [WsPtr, #TextExpandArea] + MOV dest, #0 +C32B20 + +; Expand the value in in 'hiaddr' so that each bit is stored as a word +; zero bits are stored in the background and non-zero bits are stored in +; foreground. This is indexed when expanding the 1BPP VDU font out to +; the current depth. + + TST dest, #1 <<7 + STREQ back, [tabaddr], #4 + STRNE fore, [tabaddr], #4 + TST dest, #1 <<6 + STREQ back, [tabaddr], #4 + STRNE fore, [tabaddr], #4 + TST dest, #1 <<5 + STREQ back, [tabaddr], #4 + STRNE fore, [tabaddr], #4 + TST dest, #1 <<4 + STREQ back, [tabaddr], #4 + STRNE fore, [tabaddr], #4 + TST dest, #1 <<3 + STREQ back, [tabaddr], #4 + STRNE fore, [tabaddr], #4 + TST dest, #1 <<2 + STREQ back, [tabaddr], #4 + STRNE fore, [tabaddr], #4 + TST dest, #1 <<1 + STREQ back, [tabaddr], #4 + STRNE fore, [tabaddr], #4 + TST dest, #1 <<0 + STREQ back, [tabaddr], #4 + STRNE fore, [tabaddr], #4 + + ADD dest, dest, #1 + TEQ dest, #256 + BNE C32B20 + + Pull "PC" + + ] + +; ***************************************************************************** +; +; Fast CLS used when no text window defined +; + +FastCLS ROUT + Push R14 + BL CheckTEUpdate + + TST R6, #TeletextMode ; teletext mode ? + LDREQ R0, [WsPtr, #TextBgColour] + BEQ %FT10 ; and skip + + BL TTXFastCLS ; else clear teletext map + MOV R0, #0 ; and clear to zero +10 + LDR R8, [WsPtr, #ScreenStart] + MOV R1, R0 + MOV R2, R0 + MOV R3, R0 + MOV R4, R0 + MOV R5, R0 + MOV R6, R0 + MOV R7, R0 + LDR R9, [WsPtr, #ScreenSize] ; screen size in bytes +20 + SUBS R9, R9, #256 ; if another 256 to do + STMCSIA R8!, {R0 - R7} ; a bit excessive, I know ! + STMCSIA R8!, {R0 - R7} + STMCSIA R8!, {R0 - R7} + STMCSIA R8!, {R0 - R7} + STMCSIA R8!, {R0 - R7} + STMCSIA R8!, {R0 - R7} + STMCSIA R8!, {R0 - R7} + STMCSIA R8!, {R0 - R7} + BHI %BT20 ; only loop if more to do + ADDCC R9, R9, #256 ; add back the last 256 +30 + SUBS R9, R9, #4 + STMCSIA R8!, {R0} + BHI %BT30 + + Pull PC + +; ***************************************************************************** +; +; Home cursor to "top left" + +RS +Home + MOV R0, #0 + MOV R1, #0 + B TabR0R1 + +; ***************************************************************************** +; +; Address text cursor position +; in: R0 = X position +; R1 = Y position +; +; out: CursorAddr contains screen address + +CursorR0R1 + STR R0, [WsPtr, #CursorX] + STR R1, [WsPtr, #CursorY] +CTADDR10 + Push R14 + BL AddressR0R1 + STR R2, [WsPtr, #CursorAddr] + Pull PC + +; Calculate cursor address + +AddressCursor + LDR R0, [WsPtr, #CursorX] + LDR R1, [WsPtr, #CursorY] + B CTADDR10 + + +; Address an X,Y text position in R0,R1 +; R2 is screen address on exit +; R1, R3, R4 corrupted; R0, R5-R13 preserved + +AddressR0R1 ROUT + LDR R4, [WsPtr, #RowLength] + LDR R3, [WsPtr, #Log2BPC] + LDR R2, [WsPtr, #ScreenStart] ; start address of top of screen + ADD R2, R2, R0, LSL R3 ; add in X offset + MLA R2, R4, R1, R2 ; add in Y*RowLength + MOV PC, R14 + +; ***************************************************************************** +; +; Write character in R0 (>=32) to the screen +; R6 = CursorFlags on entry +; + +font RN 1 +screen RN 2 +bigfont RN 3 +mask RN 4 +tophalf RN 5 +bottomhalf RN 6 +lbpp RN 7 +byte RN 8 +scrbyte RN 9 +scrbyte2 RN 10 +linelen RN 11 + +; *****Comment by DJS: Given we want applications to use the windowing world, +; shouldn't we be optimising VDU 5 characters a bit more here? - even if it +; makes VDU 4 characters a bit less optimal? + +TimWrch ROUT + LDR R1, [WsPtr, #VduStatus] ; test all silly flags at once + TST R1, #Vdu2Mode + TSTEQ R6, #(VduDisabled :OR: TEUpdate :OR: C81Bit :OR: Vdu5Bit) + TSTEQ R6, #(TeletextMode :OR: ClipBoxEnableBit) +10 + ADDEQ font, WsPtr, #(Font-32*8) + ADDEQ font, font, R0, LSL #3 + LDMEQIA font, {tophalf, bottomhalf} + Push R14, EQ + ADREQ R14, %FT15 + LDREQ screen, [WsPtr, #CursorAddr] + [ VIDC_Type = "VIDC20" + LDREQ bigfont, [WsPtr, #TextExpandArea] + | + ADDEQ bigfont, WsPtr, #TextExpand + ] + LDREQ linelen, [WsPtr, #LineLength] + LDREQ PC, [WsPtr, #WrchNbit] + +; *****Change made by DJS +; Moved the following code down to a place where we don't have to branch +; around it! +; B %FT20 +;15 +; Pull R14 +;PostCharMove +; LDR R6, [WsPtr, #CursorFlags] +; TST R6, #32 ; move cursor after char ? +; BEQ CHT ; move "right" & test for C81 +; MOV PC, R14 +; +;20 +; *****End of change made by DJS + +; if printing enabled then we want to print this character, +; so pull the old R14 off the stack + + TST R1, #Vdu2Mode + Pull R14, NE ; in VDU 2 mode, so pull R14 + TST R6, #VduDisabled ; if VDU disabled + MOVNE PC, R14 ; then don't print it + TST R6, #TEUpdate ; if colours need updating + BNE %FT30 ; then do it + return to %25 +25 + TST R6, #Vdu5Bit + BNE Vdu5Wrch + TST R6, #C81Bit + BNE %FT40 +35 + TST R6, #TeletextMode + BNE TTXWrch + TST R6, #ClipBoxEnableBit + BEQ %BT10 ; must enter with EQ + +; now update clip box + + Push R14 + BL ClipCursorCell + Pull R14 + TST R0, #0 ; set EQ + B %BT10 + +; *****Change made by DJS +; Code moved down from above. + +15 + Pull R14 +PostCharMove + LDR R6, [WsPtr, #CursorFlags] + TST R6, #32 ; move cursor after char ? + BEQ CHT ; move "right" & test for C81 + MOV PC, R14 + +; *****End of change made by DJS + +30 + Push "R0,R14" + BL ReallySetColours ; update colour table + Pull "R0,R14" + B %BT25 + +40 + Push "R0, R14" + BL RCRLFR6 ; do pending CRLF + Pull "R0, R14" + B %BT35 + +; ***************************************************************************** +; +; Write character in 1 bit-per-pixel mode + +Wrch1bit + +; *****Change made by DJS +; Original code was: +; MOV mask, #&FF000000 +; +; AND byte, mask, tophalf, LSL #24 +; LDRB scrbyte, [bigfont, byte, LSR #24] +; STRB scrbyte, [screen], linelen +; AND byte, mask, tophalf, LSL #16 +; LDRB scrbyte, [bigfont, byte, LSR #24] +; STRB scrbyte, [screen], linelen +; AND byte, mask, tophalf, LSL #8 +; LDRB scrbyte, [bigfont, byte, LSR #24] +; STRB scrbyte, [screen], linelen +; LDRB scrbyte, [bigfont, tophalf, LSR #24] +; STRB scrbyte, [screen], linelen +; +; AND byte, mask, bottomhalf, LSL #24 +; LDRB scrbyte, [bigfont, byte, LSR #24] +; STRB scrbyte, [screen], linelen +; AND byte, mask, bottomhalf, LSL #16 +; LDRB scrbyte, [bigfont, byte, LSR #24] +; STRB scrbyte, [screen], linelen +; AND byte, mask, bottomhalf, LSL #8 +; LDRB scrbyte, [bigfont, byte, LSR #24] +; STRB scrbyte, [screen], linelen +; LDRB scrbyte, [bigfont, bottomhalf, LSR #24] +; STRB scrbyte, [screen], linelen +; +; There is no need to use "mask" at all in this... + + MOV byte, tophalf, LSL #24 + LDRB scrbyte, [bigfont, byte, LSR #24] + STRB scrbyte, [screen], linelen + MOV byte, tophalf, LSL #16 + LDRB scrbyte, [bigfont, byte, LSR #24] + STRB scrbyte, [screen], linelen + MOV byte, tophalf, LSL #8 + LDRB scrbyte, [bigfont, byte, LSR #24] + STRB scrbyte, [screen], linelen + LDRB scrbyte, [bigfont, tophalf, LSR #24] + STRB scrbyte, [screen], linelen + + MOV byte, bottomhalf, LSL #24 + LDRB scrbyte, [bigfont, byte, LSR #24] + STRB scrbyte, [screen], linelen + MOV byte, bottomhalf, LSL #16 + LDRB scrbyte, [bigfont, byte, LSR #24] + STRB scrbyte, [screen], linelen + MOV byte, bottomhalf, LSL #8 + LDRB scrbyte, [bigfont, byte, LSR #24] + STRB scrbyte, [screen], linelen + LDRB scrbyte, [bigfont, bottomhalf, LSR #24] + STRB scrbyte, [screen], linelen + +; *****End of change made by DJS + + [ 1=0 ; *** No 1 bpc non-BBC gap modes at present *** + LDR R0, [WsPtr, #ModeFlags] ; now test for non-BBC gap mode + AND R0, R0, #(Flag_GapMode :OR: Flag_BBCGapMode) ; we want R0=0 iff + EORS R0, R0, #Flag_GapMode ; (gapmode AND NOT bbcgapmode) + MOVNE PC, R14 + LDRB scrbyte, [bigfont] ; store backgd in next 2 + STRB scrbyte, [screen], linelen + STRB scrbyte, [screen], linelen + ] + MOV PC, R14 + +Wrch1bitDouble + +; *****Change made by DJS +; Original code was: +; MOV mask, #&FF000000 +; +; AND byte, mask, tophalf, LSL #24 +; LDRB scrbyte, [bigfont, byte, LSR #24] +; STRB scrbyte, [screen], linelen +; STRB scrbyte, [screen], linelen +; AND byte, mask, tophalf, LSL #16 +; LDRB scrbyte, [bigfont, byte, LSR #24] +; STRB scrbyte, [screen], linelen +; STRB scrbyte, [screen], linelen +; AND byte, mask, tophalf, LSL #8 +; LDRB scrbyte, [bigfont, byte, LSR #24] +; STRB scrbyte, [screen], linelen +; STRB scrbyte, [screen], linelen +; LDRB scrbyte, [bigfont, tophalf, LSR #24] +; STRB scrbyte, [screen], linelen +; STRB scrbyte, [screen], linelen +; +; AND byte, mask, bottomhalf, LSL #24 +; LDRB scrbyte, [bigfont, byte, LSR #24] +; STRB scrbyte, [screen], linelen +; STRB scrbyte, [screen], linelen +; AND byte, mask, bottomhalf, LSL #16 +; LDRB scrbyte, [bigfont, byte, LSR #24] +; STRB scrbyte, [screen], linelen +; STRB scrbyte, [screen], linelen +; AND byte, mask, bottomhalf, LSL #8 +; LDRB scrbyte, [bigfont, byte, LSR #24] +; STRB scrbyte, [screen], linelen +; STRB scrbyte, [screen], linelen +; LDRB scrbyte, [bigfont, bottomhalf, LSR #24] +; STRB scrbyte, [screen], linelen +; STRB scrbyte, [screen], linelen +; +; As above, "mask" is not needed. + + MOV byte, tophalf, LSL #24 + LDRB scrbyte, [bigfont, byte, LSR #24] + STRB scrbyte, [screen], linelen + STRB scrbyte, [screen], linelen + MOV byte, tophalf, LSL #16 + LDRB scrbyte, [bigfont, byte, LSR #24] + STRB scrbyte, [screen], linelen + STRB scrbyte, [screen], linelen + MOV byte, tophalf, LSL #8 + LDRB scrbyte, [bigfont, byte, LSR #24] + STRB scrbyte, [screen], linelen + STRB scrbyte, [screen], linelen + LDRB scrbyte, [bigfont, tophalf, LSR #24] + STRB scrbyte, [screen], linelen + STRB scrbyte, [screen], linelen + + MOV byte, bottomhalf, LSL #24 + LDRB scrbyte, [bigfont, byte, LSR #24] + STRB scrbyte, [screen], linelen + STRB scrbyte, [screen], linelen + MOV byte, bottomhalf, LSL #16 + LDRB scrbyte, [bigfont, byte, LSR #24] + STRB scrbyte, [screen], linelen + STRB scrbyte, [screen], linelen + MOV byte, bottomhalf, LSL #8 + LDRB scrbyte, [bigfont, byte, LSR #24] + STRB scrbyte, [screen], linelen + STRB scrbyte, [screen], linelen + LDRB scrbyte, [bigfont, bottomhalf, LSR #24] + STRB scrbyte, [screen], linelen + STRB scrbyte, [screen], linelen + +; *****End of change made by DJS + + [ 1=0 ; *** No 1 bpc non-BBC gap modes at present *** + LDR R0, [WsPtr, #ModeFlags] ; now test for non-BBC gap mode + AND R0, R0, #(Flag_GapMode :OR: Flag_BBCGapMode) ; we want R0=0 iff + EORS R0, R0, #Flag_GapMode ; (gapmode AND NOT bbcgapmode) + MOVNE PC, R14 + LDRB scrbyte, [bigfont] ; store backgd in next 2 + STRB scrbyte, [screen], linelen + STRB scrbyte, [screen], linelen + ] + MOV PC, R14 + +Wrch2bit + +; *****Change made by DJS +; Original code was: +; +; MOV mask, #&FE000000 +; SUB linelen, linelen, #1 +; +; AND byte, mask, tophalf, LSL #24 +; LDR scrbyte, [bigfont, byte, LSR #23] +; MOVS byte, tophalf, LSR #1 +; MOVCS scrbyte, scrbyte, LSR #16 +; STRB scrbyte, [screen], #1 +; MOV scrbyte, scrbyte, LSR #8 +; STRB scrbyte, [screen], linelen +; +; AND byte, mask, tophalf, LSL #16 +; LDR scrbyte, [bigfont, byte, LSR #23] +; MOVS byte, tophalf, LSR #9 +; MOVCS scrbyte, scrbyte, LSR #16 +; STRB scrbyte, [screen], #1 +; MOV scrbyte, scrbyte, LSR #8 +; STRB scrbyte, [screen], linelen +; +; AND byte, mask, tophalf, LSL #8 +; LDR scrbyte, [bigfont, byte, LSR #23] +; MOVS byte, tophalf, LSR #17 +; MOVCS scrbyte, scrbyte, LSR #16 +; STRB scrbyte, [screen], #1 +; MOV scrbyte, scrbyte, LSR #8 +; STRB scrbyte, [screen], linelen +; +; AND byte, mask, tophalf +; LDR scrbyte, [bigfont, byte, LSR #23] +; MOVS byte, tophalf, LSR #25 +; MOVCS scrbyte, scrbyte, LSR #16 +; STRB scrbyte, [screen], #1 +; MOV scrbyte, scrbyte, LSR #8 +; STRB scrbyte, [screen], linelen +; +; AND byte, mask, bottomhalf, LSL #24 +; LDR scrbyte, [bigfont, byte, LSR #23] +; MOVS byte, bottomhalf, LSR #1 +; MOVCS scrbyte, scrbyte, LSR #16 +; STRB scrbyte, [screen], #1 +; MOV scrbyte, scrbyte, LSR #8 +; STRB scrbyte, [screen], linelen +; +; AND byte, mask, bottomhalf, LSL #16 +; LDR scrbyte, [bigfont, byte, LSR #23] +; MOVS byte, bottomhalf, LSR #9 +; MOVCS scrbyte, scrbyte, LSR #16 +; STRB scrbyte, [screen], #1 +; MOV scrbyte, scrbyte, LSR #8 +; STRB scrbyte, [screen], linelen +; +; AND byte, mask, bottomhalf, LSL #8 +; LDR scrbyte, [bigfont, byte, LSR #23] +; MOVS byte, bottomhalf, LSR #17 +; MOVCS scrbyte, scrbyte, LSR #16 +; STRB scrbyte, [screen], #1 +; MOV scrbyte, scrbyte, LSR #8 +; STRB scrbyte, [screen], linelen +; +; AND byte, mask, bottomhalf +; LDR scrbyte, [bigfont, byte, LSR #23] +; MOVS byte, bottomhalf, LSR #25 +; MOVCS scrbyte, scrbyte, LSR #16 +; STRB scrbyte, [screen], #1 +; MOV scrbyte, scrbyte, LSR #8 +; STRB scrbyte, [screen], linelen +; +; Messing around with this a bit, I found the following shorter & faster +; code: + + MOV mask, #&7F + SUB linelen, linelen, #1 + + ANDS byte, mask, tophalf, LSR #1 ;C := bit 0 of tophalf + LDR scrbyte, [bigfont, byte, LSL #2] + MOVCS scrbyte, scrbyte, LSR #16 + STRB scrbyte, [screen], #1 + MOV scrbyte, scrbyte, LSR #8 + STRB scrbyte, [screen], linelen + + ANDS byte, mask, tophalf, LSR #9 ;C := bit 8 of tophalf + LDR scrbyte, [bigfont, byte, LSL #2] + MOVCS scrbyte, scrbyte, LSR #16 + STRB scrbyte, [screen], #1 + MOV scrbyte, scrbyte, LSR #8 + STRB scrbyte, [screen], linelen + + ANDS byte, mask, tophalf, LSR #17 ;C := bit 16 of tophalf + LDR scrbyte, [bigfont, byte, LSL #2] + MOVCS scrbyte, scrbyte, LSR #16 + STRB scrbyte, [screen], #1 + MOV scrbyte, scrbyte, LSR #8 + STRB scrbyte, [screen], linelen + + ANDS byte, mask, tophalf, LSR #25 ;C := bit 24 of tophalf + LDR scrbyte, [bigfont, byte, LSL #2] + MOVCS scrbyte, scrbyte, LSR #16 + STRB scrbyte, [screen], #1 + MOV scrbyte, scrbyte, LSR #8 + STRB scrbyte, [screen], linelen + + ANDS byte, mask, bottomhalf, LSR #1 ;C := bit 0 of b'half + LDR scrbyte, [bigfont, byte, LSL #2] + MOVCS scrbyte, scrbyte, LSR #16 + STRB scrbyte, [screen], #1 + MOV scrbyte, scrbyte, LSR #8 + STRB scrbyte, [screen], linelen + + ANDS byte, mask, bottomhalf, LSR #9 ;C := bit 8 of b'half + LDR scrbyte, [bigfont, byte, LSL #2] + MOVCS scrbyte, scrbyte, LSR #16 + STRB scrbyte, [screen], #1 + MOV scrbyte, scrbyte, LSR #8 + STRB scrbyte, [screen], linelen + + ANDS byte, mask, bottomhalf, LSR #17 ;C := bit 16 of b'half + LDR scrbyte, [bigfont, byte, LSL #2] + MOVCS scrbyte, scrbyte, LSR #16 + STRB scrbyte, [screen], #1 + MOV scrbyte, scrbyte, LSR #8 + STRB scrbyte, [screen], linelen + + ANDS byte, mask, bottomhalf, LSR #25 ;C := bit 24 of b'half + LDR scrbyte, [bigfont, byte, LSL #2] + MOVCS scrbyte, scrbyte, LSR #16 + STRB scrbyte, [screen], #1 + MOV scrbyte, scrbyte, LSR #8 + STRB scrbyte, [screen], linelen + +; *****End of change made by DJS + + LDR R0, [WsPtr, #ModeFlags] ; now test for non-BBC gap mode + AND R0, R0, #(Flag_GapMode :OR: Flag_BBCGapMode) ; we want R0=0 iff + EORS R0, R0, #Flag_GapMode ; (gapmode AND NOT bbcgapmode) + MOVNE PC, R14 + LDRB scrbyte, [bigfont] ; store backgd in next 2 + STRB scrbyte, [screen], #1 + STRB scrbyte, [screen], linelen + STRB scrbyte, [screen], #1 + STRB scrbyte, [screen], linelen + MOV PC, R14 + +Wrch4bit + MOV R10, #0 ; extra rows are 0 if not TTX + LDR R0, [WsPtr, #ModeFlags] ; now test for non-BBC gap mode + AND R0, R0, #(Flag_GapMode :OR: Flag_BBCGapMode) ; we want R0=0 iff + EOR R0, R0, #Flag_GapMode ; (gapmode AND NOT bbcgapmode) + MOV mask, #&FF000000 ; don't set mask in Wrch4bitTTX +Wrch4bitTTX + AND byte, mask, tophalf, LSL #24 + LDR scrbyte, [bigfont, byte, LSR #22] + STR scrbyte, [screen], linelen + AND byte, mask, tophalf, LSL #16 + LDR scrbyte, [bigfont, byte, LSR #22] + STR scrbyte, [screen], linelen + AND byte, mask, tophalf, LSL #8 + LDR scrbyte, [bigfont, byte, LSR #22] + STR scrbyte, [screen], linelen + AND byte, mask, tophalf + LDR scrbyte, [bigfont, byte, LSR #22] + STR scrbyte, [screen], linelen + + AND byte, mask, bottomhalf, LSL #24 + LDR scrbyte, [bigfont, byte, LSR #22] + STR scrbyte, [screen], linelen + AND byte, mask, bottomhalf, LSL #16 + LDR scrbyte, [bigfont, byte, LSR #22] + STR scrbyte, [screen], linelen + AND byte, mask, bottomhalf, LSL #8 + LDR scrbyte, [bigfont, byte, LSR #22] + STR scrbyte, [screen], linelen + AND byte, mask, bottomhalf + LDR scrbyte, [bigfont, byte, LSR #22] + STR scrbyte, [screen], linelen + + TEQ R0, #0 + MOVNE PC, R14 + AND byte, mask, R10, LSL #8 + LDR scrbyte, [bigfont, byte, LSR #22] ;get 1st extra (0 or for TTX) + STR scrbyte, [screen], linelen + AND byte, mask, R10 + LDR scrbyte, [bigfont, byte, LSR #22] ;get 2nd extra (0 or for TTX) + STR scrbyte, [screen], linelen + MOV PC, R14 + +Wrch8bit + MOV mask, #&FF000000 + + AND byte, mask, tophalf, LSL #24 + ADD byte, bigfont, byte, LSR #21 + LDMIA byte, {scrbyte, scrbyte2} + STMIA screen, {scrbyte, scrbyte2} + ADD screen, screen, linelen + + AND byte, mask, tophalf, LSL #16 + ADD byte, bigfont, byte, LSR #21 + LDMIA byte, {scrbyte, scrbyte2} + STMIA screen, {scrbyte, scrbyte2} + ADD screen, screen, linelen + + AND byte, mask, tophalf, LSL #8 + ADD byte, bigfont, byte, LSR #21 + LDMIA byte, {scrbyte, scrbyte2} + STMIA screen, {scrbyte, scrbyte2} + ADD screen, screen, linelen + + AND byte, mask, tophalf + ADD byte, bigfont, byte, LSR #21 + LDMIA byte, {scrbyte, scrbyte2} + STMIA screen, {scrbyte, scrbyte2} + ADD screen, screen, linelen + + AND byte, mask, bottomhalf, LSL #24 + ADD byte, bigfont, byte, LSR #21 + LDMIA byte, {scrbyte, scrbyte2} + STMIA screen, {scrbyte, scrbyte2} + ADD screen, screen, linelen + + AND byte, mask, bottomhalf, LSL #16 + ADD byte, bigfont, byte, LSR #21 + LDMIA byte, {scrbyte, scrbyte2} + STMIA screen, {scrbyte, scrbyte2} + ADD screen, screen, linelen + + AND byte, mask, bottomhalf, LSL #8 + ADD byte, bigfont, byte, LSR #21 + LDMIA byte, {scrbyte, scrbyte2} + STMIA screen, {scrbyte, scrbyte2} + ADD screen, screen, linelen + + AND byte, mask, bottomhalf + ADD byte, bigfont, byte, LSR #21 + LDMIA byte, {scrbyte, scrbyte2} + STMIA screen, {scrbyte, scrbyte2} + + [ 1=0 ; *** No 8 bpc non-BBC gap modes at present *** + LDR R0, [WsPtr, #ModeFlags] ; now test for non-BBC gap mode + AND R0, R0, #(Flag_GapMode :OR: Flag_BBCGapMode) ; we want R0=0 iff + EORS R0, R0, #Flag_GapMode ; (gapmode AND NOT bbcgapmode) + MOVNE PC, R14 + LDMIA bigfont, {scrbyte, scrbyte2} ; store backgd in next 2 + ADD screen, screen, linelen + STMIA screen, {scrbyte, scrbyte2} + ADD screen, screen, linelen + STMIA screen, {scrbyte, scrbyte2} + ] + MOV PC, R14 + +Wrch16bit + MOV mask, #&FF000000 + SUB linelen, linelen, #16 + + AND byte, mask, tophalf, LSL #24 + ADD byte, bigfont, byte, LSR #20 + LDMIA byte!, {scrbyte, scrbyte2} + STMIA screen!, {scrbyte, scrbyte2} + LDMIA byte!, {scrbyte, scrbyte2} + STMIA screen!, {scrbyte, scrbyte2} + ADD screen, screen, linelen + + AND byte, mask, tophalf, LSL #16 + ADD byte, bigfont, byte, LSR #20 + LDMIA byte!, {scrbyte, scrbyte2} + STMIA screen!, {scrbyte, scrbyte2} + LDMIA byte!, {scrbyte, scrbyte2} + STMIA screen!, {scrbyte, scrbyte2} + ADD screen, screen, linelen + + AND byte, mask, tophalf, LSL #8 + ADD byte, bigfont, byte, LSR #20 + LDMIA byte!, {scrbyte, scrbyte2} + STMIA screen!, {scrbyte, scrbyte2} + LDMIA byte!, {scrbyte, scrbyte2} + STMIA screen!, {scrbyte, scrbyte2} + ADD screen, screen, linelen + + AND byte, mask, tophalf + ADD byte, bigfont, byte, LSR #20 + LDMIA byte!, {scrbyte, scrbyte2} + STMIA screen!, {scrbyte, scrbyte2} + LDMIA byte!, {scrbyte, scrbyte2} + STMIA screen!, {scrbyte, scrbyte2} + ADD screen, screen, linelen + + AND byte, mask, bottomhalf, LSL #24 + ADD byte, bigfont, byte, LSR #20 + LDMIA byte!, {scrbyte, scrbyte2} + STMIA screen!, {scrbyte, scrbyte2} + LDMIA byte!, {scrbyte, scrbyte2} + STMIA screen!, {scrbyte, scrbyte2} + ADD screen, screen, linelen + + AND byte, mask, bottomhalf, LSL #16 + ADD byte, bigfont, byte, LSR #20 + LDMIA byte!, {scrbyte, scrbyte2} + STMIA screen!, {scrbyte, scrbyte2} + LDMIA byte!, {scrbyte, scrbyte2} + STMIA screen!, {scrbyte, scrbyte2} + ADD screen, screen, linelen + + AND byte, mask, bottomhalf, LSL #8 + ADD byte, bigfont, byte, LSR #20 + LDMIA byte!, {scrbyte, scrbyte2} + STMIA screen!, {scrbyte, scrbyte2} + LDMIA byte!, {scrbyte, scrbyte2} + STMIA screen!, {scrbyte, scrbyte2} + ADD screen, screen, linelen + + AND byte, mask, bottomhalf + ADD byte, bigfont, byte, LSR #20 + LDMIA byte!, {scrbyte, scrbyte2} + STMIA screen!, {scrbyte, scrbyte2} + LDMIA byte!, {scrbyte, scrbyte2} + STMIA screen!, {scrbyte, scrbyte2} + + [ 1=0 ; *** No 16 bpc non-BBC gap modes at present *** + LDR R0, [WsPtr, #ModeFlags] ; now test for non-BBC gap mode + AND R0, R0, #(Flag_GapMode :OR: Flag_BBCGapMode) ; we want R0=0 iff + EORS R0, R0, #Flag_GapMode ; (gapmode AND NOT bbcgapmode) + MOVNE PC, R14 + LDMIA bigfont, {scrbyte, scrbyte2} ; store backgd in next 2 + ADD screen, screen, linelen + STMIA screen!, {scrbyte, scrbyte2} + STMIA screen!, {scrbyte, scrbyte2} + ADD screen, screen, linelen + STMIA screen!, {scrbyte, scrbyte2} + STMIA screen!, {scrbyte, scrbyte2} + ] + MOV PC, R14 + +; ***************************************************************************** + +; Write a character at 32 bit per pixel +; +; NB: This code assumes that we have no concept of gap modes. + +Wrch32bit + Push "R0-R1,R5-R7,R9-R10,R12,LR" + + MOV mask, #&FF000000 + + AND byte, mask, tophalf, LSL #24 + ADD byte, bigfont, byte, LSR #19 + LDMIA byte, {R0,R1, R6,R7, R9,R10, R12,LR} + STMIA screen, {R0,R1, R6,R7, R9,R10, R12,LR} + ADD screen, screen, linelen + + AND byte, mask, tophalf, LSL #16 + ADD byte, bigfont, byte, LSR #19 + LDMIA byte, {R0,R1, R6,R7, R9,R10, R12,LR} + STMIA screen, {R0,R1, R6,R7, R9,R10, R12,LR} + ADD screen, screen, linelen + + AND byte, mask, tophalf, LSL #8 + ADD byte, bigfont, byte, LSR #19 + LDMIA byte, {R0,R1, R6,R7, R9,R10, R12,LR} + STMIA screen, {R0,R1, R6,R7, R9,R10, R12,LR} + ADD screen, screen, linelen + + AND byte, mask, tophalf + ADD byte, bigfont, byte, LSR #19 + LDMIA byte, {R0,R1, R6,R7, R9,R10, R12,LR} + STMIA screen, {R0,R1, R6,R7, R9,R10, R12,LR} + ADD screen, screen, linelen + + LDR bottomhalf, [SP, #4*3] ; restore 'bottomhalf' (R6 pushed onto stack) + + AND byte, mask, bottomhalf, LSL #24 + ADD byte, bigfont, byte, LSR #19 + LDMIA byte, {R0,R1, R5,R7, R9,R10, R12,LR} + STMIA screen, {R0,R1, R5,R7, R9,R10, R12,LR} + ADD screen, screen, linelen + + AND byte, mask, bottomhalf, LSL #16 + ADD byte, bigfont, byte, LSR #19 + LDMIA byte, {R0,R1, R5,R7, R9,R10, R12,LR} + STMIA screen, {R0,R1, R5,R7, R9,R10, R12,LR} + ADD screen, screen, linelen + + AND byte, mask, bottomhalf, LSL #8 + ADD byte, bigfont, byte, LSR #19 + LDMIA byte, {R0,R1, R5,R7, R9,R10, R12,LR} + STMIA screen, {R0,R1, R5,R7, R9,R10, R12,LR} + ADD screen, screen, linelen + + AND byte, mask, bottomhalf + ADD byte, bigfont, byte, LSR #19 + LDMIA byte, {R0,R1, R5,R7, R9,R10, R12,LR} + STMIA screen, {R0,R1, R5,R7, R9,R10, R12,LR} + ADD screen, screen, linelen + + Pull "R0-R1,R5,R6,R7,R9-R10,R12,PC" + + +; ***************************************************************************** +; +; BS - Backspace +; move cursor "left" +; +; in: R6 = CursorFlags +; + +BS + TST R6, R6, ROR #10 ; test &1E or C81Bit or Vdu5 + BNE SpecialBS + + LDR R0, [WsPtr, #CursorX] + LDR R2, [WsPtr, #CursorAddr] + LDR R3, [WsPtr, #BytesPerChar] + LDR R4, [WsPtr, #TWLCol] + + SUB R0, R0, #1 ; no Master wazerks yet ! + SUB R2, R2, R3 + CMP R0, R4 + STRGE R0, [WsPtr, #CursorX] ; I do mean GE ! + STRGE R2, [WsPtr, #CursorAddr] + MOVGE PC, R14 + + MOV R0, #0 + LDRB R1, [R0, #OsbyteVars + :INDEX: PageModeLineCount] + TEQ R1, #0 + SUBNE R1, R1, #1 + STRB R1, [R0, #OsbyteVars + :INDEX: PageModeLineCount] + + LDR R0, [WsPtr, #TWRCol] + LDR R1, [WsPtr, #CursorY] + LDR R4, [WsPtr, #TWTRow] + + SUB R1, R1, #1 + CMP R1, R4 + + BGE CursorR0R1 + + STR R0, [WsPtr, #CursorX] + BSR ScrollDown + B AddressCursor + +; ***************************************************************************** +; +; Horizontal TAB - ie move cursor "right" +; +; in: R6 = CursorFlags +; + +HT + TST R6, R6, ROR #10 ; test for &1E or C81Bit or Vdu5 + BNE SpecialHT + + LDR R0, [WsPtr, #CursorX] + LDR R2, [WsPtr, #CursorAddr] + LDR R3, [WsPtr, #BytesPerChar] + LDR R4, [WsPtr, #TWRCol] + + ADD R0, R0, #1 + ADD R2, R2, R3 + CMP R0, R4 + STRLS R0, [WsPtr, #CursorX] + STRLS R2, [WsPtr, #CursorAddr] + MOVLS PC, R14 + + BSR PageTest + + LDR R0, [WsPtr, #TWLCol] + LDR R1, [WsPtr, #CursorY] + LDR R4, [WsPtr, #TWBRow] + + ADD R1, R1, #1 + CMP R1, R4 + BLS CursorR0R1 ; not on bottom line + + STR R0, [WsPtr, #CursorX] + BSR ScrollUp + B AddressCursor ; re-address cursor position + +; ***************************************************************************** +; +; VduLF - Line feed +; +; in: R6 = CursorFlags +; + +VduLF + TST R6, #Vdu5Bit + BNE Vdu5LF + + BSR PageTest ; check for CTRL/SHIFT, page mode + + TST R6, R6, ROR #10 + BNE SpecialLF + + LDR R1, [WsPtr, #CursorY] + LDR R2, [WsPtr, #CursorAddr] + LDR R3, [WsPtr, #RowLength] + LDR R4, [WsPtr, #TWBRow] + + ADD R1, R1, #1 ; no Master wazerks + ADD R2, R2, R3 + CMP R1, R4 + STRLS R1, [WsPtr, #CursorY] + STRLS R2, [WsPtr, #CursorAddr] + MOVLS PC, R14 + + BSR ScrollUp + B AddressCursor + +; ***************************************************************************** +; +; VT - Cursor up +; + +VT + LDR R6, [WsPtr, #CursorFlags] + TST R6, #Vdu5Bit + BNE Vdu5VT + + MOV R0, #0 + LDRB R1, [R0, #OsbyteVars + :INDEX: PageModeLineCount] + TEQ R1, #0 + SUBNE R1, R1, #1 + STRB R1, [R0, #OsbyteVars + :INDEX: PageModeLineCount] + + TST R6, R6, ROR #10 + BNE SpecialVT + + LDR R1, [WsPtr, #CursorY] + LDR R2, [WsPtr, #CursorAddr] + LDR R3, [WsPtr, #RowLength] + LDR R4, [WsPtr, #TWTRow] + + SUB R1, R1, #1 + SUB R2, R2, R3 + CMP R1, R4 + STRGE R1, [WsPtr, #CursorY] + STRGE R2, [WsPtr, #CursorAddr] + MOVGE PC, R14 + + BSR ScrollDown + B AddressCursor + +; ***************************************************************************** +; +; VduCR - Carriage return +; move to "left" boundary +; +; in: R6 = CursorFlags +; +; out: R6 = updated CursorFlags + +VduCR +CR10 ; entry point for releasing pending CRLF + TST R6, #Vdu5Bit + BNE Vdu5CR + + BIC R6, R6, #C81Bit ; destroy pending CRLF + STR R6, [WsPtr, #CursorFlags] + Push R14 + BL CursorB0 ; preserves R6 + BL AddressCursor ; preserves R6 + Pull PC + +; ***************************************************************************** +; +; FS - Define text window +; + +FS ROUT + LDRB R0, [WsPtr, #QQ+0] ; left + LDRB R1, [WsPtr, #QQ+1] ; bottom + LDRB R2, [WsPtr, #QQ+2] ; right + LDRB R3, [WsPtr, #QQ+3] ; top + LDR R4, [WsPtr, #ScrRCol] ; max right + LDR R5, [WsPtr, #ScrBRow] ; max bottom + + LDR R6, [WsPtr, #VduStatus] + ORR R6, R6, #Windowing ; we are windowing + STR R6, [WsPtr, #VduStatus] + +; Secondary entry point, for validating unpacked context variables +; NB doesn't want to set windowing bit + +FSRegs + CMP R2, R0 ; right >= left + CMPCS R4, R2 ; max right >= right + CMPCS R1, R3 ; bottom >= top + CMPCS R5, R1 ; max bottom >= bottom + MOVCC PC, R14 ; invalid window + + ADD R6, WsPtr, #TWLCol + STMIA R6, {R0-R3} ; write new window settings + +; now check for input cursor being outside window + + LDR R6, [WsPtr, #CursorFlags] + TST R6, #CursorsSplit + BEQ %FT10 ; [cursors not split] + + ASSERT InputCursorY = InputCursorX +4 + ADD R6, WsPtr, #InputCursorX ; R6 := InputCursorX + LDMIA R6, {R6, R7} ; R7 := InputCursorY + + CMP R6, R0 ; X >= left + CMPCS R2, R6 ; right >= X + CMPCS R7, R3 ; Y >= top + CMPCS R1, R7 ; bottom >= Y + + BCS %FT10 ; [not outside window] + + LDR R6, [WsPtr, #CursorX] ; get output cursor posn + LDR R7, [WsPtr, #CursorY] + LDR R4, [WsPtr, #CursorAddr] + Push "R0-R4, R6, R7, R14" ; save window and output cursor + + BL HomeVdu4 ; Home output cursor + + LDR R6, [WsPtr, #CursorX] ; Copy output ... + LDR R7, [WsPtr, #CursorY] + LDR R4, [WsPtr, #CursorAddr] + + STR R6, [WsPtr, #InputCursorX] ; ... to input + STR R7, [WsPtr, #InputCursorY] + STR R4, [WsPtr, #InputCursorAddr] + + Pull "R0-R4, R6, R7, R14" ; restore old registers + STR R6, [WsPtr, #CursorX] + STR R7, [WsPtr, #CursorY] + STR R4, [WsPtr, #CursorAddr] +10 + +; now check output cursor is inside window + + LDR R6, [WsPtr, #CursorX] ; get output cursor posn + LDR R7, [WsPtr, #CursorY] + + CMP R6, R0 ; X >= left + CMPCS R2, R6 ; right >= X + CMPCS R7, R3 ; Y >= top + CMPCS R1, R7 ; bottom >= Y + + MOVCS PC, R14 ; cursor inside window + +; and drop thru to ... + +HomeVdu4 ; home TEXT cursor, even in + ; VDU 5 mode + MOV R0, #0 ; move to "0,0" + MOV R1, #0 + LDR R6, [WsPtr, #CursorFlags] + + B TabR0R1NotVdu5 ; (destroys any pending CRLF) + +; ***************************************************************************** +; +; TCOL - Set text colour (foreground or background) +; + ASSERT TBackCol = TForeCol +4 + ASSERT back > fore + +TCOL +DC1 + TST R6, #TeletextMode ; if in teletext + MOVNE PC, R14 ; then ignore + + LDR bpp, [WsPtr, #BitsPerPix] + ADD fore, WsPtr, #TForeCol + LDMIA fore, {fore, back} + + LDR R3, [WsPtr, #NColour] + LDRB R4, [WsPtr, #QQ+0] ; get colour specified + CMP R4, #128 ; C=1 => set background + AND R4, R4, R3 + AND R4, R4, #63 ; oh no not again! + STRCC R4, [WsPtr, #TForeCol] + STRCS R4, [WsPtr, #TBackCol] + MOVCC R5, fore + MOVCS R5, back ; R5 is old appropriate colour + MOVCC fore, R4 + MOVCS back, R4 + + BCS %FT31 ; branch for background + + ; amg: only update the appropriate one + CMP R4,R5 + MOVEQ PC, R14 + Push "LR" + BL CompileTextFg + Pull "LR" + B %FT32 +31 + CMP R4, R5 + MOVEQ PC, R14 ; same as last time + Push "LR" + BL CompileTextBg ; ensure that TextBg is kosher + Pull "LR" ; preserving the return address +32 + LDR R6, [WsPtr, #CursorFlags] + ORR R6, R6, #TEUpdate +R6toCursorFlags + STR R6, [WsPtr, #CursorFlags] + + MOV PC, R14 + +CheckTEUpdate + LDR R6, [WsPtr, #CursorFlags] + TST R6, #TEUpdate + MOVEQ PC, R14 +ReallySetColours + BIC R6, R6, #TEUpdate + STR R6, [WsPtr, #CursorFlags] ; clear update flag + + Push "R6, R14" + LDR bpp, [WsPtr, #BitsPerPix] + LDR fore, [WsPtr, #TextFgColour] + LDR back, [WsPtr, #TextBgColour] + BL SetColours + Pull "R6, PC" + +; ***************************************************************************** +; +; FF - Clear text window (CLS) +; + +FF + LDR R6, [WsPtr, #CursorFlags] + TST R6, #Vdu5Bit + BNE Vdu5FF + + STROSB R0, PageModeLineCount, R0 ; zero page mode line count + + LDR R0, [WsPtr, #VduStatus] + TST R0, #Windowing + BNE SlowCLS ; windowing, so do slowly + + Push R14 + TST R6, #ClipBoxEnableBit + BLNE SetClipBoxToFullScreen + LDR R0, [WsPtr, #DriverBankAddr] ; set driver's screen start + STR R0, [WsPtr, #DisplayScreenStart] + STR R0, [WsPtr, #ScreenStart] + + LDR R0, [WsPtr, #DisplayBankAddr] + BL SetVinit ; program Vinit + ; (and set DisplayStart) + BL Home ; home cursor after ScreenStart initialised + TST R6, #CursorsSplit + BLNE AddressInputCursor + Pull R14 + + LDR R0, [WsPtr, #ModeFlags] + TST R0, #Flag_BBCGapMode ; if not BBC gap mode + BEQ FastCLS ; then use fast code + +SlowCLS + BSR Home + + ADD R0, WsPtr, #TWLCol ; R0 := TWLCol; R1 := TWBRow + LDMIA R0, {R0-R3} ; R2 := TWRCol; R3 := TWTRow + +; and drop thru to ... + +; ClearBox - Clears a box of text chars on the screen +; +; in: R0 = left column +; R1 = bottom row +; R2 = right column +; R3 = top row + +ClearBox ROUT + Push R14 + TST R6, #ClipBoxEnableBit + BLNE ClipTextArea + + TST R6, #TeletextMode + BNE TTXClearBox + + BL GetBoxInfo + Pull R14 + +ClearThisBox + STR R8, [WsPtr, #RowsToDo] + + LDR R9, [WsPtr, #CursorFlags] + TST R9, #TEUpdate + BNE %FT99 + +05 + LDR R8, [WsPtr, #TextBgColour] + LDRB R1, [WsPtr, #ModeFlags] + TST R1, #Flag_BBCGapMode ; is it a BBC gap mode ? + LDRNE R1, =&AAAAAAAA ; use colour 2 for gaps if so + MOVEQ R1, R8 ; else use background colour + EOR R1, R1, R8 ; EOR toggle for colour + STR R1, [WsPtr, #EORtoggle] + LDR R0, [WsPtr, #RowMult] ; 8 or 10 + +ClearRow + MOV R6, #0 +ClearLineNew + MOV R9, R8 + MOV R10, R8 + MOV R11, R8 +ClearLine + MOV R1, R2 ; R1 is current address + ADD R3, R2, R5 ; R3 is byte after last one +10 + CMP R1, R3 + BEQ DoneLine + TST R1, #3 + STRNEB R8, [R1], #1 ; store if not on word boundary + BNE %BT10 + + SUB R4, R3, R1 ; number of bytes left on this line + MOV R4, R4, LSR #4 ; number of 4-words left on this line + SUBS R4, R4, #1 ; C=0 if 0, C=1 if >0 +14 + STMHIIA R1!, {R8-R11} ; done if R4 > 0 + STMCSIA R1!, {R8-R11} ; done if R4 >= 0 + SUBCSS R4, R4, #2 ; this code dropped thru if R4 was 0 + BCS %BT14 + + BIC R4, R3, #3 +20 + CMP R1, R4 + STRNE R8, [R1], #4 + BNE %BT20 + +30 + CMP R1, R3 + STRNEB R8, [R1], #1 + BNE %BT30 + +DoneLine + ADD R2, R2, R7 + ADD R6, R6, #1 + CMP R6, #8 + BCC ClearLine + LDR R1, [WsPtr, #EORtoggle] + EOREQ R8, R8, R1 + CMP R6, R0 + BCC ClearLineNew + + EOR R8, R8, R1 + LDR R1, [WsPtr, #RowsToDo] + SUBS R1, R1, #1 + STR R1, [WsPtr, #RowsToDo] + BNE ClearRow + + MOV PC, R14 + +99 + Push "R2, R5-R7, R14" + MOV R6, R9 + BL ReallySetColours + Pull "R2, R5-R7, R14" + B %BT05 + + LTORG + +; ***************************************************************************** +; +; GetWindowInfo - sets up some info for current text window +; +; GetBoxInfo - sets up some info for a given box +; +; in: R0 = left +; R1 = bottom +; R2 = right +; R3 = top +; +; out: R2 = address of top left +; R5 = number of bytes horizontally +; R6 = number of pixel rows vertically +; R7 = LineLength +; R8 = number of character rows vertically + +GetWindowInfo + ADD R0, WsPtr, #TWLCol ; R0 := TWLCol; R1 := TWBRow + LDMIA R0, {R0-R3} ; R2 := TWRCol; R3 := TWTRow +GetBoxInfo + SUB R5, R2, R0 + ADD R5, R5, #1 ; number of chars horiz + LDR R6, [WsPtr, #Log2BPC] ; should be log2 bytes/char + MOV R5, R5, LSL R6 ; number of bytes horiz + + SUB R6, R1, R3 + ADD R8, R6, #1 ; number of char rows vert + + LDR R7, [WsPtr, #ModeFlags] + + MOV R6, R8, LSL #3 ; *8 + TST R7, #Flag_GapMode ; if gap mode + ADDNE R6, R6, R8, LSL #1 ; (+*2) = *10 + TST R7, #Flag_DoubleVertical ; if double mode + ADDNE R6, R6, R6 ; then double + + LDR R7, [WsPtr, #LineLength] + + MOV R1, R3 ; prepare to address top left + B AddressR0R1 + + +; ***************************************************************************** +; +; US - TAB(X,Y) +; + +US + LDRB R0, [WsPtr, #QQ+0] + LDRB R1, [WsPtr, #QQ+1] +TabR0R1 + + LDR R6, [WsPtr, #CursorFlags] + TST R6, #Vdu5Bit + BNE Vdu5TAB + +TabR0R1NotVdu5 + LDR R9, [WsPtr, #CursorX] + LDR R10, [WsPtr, #CursorY] + Push "R0,R9,R10" ; save old X,Y in case it doesn't work + + EOR R6, R6, #8 ; update Y position + MOV R0, R1 + BSR CursorBdy + + EOR R6, R6, #8 ; now try X position + Pull R0 + BSR CursorBdyCheck + MOV R7, #0 ; will be clearing C81Bit + BCS US10 ; was in window, so OK + + TEQ R6, R6, LSR #1 ; are we in 81 column mode + ; (just want to set carry) + BCC US20 ; can't do it + + SUB R0, R0, #1 ; could be attempt to move to col 81 + BSR CursorBdyCheck + BCC US20 ; still can't do it + MOV R7, #C81Bit ; set C81Bit +US10 + BIC R6, R6, #C81Bit + ORR R6, R6, R7 + STR R6, [WsPtr, #CursorFlags] + +US20 + Pull "R9,R10" + + STRCC R9, [WsPtr, #CursorX] ; couldn't do it, so restore position + STRCC R10, [WsPtr, #CursorY] + + B AddressCursor + +; ***************************************************************************** +; +; ScrollUp - Scroll the current text window up +; + +ScrollUp + LDR R0, [WsPtr, #VduStatus] + TST R0, #Windowing + BNE SoftScrollUp +HardScrollUp + LDR R1, [WsPtr, #ModeFlags] + TST R1, #Flag_HardScrollDisabled + BNE HardScrollSpriteUp + + LDR R1, [WsPtr, #RowLength] + LDR R2, [WsPtr, #TotalScreenSize] + + LDR R0, [WsPtr, #DisplayScreenStart] + ADD R0, R0, R1 + CMP R0, #ScreenEndAdr + SUBCS R0, R0, R2 + STR R0, [WsPtr, #DisplayScreenStart] + STR R0, [WsPtr, #ScreenStart] + + LDR R0, [WsPtr, #DisplayStart] + ADD R0, R0, R1 + CMP R0, #ScreenEndAdr + SUBCS R0, R0, R2 + + Push R14 + BL SetVinit ; program vinit and set DisplayStart + + TST R6, #TeletextMode + BLNE TTXHardScrollUp + Pull R14 + +ClearBottomScreenLine + MOV R0, #0 ; Don't use window coords - + LDR R1, [WsPtr, #ScrBRow] ; code also used in VDU23,7 + LDR R2, [WsPtr, #ScrRCol] + MOV R3, R1 + B ClearBox + +; Code to scroll whole 'screen' up, when hard scroll disabled +; (ie outputting to sprite) + +HardScrollSpriteUp + Push R14 + BL GetScreenInfo ; get box info for whole 'screen' + LDR R0, [WsPtr, #RowMult] + BL SoftScrollUp2 + Pull R14 + B ClearBottomScreenLine + +; Clear bottom line of window + +ClearBottomLine + ADD R0, WsPtr, #TWLCol ; R0 := TWLCol; R1 := TWBRow + LDMIA R0, {R0-R2} ; R2 := TWRCol + MOV R3, R1 ; R3 := TWBRow + B ClearBox + +SoftScrollUp + Push R14 + TST R6, #TeletextMode + BNE TTXSoftScrollUp + + BL GetWindowInfo + +; R2 = address of top left +; R5 = number of bytes horizontally +; R6 = number of pixel rows in box +; R7 = linelength +; R8 = number of character rows in box + + LDR R0, [WsPtr, #RowMult] + BL SoftScrollUp2 + Pull R14 + B ClearBottomLine + +; ***************************************************************************** +; +; SoftScrollUp2 - Called by SoftScrollUp and by Teletext to scroll map +; +; in: R0 = RowMult +; R2 = screen address of top left of area to scroll +; R5 = number of bytes horizontally +; R6 = number of pixel rows vertically +; R7 = linelength +; + +SoftScrollUp2 ROUT + SUBS R6, R6, R0 ; scroll number of rows-1 + MOVEQ PC, R14 ; single row window, nowt to scroll + +ScrollLineUp + MOV R1, R2 + LDR R3, [WsPtr, #RowLength] + ADD R0, R1, R3 ; R0 -> line below + ADD R3, R2, R5 ; R3 -> byte after last one on upper +10 + CMP R1, R3 + BEQ %FT40 ; finished + TST R1, #3 ; if not word aligned + LDRNEB R8, [R0], #1 ; then copy a byte + STRNEB R8, [R1], #1 + BNE %BT10 + + SUB R4, R3, R1 ; number of bytes left on this line + MOVS R4, R4, LSR #4 ; number of 4-words left on this line + SUBS R4, R4, #1 ; C=0 if 0, C=1 if >0 +14 + LDMHIIA R0!, {R8-R11} ; this code dropped thru if was 0 + STMHIIA R1!, {R8-R11} + LDMCSIA R0!, {R8-R11} + STMCSIA R1!, {R8-R11} + SUBCSS R4, R4, #2 + BCS %BT14 + + BIC R4, R3, #3 +20 + CMP R1, R4 + LDRNE R8, [R0], #4 + STRNE R8, [R1], #4 + BNE %BT20 + +30 + CMP R1, R3 + LDRNEB R8, [R0], #1 + STRNEB R8, [R1], #1 + BNE %BT30 + +40 + ADD R2, R2, R7 + SUBS R6, R6, #1 + BNE ScrollLineUp + + MOV PC, R14 + +; ***************************************************************************** +; +; ScrollDown - Scroll the current text window down +; + +ScrollDown + LDR R0, [WsPtr, #VduStatus] + TST R0, #Windowing + BNE SoftScrollDown +HardScrollDown + LDR R1, [WsPtr, #ModeFlags] + TST R1, #Flag_HardScrollDisabled + BNE HardScrollSpriteDown + + LDR R1, [WsPtr, #RowLength] + LDR R2, [WsPtr, #TotalScreenSize] + + LDR R0, [WsPtr, #DisplayScreenStart] + SUB R0, R0, R1 ; down one row + ADD R3, R0, R2 + CMP R3, #ScreenEndAdr ; if < then need wrap + MOVCC R0, R3 + STR R0, [WsPtr, #DisplayScreenStart] + STR R0, [WsPtr, #ScreenStart] + + LDR R0, [WsPtr, #DisplayStart] + SUB R0, R0, R1 + ADD R3, R0, R2 + CMP R3, #ScreenEndAdr + MOVCC R0, R3 + + Push R14 + BL SetVinit ; program vinit and set DisplayStart + + TST R6, #TeletextMode + BLNE TTXHardScrollDown + Pull R14 + +ClearTopScreenLine + MOV R0, #0 ; don't use window coords - + MOV R1, #0 ; code also used by VDU23,7 + LDR R2, [WsPtr, #ScrRCol] + MOV R3, #0 + B ClearBox + +; Code to scroll whole 'screen' down, when hard scroll disabled +; (ie outputting to sprite) + +HardScrollSpriteDown + Push R14 + BL GetScreenInfo ; get box info for whole 'screen' + + MOV R0, #0 + LDR R1, [WsPtr, #ScrBRow] + BL AddressR0R1 ; R2 -> top line of bottom left char + + LDR R0, [WsPtr, #RowMult] + BL SoftScrollDown2 + Pull R14 + B ClearTopScreenLine + +; Clear top line of window + +ClearTopLine + ADD R0, WsPtr, #TWLCol ; R0 := TWLCol; (R1 := TWBRow) + LDMIA R0, {R0-R3} ; R2 := TWRCol; R3 := TWTRow + MOV R1, R3 ; R1 := TWTRow + B ClearBox + +SoftScrollDown + Push R14 + TST R6, #TeletextMode + BNE TTXSoftScrollDown + + BL GetWindowInfo + +; R2 = address of top left +; R5 = number of bytes horizontally +; R6 = number of pixel rows in box +; R7 = linelength +; R8 = number of character rows in box + + ADD R0, WsPtr, #TWLCol ; R0 := TWLCol; R1 := TWBRow + LDMIA R0, {R0-R1} + BL AddressR0R1 ; R2 -> top line of bottom left char + + LDR R0, [WsPtr, #RowMult] + BL SoftScrollDown2 + Pull R14 + B ClearTopLine + +; ***************************************************************************** +; +; SoftScrollDown2 - Called by SoftScrollDown and by TTX to scroll map +; +; in: R0 = RowMult +; R2 = screen address of top line of bottom left char +; R5 = number of bytes horizontally +; R6 = number of pixel rows vertically +; R7 = linelength +; + +SoftScrollDown2 ROUT + SUBS R6, R6, R0 ; scroll number of rows-1 + MOVEQ PC, R14 ; single row window, nowt to scroll + + SUB R2, R2, R7 ; R2 -> bottom line of next-to-bottom + LDR R1, [WsPtr, #RowLength] + ADD R2, R2, R1 ; R2 -> bottom line of bottom + +ScrollLineDown + MOV R1, R2 + LDR R3, [WsPtr, #RowLength] + SUB R0, R1, R3 ; R0 -> line above,needs fudging + ADD R3, R2, R5 ; R3 -> byte after last one on upper +10 + CMP R1, R3 + BEQ %FT40 ; finished + TST R1, #3 + LDRNEB R8, [R0], #1 + STRNEB R8, [R1], #1 + BNE %BT10 + + SUB R4, R3, R1 ; number of bytes left on this line + MOVS R4, R4, LSR #4 ; number of 4-words left on this line + SUBS R4, R4, #1 ; C=0 if 0, C=1 if >0 +14 + LDMHIIA R0!, {R8-R11} ; this code dropped thru if was 0 + STMHIIA R1!, {R8-R11} + LDMCSIA R0!, {R8-R11} + STMCSIA R1!, {R8-R11} + SUBCSS R4, R4, #2 + BCS %BT14 + + BIC R4, R3, #3 +20 + CMP R1, R4 + LDRNE R8, [R0], #4 + STRNE R8, [R1], #4 + BNE %BT20 + +30 + CMP R1, R3 + LDRNEB R8, [R0], #1 + STRNEB R8, [R1], #1 + BNE %BT30 + +40 + SUB R2, R2, R7 + SUBS R6, R6, #1 + BNE ScrollLineDown + + MOV PC, R14 + +; ***************************************************************************** +; +; SetVinit - Program Vinit with address in R0 +; SetVstart - Program Vstart --------""-------- +; SetVend - Program Vend --------""-------- +; +; out: R0-R2 corrupted +; + +SetVstart + MOV R1, #MEMCDAG_VStart +SetLag + SUB R0, R0, #ScreenEndAdr + LDR R2, [WsPtr, #TotalScreenSize] + ADD R0, R0, R2 ; make startofscreen 0 + B SetDAGOffset ; call generic interface + +SetVendDefault + [ MEMC_Type = "IOMD" + MOV R0, #0 + LDR R0, [R0, #VRAMWidth] + CMP R0, #1 + MOVCC R0, #16 ; DRAM-only, subtract 16 + MOVEQ R0, #SAMLength/2 ; 1 bank of VRAM - 1/2 SAM + MOVHI R0, #SAMLength ; 2 banks of VRAM - 1/2 SAM * 2 + RSB R0, R0, #ScreenEndAdr + | + MOV R0, #ScreenEndAdr + SUB R0, R0, #16 + ] + MOV R1, #MEMCDAG_VEnd + B SetLag + +SetVinit + STR R0, [WsPtr, #DisplayStart] + SUB R0, R0, #ScreenEndAdr + LDR R2, [WsPtr, #TotalScreenSize] + ADD R0, R0, R2 ; make start of screen 0 + LDR R1, [WsPtr, #TeletextOffset] + ADD R0, R0, R1 ; add on teletext bank offset + CMP R0, R2 ; if out of range + SUBCS R0, R0, R2 ; then subtract total size +SetVinitPhys + STR R0, [WsPtr, #VinitCopy] + MOV R1, #MEMCDAG_VInit +SetDAGOffset + [ MEMC_Type = "IOMD" + MOV R2, #0 + LDR R2, [R2, #VideoPhysAddr] ; add on physical address of start of video RAM + ADD R0, R0, R2 + ] + B SetDAG ; call generic interface + +; ***************************************************************************** +; +; ConvertBankToAddress - Convert bank number into default start address +; +; in: R2 = screen bank number (0..n) +; +; out: R3 = default start address for that bank +; R0-R2 preserved +; R4,R5 corrupted +; + +ConvertBankToAddress ROUT + MOV R4, R2 + LDR R3, [WsPtr, #TotalScreenSize] + RSB R3, R3, #ScreenEndAdr ; R3 := start of all screen mem + LDR R5, [WsPtr, #ScreenSize] +10 + MOVS R4, R4, LSR #1 ; add on R4*ScreenSize + ADDCS R3, R3, R5 + ADD R5, R5, R5 + BNE %BT10 + MOV PC, R14 + +; ***************************************************************************** +; +; Delete - delete a character +; +; in: R6 = CursorFlags +; + +Delete ROUT + Push R14 + + TST R6, #TEUpdate ; if colours dirty + BLNE ReallySetColours ; then update them + + TST R6, #32 ; Bit 5 set => no cursor move + BLEQ BS + LDR R6, [WsPtr, #CursorFlags] ; reload in case BS corrupts it + + TST R6, #Vdu5Bit + TSTEQ R6, #(TeletextMode :OR: ClipBoxEnableBit) + BNE %FT20 +10 + Pull R14 + MOV tophalf, #0 ; Print with space + MOV bottomhalf, #0 + LDR screen, [WsPtr, #CursorAddr] + [ VIDC_Type = "VIDC20" + LDR bigfont, [WsPtr, #TextExpandArea] + | + ADD bigfont, WsPtr, #TextExpand + ] + LDR linelen, [WsPtr, #LineLength] + LDR PC, [WsPtr, #WrchNbit] + +20 + TST R6, #Vdu5Bit + Pull R14, NE + BNE Vdu5Delete + + TST R6, #TeletextMode + MOVNE R0, #32 ; wipe out with space + Pull R14, NE + BNE TTXDoChar + + BL ClipCursorCell ; must be ClipBoxEnable + B %BT10 ; so clip cursor and continue + + [ {FALSE} + +; ***************************************************************************** +; +; Convert colours if in 256 colour mode +; +; in: bpp = BitsPerPix +; fore = foreground colour (in 'user' format) +; back = background colour (-------""-------) +; +; out: fore, back = adjusted colours (if necessary) + +ConvertCol + CMP bpp, #8 + MOVNE PC, R14 + + Push R14 + MOV col, fore + LDR index, [WsPtr, #TFTint] + BL FudgeColour + MOV fore, col + + MOV col, back + LDR index, [WsPtr, #TBTint] + BL FudgeColour + MOV back, col + + Pull PC + +FudgeColour ; col = 0 0 B3 B2 G3 G2 R3 R2 + ; index = t1 t0 0 0 0 0 0 0 + + MOV R3, col, LSL #2 ; R3 := B3 B2 G3 G2 R3 R2 0 0 + AND R3, R3, #&84 ; R3 := B3 0 0 0 0 R2 0 0 + MOVS col, col, LSL #28 ; C := B2 + MOV col, col, LSR #29 ; col := 0 0 0 0 0 G3 G2 R3 + ORR col, R3, col, LSL #4 ; col := B3 G3 G2 R3 0 R2 0 0 + ORRCS col, col, #&08 ; col := B3 G3 G2 R3 B2 R2 0 0 + ORR col, col, index, LSR #6 ; col := B3 G3 G2 R3 B2 R2 T1 T0 + MOV PC, R14 + + ] + +; ***************************************************************************** + +PlainBit ROUT + +; first set up RAMMaskTb + + ASSERT bpp=0 + + LDR bpp, [WsPtr, #BytesPerChar] + MOV R1, #1 + +; *****Change made by DJS +; Original code was: +; MOV R1, R1, LSL bpp ; first form mask for leftmost pixel +; SUB R1, R1, #1 ; = (2^BytesPerChar)-1 + + RSB R1, R1, R1, LSL bpp ; first form mask for leftmost pixel + ; = (2^BytesPerChar)-1 + +; *****End of change made by DJS + + ADD R3, WsPtr, #RAMMaskTb +10 + STR R1, [R3], #4 ; store mask + MOVS R1, R1, LSL bpp ; shift to next pixel + BNE %BT10 ; loop until all shifted out + +; DDV: Original code used to read: +; +; TEQ bpp, #16 +; MOVEQ PC, R14 ; nothing to do on a mode change in this mode +; +; In 32 bit per pixel modes this used to cause an overflow, new function +; drops out if the bpp >= 16. +; + CMP bpp, #16 + MOVGT PC, R14 ; nothing to do on a mode change in this mode + Push R14 + + [ VIDC_Type = "VIDC20" + LDR tabaddr, [WsPtr, #TextExpandArea] + | + ADD tabaddr, WsPtr, #TextExpand + ] + ADD tabaddr, tabaddr, bpp, LSL #8 ; TextPlain now dynamic + + MOV dest, #&80000000 + + CMP bpp, #4 + BHI Plain8Bit + BEQ Plain4Bit + CMP bpp, #1 + BHI Plain2Bit + +Plain1Bit + ADR hiaddr, P1BTab + ADD R10, hiaddr, #8 ; end address +P1B20 + LDR hiword, [hiaddr], #4 +P1B25 + ADR loaddr, P1BTab +P1B30 + LDR loword, [loaddr], #4 +P1B40 + MOV cbyte, hiword, LSL #28 + ORR dest, cbyte, dest, LSR #4 + MOV cbyte, loword, LSL #28 + ORRS dest, cbyte, dest, LSR #4 + BLCS OutputNoColour + + MOVS loword, loword, LSR #4 + BNE P1B40 + TEQ loaddr, R10 + BNE P1B30 + + MOVS hiword, hiword, LSR #4 + BNE P1B25 + TEQ hiaddr, R10 + BNE P1B20 + + Pull PC + +OutputColour + AND cbyte, dest, fore + BIC dest, back, dest + ORR dest, dest, cbyte +OutputNoColour + STR dest, [tabaddr], #4 + MOV dest, #&80000000 + MOV PC, R14 + +P1BTab + & &E6A2C480 + & &F7B3D591 + +; ***************************************************************************** + +Plain2Bit + ADR hiaddr, P2BTab + ADD R10, hiaddr, #16 +P2B20 + LDR hiword, [hiaddr], #4 +P2B25 + ADR loaddr, P2BTab +P2B30 + LDR loword, [loaddr], #4 +P2B40 + MOV cbyte, hiword, LSL #24 + ORR dest, cbyte, dest, LSR #8 + MOV cbyte, loword, LSL #24 + ORRS dest, cbyte, dest, LSR #8 + BLCS OutputNoColour + + MOVS loword, loword, LSR #8 + BNE P2B40 + TEQ loaddr, R10 + BNE P2B30 + + MOVS hiword, hiword, LSR #8 + BNE P2B25 + TEQ hiaddr, R10 + BNE P2B20 + + Pull PC + +P2BTab + & &F030C000 + & &FC3CCC0C + & &F333C303 + & &FF3FCF0F + +; ***************************************************************************** + +Plain4Bit + ADR hiaddr, P4BTab + ADD R10, hiaddr, #32 +P4B20 + LDR hiword, [hiaddr], #4 +P4B25 + ADR loaddr, P4BTab +P4B30 + LDR loword, [loaddr], #4 +P4B40 + MOV cbyte, hiword, LSL #16 + ORR dest, cbyte, dest, LSR #16 + MOV cbyte, loword, LSL #16 + ORRS dest, cbyte, dest, LSR #16 + BLCS OutputNoColour + + MOVS loword, loword, LSR #16 + BNE P4B40 + TEQ loaddr, R10 + BNE P4B30 + + MOVS hiword, hiword, LSR #16 + BNE P4B25 + TEQ hiaddr, R10 + BNE P4B20 + + Pull PC + +P4BTab + & &F0000000 + & &FF000F00 + & &F0F000F0 + & &FFF00FF0 + & &F00F000F + & &FF0F0F0F + & &F0FF00FF + & &FFFF0FFF + +; ***************************************************************************** + +Plain8Bit + ADR hiaddr, P8BTab + ADD R10, hiaddr, #64 +P8B20 + LDR hiword, [hiaddr], #4 + ADR loaddr, P8BTab +P8B30 + MOV dest, hiword + BL OutputNoColour + LDR dest, [loaddr], #4 + BL OutputNoColour + + TEQ loaddr, R10 + BNE P8B30 + + TEQ hiaddr, R10 + BNE P8B20 + + Pull PC + +P8BTab + & &00000000 + & &FF000000 + & &00FF0000 + & &FFFF0000 + & &0000FF00 + & &FF00FF00 + & &00FFFF00 + & &FFFFFF00 + & &000000FF + & &FF0000FF + & &00FF00FF + & &FFFF00FF + & &0000FFFF + & &FF00FFFF + & &00FFFFFF + & &FFFFFFFF + +; ***************************************************************************** +; +; ReadCharacter - Read character at (input) text cursor position +; +; out: R0 = character, 0 if unrecognised +; + +ReadCharacter + Push R14 + + BL PreWrchCursor ; remove both cursors + BL CheckTEUpdate ; update TextExpand if necessary + ; R6 = CursorFlags on exit + TST R6, #TeletextMode + BNE TTXReadCharacter + + TST R6, #CursorsSplit + LDREQ R2, [WsPtr, #CursorAddr] ; point to correct address + LDRNE R2, [WsPtr, #InputCursorAddr] + + LDR R4, [WsPtr, #TextBgColour] + LDR R8, [WsPtr, #LineLength] + + LDR R1, [WsPtr, #ModeFlags] + TST R1, #Flag_DoubleVertical + BNE RdCh1BitDouble + + LDR R1, [WsPtr, #Log2BPC] + CMP R1, #1 + BCC RdCh1Bit + BEQ RdCh2Bit + CMP R1, #3 + BCC RdCh4Bit + BEQ RdCh8Bit + [ VIDC_Type = "VIDC20" + CMP R1, #4 + BEQ RdCh16Bit + +; Read character from cursor position for 32 bit per pixel + +; in R2 -> cursor address +; R4 = background colour +; R8 = line length to be used +; +; out R6 = first four bytes of char defn +; R7 = last four bytes of char defn + +; used R0,R1,R3,R5,R9,R10,R11,LR = loading screen data! + + MACRO + ConvertTo1BPP $source, $dest, $bit + EORS $source, $source, R4 + ORRNE $dest, $dest, #$bit + MEND + +RdChr32Bit + Push "R0-R1,R3,R5,R9,R10-R12" + + BL RdCh32Bit_GetData + MOV R6,R7 + BL RdCh32Bit_GetData + + Pull "R0-R1,R3,R5,R9,R10-R12" + B RDCH14 + +; *********************************************************************** + +RdCh32Bit_GetData + MOV R7, #1:SHL:31 + +RdCh32Bit_Loop + MOVS R7, R7, LSR #8 + + LDMIA R2,{R0,R1,R3,R5,R9,R10,R11,R12} + ConvertTo1BPP R0, R7, 1<<31 + ConvertTo1BPP R1, R7, 1<<30 + ConvertTo1BPP R3, R7, 1<<29 + ConvertTo1BPP R5, R7, 1<<28 + ConvertTo1BPP R9, R7, 1<<27 + ConvertTo1BPP R10, R7, 1<<26 + ConvertTo1BPP R11, R7, 1<<25 + ConvertTo1BPP R12, R7, 1<<24 + + ADD R2, R2, R8 + BCC RdCh32Bit_Loop + + MOVS PC,LR + + ] + +RdCh16Bit + ADD R2, R2, #12 + ADD R5, R2, R8, LSL #2 ; half way + ADD R3, R2, R8, LSL #3 ; one-after-finishing R2 + ADD R8, R8, #12 + MOV R7, #0 +RDCH90 + LDR R1, [R2], #-4 + EOR R1, R1, R4 + CMP R1, #&00010000 + MOV R7, R7, RRX + MOV R1, R1, LSL #16 + CMP R1, #&00010000 + MOV R7, R7, RRX + + LDR R1, [R2], #-4 + EOR R1, R1, R4 + CMP R1, #&00010000 + MOV R7, R7, RRX + MOV R1, R1, LSL #16 + CMP R1, #&00010000 + MOV R7, R7, RRX + + LDR R1, [R2], #-4 + EOR R1, R1, R4 + CMP R1, #&00010000 + MOV R7, R7, RRX + MOV R1, R1, LSL #16 + CMP R1, #&00010000 + MOV R7, R7, RRX + + LDR R1, [R2], R8 + EOR R1, R1, R4 + CMP R1, #&00010000 + MOV R7, R7, RRX + MOV R1, R1, LSL #16 + CMP R1, #&00010000 + MOV R7, R7, RRX + + TEQ R2, R5 ; half-way, so copy out word + MOVEQ R6, R7 ; top word + MOVEQ R7, #0 + + TEQ R2, R3 ; finished ? + BNE RDCH90 + BEQ RDCH14 + + +RdCh8Bit + ADD R2, R2, #4 + ADD R5, R2, R8, LSL #2 ; half way + ADD R3, R2, R8, LSL #3 ; one-after-finishing R2 + MOV R7, #0 + ADD R8, R8, #4 ; alternate between -4 and LL+4 + MVN R9, R8 + EOR R9, R9, #3 ; thing to EOR R8 with +RDCH84 + EOR R8, R8, R9 + LDR R1, [R2], R8 + EOR R1, R1, R4 + CMP R1, #&01000000 + MOV R7, R7, RRX + MOV R1, R1, LSL #8 + ORR R1, R1, #1 ; dummy bit + CMP R1, #&01000000 +RDCH88 + MOV R7, R7, RRX + MOV R1, R1, LSL #8 + CMP R1, #&01000000 ; Z => finish, C = output bit + BNE RDCH88 + + TEQ R2, R5 ; half-way, so copy out word + MOVEQ R6, R7 ; top word + MOVEQ R7, #0 + + TEQ R2, R3 ; finished ? + BNE RDCH84 + BEQ RDCH14 + + +RdCh4Bit + ADD R5, R2, R8, LSL #2 ; half way + ADD R3, R2, R8, LSL #3 ; one-after-finishing R2 + MOV R7, #0 +RDCH44 + LDR R1, [R2], R8 + EOR R1, R1, R4 + CMP R1, #&10000000 + MOV R7, R7, RRX + MOV R1, R1, LSL #4 + ORR R1, R1, #1 ; dummy bit + CMP R1, #&10000000 +RDCH48 + MOV R7, R7, RRX + MOV R1, R1, LSL #4 + CMP R1, #&10000000 ; Z => finish, C = output bit + BNE RDCH48 + + TEQ R2, R5 ; half-way, so copy out word + MOVEQ R6, R7 ; top word + MOVEQ R7, #0 + + TEQ R2, R3 ; finished ? + BNE RDCH44 + BEQ RDCH14 + + +RdCh2Bit + ANDS R0, R2, #3 + EOR R2, R2, R0 ; make R2 -> word boundary + MOVNE R0, #16 ; shift adjust + ADD R5, R2, R8, LSL #2 ; half way + ADD R3, R2, R8, LSL #3 ; one-after-finishing R2 + MOV R7, #0 +RDCH24 + LDR R1, [R2], R8 + EOR R1, R1, R4 + MOV R1, R1, ROR R0 + MOV R1, R1, LSL #16 ; important bits at top + ORR R1, R1, #&4000 ; dummy bit + CMP R1, #&40000000 +RDCH28 + MOV R7, R7, RRX + MOV R1, R1, LSL #2 + CMP R1, #&40000000 ; Z => finish, C = output bit + BNE RDCH28 + + TEQ R2, R5 ; half-way, so copy out word + MOVEQ R6, R7 ; top word + MOVEQ R7, #0 + + TEQ R2, R3 ; finished ? + BNE RDCH24 + BEQ RDCH14 + +RdCh1Bit + LDRB R6, [R2], R8 + MOV R6, R6, LSL #24 + LDRB R0, [R2], R8 + ORR R6, R6, R0, LSL #16 + LDRB R0, [R2], R8 + ORR R6, R6, R0, LSL #8 + LDRB R0, [R2], R8 + ORR R0, R6, R0 + EOR R0, R0, R4 ; make background zero + + MOV R6, #1 ; now invert order of bits +RDCH10 + MOVS R0, R0, LSR #1 + ADCS R6, R6, R6 + BCC RDCH10 + + LDRB R7, [R2], R8 + MOV R7, R7, LSL #24 + LDRB R0, [R2], R8 + ORR R7, R7, R0, LSL #16 + LDRB R0, [R2], R8 + ORR R7, R7, R0, LSL #8 + LDRB R0, [R2], R8 + ORR R0, R7, R0 + EOR R0, R0, R4 + + MOV R7, #1 ; now invert order of bits +RDCH12 + MOVS R0, R0, LSR #1 + ADCS R7, R7, R7 + BCC RDCH12 + +RDCH14 + MOV R0, #32 + ADD R1, WsPtr, # Font +RDCH16 + LDMIA R1!, {R2,R3} + TEQ R2, R6 + TEQEQ R3, R7 + BEQ RDCH17 ; successful match + ADD R0, R0, #1 + TEQ R0, #127 + ADDEQ R0, R0, #1 + ADDEQ R1, R1, #8 + ANDS R0, R0, #&FF ; 0 if finished + BNE RDCH16 + +RDCH17 + Push R0 ; save char + BL PostWrchCursor + Pull "R0, PC" + +; ***************************************************************************** + +RdCh1BitDouble ; double height mode + LDRB R0, [R2], R8 + LDRB R3, [R2], R8 + TEQ R0, R3 + MOVEQ R6, R0, LSL #24 + LDREQB R0, [R2], R8 + LDREQB R3, [R2], R8 + TEQEQ R0, R3 + ORREQ R6, R6, R0, LSL #16 + LDREQB R0, [R2], R8 + LDREQB R3, [R2], R8 + TEQEQ R0, R3 + ORREQ R6, R6, R0, LSL #8 + LDREQB R0, [R2], R8 + LDREQB R3, [R2], R8 + TEQEQ R0, R3 + ORREQ R0, R6, R0 + + MOVNE R0, #0 ; indicate bad character + BNE RDCH17 ; and branch + + EOR R0, R0, R4 ; make background zero + + MOV R6, #1 ; now invert order of bits +RDCH10D + MOVS R0, R0, LSR #1 + ADCS R6, R6, R6 + BCC RDCH10D + + LDRB R0, [R2], R8 + LDRB R3, [R2], R8 + TEQ R0, R3 + MOVEQ R7, R0, LSL #24 + LDREQB R0, [R2], R8 + LDREQB R3, [R2], R8 + TEQEQ R0, R3 + ORREQ R7, R7, R0, LSL #16 + LDREQB R0, [R2], R8 + LDREQB R3, [R2], R8 + TEQEQ R0, R3 + ORREQ R7, R7, R0, LSL #8 + LDREQB R0, [R2], R8 + LDREQB R3, [R2], R8 + TEQEQ R0, R3 + ORREQ R0, R7, R0 + + MOVNE R0, #0 ; indicate bad character + BNE RDCH17 ; and branch + + EOR R0, R0, R4 + + MOV R7, #1 ; now invert order of bits +RDCH12D + MOVS R0, R0, LSR #1 + ADCS R7, R7, R7 + BCC RDCH12D + B RDCH14 + +; ***************************************************************************** + +TTXReadCharacter + TST R6, #CursorsSplit + ADRL R1, TTXLineStarts + LDREQ R2, [WsPtr, #CursorY] + LDRNE R2, [WsPtr, #InputCursorY] + LDR R1, [R1, R2, LSL #2] + LDREQ R2, [WsPtr, #CursorX] + LDRNE R2, [WsPtr, #InputCursorX] + ADD R2, R2, #1 ; skip dummy + LDRB R1, [R1, R2, LSL #2] + MOV R0, R1 + TEQ R1, #"#" ; not those again ! + MOVEQ R0, #"`" + TEQ R1, #"`" + MOVEQ R0, #"_" + TEQ R1, #"_" + MOVEQ R0, #"#" + B RDCH17 + +; ***************************************************************************** +; +; DoOSBYTE87 - OSBYTE &87 entry point +; +; in: - +; +; out: R0 = &87 +; R1 = character at text cursor, 0 if unrecognised +; R2 = screen mode +; + +DoOSBYTE87 + Push "R3-R11,R14" + BL ReadCharacter + MOV R1, R0 + MOV R0, #&87 + LDR R2, [WsPtr, #ModeNo] + CMP R0, #0 ; clear V for any wallies! + Pull "R3-R11,PC" + +; ***************************************************************************** +; +; PageTest - check for CTRL/SHIFT, page mode +; +; in: R6 = CursorFlags +; + +PageTest + Push R14 + + CLC ; don't set leds first time + BL CtrlShiftTest ; on exit, C=CTRL, N=SHIFT + BCC Page20 ; CTRL up, then branch + BPL Page20 ; SHIFT up, then branch + +; CTRL and SHIFT are down + + BL ClearLines ; CTRL+SHIFT down, so clear lines + BL PostWrchCursor ; we may be some time, so enable cursor +CSWaitLoop + SEC ; set leds + BL CtrlShiftTest + BCC Page18 + BMI CSWaitLoop ; and wait for change (NB C=1 now) +Page18 + BL PreWrchCursor ; get rid of cursor again + +; CTRL and SHIFT are not both down + +Page20 + CLC ; don't set leds first time + BL CtrlShiftTest + BCC Page40 ; [CTRL not down] + +; CTRL down, so wait for auto repeat delay time before continuing + + BL PostWrchCursor ; we may be some time, so enable cursor + + LDROSB R1, KeyRepRate + STROSB R1, CentiCounter, R0 + CLC +Page30 + BL CtrlShiftTest + BCC Page35 ; CTRL no longer down + LDROSB R1, CentiCounter + CMP R1, #1 + BCS Page30 ; loop with carry set +Page35 + BL PreWrchCursor ; remove cursor again + +; CTRL not down, test for page mode + +Page40 + EOR R0, R6, #PageMode + TST R0, #(PageMode :OR: CursorsSplit) + Pull PC, NE ; cursors split or not in page mode + + LDROSB R3, PageModeLineCount + BL BotRowCheck ; are we on bottom row ? + BNE IncLinesExit + TST R6, #8 + LDREQ R0, [WsPtr, #TWBRow] + LDREQ R1, [WsPtr, #TWTRow] + LDRNE R0, [WsPtr, #TWRCol] + LDRNE R1, [WsPtr, #TWLCol] + SUB R0, R0, R1 ; get number of lines in window + SUB R0, R0, R0, LSR #2 ; * 3/4 (rounded up) + CMP R0, R3 ; does PageModeLineCount exceed this ? + BCC Page50 ; yes, then wait until SHIFT up +IncLinesExit + ADD R3, R3, #1 + STROSB R3, PageModeLineCount, R0 + Pull PC + +Page50 ; NB C=0 on entry from above + BL CtrlShiftTest + BMI Page55 + +; Waiting for shift + + BL PostWrchCursor ; put cursor back on for now +PageWaitLoop + SEC + BL CtrlShiftTest + BPL PageWaitLoop + BL PreWrchCursor + +Page55 + Pull R14 +ClearLines + MOV R0, #1 ; fudge for MASTER compatibility + STROSB R0, PageModeLineCount, R1 + MOV PC, R14 + +BotRowCheck + TST R6, #2 + LDREQ R1, [WsPtr, #TWRCol] + LDRNE R1, [WsPtr, #TWLCol] + TST R6, #4 + LDREQ R0, [WsPtr, #TWBRow] + LDRNE R0, [WsPtr, #TWTRow] + TST R6, #8 + EORNE R0, R0, R1 ; swap R0, R1 + EORNE R1, R0, R1 + EORNE R0, R0, R1 + LDREQ R2, [WsPtr, #CursorY] + LDRNE R2, [WsPtr, #CursorX] + TEQ R0, R2 + MOV PC, R14 + +CtrlShiftTest ROUT + MOV R0, #0 + LDRB R0, [R0, #ESC_Status] + TST R0, #&40 ; escape condition ? + LDROSB R0, KeyBdStatus ; (preserves PSR) + BEQ %FT10 ; [no escape] + + Push R14 + BIC R0, R0, #KBStat_ScrollLock ; escape, so cancel scroll lock + STROSB R0, KeyBdStatus, R14 ; and store back + MOV R0, #&20 ; pretend shift down, ctrl up + MOVS R0, R0, LSL #(32-6) ; C=CTRL, N=SHIFT + Pull PC + +10 + TST R0, #&08 ; shift bit + ORRNE R0, R0, #&20 ; move it to bit below ctrl (bit 6) + BICEQ R0, R0, #&20 + TST R0, #KBStat_ScrollLock ; if scroll lock on + ORRNE R0, R0, #&60 ; then pretend ctrl and shift down + MOVS R0, R0, LSL #(32-6) ; C=CTRL, N=SHIFT + MOV PC, R14 + +; ***************************************************************************** +; +; SO - Page mode on +; +; in: R6 = CursorFlags +; + +SO + MOV R0, #0 + STRB R0, [R0, #OsbyteVars + :INDEX: PageModeLineCount] + + ORR R6, R6, #PageMode + STR R6, [WsPtr, #CursorFlags] + + MOV PC, R14 + +; ***************************************************************************** +; +; SI - Page mode off +; +; in: R6 = CursorFlags +; + +SI + BIC R6, R6, #PageMode + STR R6, [WsPtr, #CursorFlags] + + MOV PC, R14 + +; ***************************************************************************** +; +; DoResetFont - Reset some or all of the soft font from the hard font +; +; in: R1*32 = start character, R2 = number of pages to copy +; +; NB no range checking is done on these numbers + +DoResetFont ROUT + + ADRL R0, HardFont-32*8 + ADD R3, WsPtr, #(Font-32*8) + + ADD R0, R0, R1, LSL #8 ; start source + ADD R3, R3, R1, LSL #8 ; start dest + ADD R1, R0, R2, LSL #8 ; end source + +10 + LDR R2, [R0], #4 + STR R2, [R3], #4 + TEQ R0, R1 + BNE %BT10 + + MOV PC, R14 + +; ***************************************************************************** +; +; DoReadFont - Read character font +; +; in: R1 -> control block +; [R1, #0] = character to read (2..5 => read ecf, 6=> read dotdash) +; +; out: [R1, #1..8] = font for that character +; + +DoReadFont + LDRB R0, [R1] + CMP R0, #32 + ADD R0, WsPtr, R0, LSL #3 + ADDCS R0, R0, #(Font-32*8) ; R0 -> font + ADDCC R0, R0, #(Ecf1-2*8) + LDMIA R0, {R2,R3} + + STRB R2, [R1, #1] + MOV R2, R2, LSR #8 + STRB R2, [R1, #2] + MOV R2, R2, LSR #8 + STRB R2, [R1, #3] + MOV R2, R2, LSR #8 + STRB R2, [R1, #4] + + STRB R3, [R1, #5] + MOV R3, R3, LSR #8 + STRB R3, [R1, #6] + MOV R3, R3, LSR #8 + STRB R3, [R1, #7] + MOV R3, R3, LSR #8 + STRB R3, [R1, #8] + + MOV PC, R14 + +; ***************************************************************************** +; +; NAK - Disable VDU +; +; in: R6 = CursorFlags +; + +NAK + ORR R6, R6, #VduDisabled + STR R6, [WsPtr, #CursorFlags] + MOV PC, R14 + +; ***************************************************************************** +; +; STX - Turn printer on +; ETX - Turn printer off +; +; in: R0 = 2 or 3 +; + +STX +ETX + +; insert code here to call UPTVEC or NETVEC +; (probably need to restore cursor while doing so in case of 'Not listening') + + LDR R1, [WsPtr, #VduStatus] + TEQ R0, #2 ; turning on ? + ORREQ R1, R1, #Vdu2Mode ; yes, then set bit + BICNE R1, R1, #Vdu2Mode ; no, then clear bit + STR R1, [WsPtr, #VduStatus] + MOVEQ PC, R14 ; exit if not turning off + + Push R14 + MOV R0, #&7B ; make printer dormant + SWI XOS_Byte + Pull PC, VC + +; bad exit from the OSBYTE + + Pull R14 + B VduBadExit + +; ***************************************************************************** +; +; BEL - Do VDU 7 +; +; in: BELLchannel, BELLinfo, BELLfreq, BELLdur contain info for bell +; BELLinfo: Bits 0,1 S bits +; Bit 2 H bit +; Bits 3-6 (envelope-1) OR (volume+15) +; Bit 7 0 => envelope, 1 => volume +; +; out: SOUND &HFSC, A, P, D +; + +BEL ROUT + Push R14 + BYTEWS R0 + ADD R1, WsPtr, #(BeepBlock :AND: &FF) + ADD R1, R1, #(BeepBlock :AND: &FF00) + + MOV R2, #0 + STRB R2, [R1, #5] ; zero hi-byte of pitch + STRB R2, [R1, #7] ; zero hi-byte of duration + + LDRB R2, [R0, #:INDEX: BELLchannel] ; copy channel + STRB R2, [R1, #0] ; into OSWORD block + + LDRB R2, [R0, #:INDEX: BELLinfo] ; get info + AND R3, R2, #7 ; bit 2 of R3 is H, bits 0,1=S + TST R3, #4 + EORNE R3, R3, #(4 :EOR: &10) ; put H into bit 4 + STRB R3, [R1, #1] ; store H and S + + MOV R2, R2, LSL #24 + MOV R2, R2, ASR #(24+3) ; shift down, sign extending + ADD R2, R2, #1 + STRB R2, [R1, #2] ; store lo-byte of env/vol + MOV R2, R2, LSR #8 + STRB R2, [R1, #3] ; store hi-byte of env/vol + + LDRB R2, [R0, #:INDEX: BELLfreq] + STRB R2, [R1, #4] ; copy pitch + + LDRB R2, [R0, #:INDEX: BELLdur] + STRB R2, [R1, #6] ; copy duration + + MOV R0, #7 ; OSWORD SOUND + SWI XOS_Word + Pull PC + +; ***************************************************************************** + +; Compile the text fg / bg (and tint info if required) into a sensible set of +; colour words. + +; The routines take the TextFg and TextBg colours, if NColour >= 63 then +; we attempt to combine the tint information, this is then passed onto +; ColourTrans to force the colour change. + +; in - +; out [TextFgColour] / [TextBgColour] updated to contain new values + +; amg: 30/11/93 split these into separate routines to sort out a problem. +; When OS_SetColour was being used for text colours in >=8bpp TForeCol/TBackCol +; and TForeTint/TBackTint went out of step. Thus when a VDU 17 or VDU 23,17,0 | 1 +; came along both fore and back text colours were getting changed. This solution +; is not perfect, since doing a TINT command before a colour change will still +; go wrong but I consider that worth leaving against the alternative of changing +; the function of this area of the code by having some magic value. + +CompileTextBg ROUT + + Push "R0-R1,LR" + + LDR R1, [WsPtr, #NColour] + CMP R1, #63 ; is this a daft mode? + + LDR R0, [WsPtr, #TBackCol] + LDRCS LR, [WsPtr, #TBTint] + ANDCS LR, LR, #&C0 ; only look at 2 bits of tint + ORRCS R0, R0, LR ; combine tint value to bg colour + BLCS ConvertGCOLToColourNumber + STRVC R0, [WsPtr, #TextBgColour] + + Pull "R0-R1,PC",,^ + +CompileTextFg ROUT + + Push "R0-R1,LR" + + LDR R1, [WsPtr, #NColour] + CMP R1, #63 ; is this a daft mode? + + LDR R0, [WsPtr, #TForeCol] + LDRCS LR, [WsPtr, #TFTint] + ANDCS LR, LR, #&C0 ; only look at 2 bits of tint + ORRCS R0, R0, LR ; combine in the tint value + BLCS ConvertGCOLToColourNumber ; convert colour using ColourTrans + STRVC R0, [WsPtr, #TextFgColour] ; store the value away - assume it worked!?!@? + + Pull "R0-R1,PC",,^ + + +; ***************************************************************************** +; +; Convert a GCOL including Tint information to a physical colour, returning +; the colour number. This is used for backwards compatibility with the +; existing 8 bit interfaces providided within the kernel. +; +; in R0 = GCOL ( + tint ) := t t b b g g r r +; out R0 = colour number (at current depth) +; V set if no ColourTrans module. + +; don't call CTrans if in 8bpp since otherwise GCOL numbers vary with +; palette changes! + +ConvertGCOLToColourNumber ROUT + + Push "R1-R2, LR" + + LDR R1, [WsPtr, #NColour] + CMP R1, #63 + CMPNE R1, #255 + BEQ %FT20 + + AND LR, R0, #4_3000 ; extract the tint information + MOV R0, R0, LSL #14 ; convert to a sensible bit location + AND R2, R0, #4_0003 :SHL: 14 ; extract the red + ORR R2, R2, LR, LSL #6 ; and then combine the tint information + AND R1, R0, #4_0030 :SHL: 14 ; extract the green + ORR R2, R2, R1, LSL #6 + ORR R2, R2, LR, LSL #14 ; and combine with tint and green + AND R1, R0, #4_0300 :SHL: 14 ; finally extract the blue component + ORR R2, R2, R1, LSL #12 + ORR R2, R2, LR, LSL #22 ; combine in the tint and blue + ORR R0, R2, R2, LSR #4 ; ensure physcial colour yeilds pure-white! + + SWI XColourTrans_ReturnColourNumber + + Pull "R1-R2, PC",,^ +20 + MOV r1, r0, LSR #6 ; r1 = 0 0 0 0 0 0 T1 T0 + AND r2, r0, #2_00100001 ; r2 = 0 0 B3 0 0 0 0 R2 + ORR r1, r1, r2, LSL #2 ; r1 = B3 0 0 0 0 R2 T1 T0 + AND r2, r0, #2_00010000 ; r2 = 0 0 0 B2 0 0 0 0 + ORR r1, r1, r2, LSR #1 ; r1 = B3 0 0 0 B2 R2 T1 T0 + AND r2, r0, #2_00001110 ; r2 = 0 0 0 0 G3 G2 R3 0 + ORR r0, r1, r2, LSL #3 ; r0 = B3 G3 G2 R3 B2 R2 T1 T0 + Pull "R1-R2, PC",,^ + + LTORG + + END