Giter Site home page Giter Site logo

zenv's Introduction

zenv - Forth for the ZX Spectrum

This project is a Forth environment for the ZX Spectrum.

screenshot of zenv in emulator

Community

IRC channel #zenv on OFTC.

Design

zenv implements most of the ANS Forth core words and some extension/alternative word sets.

zenv can be built with direct threading and tokenised direct threading (see tokenised variable in src/zenv.asm).


Copyright 2021-2024 (C) - Christopher Leonard, MIT Licence
https://github.com/veltas/zenv

zenv's People

Contributors

veltas avatar

Stargazers

Volodymyr Anokhin avatar Sylvain Glaize avatar Mikhail Koninin avatar  avatar Brad Howes avatar Kyle Mitchell avatar Tim Kersey avatar Pierre R. avatar Alessandro Iob avatar Job van der Zwan avatar Liam Proven avatar Pierre Nel avatar The <XHTMLBoy/> avatar Aleksandr Zhuravlev avatar Xavier Van de Woestyne avatar Sandalots avatar chad royal avatar koutsie avatar Steve Kemp avatar Steve Purcell avatar Michael Kohl avatar Ákos Kiss avatar 49fl avatar Anonymous Monk  avatar Barrett Otte avatar 谢宇恒 / Xie Yuheng avatar Fırat Salgür avatar Karlin Fox avatar Gary Renes avatar

Watchers

James Cloos avatar  avatar  avatar

Forkers

gutpuncher

zenv's Issues

`<const> ?` just says `ok` if `?` is undefined

Weirdly, <const> ? just says ok if ? is undefined, when it should say ??. In other situations ? rightly results in ??. There is probably something wrong with the interpreter or SFIND.

Optimize "DU<" with "U<"

Part of the "U<" code can be used in "DU<".
` HEADER du_less_than, "DU<", 0
du_less_than:
LD C, L
LD B, H
POP DE
POP HL
OR A
SBC HL, BC
JR Z, u_less_than.equal
JR common_less_than.not_equal

HEADER u_less_than, "U<", 0

u_less_than:
EX DE, HL
.equal:
POP HL
common_less_than:
OR A
SBC HL, DE
.not_equal:
LD HL, 0
JR NC, .exit
DEC HL
.exit: JP next
`

Small optimization of COMPARE

`; \ -1 if s1<s2, 1 if s1>s2, 0 if s1=s2
; CODE COMPARE ( a1 u1 a2 u2 -- n )
HEADER compare, "COMPARE", 0
compare:
LD C, L
LD B, H
POP DE
POP HL
PUSH HL
XOR A
SBC HL, BC
JR C, .u2_larger
JR Z, .u1_u2_equal
POP BC
INC A; A=1
JR .cont
.u1_u2_equal:
;A=0
INC A
.u2_larger:
DEC A ;A=-1
POP HL
.cont:
POP HL
PUSH AF
; HL = a1, DE = a2, BC = min(u1,u2)
LD A, C
OR B
JR Z, .skip_loop
.loop:
LD A, (DE)
INC DE
CPI
JR C, .s1_larger
JR NZ, .s2_larger
JP PE, .loop
.skip_loop:
POP AF
LD L, A
LD H, 0
JP next

.s1_larger:
LD HL, 1
JR .cont2

.s2_larger:
LD HL, -1
.cont2:
POP DE
JP next
`

Replace "create_code" with "swap"

I noticed that "create_code" and "swap" are equivalent.
`create_code:
POP DE
PUSH HL
EX DE, HL
JP next
...
swap:
EX (SP), HL
JP next

`
So we can replace "CALL create_code" with "CALL swap", and delete the fragment create_code. Also, "DW create_code" should be replaced by "DW swap".

Stack pointer moving: use low byte increment instead increment of word if stack is aligned

