mindbox77/zxdesk: A GUI working system for the 48K ZX Spectrum, in Z80 meeting · GitHub
A graphical desktop for the ZX Spectrum 48K, written in Z80 meeting.
Overlapping home windows with a z order and focus, pull down menus, a heap,
an occasion queue, a storage layer with swappable backends, dialogues,
controls, a notepad, a clock, a calendar, a two pane file supervisor, and
a settings panel that truly adjustments issues. It all suits in 48K on a
machine from 1982, and it may drag a window inside a single 69,888 T
state body.
It runs on the true factor, not simply an emulator.
Back within the eighties I wished an Atari ST and could not afford one.
What I actually wished was
GEM: the
desktop, the home windows, the menu bar that was all the time there, the sensation
that the machine was a spot slightly than a immediate. I had a Spectrum
as a substitute, and I spent a very long time questioning how a lot of that you could possibly
do on it. I began writing bits of it, and by no means completed.
So that is that, completed. It is not a port of GEM and would not fake
to be. It’s what the thought turns into while you push it up towards a
3.5 MHz Z80, 48K of RAM, a one bit show with attribute conflict, and a
video chip that steals cycles from the CPU whereas it paints. Quite a lot of
the solutions turned out to be extra attention-grabbing than the query, and
almost all of them got here from measuring the machine slightly than
reasoning about it.
It’s a enjoyable mission and a labour of affection, and the rationale it is written
up at this size is that the measurements are the helpful bit. If
you are constructing one thing on this {hardware}, the numbers beneath price me
plenty of evenings. They’re yours.
| Windows | Overlapping, z ordered, movable, resizable, with title bar, shut field and grip. Focus is the entrance of the z order, so elevating and focusing are one motion. |
| Menus | A everlasting menu bar with pull downs, save underneath, and hit testing. |
| Input | Kempston mouse, Kempston joystick, and the total keyboard matrix decoded throughout three tables with repeat. All of it arrives as occasions. |
| Events | A sixteen slot ring. The primary loop accommodates no window particular code. |
| Storage | A registry of backends behind six vectors. RAM, tape (by way of the true ROM loader), and the 128K’s spare banks as a RAM disk. esxDOS has a reserved id. |
| Memory | An actual heap with an proprietor byte, 8,112 bytes, allocating window buffers sized to their home windows. |
| Applications | A descriptor with init, occasion and paint, plus per occasion state swapped out and in. Notepad, clock, calendar, commander, about. |
| Persistence | Settings written to storage with a magic byte and a model, and skim again at boot. |
Screenshots:
![]() |
![]() |
| Two home windows, z ordered | The notepad, with the Sinclair model shift-reporting cursor |
![]() |
![]() |
| Two pane commander, over gadgets slightly than directories | Clock and calendar |
The toolchain is native and small: pasmo
0.5.5, constructed from supply into instruments/.
./construct.sh assemble src/zxdesk.asm to construct/zxdesk.faucet
./run.sh construct and cargo onto the machine
MACHINE=128 ./run.sh the identical on a 128K, and put the setting again
esxDOS runs right here too, on an emulated DivMMC with a 64MB card picture.
instruments/ is not within the repository as a result of pasmo, the emulators and the
esxDOS ROM aren’t mine to redistribute, so you may have to construct the
picture your self from an esxDOS launch and a DivMMC card picture. Once
it exists, launch instruments/esxdos/esxdos.szx and esxDOS is already
resident; Machine > NMI will get you its file browser.
Build flags, all handed by way of --equ:
DEMO=1 ./construct.sh a self dragging construct, for reproducible captures
NOWAIT=1 with DEMO, the identical drag with no beam scheduler
SCRIPT=1 ./construct.sh drive the desktop from artificial enter
MOUSETEST=1 ./construct.sh the uncooked Kempston mouse diagnostic
construct.sh should go --name explicitly, as a result of pasmo takes the tape
header title from the output path precisely as written and would
in any other case put construct/zxde within the header. It additionally refuses to construct a
tape if the code has grown into the buffer area, as a result of that overrun
is silent in any other case: the primary window seize writes over this system and
a couple of seconds later the machine drops into BASIC with an unrelated
error.
Dragging a window underneath Fuse wants the house bar, not the mouse
button. Fuse for macOS, 1.9.2, stops delivering Kempston mouse
motion whereas a button is held, so the pointer freezes in the meanwhile a
drag begins and the window by no means follows. Point on the title bar, maintain
SPACE, transfer, launch. The mouse is okay for the whole lot else and the
buttons themselves register accurately; it is just motion that stops.
This is the emulator, not the desktop, and MOUSETEST=1 is how I
proved it: it reads the mouse ports as soon as every with nothing between the
port and the display, and the counters nonetheless stand nonetheless whereas a button
is down. RiBtn in ReadvertInput is what makes SPACE work, and it is
there so the desktop is usable on a machine with no mouse in any respect. A
actual Kempston mouse drags usually.
SCRIPT=1 is the one price figuring out about. It drives the desktop from a
record of artificial enter occasions as a substitute of the mouse, so an interplay
(open a menu, choose an merchandise, drag the window over one other one, sort
into the sector, save) runs the identical approach each time and will be in contrast
towards the final run slightly than watched.
From the underside up.
Device layer. DevFillRect, DevFillDesk, DeskFillCol,
AddrAt, BlitRect, RectGrab. Everything above works in byte
columns and pixel rows and by no means touches the display’s third and
interleave format instantly. This is the boundary a port swaps out, and
I drew it on day one for precisely that cause.
Frame self-discipline. The primary loop halts on the interrupt, does all
pointer work within the prime border, waits for the beam if the window
moved, redraws, then reads enter and dispatches on the finish of the
body. Input goes final in order that the price earlier than the beam wait is
fixed, which is what makes the scheduler precise.
Event queue. A sixteen slot ring of 4 byte occasions. EvPoll
turns uncooked enter into pointer strikes, button presses and keys; EvDispatch
drains it by way of a handler desk.
Hit testing. A 5 byte row per management, entrance to again in z
order, $FF terminated, refilled from the mannequin earlier than each search so
there is no such thing as a second copy of the window place to go stale. A closed
menu will get a top of zero, which might by no means match, so HitTake a look at has no
particular case for it.
Transient surfaces. A 4 deep area, every floor as much as 16 by 96,
pushed and popped. Two stacks slightly than one, as a result of the pixels underneath
a menu are pushed by one thing that has no panel document in any respect.
Windows. A document swapped right into a stay copy, the identical trick because the
panel document, as a result of the window place is referenced ninety three
instances throughout six information. The z order can also be the paint order reversed
and the hit check order.
Storage. A registry of backends, every a fourteen byte row of id,
functionality bits and 6 entry factors. The six operations are hand laid
JP directions whose operands are patched on choice, so dispatch
prices ten T states and clobbers no registers.
Controls. A panel is a stack of rows and each management is a row, so
a row’s index is three shifts slightly than a search. Four varieties, of
which the helpful one is a cycle: a checkbox is a cycle whose restrict is
two, and a radio group is a cycle whose restrict is N. The settings panel,
the file record and the save field are all the identical code with completely different
tables.
$6000-$727C the sluggish area: panels, the calendar, the file
panels, the desktop setup, the commander
$727D-$7FFF free, 3,460 bytes, contended
$8000-$B1B7 the quick area: the whole lot else
$B1B8-$BCFF free, 2,889 bytes
$BD00 stack prime
$BDBD interrupt handler
$BE00-$BEFF interrupt vector desk
$C000-$C63F the RAM disk, its listing, and the tape buffer
$C640-$C74F the stay notepad state
$C750-$DF4F 4 transient surfaces
$DF50-$FEFF the heap, 8,112 bytes
$FF00-$FFFF intentionally unused
Two issues in that map are price explaining.
The sluggish area exists as a result of the ULA steals cycles beneath $8000
whereas the show is being painted, so code there runs maybe a 3rd
slower. The rule for it’s one line: nothing in it could run inside a
body. Nothing there’s on the drag path, the pointer path or within the
interrupt, and the timings have been unchanged to the T state throughout
the transfer. It begins at $6000 slightly than on the prime of the system
variables as a result of the tape loader indexes the system variable space
by way of IY and the BASIC loader itself lives simply above it, and a CODE
block that overwrote this system doing the loading could be a novel approach
to fail.
The heap stops a web page in need of the highest of reminiscence slightly than at
$FFFF. Every stroll computes the following block as deal with plus header plus
dimension, and a block ending at $10000 would wrap to nought and evaluate
as beneath the bottom of the heap. Stopping at $FF00 prices 256 bytes of
8,272 and removes your complete class of failure.
This is the half I’d need if I have been studying another person’s repo.
Every determine beneath was measured by operating the code and timing it
towards the machine’s personal clock. None of it comes from counting
directions, and the few claims which might be derived say so.
The 48K interrupt interval is strictly 69,888 T states and nothing a
program does can transfer it, so it’s the solely usable clock on the
machine. So a timing run syncs on HALT, optionally delays a identified
variety of T states to position the routine at a selected level within the body,
calls it, then counts turns of a sixteen T loop till the following
interrupt. Comparing towards an empty calibration run cancels each
mounted overhead:
price = (Okay - K0) * (69888 - 118) - 16 * (C - C0) - delay
118 T is the precise price of the returning interrupt path, counted
instruction by instruction. It is precise slightly than estimated as a result of
the handler, its variables, the counting loop and the stack all stay
above $8000, the place the ULA by no means steals a cycle. Only the routine
being timed touches contended reminiscence.
Measured blind towards three delays of identified size:
| nominal | measured | error |
|---|---|---|
| 2,599 T | 2,592 T | −7 T |
| 51,999 T | 52,000 T | +1 T |
| 103,999 T | 103,994 T | −5 T |
Worst error is 7 T in 104,000, or 0.007%. The third crosses a body
boundary, which is what confirms the 118 T determine.
Every finances within the mission began from a pessimistic 50% penalty on
display writes, taken from the folklore. Sweeping a 1,024 byte fill
throughout the body:
| begin | price |
|---|---|
| prime border | 11,744 T |
| 10,399 T | 12,913 T |
| 20,799 T | 13,441 T |
| 31,199 T | 13,473 T |
| 41,599 T | 13,441 T |
| 51,999 T | 12,369 T |
| backside border | 11,745 T |
The two border figures comply with 1 T, which is the uncontended price. The
worst case contained in the show is 13,473 T. That is 14.7%, or about
1.7 T per contended byte written. Budgets constructed on the 50% determine are
roughly a 3rd too conservative, and mine have been.
WinDraw break up into its 4 phases and every timed individually. The
phases sum to inside 330 T of the entire, which is the 4 name and
return pairs plus the sixteen T counting granularity.
| section | prime of body | mid show | share |
|---|---|---|---|
| textual content | 35,872 T | 35,969 T | 50% |
| edges | 19,552 T | 19,841 T | 27% |
| fills | 14,688 T | 16,641 T | 21% |
| shut field | 832 T | 849 T | 1% |
| entire | 71,274 T | 73,099 T |
Twenty seven characters of title and physique textual content, at roughly 1,330 T
every. The fills, which I had assumed have been the issue, are a fifth of
it. Optimising the fill would have purchased a couple of per cent of a drag
body and I’d have spent every week on it.
An earlier observe recorded the cell conscious push fill at 7.4 T per byte.
The actual routine prices 11.5 T per byte, 54% extra. The benchmark had
measured the method; the routine carries per row deal with arithmetic
the benchmark by no means paid. Of the 183 T a row prices, 88 T is the push
chain truly writing pixels and 95 T is the register change, the
deal with step, the cell boundary check and the loop.
Over half the price of the quickest fill on the machine is just not writing
pixels. That generalises: on this processor, per row overhead is the
factor to assault, not per byte throughput.
This is the one I’d most like different individuals on this {hardware} to know
about, as a result of it produces a fault that appears like something besides its
trigger.
The fills held DI for his or her entire run, as a result of SP walks by way of
display reminiscence and stops being a stack. The obtained knowledge is that this
delays the interrupt. It doesn’t. The Spectrum asserts INT for less than
32 T states after which withdraws it, so a DI window that covers these
32 T destroys the interrupt slightly than suspending it.
It was noticed earlier than it was understood. A fill positioned at 62,399 T
into the body reported crossing no body boundary when it plainly
crossed one. Rescoring it as a misplaced interrupt offers 11,745 T towards
11,744 T for a similar fill within the prime border, and the 2 agreeing to
1 T is what confirmed the prognosis.
Then it was measured correctly. With an interrupt injected after each
single instruction of an 8 by 24 fill, the interrupt was refused at 458
of 500 instruction boundaries in a single fill routine and 710 of 752 within the
different.
The apparent repair doesn’t work. Re-enabling interrupts between rows
sounds proper and fails, as a result of the interrupt is just not pending, it’s
gone. An EI window a couple of T states vast, as soon as each 236 T, catches it
about one row in thirty. Making the DI area brief is just not the identical
as making it absent, and solely absent is a repair.
What works is owing the final push. The fills now run with
interrupts enabled all through. What DI was defending was SP, so the
repair is to ensure that the 2 bytes of return deal with all the time land
someplace that’s about to be overwritten anyway. SP takes two sorts of
worth: contained in the rectangle, the place a push writes precisely what the
chain’s subsequent push will write, and the low level after the final push of
a row, which the chain by no means returns to. So the chain is made one push
shorter than the row, and the leftmost two bytes are owed — paid one
iteration later, as soon as SP has moved into the following row and might not
attain them.
Afterwards: 0 of 607 and 0 of 904 instruction boundaries destroy the
interrupt, the rectangle is byte for byte an identical each time, nothing
outdoors it’s touched, and the display checksums are unchanged
both aspect of the change.
| earlier than | after | ||
|---|---|---|---|
| 16×96 rectangle fill | 17,414 T | 22,068 T | +48 T a row |
| 16×96 desktop fill | 25,351 T | 30,125 T | +50 T a row |
That’s an actual price, and it is price it. The drag path is generally the
column fill, which writes by way of HL, by no means touched SP and was by no means at
danger.
A body watchdog counts interrupts within the handler and frames within the
primary loop; the distinction is frames dropped. The handler is the awkward
half, as a result of it fires inside a fill the place the stack is just not a stack.
The first model borrowed IX and counted with INC (IX+0), and the
interrupt sweep above failed on its first run. That instruction units
the flags, and a fill holds a stay carry throughout the deal with step that
finds the tip of a row and the department that decides whether or not the row
crossed a boundary. An interrupt in that hole stole the carry and the
row stepped to the improper deal with.
INC IX is a sixteen bit increment and sixteen bit increments depart
the flags alone. So the counter is a phrase, the handler is clear,
and it prices 104 T fifty instances a second with not one flag or register
altered. The roadmap had predicted {that a} watchdog would have caught
the interrupt bug earlier. What truly occurred is that the interrupt
check caught the watchdog.
Letting the handler push can also be a useless finish. A handler that pushes
AF makes use of 4 bytes beneath SP slightly than two, so the owed area has to
double and each row pays one other 22 T.
The beginning place was hopeless: a full erase and redraw of a window
price 96,010 T towards a body of 69,888 T. That is 137% of a body, and
it’s why dragging ran at 25 Hz. Four adjustments, so as, every measured:
| change | impact |
|---|---|
| Off display buffer. Compose as soon as right into a buffer, blit per body. The costly work is composition, not switch. | redraw 71,274 T → 26,048 T |
| Faster textual content. Rewriting the pixel textual content renderer. | 1,307 T → 622 T a personality, 2.10× |
| Damage rectangles. Erase solely the strip the window has vacated, not the entire window. | erase 19,664 T → 1,456 T |
| A slim desktop fill. Two bytes straight by way of HL with the sample held in registers, unrolled 4 methods so no row works out its section. | single column strip 14,256 T → 5,712 T |
| Chasing the beam slightly than ready for it to clear the entire window. | an extra 16,128 T |
A drag body now ends at 59,858 T, contained in the body, and dragging
runs at 50 Hz.
The beam scheduler counts scan traces slightly than T states, as a result of one
line is strictly 224 T and the highest border is strictly 64 traces, so the
goal is an eight bit addition slightly than a division. It measured
36,576 T for 163 traces towards 36,353 T counted by hand.
The textual content rewrite is price a observe as a result of measuring it proved each of
my guesses improper. The deal with routine was known as as soon as per character, not
as soon as per pixel row, and crossing a cell boundary price nothing. The actual
prices have been 232 T re-testing an inversion flag on each pixel row, 344 T
on eight calls to a row stepping routine, and 126 T recomputing an
deal with that was one byte to the fitting of the earlier one. The
substitute makes the inversion a self modified XOR operand set as soon as
per string, walks one deal with throughout the entire string, and splits the
eight pixel rows both aspect of the one cell boundary they’ll
cross.
Damage conscious blitting doesn’t observe. When a window strikes
vertically each row nonetheless must be written, as a result of the pixels
beneath are the identical window on the improper offset. Damage shrinks the
erase solely. A per row signature constructed at seize time would let uniform
interiors be skipped, price maybe 9,700 T on this window, nevertheless it solely
pays for home windows with massive flat areas. Held in reserve slightly than
rejected.
The stack primarily based blit doesn’t observe both. Popping eight register
pairs from the buffer and pushing them to the display prices about 212 T
a row towards LDI‘s 256, however the pointer bookkeeping wants LD (nn),SP
and a reload every row, which places it again at roughly 304 T towards the
present 327. It additionally wants DI, which reintroduces the misplaced interrupt
hazard, and operating it with interrupts on by way of the owed push method
prices 48 T a row, which makes the arithmetic worse slightly than higher.
The 48K body is strictly 69,888 T at 3.5 MHz, so the speed is 50.0801 Hz.
Ticking a second each fifty interrupts beneficial properties 0.16%, which is 2
minutes eighteen seconds a day. The clock as a substitute makes a second fifty
interrupts and, now and again, fifty one, determined by accumulating a
hundredth every second and demanding an additional interrupt when it carries.
Driven for an hour it takes 180,287 interrupts towards a real
180,288, which is half a second a day.
On a 128K the body is 70,908 T at 3.5469 MHz, so the speed is 50.0211 Hz
and the addend differs. Machine detection has already run by the point
the clock initialises.
What the clock counts is the interrupt counter that the watchdog constructed
to note dropped frames, learn as a distinction because the final look, so
a body the primary loop missed nonetheless advances the time — as a result of the
interrupt occurred whether or not or not something was listening.
Day of the week is counted ahead from 1 January 1980, a Tuesday,
slightly than by Zeller
or Sakamoto,
as a result of each of these need division
by 4, 100 and 400 and this machine has no divide instruction. A 12 months is
1 modulo 7, or 2 in a bissextile year, so strolling a century is at most a
hundred additions, and it occurs as soon as per repaint.
The century rule by no means fires, and that may be a property of the vary
slightly than a nook being minimize: 1980 to 2079 accommodates one century 12 months
and 2000 is a bissextile year, so inside that vary a bissextile year is strictly a
12 months divisible by 4. All 1,200 months it may show are checked
towards Python’s datetime for each the primary weekday and the size.
Every actual discovery on this mission got here from operating code, not from
studying it. These are those that generalise.
A bug that repaired itself in entrance of me. The heap’s free routine
had one DEC HL too many, so it cleared the used flag after which wrote a
nought into the excessive byte of the block’s dimension. The heap ought to have
been ruined on the primary free. It was not, as a result of the coalescer then
discovered a brief free block, appeared previous it right into a payload that occurred
to be all zeros, learn these zeros as an empty free block, and absorbed
them 4 bytes at a time till it arrived again at precisely the true
whole. Every quantity agreed. It solely surfaced when a freed block held
one thing aside from zeros — the primary block sufficiently big to have held
window pixels — after which the stroll went into the pixels and the heap
got here again 2,619 bytes brief.
The lesson is concerning the check slightly than the allocator. A heap check
that frees blocks it by no means wrote to is testing a zero fill. It writes
$A5 over the payload earlier than liberating now, and asserts on the header
instantly slightly than by way of a complete that may heal.
The register that carries the reply should not be the register that
carries the argument. This household accounted for 5 separate bugs.
A search routine held its index in AF throughout the evaluate that determined
whether or not it had discovered something, so the POP AF restored the flags from
earlier than the evaluate and it by no means matched. A digit printer used B to
rely tens and was known as twice with the opposite digit in B, so the
calendar’s 12 months got here out as 2050. Two routines ending in LDIR return
with A clobbered and BC zero, which produced a second window that was
a precise copy of the primary and a panel whose row rely was nought.
Loading a DJNZ counter earlier than calling a routine that makes use of B as a row
counter makes the loop run 256 instances, which has now occurred twice.
On the Z80 the flags are a register too. If a worth should survive a
name, it goes in reminiscence or on the stack. That rule is just not learnable as
“be careful for B”.
A row step that subtracts solely from E. The blit did this from the
day it was written. The LDIs advance DE sixteen bits, so when a
rectangle’s row begin plus its width crosses 256, D has already been
incremented and incrementing it once more places the following row a web page too
excessive. The solely window within the system lived at column 8 and was eight
bytes in need of crossing, so it by no means confirmed till a second window moved
to column 16. Anything strolling a rectangle a row at a time has to
deal with the borrow.
A quantity that reads backwards. Timings are taken by counting a
sixteen T loop till the following interrupt, so a slower routine leaves
fewer turns. That was misinterpret twice in a single session, as soon as reporting a
16 T saving as a 1 T loss, and as soon as reporting a 1,216 T price as a 76 T
saving — which meant an actual regression went unnoticed for being
displayed as an enchancment. Anything that studies a derived amount
ought to report it within the models individuals will cause in.
A corrupt block dimension hangs the machine slightly than failing. Every
heap stroll computes the following block as deal with plus header plus dimension, and
a rubbish dimension wraps previous $FFFF, lands beneath the bottom and compares as
nonetheless contained in the heap, so the stroll loops endlessly. Nothing can produce a
rubbish dimension now, so no guard was added, however it’s the form of the
subsequent failure and it’s price figuring out it presents as a freeze.
Earlier, and in the identical spirit: an LFSR shifting the improper
course gave a interval of 71 as a substitute of 65,535; a register clobber
rendered the improper card within the endurance recreation that was this mission’s
proving floor; a raster timing bug made the pointer invisible within the
higher half of the show on actual {hardware} however not within the emulator; and
an indication bit underflow teleported home windows to the highest of the display the
second Y exceeded 127.
Every piece of labor went by way of the identical three passes, in a single
sitting.
- Research. Find the prior artwork earlier than writing something. The
Spectrum demoscene, the ULA and floating bus documentation, the
esxDOS API notes, the Next register record. Half of those issues
have been solved by any person in 1987, and the demoscene reply is often
quicker than the textbook one. - Build. The smallest factor that may be measured, with the best way to
measure it dedicated alongside the routine. - Critique. Argue towards the end result earlier than accepting it. Look for
the clobbered register, the boundary case on the display edge, and
the determine from a earlier session that is not true.
I attempted to play three elements in each session: the critic who argues
the change is improper, the researcher who goes in search of the 1987
reply, and the measurer who will not settle for a efficiency declare with out
a timing or a correctness declare with no display checksum.
Three guidelines that earned their place:
- It is not carried out as a result of it seems proper on display. The pointer that
vanished within the higher half of the show appeared proper on display. - Anything that could not be noticed instantly is labelled derived,
not measured. Raster behaviour particularly, which is why each
raster derived declare on this repository says so. That distinction is
what ultimately defined the invisible pointer. - One commit per verified piece of labor, with the acceptance numbers
within the commit message. The numbers on this doc are those
from these commits.
esxDOS is written and passes. For a very long time it could not be,
as a result of I had no DivMMC and I do not commit code I have not run. An
emulated DivMMC with esxDOS resident unblocked it in September 2026,
after three useless ends.
The Next did not flip right into a port. It turned its personal system, in its
personal repository, as a result of the window mannequin is completely different: it tiles slightly
than overlaps, so the compositor, the save underneath area and a lot of the
injury equipment don’t have anything to do there. Everything beneath the window
mannequin carried throughout. It is not revealed but.
Known gaps. A clock behind one other window holds its final time
till it is raised, as a result of window buffers are grabbed from the display
slightly than composed into. An utility cannot refuse to shut,
as a result of there isn’t any teardown vector that may say no, and including one
earlier than something wanted it will have been guessing. Every notepad is
titled from its utility slightly than its doc. The notepad has
no choice, clipboard, undo or phrase wrap. Mouse presence detection
remains to be a heuristic, and I am unable to check it as a result of I haven’t got a
machine with no mouse.
No identified stay bugs. The final one closed with the interrupt protected
fills and nothing since has opened one other.
The 48K system was constructed with a port in thoughts from the primary commit,
and the guess was that the machine layer boundary would maintain. It held for
storage, esxDOS, the applying mannequin and the settings document. It
did not maintain for the window mannequin, which is why ZX Desk Next is a second
system slightly than a port: on a 28 MHz Z80 with Layer 2, a tilemap,
{hardware} sprites and a DMA, the fitting desktop tiles, and a tiling
desktop has no use for a compositor constructed to type out overlap.
It lives in its personal repository and might be revealed individually. I
haven’t got a Next but, solely 48K and 128K machines, and I’m not going to
construct it blind on an emulator, so it waits till one arrives.
construct.sh, run.sh assemble, and cargo onto the machine
tstates.py, taplant.py timing arithmetic, and tape block planting
src/zxdesk.asm the desktop
src/injury.inc injury rectangles and the slim desktop fill
src/saveunder.inc transient surfaces
src/occasions.inc the occasion ring and dispatch
src/kbd.inc the keyboard matrix and decode
src/hittest.inc the area desk, z order, what was hit
src/menus.inc the menu bar and pull downs
src/panel.inc panels and their rows
src/dialog.inc the alert and the verify
src/storage.inc the storage layer and the RAM backend
src/tape.inc the tape backend, by way of the true ROM loader
src/financial institution.inc the 128K's spare banks as a RAM disk
src/heap.inc the heap and its proprietor byte
src/app.inc utility descriptors and the state swap
src/resize.inc the grip, the define drag, the realloc
src/observe.inc the notepad
src/clock.inc the clock
src/calendar.inc the calendar
src/commander.inc the 2 pane file supervisor
src/desktop.inc desktop shortcuts
src/filemgr.inc the file panels
src/settings.inc the settings document
src/script.inc scripted enter, for finish to finish verification
photos/ the screenshots above
To Fuse and to César
Hernández Baño’s ZEsarUX,
that are how this was developed earlier than it ever ran on the true factor.
To Julián Albo’s pasmo, which is small and
does precisely what it says.
To the Spectrum group, whose thirty years of documentation about
competition, the floating bus and the ROM entry factors is the rationale
this took months slightly than years. And to whoever wrote the ULA timing
notes I saved going again to: your figures have been proper and my assumptions
weren’t.
To Inkbox‘s NES-OS, which is the
proof that this sort of factor is price doing.
And to a machine that was by no means meant to do any of this, and does.
MIT, see LICENSE. Nothing right here is derived from anybody else’s code.
The toolchain, emulators and ROMs it makes use of aren’t distributed with it.







