;HL must be non-zero add hl,hl sbc a,a and %00101101 xor l ld l,a ld a,r add a,a ;Because R is a 7-bit register add a,h ;HL is the new seed ;A is the output, or AL for 16 bits.
Spoiler For Explanation:
Upon first inspection, that use of the R register might look like it is being used as a source of randomness, but it is in fact being used as a cheap counter. This leaves us in a very interesting position: If the R register happens to be random or chaotic in your use-case, then that is good! But if R just acts as a counter, then that is also good, because that is what the PRNG needs.
The basic trick is to combine a counter or LCG with an LFSR to smooth out the distribution of the LSFR. Since LSFRs are very fast, and R is a built-in counter on the Z80, we can combine them to make a very, very fast random number generator that is decent quality.
Now, there are some caveats. Due to the nature of the R register, this does not have a fixed cycle length. On average, it has a cycle length of 5592320 (meaning you could expect it to loop after every 5592320 numbers generated). The cycle length could be as low as 65535 (it is essentially just the LFSR), or as high as 8388480. If you wait for external input between calls, then you basically have a true RNG.
Spoiler For Images:
Here is a gif demonstration: Another good use-case is fire animation! (sorry for the poor quality gif, it's really a lot smoother IRL)
eZ80 8-bit RNG If HL is 24-bit, as in ADL mode on the eZ80, then your LFSR needs different taps (but in this case, it doesn't improve cycle length because we are still using H instead of UHL):
;HL must be non-zero add hl,hl sbc a,a and %10000111 xor l ld l,a ld a,r add a,a ;Because R is a 7-bit register add a,h ;HL is the new seed ;A is the output, or AL for 16 bits.
I have no idea what the speed is on the eZ80. 10 fetches, maybe?
Spoiler For Comparison Images:
this comparison might be a little easier to interpret: (LFSR only)
(combined with R as a counter)
8-bit RNG, 39cc Apparently even an 8-bit LFSR combined with the R register does a great job at generating noise, so here is an even faster version (faster for the Z80, though this code also works on the eZ80):
It has been a long time since I did 68k C and Assembly, but I thought that you could basically "include" a .bmp or .png or what-have-you. I know I can do that with the Z80 calcs and probably eZ80.
If so, I always opt for old-school MS Paint, or mtpaint on Linux.
I have two routines that I am proud of and thought they'd be useful! Binary Search Binary Search is an efficient way to search through sorted data. Regardless of the data, the core of the algorithm is the same, so I made a routine that is the core algorithm! All you have to do is pass a pointer to a routine in IX that compares two pieces of data
;Requires `call_ix` routine that looks like: ; call_ix: ; jp (ix) ; ;IX points to a comparison routine that takes as input: ; HL points to the input element to find ; DE is the element to compare to ;Outputs are: ; carry set if the HL element is less than the DE element ; carry reset if the HL element is greater than or equal to the DE element ; z set if the HL element is equal to the DE element ; nz set if the HL element is not equal to the DE element ; ;This is useful if you have a table of pointers to strings, and want to find a ;string in the array. See the end of this file for an example. ;
binarysearch: ;This is a general-purpose binary search routine. ; ;Inputs: ; BC is the element to find ; HL is the number of elements ; IX points to a callback routine that compares the input element ;Outputs: ; DE is the matching element index ; z means match found ; nz means no match ; In this case, DE is interpreted as where the match should have been ;Destroys: ; AF, DE ;RAM needed: ; 10 bytes of stack space (4 pushes and a call) ; ld de,-1 binarysearch_loop_inc_lower: inc de binarysearch_loop: push hl push de or a sbc hl,de jr z,binarysearch_nomatch rr h rr l add hl,de ld d,h ld e,l push hl ;test index push bc ;input ld h,b ld l,c call call_ix pop bc ;input jr nc,binarysearch_input_bigger_or_equal pop hl ;test index is the new upper index pop de ;restore the lower index pop af ;dummy pop jr binarysearch_loop
binarysearch_input_bigger_or_equal: pop de ;test index +1 is the new lower index pop hl ;dummy pop pop hl ;restore upper index jr nz,binarysearch_loop_inc_lower ;a match was found ;DE is left as the index ret
binarysearch_nomatch: pop de ;lower index pop hl ;upper index (also lower index and test index) or 1 ret
Heapsort Heapsort is a clever and efficient sorting algorithm. Much like the Binary Search routine above, you pass IX pointing to a routine that actually interprets your data, so this can work on even your weirdest data format. IX points to a routine that either swaps two elements, or compares two elements (based on carry flag passed in). NOTE: This also includes the heapify routine, used by heapsort. This might also be useful if you only need to arrange data into a heap structure, but don't need to sort.
; This routine requires the following subroutine: ; call_ix: ; jp (ix) ; ; To use SMC, define SMC. ; #define SMC ; ; If you are not using SMC, you'll need to define `arraylen` to point ;to 2 bytes of scrap RAM
heapsort: ;Inputs: ; BC is the size of the array. ; IX points to the routine that compares or swpas two entries ; HL is the index of the first element ; DE is the index of the second element ; c means swap ; nc means compare HL to DE ; Should return: ; z if they are equal ; nc if HL>=DE ; c if HL<DE ;Outputs: ; The data is sorted. ;Destroys: ; All ;Notes: ; You can make the comparison routine work any way that you want :) ; For example, you can invert the carry flag output to sort descending.
;If the array is size 0 or 1, then it is sorted inc b dec b jr nz,heapsort_heapify dec c ret z inc c ret z
heapsort_heapify: call heapify ld hl,(arraylen) heapsort_loop: dec hl ld (arraylen),hl push hl ;HL is the last element ld de,0 call heapsort_swap ld bc,1 call propogate pop hl ld a,h or l jr nz,heapsort_loop ret
heapify: ;Inputs: ; HL points to the array data ; BC is the size of the array. NOT GREATER THAN 32767 ; IX points to the routine that compares the values ld (arraylen),bc srl b rr c _: push bc call propogate pop bc dec bc ld a,b or c jr nz,-_ ret
propogate: ;BC-1 is the parent index ;2BC-1 is the child0 index ;2BC is the child1 index sla c rl b ld d,b ld e,c
sbc hl,de add hl,de ret c ;no children ;z means one child ;compare the two children ld h,b ld l,c dec hl ;HL is the child0 index ;DE is the child1 index call nz,heapsort_cmp jr nc,+_ ex de,hl _:
;parent is (HL+1)>>1 ;child is HL ld d,h ld e,l inc hl srl h rr l dec hl call heapsort_cmp ret nc call heapsort_swap
;values heapsort_swapped, now set parent=child+1 ld b,d ld c,e inc bc jr propogate
heapsort_swap: ;HL and DE are the indices of the elements to heapsort_swap push hl push de scf call call_ix pop de pop hl ret
heapsort_cmp: push hl push de or a call call_ix pop de pop hl ret
Necro Update! I rewrote the heapsort to be really general-purpose. This significantly reduced the size of ListSort and it made it so that it doesn't require any additional user RAM (but it did make it slightly slower).
I've attached the new heapsort.z80 and listsort.z80
But then I tailored the new heapsort to the task of sorting lists and made it even smaller (200 bytes, saving 157 bytes)! And it is faster, AND this version now uses 15MHz mode if available.
Which reminds me: In the original benchmarks, I was apparently comparing my 6MHz program to TI's 15MHz SortA(, so my program is actually over 50 times faster than TI's on a 999-element list.
7 years was a long time. I hope we won't have to wait 7 more years for another update. haha
Oh trust me you won't. You got any suggestions for new updates? If you do feel free to post them here. I'm a contributer to the project and I use this instead of Axe and Assembly.
Oof, I just recently got a new job and so far as I can tell, it's going to be taking up most of my programming time
I'm definitely glad I put it up on GitHub as that makes it much easier for other people like Nonstickatom to contribute.
As NSA ( ) said, if you find any bugs or have any requests that you would like to be considered, feel free to post in the forums (or GitHub)
It should start with 1-byte for the width, followed by 7 bytes of data. I imagine that you can technically edit the widths of the zStart font and then the large font would also technically be variable-width on the graph-screen (The OS's format is the same for both fonts, just all the large font chars have a width of 5).
How do you actually create ZStart fonts? I could never find a computer editor back in the days (there was none included with ZStart or it was missing?) and I liked ZStart fonts because they could be a different size than Omnicalc's.
Oh, zStart actually has a built-in font editor. The format is actually like the OS' internal format, which is sightly different from Omnicalc or BatLib font, but also slightly easier to access.