PSP and RS are (or can be done) aligned to even-address. Therefore, when fetching the first byte from the stack, we can write "INC R" instead of "INC RR" (R is low register in register pair RR). It does not reduce the length but reduces the time (for undocumented IX\IY too).
Unfortunately it gives a small gain in zenv: PUSH and POP use automatically 2 bytes at once, the threaded code pointer (IY) is unaligned, RS pointer IX uses indexing instead of increment\decrement.
Here are a few places where it can be applied:

colon_code:                       
   ; Push current PC to RS   
   DEC IX                    
   DEC IXL ; from odd-addr to even-addr                       
...
two_over:
   PUSH HL
   LD HL, 4
   ADD HL, SP
   LD E, (HL)
   INC L ; from even-addr to odd-addr
   LD D, (HL)
   INC HL
   LD C, (HL)
   INC L ; from even-addr to odd-addr
...
r_from:              
   PUSH HL      
   LD L, (IX+0) 
   LD H, (IX+1) 
   INC IXL ;  from even-addr to odd-addr       
   INC IX       
   JP next      
...
exit:               
   LD C, (IX+0)
   LD B, (IX+1)
   INC IXL ;  from even-addr to odd-addr       
   INC IX      
...
to_r:             
   DEC IX                    
   DEC IXL ; from odd-addr to even-addr       
...
pick:             
   ADD HL, HL
   ADD HL, SP
   LD E, (HL)
   INC L ; from even-addr to odd-addr

Remove "CALL colon_code" and "DX exit" from words that do not return control

Most high-level words have "CALL colon_code" and "DX exit" at the end. But there are words that do not return control. They are "WHAT?", "CWHAT?", "MAIN", "ABORT", "QUIT". They should not have "DX exit" at the bottom. In addition, we need to replace "CALL colon_code" with "CALL pop_pc_next" at the top of this words.

Another register allocation

Why does the system have such a register allocation (HL as top, IY as PC, IX as RS counter)?

Brad Rodriguez. MOVING FORTH recommends another register allocation for Z80. For example, HL is used as a work register:

HL is undoubtedly the most versatile register, and at one time or another it is tempting to use it for each of the Forth virtual registers. However, because of its versatility -- and because it is the only register which can be fetched byte-wise and used in an indirect jump -- HL should be used for W, Forth's all-purpose working register. (CASE STUDY 3: THE Z80)

In the paper the choice of registers is explained. Maybe the another register allocation could be more optimal?

Macro for asm-code inline

I suggest a macro ASM_INLINE ... END_INLINE to include asm-code into a DX-sequence:

	IF tokenised
		MACRO ASM_INLINE
	    		DB high($+2), low($+2)
		ENDM
	ELSE
		MACRO ASM_INLINE
	    		DW $+2	
		ENDM
	ENDIF

	MACRO END_INLINE
	    LD IY,$+7
	    JP next		
	ENDM

This macro can be placed into zenv.asm after MACRO HEADER, for example.

There are small Forth-words (few asm-instructions) but "JP next" is an expensive operation. Including code allows us to improve efficiency (by decreasing clarity, perhaps).
For example, let's use this macro in "DABS" (zenv.asm).

	; ( d -- |d|)    - in original zenv.asm incomplete comment "; ( d -- d)"
	; : DABS
	HEADER dabs, "DABS", 0
dabs:
	CALL colon_code
	; DUP 0< IF
	DX dup
	DX zero_less
	DX if_raw
	DB .then-$-1
         	; 0. 2SWAP D-
	      ASM_INLINE		
         	LD DE,0
         	POP BC
         	PUSH DE
         	PUSH DE
         	PUSH BC
	      END_INLINE
              	;( 0 d ) 		
	      DX d_minus 
	; THEN ;
.then:
	DX exit

Replace "POP HL \ JP next" to "JP pop_tos_next"

System has several "POP HL \ JP next" fragments. This can be replaced with "JP pop_tos_next". Jumping into center of an operation is a "dirty trick" of course, but it works!

pop_pc_next: 
;drop prefix to change POP IY (FD E1) into POP HL (E1) 
pop_tos_next=$+1 
	POP IY  
	; fall through

Add 16K build mode

Add build mode that supports running on a 16K model (or model with broken upper 32K RAM).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.