diff --git a/Source/HBIOS/Build.ps1 b/Source/HBIOS/Build.ps1 index 84e0b717..716caf7d 100644 --- a/Source/HBIOS/Build.ps1 +++ b/Source/HBIOS/Build.ps1 @@ -163,6 +163,7 @@ Copy-Item '..\zsdos\zsdos.bin' 'zsdos.bin' Asm 'dbgmon' Asm 'prefix' Asm 'romldr' +Asm 'eastaegg' Asm 'nascom' Asm 'tastybasic' Asm 'imgpad' @@ -189,7 +190,7 @@ Concat 'prefix.bin','cpm.bin' 'cpm.sys' Concat 'prefix.bin','zsys.bin' 'zsys.sys' # Build 32K OS chunk containing the loader, debug monitor, and OS images -Concat 'romldr.bin', 'dbgmon.bin','cpm.bin','zsys.bin', 'imgpad.bin' osimg.bin +Concat 'romldr.bin', 'dbgmon.bin','cpm.bin','zsys.bin', 'eastaegg.bin', 'imgpad.bin' osimg.bin Concat 'nascom.bin', 'tastybasic.bin', 'imgpad0.bin' osimg1.bin # diff --git a/Source/HBIOS/eastaegg.asm b/Source/HBIOS/eastaegg.asm new file mode 100644 index 00000000..24744f11 --- /dev/null +++ b/Source/HBIOS/eastaegg.asm @@ -0,0 +1,300 @@ +; Adapted from https://rosettacode.org/wiki/Mandelbrot_set#Z80_Assembly +; by Phillip Summers difficultylevelhigh@gmail.com +; +; WBWROM SBV V2 Easteregg +; +; Compute a Mandelbrot set on a simple Z80 computer. +; +; Porting this program to another Z80 platform should be easy and straight- +; forward: The only dependencies on my homebrew machine are the system-calls +; used to print strings and characters. These calls are performed by loading +; IX with the number of the system-call and performing an RST 08. To port this +; program to another operating system just replace these system-calls with +; the appropriate versions. Only three system-calls are used in the following: +; _crlf: Prints a CR/LF, _puts: Prints a 0-terminated string (the adress of +; which is expected in HL), and _putc: Print a single character which is +; expected in A. RST 0 give control back to the monitor. +; +#include "std.asm" + +cr .equ 0dh +lf .equ 0ah +eos .equ 00h + + .org EGG_LOC + +scale .equ 256 ; Do NOT change this - the + ; arithmetic routines rely on + ; this scaling factor! :-) +divergent .equ scale * 4 + + ld sp,0fdffh + ld hl, welcome ; Print a welcome message + call _puts + +; for (y = ; y <= y_end; y += y_step) +; { +outer_loop ld hl, (y_end) ; Is y <= y_end? + ld de, (y) + and a ; Clear carry + sbc hl, de ; Perform the comparison + jp m, mandel_end ; End of outer loop reached + +; for (x = x_start; x <= x_end; x += x_step) +; { + ld hl, (x_start) ; x = x_start + ld (x), hl +inner_loop ld hl, (x_end) ; Is x <= x_end? + ld de, (x) + and a + sbc hl, de + jp m, inner_loop_end ; End of inner loop reached + +; z_0 = z_1 = 0; + ld hl, 0 + ld (z_0), hl + ld (z_1), hl + +; for (iteration = iteration_max; iteration; iteration--) +; { + ld a, (iteration_max) + ld b, a +iteration_loop push bc ; iteration -> stack +; z2 = (z_0 * z_0 - z_1 * z_1) / SCALE; + ld de, (z_1) ; Compute DE HL = z_1 * z_1 + ld b,d + ld c,e + + call mul_16 + ld (z_0_square_low), hl ; z_0 ** 2 is needed later again + ld (z_0_square_high), de + + ld de, (z_0) ; Compute DE HL = z_0 * z_0 + ld b,d + ld c,e + + call mul_16 + ld (z_1_square_low), hl ; z_1 ** 2 will be also needed + ld (z_1_square_high), de + + and a ; Compute subtraction + ld bc, (z_0_square_low) + sbc hl, bc + ld (scratch_0), hl ; Save lower 16 bit of result + ld h,d + ld l,e + ld bc, (z_0_square_high) + sbc hl, bc + ld bc, (scratch_0) ; HL BC = z_0 ** 2 - z_1 ** 2 + + ld c, b ; Divide by scale = 256 + ld b, l ; Discard the rest + push bc ; We need BC later + +; z3 = 2 * z0 * z1 / SCALE; + ld hl, (z_0) ; Compute DE HL = 2 * z_0 * z_1 + add hl, hl + ld d,h + ld e,l + ld bc, (z_1) + call mul_16 + + ld b, e ; Divide by scale (= 256) + ld c, h ; BC contains now z_3 + +; z1 = z3 + y; + ld hl, (y) + add hl, bc + ld (z_1), hl + +; z_0 = z_2 + x; + pop bc ; Here BC is needed again :-) + ld hl, (x) + add hl, bc + ld (z_0), hl + +; if (z0 * z0 / SCALE + z1 * z1 / SCALE > 4 * SCALE) + ld hl, (z_0_square_low) ; Use the squares computed + ld de, (z_1_square_low) ; above + add hl, de + + ld b,h ; BC contains lower word of sum + ld c,l + + ld hl, (z_0_square_high) + ld de, (z_1_square_high) + adc hl, de + + ld h, l ; HL now contains (z_0 ** 2 + + ld l, b ; z_1 ** 2) / scale + + ld bc, divergent + and a + sbc hl, bc + +; break; + jp c, iteration_dec ; No break + pop bc ; Get latest iteration counter + jr iteration_end ; Exit loop + +; iteration++; +iteration_dec pop bc ; Get iteration counter + djnz iteration_loop ; We might fall through! +; } +iteration_end +; printf("%c", display[iteration % 7]); + ld a, b + and $7 ; lower three bits only (c = 0) + sbc hl, hl + ld l, a + ld de, display ; Get start of character array + add hl, de ; address and load the + ld a, (hl) ; character to be printed + call _putc ; Print the character + + ld de, (x_step) ; x += x_step + ld hl, (x) + add hl, de + ld (x), hl + + jp inner_loop +; } +; printf("\n"); +inner_loop_end call _putcrlf ; Print a CR/LF pair + + ld de, (y_step) ; y += y_step + ld hl, (y) + add hl, de + ld (y), hl ; Store new y-value + + jp outer_loop +; } + +mandel_end ld hl, finished ; Print finished-message + call _puts + ; GET CONSOLE INPUT STATUS VIA HBIOS +waitch LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C + LD B,BF_CIOIST ; HBIOS FUNC: INPUT STATUS + RST 08 ; HBIOS RETURNS STATUS IN A + ; RESTORE REGISTERS (AF IS OUTPUT) + JR Z,waitch + ; Return to the loader + LD A,BID_BOOT ; BOOT BANK + LD HL,0 ; ADDRESS ZERO + CALL HB_BNKCALL ; DOES NOT RETURN + HALT + +_putcrlf ld hl, crlf +_puts push af +puts0 ld a,(hl) + cp eos + jr z,puts1 + call _putc + inc hl + jr puts0 +puts1 pop af + ret + +_putc PUSH AF + PUSH BC + PUSH DE + PUSH HL + LD E,A ; OUTPUT CHAR TO E + LD C,CIODEV_CONSOLE; CONSOLE UNIT TO C + LD B,BF_CIOOUT ; HBIOS FUNC: OUTPUT CHAR + RST 08 ; HBIOS OUTPUTS CHARACTDR + POP HL + POP DE + POP BC + POP AF + RET + +welcome .db "Generating a Mandelbrot set" + .db cr, lf, eos +finished .db "Computation finished." +crlf .db cr, lf, eos + +iteration_max .db 10 ; How many iterations +x .dw 0 ; x-coordinate +x_start .dw -2 * scale ; Minimum x-coordinate +x_end .dw 5 * scale / 10 ; Maximum x-coordinate +x_step .dw 4 * scale / 100 ; x-coordinate step-width +y .dw -1 * scale ; Minimum y-coordinate +y_end .dw 1 * scale ; Maximum y-coordinate +y_step .dw 1 * scale / 10 ; y-coordinate step-width +z_0 .dw 0 ;0 +z_1 .dw 0 ;0 +scratch_0 .dw 0 +z_0_square_high .dw 0 +z_0_square_low .dw 0 +z_1_square_high .dw 0 +z_1_square_low .dw 0 +display .db " .-+*=#@" ; 8 characters for the display + +; +; Compute DEHL = BC * DE (signed): This routine is not too clever but it +; works. It is based on a standard 16-by-16 multiplication routine for unsigned +; integers. At the beginning the sign of the result is determined based on the +; signs of the operands which are negated if necessary. Then the unsigned +; multiplication takes place, followed by negating the result if necessary. +; +mul_16 xor a ; Clear carry and A (-> +) + bit 7, b ; Is BC negative? + jr z, bc_positive ; No + sub c ; A is still zero, complement + ld c, a + ld a, 0 + sbc a, b + ld b, a + scf ; Set carry (-> -) +bc_positive bit 7, D ; Is DE negative? + jr z, de_positive ; No + push af ; Remember carry for later! + xor a + sub e + ld e, a + ld a, 0 + sbc a, d + ld d, a + pop af ; Restore carry for complement + ccf ; Complement Carry (-> +/-?) +de_positive push af ; Remember state of carry + and a ; Start multiplication + sbc hl, hl + ld a, 16 ; 16 rounds +mul_16_loop add hl, hl + rl e + rl d + jr nc, mul_16_exit + add hl, bc + jr nc, mul_16_exit + inc de +mul_16_exit dec a + jr nz, mul_16_loop + pop af ; Restore carry from beginning + ret nc ; No sign inversion necessary + xor a ; Complement DE HL + sub l + ld l, a + ld a, 0 + sbc a, h + ld h, a + ld a, 0 + sbc a, e + ld e, a + ld a, 0 + sbc a, d + ld d, a + ret + +lastbyte .equ $ + +SLACK .EQU (EGG_END - lastbyte) + .FILL SLACK,'e' +; + .ECHO "EASTEREGG space remaining: " + .ECHO SLACK + .ECHO " bytes.\n" + + .end + \ No newline at end of file diff --git a/Source/HBIOS/imgpad.asm b/Source/HBIOS/imgpad.asm index 972ba3b9..3846a294 100644 --- a/Source/HBIOS/imgpad.asm +++ b/Source/HBIOS/imgpad.asm @@ -1,6 +1,6 @@ #INCLUDE "std.asm" ; -SLACK .EQU ($8000-LDR_SIZ-MON_SIZ-SYS_SIZ-SYS_SIZ) +SLACK .EQU ($8000-LDR_SIZ-MON_SIZ-SYS_SIZ-SYS_SIZ-EGG_SIZ) .FILL SLACK,00H ; MON_STACK .EQU $ diff --git a/Source/HBIOS/romldr.asm b/Source/HBIOS/romldr.asm index fcbf8748..175bc4fc 100644 --- a/Source/HBIOS/romldr.asm +++ b/Source/HBIOS/romldr.asm @@ -13,6 +13,7 @@ MONIMG .EQU $0A00 ;SIZE 1000 > 0A00-1A00 CPMIMG .EQU $1A00 ;SIZE 3000 > 1A00-4A00 ZSYSIMG .EQU $4A00 ;SIZE 3000 > 4A00-7A00 +EGGIMG .EQU $7A00 ;SIZE 0200 > 7A00-7C00 ; ; osimg1.bin ; @@ -20,22 +21,6 @@ BASIMG .EQU $0000 ;SIZE 2000 > 0000-2000 TBCIMG .EQU $2000 ;SIZE 0900 > 2000-2900 ; INT_IM1 .EQU $FF00 -; -;---------------------------------------------------------- -; NAME NAME OF ROM 8 CHAR -; BANK WHICH ROM BANK THE IMAGE IS IN. -; IMAGE LOCATION OF IMAGE IN 32K ROM BANK. -; LOCATION WHERE IMAGE NEEDS TO BE COPIED TO IN RAM. -; EXECUTE ADDRESS TO START EXECUTING. -; - -;ROMTBL .DB "B","BASIC $", 0, BASIMG, BAS_LOC, BAS_SIZ, BASE_LOC -; .DB "C","CP/M $", 0, -; .DB "F","FORTH $", 1, -; .DB "Z","ZSYSTEM$", 1, -; -; -; .DB "MONITOR$", 0, ; .ORG 0 @@ -176,6 +161,8 @@ DB_BOOTLOOP: JP Z,GOBASIC CP 'C' ; CP/M BOOT FROM ROM JP Z,GOCPM + CP 'E' ; CP/M BOOT FROM ROM + JP Z,GOEASTA CP 'M' ; MONITOR JP Z,GOMONSER ; CP 'L' ; LIST DRIVES @@ -238,6 +225,8 @@ DB_DSKYEND: JP Z,GOBASIC CP 'C' ; CP/M BOOT FROM ROM JP Z,GOCPM + CP 'E' ; CP/M BOOT FROM ROM + JP Z,GOEASTA CP 'M' ; MONITOR JP Z,GOMONSER ; CP 'L' ; LIST DRIVES @@ -283,7 +272,7 @@ GOBASIC: LD HL,BAS_LOC JP CHAIN -; LD HL,BAS_LOC +; LD HL,BAS_LOC ; FIRST BANK CODE ; PUSH HL ; LD DE,STR_BOOTBAS ; DE POINTS TO MESSAGE ; CALL WRITESTR ; WRITE IT TO CONSOLE @@ -293,7 +282,21 @@ GOBASIC: ; LD BC,BAS_SIZ ; BC := BASIC SIZE ; LDIR ; COPY BASIC CODE TO EXEC ADDRESS ; POP HL ; RECOVER ENTRY ADDRESS -; JR CHAIN ; AND CHAIN TO IT +; JR CHAIN ; AND CHAIN TO IT + +GOEASTA: + + LD HL,EGG_LOC + PUSH HL + LD DE,STR_LAUNCH ; DE POINTS TO MESSAGE + CALL WRITESTR ; WRITE IT TO CONSOLE + ; COPY IMAGE TO EXEC ADDRESS + LD HL,EGGIMG ; HL := BASIC IMAGE ADDRESS + LD DE,EGG_LOC ; DE := BASIC EXEC ADDRESS + LD BC,EGG_SIZ ; BC := BASIC SIZE + LDIR ; COPY BASIC CODE TO EXEC ADDRESS + POP HL ; RECOVER ENTRY ADDRESS + JR CHAIN ; AND CHAIN TO IT GOTBAS: LD DE,STR_BOOTTBC ; DE POINTS TO MESSAGE @@ -315,7 +318,7 @@ GOTBAS: LD HL,TBC_LOC JP CHAIN -; LD HL,TBC_LOC +; LD HL,TBC_LOC ; FIRST BANK CODE ; PUSH HL ; LD DE,STR_BOOTTBC ; DE POINTS TO MESSAGE ; CALL WRITESTR ; WRITE IT TO CONSOLE diff --git a/Source/HBIOS/std.asm b/Source/HBIOS/std.asm index f37325b8..8b388074 100644 --- a/Source/HBIOS/std.asm +++ b/Source/HBIOS/std.asm @@ -378,6 +378,10 @@ TBC_LOC .EQU $0A00 ; TASTYBASIC TBC_SIZ .EQU $0900 TBC_END .EQU TBC_LOC + TBC_SIZ +EGG_LOC .EQU $0A00 ; EASTER EGG +EGG_SIZ .EQU $0200 +EGG_END .EQU EGG_LOC + EGG_SIZ + MON_DSKY .EQU MON_LOC + (0 * 3) ; MONITOR ENTRY (DSKY) MON_SERIAL .EQU MON_LOC + (1 * 3) ; MONITOR ENTRY (SERIAL PORT) ;