collapseos/apps/ed
Clanmaster21 38333e9e07 Decimal parse optimisations (#45)
* Optimised parsing functions and other minor optimisations

UnsetZ has been reduced by a byte, and between 17 and 28 cycles saved based on branching. Since branching is based on a being 0, it shouldn't have to branch very often and so be 28 cycles saved most the time. Including the initial call, the old version was 60 cycles, so this should be nearly twice as fast. 
fmtHex has been reduced by 4 bytes and between 3 and 8 cycles based on branching.
fmtHexPair had a redundant "and" removed, saving two bytes and seven cycles.
parseHex has been reduced by 7 bytes. Due to so much branching, it's hard to say if it's faster, but it should be since it's fewer operations and now conditional returns are used which are a cycle faster than conditional jumps. I think there's more to improve here, but I haven't come up with anything yet.

* Major parsing optimisations

Totally reworked both parseDecimal and parseDecimalDigit
parseDecimalDigit no longer exists, as it could be replaced by an inline alternative in the 4 places it appeared. This saves one byte overall, as the inline version is 4 bytes, 1 byte more than a call, and removing the function saved 5 bytes. It has been reduced from between 52 and 35 cycles (35 on error, so we'd expect 52 cycles to be more common unless someone's really bad at programming) to 14 cycles, so 2-3 times faster.
parseDecimal has been reduced by a byte, and now the main loop is just about twice as fast, but with increased overhead. To put this into perspective, if we ignore error cases:
For decimals of length 1 it'll be 1.20x faster, for decimals of length 2, 1.41x faster, for length 3, 1.51x faster, for length 4, 1.57x faster, and for length 5 and above, at least 1.48x faster (even faster if there's leading zeroes or not the worst case scenario).
I believe there is still room for improvement, since the first iteration can be nearly replaced with "ld l, c" since 0*10=0, but when I tried this I could either add a zero check into the main loop, adding around 40 cycles and 10 bytes, or add 20 bytes to the overhead, and I don't think either of those options are worth it.

* Inlined parseDecimalDigit

See previous commit, and /lib/parse.asm, for details

* Fixed tabs and spacing

* Fixed tabs and spacing

* Better explanation and layout

* Corrected error in comments, and a new parseHex

5 bytes saved in parseHex, again hard to say what that does to speed, the shortest possible speed is probably a little slower but I think non-error cases should be around 9 cycles faster for decimal and 18 cycles faster for hex as there's now only two conditional returns and no compliment carries.

* Fixed the new parseHex

I accidentally did `add 0xe9` without specifying `a`

* Commented the use of daa

I made the comments surrounding my use of daa much clearer, so it isn't quite so mystical what's being done here.

* Removed skip leading zeroes, added skip first multiply

Now instead of skipping leading zeroes, the first digit is loaded directly into hl without first multiplying by 10. This means the first loop is skipped in the overhead, making the method 2-3 times faster overall, and is now faster for the more common fewer digit cases too. The number of bytes is exactly the same, and the inner loop is slightly faster too thanks to no longer needing to load a into c.
To be more precise about the speed increase over the current code, for decimals of length 1 it'll be 3.18x faster, for decimals of length 2, 2.50x faster, for length 3, 2.31x faster, for length 4, 2.22x faster, and for length 5 and above, at least 2.03x faster. In terms of cycles, this is around 100+(132*length) cycles saved per decimal.

* Fixed erroring out for all number >0x1999

I fixed the errors for numbers >0x1999, sadly it is now 6 bytes bigger, so 5 bytes larger than the original, but the speed increases should still hold.

* Fixed more errors, clearer choice of constants

* Clearer choice of constants

* Moved and indented comment about fmtHex's method

* Marked inlined parseDecimalDigit uses

* Renamed .error, removed trailing whitespace, more verbose comments.
2019-10-24 07:58:32 -04:00
..
buf.asm recipes/sms/romasm: make ed's memory usage fit the SMS 2019-07-23 16:13:52 -04:00
cmd.asm Decimal parse optimisations (#45) 2019-10-24 07:58:32 -04:00
glue.asm zasm: rename #inc to .inc 2019-10-06 14:32:23 -04:00
io.asm ed: Add 'w' command 2019-07-21 11:40:26 -04:00
main.asm ed: add '.' and '$' support 2019-10-04 13:49:33 -04:00
README.md Fix misc. source comment typos 2019-10-09 11:12:08 -04:00

ed - line editor

Collapse OS's ed is modeled after UNIX's ed (let's call it Ued). The goal is to have an editor that is tight on resources and that doesn't require ncurses-like screen management.

In general, we try to follow Ued's conventions and the "Usage" section is mostly a repeat of Ued's man page.

Differences

There are a couple of differences with Ued that are intentional. Differences not listed here are either bugs or simply aren't implemented yet.

  • Always has a prompt, :.
  • No size printing on load
  • Initial line is the first one
  • Line input is for one line at once. Less scriptable for Ued, but we can't script ed in Collapse OS anyway...
  • For the sake of code simplicity, some commands that make no sense are accepted. For example, 1,2a is the same as 2a.

Usage

ed is invoked from the shell with a single argument: the name of the file to edit. If the file doesn't exist, ed errors out. If it exists, a prompt is shown.

In normal mode, ed waits for a command and executes it. If the command is invalid, a line with ? is printed and ed goes back to waiting for a command.

A command can be invalid because it is unknown, malformed or if its address range is out of bounds.

Commands

  • (addrs)p: Print lines specified in addrs range. This is the default command. If only (addrs) is specified, it has the same effect.
  • (addrs)d: Delete lines specified in addrs range.
  • (addr)a: Appends a line after addr.
  • (addr)i: Insert a line before addr.
  • w: write to file. For now, q is implied in w.
  • q: quit ed without writing to file.

Current line

The current line is central to ed. Address ranges can be expressed relatively to it and makes the app much more usable. The current line starts at 1 and every command changes the current line to the last line that the command affects. For example, 42p changes the current line to 42, 3,7d, to 7.

Addresses

An "address" is a line number. The first line is 1. An address range is a start line and a stop line, expressed as start,stop. For example, 2,4 refer to lines 2, 3 and 4.

When expressing ranges, stop can be omitted. It will then have the same value as start. 42 is equivalent to 42,42.

Addresses can be expressed relatively to the current line with + and -. +3 means "current line + 3", -5, +2 means "address range starting at 5 lines before current line and ending 2 lines after it`.

+ alone means +1, - means -1.

. means current line. It can usually be omitted. p is the same as .p.

$ means the last line of the buffer.