CPCWiki forum

General Category => Programming => Topic started by: zhulien on 17:54, 12 February 25

Title: Julian's Long List of Ideas Thread
Post by: zhulien on 17:54, 12 February 25
Hi,

I figured I will start this thread and try keep my ideas in here, up to you if you want to ignore them or read them.

:D
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 17:59, 12 February 25
- UNIDOS Stream ROM - in progress, proven some cool things can be done to extend BASIC, coded in Z80
 

This ideas was to create an easy way of exposing drivers or other functionality to BASIC in a way that BASIC only has to read/write to them like files.  As of now, in a POC state, proves the idea works.

https://github.com/PrimalNinja/Streamer
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:01, 12 February 25
- 8bitology API and SDK: for in-game lobby, messaging, achievements (mostly running and live at 8bitology.net), coded in JS and PHP

This idea is to provide internet functions for CPC, sort of like a proxy.  The API is available and running now, the status of it is documented in the AIP Ref section of the website

http://8bitology.net/
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:02, 12 February 25
- 8BML browser to bring web browsing to CPC, protocol and SDK already available for years at 8bitology.net as well as logic for the browser (not yet coded on CPC), coded in JS and PHP

The SDK and protocol is documented and working now for some years, I didn't yet create a real 8BML client yet though.  There is documentation on the website.

http://8bitology.net/
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:22, 12 February 25
- Virtual Display Units (VDU) for CPC API: been online for ages, please someone put support for it in your game and / or utilities - it gives CPC software the ability to display stuff on any of your old redundant displays laying around that may include a web browser: Wii, PS4, Xbox One, PC, Android Phones/Tablets, iPhones/iPads and smart TVs - an unlimited number of them!!! graphics can be added, we could put sound if wanted but it isn't there yet. display debug info in there when you are programming, run-time game comentary for anyone in the World to view... it's sort of a BETA but been online for years now, coded in JS and PHP

A POC is here.

http://8bitology.net/poc/vdu/

Documentation currently as follows: ( previously posted here: https://www.cpcwiki.eu/forum/programming/unlimited-number-of-networked-displays-api-for-m4-and-other-connected-devices/ )

I have created the first working version of my networked display API.  There is very little left to do to make it useful, then it can only get more useful from then as I add further commands to the API.


What is it?


Imagine you have all these old devices laying around your place, some useless old phones, tablets, smart TVs, PS3s, Wiis, PCs etc... or you just want some extra screen real-estate... so you stick them all on your desk and wall near your CPC... or you want to display information for the World to watch... status information?  debug information? etc...


You can now do that from your CPC.  With an unlimited number of networked screens for your game or application, with CPC-style Windows support too.  And they generally update at 10 frames per second from the server - almost suitable for real-time internet games!!!


How does it work?


First setup a channel.  You need a private channel GUID (or code) that no-one else knows.  It shouldn't be told to anyone as it is what gives you permissions to update the screens and windows within your channel.  You can give your channel a unique public name though which everyone can know - of course you can even create a private channel that is not known to anyone but yourself (and set it visible later if you like, or never - don't put really private stuff in there though, as there is no HTTPS for now on CPC is there).  This private channel GUID should really be read from a central config file on your SDCard so that all your games and apps can use your channel.


Second setup a screen, or as many screens as you need.  These screens you would normally create dynamically when your game or application starts - afterall, if you have a bunch of CPCs that you all use your channel, you don't want them all writing to the same screen do you?  But you can also have as many screens for your one game or application as you like - a status screen?  a debug screen?  a 24bit graphics screen?  All updated in realtime from your CPC to the rest of the World and your other devices.


Thirdly (optionally) setup some Windows, CPC style on your screens.  These are just labelled regions of your screen which you can use relative locating and printing to...


Fourthly, do something on your screen.  Locate, Print, clear the screen... more to come...  The screens are not static, they are 100% dynamically updated over the internet as fast as your internet connection allows on your display devices - but i have capped it at 10fps for now.


Lastly...  Connect your devices!  Yep, you can go to the channel index, or directly to your own channel to see all your screens.  Alternatively you can even bookmark a specific screen if you know the code (it should be dynamic, but depends how you choose to use them).


Commands for the POC environment:


NOTE: All the below examples, prefix with the following:  http://8bitology.net/poc/vdu/vdu.php (http://8bitology.net/poc/vdu/vdu.php)


newchannel:


?function=channel&cmd=newchannel&ownerguid=<your private channel guid>&channel=<your public channel name>&description=<a text description of your channel>
eg: ?function=channel&cmd=newchannel&ownerguid=ABCD&channel=batman&description=I%20really%20am%20Batman


newscreen:



?function=screen&cmd=newscreen&owner=<your private channel guid>&ownerguid=<your private screen GUID>&publicguid=<your public screen guid>
eg: ?function=screen&cmd=newscreen&owner=ABCD&ownerguid=XYZ&publicguid=batmask


newwindow:



?function=window&cmd=newwindow&screen=<your private screen guid>&window=<your windowcode>&x=<x position>&y=<y position>&w=<width>&h=<height>
eg: ?function=window&cmd=newwindow&screen=XYZ&window=1&x=1&y=10&w=40&h=5


locate:


?function=window&cmd=locate&screen=<your private screen guid>&window=<your windowcode>&x=<x position>&y=<y position>
eg: ?function=window&cmd=locate&screen=XYZ&window=1&x=15&y=1


print:


?function=window&cmd=print&screen=<your private screen guid>&window=<your windowcode>&text=<the text to print>
eg: ?function=window&cmd=print&screen=XYZ&window=1&text=I am Batman!


Channel Index:  http://8bitology.net/poc/vdu/ (http://8bitology.net/poc/vdu/)


Internet Call Demo: http://8bitology.net/poc/framework/itpdemo.htm (http://8bitology.net/poc/framework/itpdemo.htm)


Sprite Demo: http://8bitology.net/poc/framework/spritedemo.htm (http://8bitology.net/poc/framework/spritedemo.htm) (yep, I have coded sprites too but not yet collision detection).  These sprites will soon be in the networked display and more.



optional &tag=<tag> can now be added to all window functions.


What this allows is eg: you setup a display, you can simply update a tagged function in-place with a single call instead of having to re-create the display.


Some uses:


You can put a score somewhere with print given a tag of score (?function=window&cmd=print&screen=XYZ&window=1&tag=score&text=0).  You can then just update the score by issuing a replacement command for that specific tag (?function=window&cmd=print&screen=XYZ&window=1&tag=score&text=100).



You can put something somewhere on the screen and locate with a tag such as position (?function=window&cmd=locate&screen=XYZ&window=1&tag=position&x=1&y=1).  You can then just update the position by issuing a replacement command for that specific tag (?function=window&cmd=locate&screen=XYZ&window=1&tag=position&x=1&y=2).  Repeat this and it animates.


Anyone think this is useful enought to continue with?
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:23, 12 February 25
- JSASM (proven) the dev environment can work, translator to z80 is not started, coded in JS*

* I was thinking of making my VB6 cross compiler and JS cross compiler all share the same code generator in the end... but if anyone is to use them but me, input is most welcome...

https://www.cpcwiki.eu/forum/programming/jsasm-js-virtual-assembler/
https://github.com/PrimalNinja/jsasm

Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:24, 12 February 25
- Visual BASIC 6 (very large subset) cross compiler for CPC, and it can correctly parse itself - the code generator is unfinished, coded in VB5/VB6 (either work) *

Visual BASIC cross compiler, not completed but you can see where it's going and it can compile itself

https://github.com/PrimalNinja/vbcc
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:26, 12 February 25
- JavaScript (subset) cross compiler for CPC, and it can correctly parse itself - the code generator is unfinished, coded in JS (cannot compile itself) *

https://github.com/PrimalNinja/jscc

more of a POC at the moment, I have now some other ideas relating to this.

https://youtube.com/video/q8kBgWHT944
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:31, 12 February 25
- I created a POC of virtual Z80s as a webservice where you can prepare a memory model and have it execute code and return a response.  The POC is no longer online and was based on an open source GB Z80 (missing some typical Z80 instructions).

Any use? You could make a cluster of 1000s of them in AWS.

https://www.cpcwiki.eu/forum/programming/z80-clusters/

note: I did get a 2nd CPLink card so multiple can run at once in the same CPC too - the goal of this is related to the virtual Z80 in the cloud.  If I can finalise the API to work with 2, then it can also be 4 (across to a 2nd wifi connected CPC) or more (to the cloud) via a single API.

btw, EVERYONE please get yourself a CPC-CPLINK card or two!!!    https://www.cpcwiki.eu/forum/amstrad-cpc-hardware/cpc-cplink-a-coprocessor-interface-card-for-all-cpcs
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:35, 12 February 25
- Stack Programming.

I am planning to code a better demonstration of highly performant Z80 code.  I've been brainstorming a BASIC compiler to 'optionally' generate this code too so both typical code and stack based code can be directly compared.  Likely a subset of Locomotive BASIC - which relates to my JSCC ideas above - why not allow subsets of JS, Locomotive BASIC and C all compile to the same source.

https://www.cpcwiki.eu/forum/programming/stack-programming/msg245465
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:37, 12 February 25
- PrimalOS: let's call it early alpha is there in github, to allow multiple computers to run the same software - in itially text-only, but... not limited to that if you don't mind breaking compatability... it's not that complex like FutureOS or Symbos... but also at this moment not so important, coded in Z80

https://docs.google.com/spreadsheets/d/14JQa3cTEd9fIz9lyoQRkzVc5xBz5FhEdr_DC41xPkJs/edit
https://github.com/PrimalNinja/Primal

Still more to do, I did a minor update late last year so it is a work in progress I plan to finish.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:41, 12 February 25
- MCP / MOS - Multitasking mini kernel for AMSDOS drivers, proven and working but doesn't do a lot yet - perhaps this can share drivers with PrimalOS? feedback welcome, coded in Z80

https://drive.google.com/drive/folders/1Xvirgaep8dHFQUSaQxa5aQRV_SIbAfbR

What I think is cool is the current POC code there (you can build the ROM and play) allows you to run code in the background, even reset the CPC and have it optionally resume.

Why? Before the advent of M4 cards and such where we can store autoexecs on the SDCARD, there was no way to resume something...

I'd love to work with someone in the CPC World on a driver standard if they don't like what I've done so far.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:43, 12 February 25
- Locomotive Shell ROM - in progress, proven a custom shell based on BASIC is very viable, the plan could be to integrate MOS with Primal compatible drivers and design a very nice user experience as an alternative to BASIC, coded in Z80

and

- Locomotive BASIC 2 ROM - in progress, proven the language can be extended, and likely in a backward compatible way (at least to a high percentage) with current BASIC, coded in Z80

These are very closely related - they are new replacements for the existing Locomotive BASIC based on Bread80s ROM disassembly.

https://www.cpcwiki.eu/forum/programming/extending-locomotive-basic

Very interesting results and if anyone wants it put online to continue working on it, happy to do so.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:48, 12 February 25
- My first hardware project (beyond simple switches and piggybacked ROMs), I guess a bit dead in the water after having obtained all the parts necessary.  Although I have lots of research suggesting it is possible to use a standard Pi to behave as a CPU, whether the timings can be tight enough for a CPC hardware expansion are uncertain still.  Lots of docs here and maybe Pi 5 is now faster enough?  CPLink gives an awesome "different" way to give some features in software, that is proven!

https://www.cpcwiki.eu/forum/amstrad-cpc-hardware/cpc-raspberry-pi-bridge-card/
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:50, 12 February 25
- Network Card driver for a game I am making, game is mostly designed but I am having difficulty developing it for now when I don't have a usable monitor for my CPC where I live.  The driver will be coded in Z80 (and work with 2 CPC network cards), game details will be anounced when I get the driver working.

yes, I failed to do simple data transfers in both the M4 as well as they Cyboard.  Grrr

If I can resolve that, I can then create a ROM that gives an 8bitology API RSX set and examples in assembly for using it in games.  Also if included in MCP ROM above, then we can simply send and receive messages between CPC users via CPC Basic RSXs.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:51, 12 February 25
- CPC online multiplayer games, server-side POC already up and running, prove that we can design a game together, coded in JS and PHP

Server Side has been online for ages, can't find the thread now in the forums - but the Network Card code I need working first before I can make a real CPC talk to it.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:52, 12 February 25
- Web based development environment with source control, modules and more (I think it's somewhat cool), coded in Z80 - would be more useful when the JavaScript cross compiler is more working... but can work with Z80 now if people wanted it to, just still thinking of the features to expose, coded in JS and PHP (this is the only somewhat closed source project of them all - but it could turn into the World's best dev environment - or not)

This is currently working but not currently public.  Debating whether it's worth to extend this to allow for an online dev environment for CPC (and other platforms).
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:59, 12 February 25
- Web based environment for new SlaveOS.  I am debating using the Web based development environment above vs a fresh open source minimal for this... mainly because the environment already has a document repo and ESB (enterprise service bus) built in.

Imagine you code an implementation of SlaveOS for your Commodore 64 (Blah 64) and your Amstrad CPC (Blah CPC).  Could just be a ROM on CPC you type |iamslave,"BLAHCPC","PUBLIC" or |iamslave,"BLAHCPC","PRIVATE" <-- CPC displays a code, or QRCode or 2D barcode

what it would do is connect to the server, and say, hey, I have speech synthesizer capability and AY-8-8912 music file playback capability and text output.  Or a C64 might say I have SID playback capability and text output.

Another program, on another computer that isn't a slave, can connect to the server and say, hey, what slaves are available for me?  SID Playback on Blah 64, text output on Blah 64, AY-3-8912 playback on Blah CPC, text output on Blah CPC.  This 'another' computer could be another CPC, C64, Smart Phone, PC or whatever anywhere around the World.  Any capabilities can be published and subscribed to and... our beloved old computers can joing the IOT World.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 19:10, 12 February 25
SlaveOS API

|iamslave,"BLAHCPC","PUBLIC" or "PRIVATE", the computer becomes a slave, either publshing a set of services from a local config file, or maybe a 2nd parameter to the RSX

|slaves, would ask the server to list all slaves
|slaves,"AY-3-8912", would ask for a list of all slaves with SID playback
|slave,"BLAHCPC" would list all services on BLAHCPC
|order,"BLAHCPC"," AY-3-8912 ",<sidfile> would send the server the AY-3-8912 file for BLAHCPC to play


Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 22:34, 12 February 25
Quote from: zhulien on 18:35, 12 February 25- Stack Programming.


Here is an example if someone wants to fill in the fast print char function (remember: don't use call or push).  and... the mode command, or just change the kw_mode to kw_cls

I put my hand coded example in the comments too, the purpose is not to create the most optimal assembly language program - that is likely by hand but... interestingly depending on some factors the stack programming can actually be faster AND smaller than the hand coded.

** if a program spends more time calling keywords in a function than calling functions, then the stack programming approach is positive **

but the goal is... to see how well potentially compiled code can be.  I am aware I can generate better examples of compiled code too with the keywords provided, just trying to think how a simple compiler might execute without much optimisation.  such as jumping over the loop to return is slower than a return_iftrue...


;restrictions
; interrupts must be disabled
; don't use call or push

;prefix key
; fn = subroutine called via kw_gosub, returned via kw_return
; kw = keyword statement, ends in any ret

;keywords implemented:

;flow control:
; kw_gosub, <label>
; kw_gosub_iftrue, <label>
; kw_gosub_iffalse, <label>
; kw_goto, <label>
; kw_goto_iftrue, <label>
; kw_goto_iffalse, <label>
; kw_return
; kw_return_iftrue
; kw_return_iffalse
; kw_stop

;logic:
; kw_dec8, <label>
; kw_dec16, <label>
; kw_inc8, <label>
; kw_inc16, <label>
; kw_iszero8, <label>
; kw_iszero16, <label>
; kw_let8, <label>, <value>
; kw_let16, <label>, <value>

;other:
; kw_cls
; kw_locate, <x>, <y>
; kw_mode, <n>
; kw_print, <stringaddr>

; ==============================================================================

; setup code

org #100

di
ld sp, main
ret

; ==============================================================================

; 10  gosub 30
; 20  stop

; 30  mode 1
; 40  for counter = 1 to 5
; 50    print "Hello"
; 60    print "Goodbye"
; 70    print "Hello"
; 80    print "Goodbye"
; 90    print "Hello"
; 100   print "Goodbye"
; 110   print "Hello"
; 120   print "Goodbye"
; 130 next counter
; 140 return

; typical handcoded:
;
; main:
; call fn_printscreen ; 3 bytes, 5 nops
; ret ; 1 byte, 3 nops
;
; fn_printscreen:
; ld a, 1 ; 2 bytes, 2 nops
; call kw_mode ; 3 bytes, 5+3 nops
;
; ld b, 5 ; 2 bytes, 2 nops
; fn_printscreen1:
; push bc ; 1 byte, 4 nops

; ld hl, msg_hello ; 3 bytes, 3 nops
; call kw_print ; 3 bytes, 5+3 nops
; ld hl, msg_goodbye ; 3 bytes, 3 nops
; call kw_print ; 3 bytes, 5+3 nops
; ld hl, msg_hello ; 3 bytes, 3 nops
; call kw_print ; 3 bytes, 5+3 nops
; ld hl, msg_goodbye ; 3 bytes, 3 nops
; call kw_print ; 3 bytes, 5+3 nops
; ld hl, msg_hello ; 3 bytes, 3 nops
; call kw_print ; 3 bytes, 5+3 nops
; ld hl, msg_goodbye ; 3 bytes, 3 nops
; call kw_print ; 3 bytes, 5+3 nops
; ld hl, msg_hello ; 3 bytes, 3 nops
; call kw_print ; 3 bytes, 5+3 nops
; ld hl, msg_goodbye ; 3 bytes, 3 nops
; call kw_print ; 3 bytes, 5+3 nops loopwork: 48 bytes, 88 nops x 5 = 440 nops

; pop bc ; 1 byte, 4 nops
; djnz fn_printscreen1 ; 3 bytes, 5 nops work: 5 bytes, 13 nops x 5 = 65 nops

; ret ; 1 byte, 3 nops
; ; total 65 bytes, 528 nops (caters for the 5 iterations)

main:
dw kw_gosub, fn_printscreen ; 10, 2 words, ? nops
dw kw_stop ; 20, 1 word, 3 nops

fn_printscreen: ; 30
dw kw_mode, 1 ; 30, 2 words, 3 nops
dw kw_let8, var_counter, 5 ; 40, 3 words, 3 nops

fn_printscreen1: ; 40
dw kw_iszero8, var_counter, kw_goto_iftrue, fn_printscreen2 ; 40, 4 words, 6 nops
dw kw_print, msg_hello ; 50, 2 words, 3 nops
dw kw_print, msg_goodbye ; 60, 2 words, 3 nops
dw kw_print, msg_hello ; 70, 2 words, 3 nops
dw kw_print, msg_goodbye ; 80, 2 words, 3 nops
dw kw_print, msg_hello ; 90, 2 words, 3 nops
dw kw_print, msg_goodbye ; 100, 2 words, 3 nops
dw kw_print, msg_hello ; 110, 2 words, 3 nops
dw kw_print, msg_goodbye ; 120, 2 words, 3 nops loopwork: 8 words (16 bytes), 24 nops x 5 = 120 nops
dw kw_dec8, var_counter, kw_goto, fn_printscreen1 ; 130, 4 words, 6 nops loop: 8 words (16 bytes), 12 nops x 5 = 60 nops

fn_printscreen2: ; 40

dw kw_return ; 140, 1 word, ? nops
; total 33 words (66 bytes), 189+ nops (caters for the 5 iterations)

; ------------------------------------------------------------------------------

var_counter: db 0

msg_hello: db "Hello", 0
msg_goodbye: db "Goodbye", 0

; ==============================================================================

kw_gosub:
pop bc ; where do we want to go, pop it first as we want
; the next statement upon kw_return

ld hl, 0 ; hl = hsp
add hl, sp

ld de,(ssp) ; de = ssp
ex de, hl ; hl = ssp, de = hsp

ld (hl), e ; push hsp on the ssp
dec hl ;
ld (hl), d ;
dec  hl ;

ld (ssp), hl ; store the new ssp

ld l, c
ld h, b
ld sp, hl
;end of kw_gosub

kw_gosub_iftrue:
pop bc ; where do we want to go, pop it first as we want
; the next statement upon kw_return
ret z

ld hl, 0 ; hl = hsp
add hl, sp

ld de,(ssp) ; de = ssp
ex de, hl ; hl = ssp, de = hsp

ld (hl), e ; push hsp on the ssp
dec hl ;
ld (hl), d ;
dec  hl ;

ld (ssp), hl ; store the new ssp

ld l, c
ld h, b
ld sp, hl
;end of kw_gosub_iftrue

kw_gosub_iffalse:
pop bc ; where do we want to go, pop it first as we want
; the next statement upon kw_return
ret nz

ld hl, 0 ; hl = hsp
add hl, sp

ld de,(ssp) ; de = ssp
ex de, hl ; hl = ssp, de = hsp

ld (hl), e ; push hsp on the ssp
dec hl ;
ld (hl), d ;
dec  hl ;

ld (ssp), hl ; store the new ssp

ld l, c
ld h, b
ld sp, hl
;end of kw_gosub_iffalse

kw_goto:
pop hl
ld sp, hl
;end of kw_goto

kw_goto_iftrue:
pop hl
ret z

ld sp, hl
;end of kw_goto_iftrue

kw_goto_iffalse:
pop hl
ret nz

ld sp, hl
;end of kw_goto_iffalse

kw_return: ; do a software return

ld hl, (ssp) ; get the ssp

inc hl ; pop hsp from ssp
ld d, (hl) ;
inc hl ;
ld e, (hl) ;

ld (ssp), hl ; store the new ssp

ex de, hl ; hl = hsp, de = ssp
ld sp, hl
;end of kw_return

kw_return_iftrue:
ret nz ; if z we want to do a software return

ld hl, (ssp) ; get the ssp

inc hl ; pop hsp from ssp
ld d, (hl) ;
inc hl ;
ld e, (hl) ;

ld (ssp), hl ; store the new ssp

ex de, hl ; hl = hsp, de = ssp
ld sp, hl
;end of kw_return_iftrue

kw_return_iffalse:
ret z ; if nz we want to do a software return

ld hl, (ssp) ; get the ssp

inc hl ; pop hsp from ssp
ld d, (hl) ;
inc hl ;
ld e, (hl) ;

ld (ssp), hl ; store the new ssp

ex de, hl ; hl = hsp, de = ssp
ld sp, hl
;end of kw_return_iffalse

kw_stop:
halt
;end of kw_stop

; ------------------------------------------------------------------------------

kw_dec8:
pop hl
dec (hl)
ret
;end of kw_dec16

kw_dec16:
pop hl
ld e,(hl)
inc hl
ld d, (hl)
dec de
ld (hl), d
dec hl
ld (hl), e
ret
;end of kw_dec16

kw_inc8:
pop hl
inc (hl)
ret
;end of kw_dec16
;end of kw_inc

kw_inc16:
pop hl
ld e,(hl)
inc hl
ld d, (hl)
inc de
ld (hl), d
dec hl
ld (hl), e
ret
;end of kw_inc

kw_iszero8:
pop hl
ld a, (hl)
or a
ret
;end of kw_iszero8

kw_iszero16:
pop hl
ld e, (hl)
inc hl
ld d, (hl)
ld a, e
or e
ret
;end of kw_iszero16

kw_let8:
pop hl
pop de
ld (hl), e
ret
;end of kw_let8

kw_let16:
pop hl
pop de
ld (hl), e
inc hl
ld (hl), d
ret
;end of kw_let16

; ------------------------------------------------------------------------------

kw_cls:
ld hl,#c000
ld de,#c001
ld bc,#3fff
xor a
ld (hl), a
ldir
ret
;end of kw_cls

kw_locate:
pop de
ld (var_cursorx), de
pop de
ld (var_cursory), de
ret
;end of kw_locate

kw_mode:
;TODO: set the mode

ret
;end of kw_mode

kw_print:
pop hl
kw_print1: ld a,(hl)
or a
ret z

;TODO: output a char

inc hl
jr kw_print1
;end of kw_print

; ------------------------------------------------------------------------------

ssp: dw sss ; software stack pointer
ssb: ds 128 ; bottom of software stack
sss:
; start of software stack

; ------------------------------------------------------------------------------

var_cursorx: dw 0
var_cursory: dw 0

Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 22:35, 12 February 25
- Stack Programming.

Just a thought... I might be able to optimise the software stack a little too, but it serves the demonstration purpose. Code is untested but it does assemble.

Typical code example:

Total bytes: 65
Total nops: 528

Stack example:

Total bytes: 66
Total nops: 189+

The + for total nops in the stack example is because the software stack overhead of the single software call.  The DJNZ also helps a lot in the handcoded example.


timings from: https://www.cpcwiki.eu/imgs/b/b4/Z80_CPC_Timings_cheat_sheet.20230709.pdf


The thing I never got with all traditional programming, why return back to the logic after calling a keyword just to go back to the next keyword... this allows keywords to go directly from one to the next.  If only they made a  cpu with 2 stacks, an execution stack and a call stack.
Title: Re: Julian's Long List of Ideas Thread
Post by: Prodatron on 23:51, 12 February 25
I wonder why you don't finally complete one of your ideas and turn it into a useful product?
Title: Re: Julian's Long List of Ideas Thread
Post by: Pollo on 00:42, 13 February 25
Ideas are a dime a dozen. It's execution that counts.
— Frank Herbert
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 01:56, 13 February 25
Quote from: Prodatron on 23:51, 12 February 25I wonder why you don't finally complete one of your ideas and turn it into a useful product?
Complete or make useable?  I have many completed (depending on your definition) but so far no uptake, so more ideas come and will become Siamese ideas when combined.

Nobody wants online highscores or achievements or game lobby in cpc games it seems... so maybe I need to make a ROM so basic programmers can. Maybe they still won't. Maybe a 8bml browser but the  Maybe only me makes websites with the sdk.   

Maybe nobody wants to display debug info from their cpc or game info or commentary on remote displays private on their desk or across the world like a chess game commentary.

But... for me it is fun creating them.
Title: Re: Julian's Long List of Ideas Thread
Post by: eto on 08:54, 13 February 25
How can I use the VDU from the CPC? All the examples just specify the URL but what hardware/software on the CPC is required?
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 02:05, 14 February 25
Quote from: eto on 08:54, 13 February 25How can I use the VDU from the CPC? All the examples just specify the URL but what hardware/software on the CPC is required?
You need an M4 card or a Cyboard.
Title: Re: Julian's Long List of Ideas Thread
Post by: eto on 08:14, 14 February 25
Quote from: zhulien on 02:05, 14 February 25
Quote from: eto on 08:54, 13 February 25How can I use the VDU from the CPC? All the examples just specify the URL but what hardware/software on the CPC is required?
You need an M4 card or a Cyboard.
So nothing on the CPC side, but an endpoint on a webserver?
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 09:01, 14 February 25
Quote from: eto on 08:14, 14 February 25
Quote from: zhulien on 02:05, 14 February 25
Quote from: eto on 08:54, 13 February 25How can I use the VDU from the CPC? All the examples just specify the URL but what hardware/software on the CPC is required?
You need an M4 card or a Cyboard.
So nothing on the CPC side, but an endpoint on a webserver?
Yes, you do an http get with the rsx provided by m4

I have been thinking of making a library of rsx commands to make it easier for those who never called webserviced before
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 14:57, 26 February 25
Today on the way home from work, I was thinking, I have lots of RAM on my CPC, why can't i run lots of BASICs at the same time.

Now, this is far from doing that, but as an initial POC, I was thinking, from memory there is nothing stored in the OS ROMs that do anything with banking, so... we should in theory be able to store lots of the first 64kb into the other banks, and swap between them.  To make it "safer" for now, to avoid e.g. keyboard presses to swap tasks, we could use RSXs, like |1, |2, |3 (first 192kb of 256kb memory expansion).  the 4th bank first block initially to preserve the registers and anything else we may need to preserve.

Anyway, it is ALMOST finished, but was wondering is there any reason it shouldn't work?  If the entire state of the computer is stored (ok, as much as we can store) in each 64kb bank upon system reset, then we could do some BASIC in |1, change to |2 to do something else, maybe an other BASIC program, |3 to do something else etc...  If this POC works, it could be extended to be more useful - maybe instead of preserving just 64kb, maybe preserve 128kb on 1mb computers, and have |1 to |2.  Maybe then an alt+tab extension, or ctrl+1, ctrl+2...

Code so far (a little to do to make a working POC):

; TODO:
; honor lower ROM enabling
; enable and disable upper ROM in the ramlam function
; preserve initial registers correctly (including alternate and SP)
;
;FUTURE:
; can we fit a |4 within the 256kb extra RAM?
; perhaps support 128kb machines with memory swap-in-place
; dynamically detect memory sizes
; don't use macros? but we have plenty of ROM space for now

TXT_OUT_CHAR equ #bb5a
RAM_LAM equ #2000

org #c000

write direct -1,1,#C0

macro block_main
push bc
ld bc,  #7fc0
out (c), c
pop bc
endm

macro block_4
ld bc,  #7fc4
out (c), c
endm

macro block_5
ld bc,  #7fc5
out (c), c
endm

macro block_6
ld bc,  #7fc6
out (c), c
endm

macro block_7
ld bc,  #7fc7
out (c), c
endm

macro block_8
ld bc,  #7fcc
out (c), c
endm

macro block_9
ld bc,  #7fcd
out (c), c
endm

macro block_10
ld bc,  #7fce
out (c), c
endm

macro block_11
ld bc,  #7fcf
out (c), c
endm

macro block_12
ld bc,  #7fd4
out (c), c
endm

macro block_13
ld bc,  #7fd5
out (c), c
endm

macro block_14
ld bc,  #7fd6
out (c), c
endm

macro block_15
ld bc,  #7fd7
out (c), c
endm

macro block_registers
push bc
ld bc,  #7fdc
out (c), c
pop bc
endm

macro save_reg1 ;save registers for bank 1
block_registers

ld (#4000), sp

ld sp, #4100 ;set new sp so we can push the other registers faster
push af
push bc
push de
push hl
push ix
push iy
exx
push bc
push de
push hl
exx

ld sp, (#4000)

block_main
endm

macro save_reg2 ;save registers for bank 2
block_registers

ld (#5000), sp

ld sp, #5100 ;set new sp so we can push the other registers faster
push af
push bc
push de
push hl
push ix
push iy
exx
push bc
push de
push hl
exx

ld sp, (#5000)

block_main
endm

macro save_reg3 ;save registers for bank 3
block_registers

ld (#6000), sp

ld sp, #6100 ;set new sp so we can push the other registers faster
push af
push bc
push de
push hl
push ix
push iy
exx
push bc
push de
push hl
exx

ld sp, (#6000)

block_main
endm

macro load_reg1 ;load registers for bank 1
block_registers

ld (#4000), sp

ld sp, #4100-18 ;set new sp so we can pop the other registers faster
exx
pop hl
pop de
pop bc
exx
pop iy
pop ix
pop hl
pop de
pop bc
pop af

ld sp, (#4000)

block_main
endm

macro load_reg2 ;load registers for bank 2
block_registers

ld (#5000), sp

ld sp, #5100-18 ;set new sp so we can pop the other registers faster
exx
pop hl
pop de
pop bc
exx
pop iy
pop ix
pop hl
pop de
pop bc
pop af

ld sp, (#5000)

block_main
endm

macro load_reg3 ;load registers for bank 3
block_registers

ld (#6000), sp

ld sp, #6100-18 ;set new sp so we can pop the other registers faster
exx
pop hl
pop de
pop bc
exx
pop iy
pop ix
pop hl
pop de
pop bc
pop af

ld sp, (#6000)

block_main
endm

macro bank_0to1
;copy block 0 to 4
block_4
ld hl, #0000
ld de, #4000
ld bc, #4000
ldir

;copy block 3 to 7 via 0 (corrupts block 0)
ld hl, ramlam
ld de, RAM_LAM
ld bc, ramlam_end - ramlam
ldir
block_7
call RAM_LAM

;copy block 1 to 5 via 0 (corrupts block 0)
block_main
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir
block_5
ld hl, #0000
ld de, #4000
ld bc, #4000
ldir

;restore block 0
block_4
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir

;copy block 2 to 6
block_6
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

block_main
endm

macro bank_0to2
;copy block 0 to 8
block_8
ld hl, #0000
ld de, #4000
ld bc, #4000
ldir

;copy block 3 to 11 via 0 (corrupts block 0)
ld hl, ramlam
ld de, RAM_LAM
ld bc, ramlam_end - ramlam
ldir
block_11
call RAM_LAM

;copy block 1 to 9 via 0 (corrupts block 0)
block_main
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir
block_9
ld hl, #0000
ld de, #4000
ld bc, #4000
ldir

;restore block 0
block_8
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir

;copy block 2 to 10
block_10
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

block_main
endm

macro bank_0to3
;copy block 0 to 12
block_12
ld hl, #0000
ld de, #4000
ld bc, #4000
ldir

;copy block 3 to 15 via 0 (corrupts block 0)
ld hl, ramlam
ld de, RAM_LAM
ld bc, ramlam_end - ramlam
ldir
block_15
call RAM_LAM

;copy block 1 to 13 via 0 (corrupts block 0)
block_main
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir
block_13
ld hl, #0000
ld de, #4000
ld bc, #4000
ldir

;restore block 0
block_12
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir

;copy block 2 to 14
block_14
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

block_main
endm

macro bank_1to0
;copy block 5 to 1 via 0
block_5
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir
block_main
ld hl, #0000
ld de, #4000
ld bc, #4000
ldir

;copy block 4 to 0
block_4
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir

;copy block 6 to 2
block_6
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir

;copy block 7 to 3, LOSES STACK
block_7
ld hl, #4000
ld de, #c000
ld bc, #4000
ldir
endm

macro bank_2to0
;copy block 9 to 1 via 0
block_9
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir
block_main
ld hl, #0000
ld de, #4000
ld bc, #4000
ldir

;copy block 8 to 0
block_8
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir

;copy block 10 to 2
block_10
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir

;copy block 11 to 3 LOSES STACK
block_11
ld hl, #4000
ld de, #c000
ld bc, #4000
ldir
endm

macro bank_3to0
;copy block 13 to 1 via 0
block_13
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir
block_main
ld hl, #0000
ld de, #4000
ld bc, #4000
ldir

;copy block 12 to 0
block_12
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir

;copy block 14 to 2
block_10
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir

;copy block 15 to 3 LOSES STACK
block_11
ld hl, #4000
ld de, #c000
ld bc, #4000
ldir
endm

; CPC ROM header
               
defb 1 ; background ROM
defb 1 ; mark
defb 0 ; version
defb 0 ; modification

defw rsx_names

; RSX jumpblock

jp rom_init

; general

jp rsx_help
jp rsx_1
jp rsx_2
jp rsx_3

rsx_names: defb 'FLIPP', 'Y'+#80

defb 'FLIPPYHEL', 'P'+#80
defb '1'+#80
defb '2'+#80
defb '3'+#80

defb 0

; --------------------------------------------------

; help for RSXs are in the order that we want to display the entire online help

hlp_all:

hlp_help: defb '|flippyhelp - Displays online help.', 0
hlp_1: defb '|1 - Change to task 1.', 0
hlp_2: defb '|2 - Change to task 2.', 0
hlp_3: defb '|3 - Change to task 3.', 0

defb 0 ; terminator for |help

; system statuses & messages

msg_signon: defb ' FLIPPY V0.9 ROM BY VORAX 2025', 0
msg_version: defb '0.9', 0
msg_newline: defb 13, 10, 0

rom_init: di
ld a,(#8000) ;skip initialisation if not the first block
cp 1 ;as we don't want to get into an infinite loop
jp nz, init_end ;#8000 is used not #be80 as #8000 is zeroed out by
;the boot process

;#be80 is used to know which current bank we are in
;currently use bank 4 for register preservation & rom state

;for |3
ld a,3
ld (#be80), a
bank_0to3
save_reg3

;for |2
ld a,2
ld (#be80), a
bank_0to2
save_reg2

;for |1
ld a,1
ld (#be80), a
bank_0to1
save_reg1

init_end:
push af
push bc
push de
push hl

xor a
ld (#8000), a

ld hl, msg_signon ; signon
call str_output

ld hl, msg_newline
call str_output

pop hl
pop de
pop bc
pop af

ei
ret

rsx_1: di
push af
push bc

ld a,(#be80)
cp 2
jp z, rsx_1store2
cp 3
jp z, rsx_1store3

pop bc
pop af
ei
ret

rsx_1store2:
pop bc
pop af
save_reg2
bank_0to2
jp rsx_1end

rsx_1store3:
pop bc
pop af
save_reg3
bank_0to3

rsx_1end: bank_1to0
load_reg1
ei
ret

rsx_2: di
push af
push bc

ld a,(#be80)
cp 1
jp z, rsx_2store1
cp 3
jp z, rsx_2store3

pop bc
pop af
ei
ret

rsx_2store1:
pop bc
pop af
save_reg1
bank_0to1
jp rsx_2end

rsx_2store3:
pop bc
pop af
save_reg3
bank_0to3

rsx_2end: bank_2to0
load_reg2
ei
ret

rsx_3: di
push af
push bc

ld a,(#be80)
cp 1
jp z, rsx_3store1
cp 1
jp z, rsx_3store2

pop bc
pop af
ei
ret

rsx_3store1:
pop bc
pop af
save_reg1
bank_0to1
jp rsx_3end

rsx_3store2:
pop bc
pop af
save_reg2
bank_0to2

rsx_3end: bank_3to0
load_reg3
ei
ret

; ------------------------- display help

rsx_help: and a
jr z, fn_help
               
ld hl, hlp_help
jp str_outputln

fn_help: ld hl, hlp_all
fn_help_lp: ld a, (hl)
and a
ret z ; no more help
call str_outputln
inc hl
jr fn_help_lp

; ------------------------- ramlam

ramlam:
; TODO: disable upper rom
ld hl, #c000
ld de, #4000
ld bc, #4000
ldir
; TODO: enable upper rom
ret
ramlam_end:

; ------------------------- string output - no interrupts?
; -- parameters:
; -- HL = zero terminated string
; -- return:
; --
; -- corrupt:
; -- AF, HL

str_output: ld a, (hl)
and a
ret z
call TXT_OUT_CHAR
inc hl
jr str_output

; ------------------------- string output and a newline - no interrupts?
; -- parameters:
; -- HL = zero terminated string
; -- return:
; --
; -- corrupt:
; -- AF, HL

str_outputln:
call str_output
push hl
ld hl, msg_newline
call str_output
pop hl
ret



Any thoughts?
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 15:05, 26 February 25
fixed quite a few things, search for TODO to see what there is TODO

How is the best way to get the current state of the upper and lower ROMS and re-enable them without firmware?

I wreckon someone smarter than me could have this running in 20 minutes :D
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 15:42, 26 February 25
Someone suggested ROM space is a good place to put maths functions - because... likely you can store lots of precalculated tables.

Some ideas for inclusion within a MATHS ROM which lots of future programs 'could' use.

- multiplication tables, integer
- division tables, integer
- remainder tables, integer
- sin, cos, tan
- matrix transformations using table lookups

are float functions worth putting in also? i guess why not put the best ones available.  The good thing about a standard MATHS rom, it would behave like an Amiga library or a Windows DLL, when better routines get put in, software gets faster.
Title: Re: Julian's Long List of Ideas Thread
Post by: andycadley on 15:58, 26 February 25
Quote from: zhulien on 14:57, 26 February 25Today on the way home from work, I was thinking, I have lots of RAM on my CPC, why can't i run lots of BASICs at the same time.

Now, this is far from doing that, but as an initial POC, I was thinking, from memory there is nothing stored in the OS ROMs that do anything with banking, so... we should in theory be able to store lots of the first 64kb into the other banks, and swap between them.  To make it "safer" for now, to avoid e.g. keyboard presses to swap tasks, we could use RSXs, like |1, |2, |3 (first 192kb of 256kb memory expansion).  the 4th bank first block initially to preserve the registers and anything else we may need to preserve.


I'm not sure you'd really need to preserve the registers, since RSX's by definition don't so presumably the ROM calling code is good as it is. And interrupts will presumably always be enabled. The Stack pointer would need preserving, but I think that's about it.

The trickiest part would be juggling ROM/RAM usage around to be able to copy all 64K around, but that shouldn't be insurmountable (I'm not sure I've had enough coffee or thinking time to convince myself of the best approach).
Title: Re: Julian's Long List of Ideas Thread
Post by: andycadley on 16:00, 26 February 25
Quote from: zhulien on 15:42, 26 February 25Someone suggested ROM space is a good place to put maths functions - because... likely you can store lots of precalculated tables.

Some ideas for inclusion within a MATHS ROM which lots of future programs 'could' use.

- multiplication tables, integer
- division tables, integer
- remainder tables, integer
- sin, cos, tan
- matrix transformations using table lookups

are float functions worth putting in also? i guess why not put the best ones available.  The good thing about a standard MATHS rom, it would behave like an Amiga library or a Windows DLL, when better routines get put in, software gets faster.
I think this could be a great idea. Especially if clear machine code entry points were provided as well as RSX entry points (so that it could be used in cartridges that don't include the firmware). And as long as people don't license it up the wazoo with GPL and such.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 16:07, 26 February 25
Quote from: andycadley on 15:58, 26 February 25
Quote from: zhulien on 14:57, 26 February 25Today on the way home from work, I was thinking, I have lots of RAM on my CPC, why can't i run lots of BASICs at the same time.

Now, this is far from doing that, but as an initial POC, I was thinking, from memory there is nothing stored in the OS ROMs that do anything with banking, so... we should in theory be able to store lots of the first 64kb into the other banks, and swap between them.  To make it "safer" for now, to avoid e.g. keyboard presses to swap tasks, we could use RSXs, like |1, |2, |3 (first 192kb of 256kb memory expansion).  the 4th bank first block initially to preserve the registers and anything else we may need to preserve.


I'm not sure you'd really need to preserve the registers, since RSX's by definition don't so presumably the ROM calling code is good as it is. And interrupts will presumably always be enabled. The Stack pointer would need preserving, but I think that's about it.

The trickiest part would be juggling ROM/RAM usage around to be able to copy all 64K around, but that shouldn't be insurmountable (I'm not sure I've had enough coffee or thinking time to convince myself of the best approach).
The juggling is already coded there, i am in the process of testing now, it is copying the ROM content though as the ROM is enabled.  I created my own ramlam sort of, it copies a small routing from ROM into RAM to disable ROMs and copy the screen RAM, but... still i have to figure out how to disable and enable the ROMs.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 16:25, 26 February 25
fixed the RAMLAMs other than the rom disabling/enabling

; TODO:
; honor lower ROM enabling
; enable and disable upper ROM in the ramlam function
; preserve initial registers correctly (including alternate and SP)
;
;FUTURE:
; can we fit a |4 within the 256kb extra RAM?
; perhaps support 128kb machines with memory swap-in-place
; dynamically detect memory sizes
; don't use macros? but we have plenty of ROM space for now

TXT_OUT_CHAR equ #bb5a
RAM_LAM_0000 equ #8000 ; above lower ROM and below upper ROM, copies RAM under lower ROM
RAM_LAM_C000 equ #8100 ; above lower ROM and below upper ROM, copies RAM under upper ROM

org #c000

;write direct -1,1,#C0

macro block_main
push bc
ld bc,  #7fc0
out (c), c
pop bc
endm

macro block_1_0
ld bc,  #7fc4
out (c), c
endm

macro block_1_1
ld bc,  #7fc5
out (c), c
endm

macro block_1_2
ld bc,  #7fc6
out (c), c
endm

macro block_1_3
ld bc,  #7fc7
out (c), c
endm

macro block_2_0
ld bc,  #7fcc
out (c), c
endm

macro block_2_1
ld bc,  #7fcd
out (c), c
endm

macro block_2_2
ld bc,  #7fce
out (c), c
endm

macro block_2_3
ld bc,  #7fcf
out (c), c
endm

macro block_3_0
ld bc,  #7fd4
out (c), c
endm

macro block_3_1
ld bc,  #7fd5
out (c), c
endm

macro block_3_2
ld bc,  #7fd6
out (c), c
endm

macro block_3_3
ld bc,  #7fd7
out (c), c
endm

macro block_registers
push bc
ld bc,  #7fdc
out (c), c
pop bc
endm

macro save_reg1 ;save registers for bank 1
block_registers

ld (#4000), sp

ld sp, #4100 ;set new sp so we can push the other registers faster
push af
push bc
push de
push hl
push ix
push iy
exx
push bc
push de
push hl
exx

ld sp, (#4000)

block_main
endm

macro save_reg2 ;save registers for bank 2
block_registers

ld (#5000), sp

ld sp, #5100 ;set new sp so we can push the other registers faster
push af
push bc
push de
push hl
push ix
push iy
exx
push bc
push de
push hl
exx

ld sp, (#5000)

block_main
endm

macro save_reg3 ;save registers for bank 3
block_registers

ld (#6000), sp

ld sp, #6100 ;set new sp so we can push the other registers faster
push af
push bc
push de
push hl
push ix
push iy
exx
push bc
push de
push hl
exx

ld sp, (#6000)

block_main
endm

macro load_reg1 ;load registers for bank 1
block_registers

ld (#4000), sp

ld sp, #4100-18 ;set new sp so we can pop the other registers faster
exx
pop hl
pop de
pop bc
exx
pop iy
pop ix
pop hl
pop de
pop bc
pop af

ld sp, (#4000)

block_main
endm

macro load_reg2 ;load registers for bank 2
block_registers

ld (#5000), sp

ld sp, #5100-18 ;set new sp so we can pop the other registers faster
exx
pop hl
pop de
pop bc
exx
pop iy
pop ix
pop hl
pop de
pop bc
pop af

ld sp, (#5000)

block_main
endm

macro load_reg3 ;load registers for bank 3
block_registers

ld (#6000), sp

ld sp, #6100-18 ;set new sp so we can pop the other registers faster
exx
pop hl
pop de
pop bc
exx
pop iy
pop ix
pop hl
pop de
pop bc
pop af

ld sp, (#6000)

block_main
endm

macro bank_0to1
;copy block 0_2 to 1_2
block_1_2
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

;copy ramlams into 0_2 (corrupts block 0_2)
ld hl, ramlam_l
ld de, RAM_LAM_0000
ld bc, ramlam_l_end - ramlam_l
ldir

ld hl, ramlam_h
ld de, RAM_LAM_C000
ld bc, ramlam_h_end - ramlam_h
ldir

;copy block 0_0 to 1_0
block_1_0
call RAM_LAM_0000

;copy block 0_3 to 1_3
block_1_3
call RAM_LAM_C000

;copy block 0_1 to 1_1 via into 0_2 (corrupts block 0_2)
block_main
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir
block_1_1
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

;restore block 0_2
block_1_2
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir

block_main
endm

macro bank_0to2
;copy block 0_2 to 2_2
block_2_2
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

;copy ramlams into 0_2 (corrupts block 0_2)
ld hl, ramlam_l
ld de, RAM_LAM_0000
ld bc, ramlam_l_end - ramlam_l
ldir

ld hl, ramlam_h
ld de, RAM_LAM_C000
ld bc, ramlam_h_end - ramlam_h
ldir

;copy block 0_0 to 2_0
block_2_0
call RAM_LAM_0000

;copy block 0_3 to 2_3
block_2_3
call RAM_LAM_C000

;copy block 0_1 to 2_1 via into 0_2 (corrupts block 0_2)
block_main
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir
block_2_1
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

;restore block 0_2
block_2_2
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir

block_main
endm

macro bank_0to3
;copy block 0_2 to 3_2
block_3_2
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

;copy ramlams into 0_2 (corrupts block 0_2)
ld hl, ramlam_l
ld de, RAM_LAM_0000
ld bc, ramlam_l_end - ramlam_l
ldir

ld hl, ramlam_h
ld de, RAM_LAM_C000
ld bc, ramlam_h_end - ramlam_h
ldir

;copy block 0_0 to 3_0
block_3_0
call RAM_LAM_0000

;copy block 0_3 to 3_3
block_3_3
call RAM_LAM_C000

;copy block 0_1 to 3_1 via into 0_2 (corrupts block 0_2)
block_main
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir
block_3_1
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

;restore block 0_2
block_3_2
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir

block_main
endm

; no need for RAMLAMs here because all writes to ROM go to underlying RAM
macro bank_1to0
;copy block 5 to 1 via 2
block_1_1
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir
block_main
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

;copy block 4 to 0
block_1_0
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir

;copy block 6 to 2
block_1_2
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir

;copy block 7 to 3, LOSES STACK
block_1_3
ld hl, #4000
ld de, #c000
ld bc, #4000
ldir
endm

; no need for RAMLAMs here because all writes to ROM go to underlying RAM
macro bank_2to0
;copy block 9 to 1 via 2
block_2_1
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir
block_main
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

;copy block 8 to 0
block_2_0
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir

;copy block 10 to 2
block_2_2
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir

;copy block 11 to 3 LOSES STACK
block_2_3
ld hl, #4000
ld de, #c000
ld bc, #4000
ldir
endm

; no need for RAMLAMs here because all writes to ROM go to underlying RAM
macro bank_3to0
;copy block 13 to 1 via 2
block_3_1
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir
block_main
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

;copy block 12 to 0
block_3_0
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir

;copy block 14 to 2
block_2_2
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir

;copy block 15 to 3 LOSES STACK
block_2_3
ld hl, #4000
ld de, #c000
ld bc, #4000
ldir
endm

; CPC ROM header
               
defb 1 ; background ROM
defb 1 ; mark
defb 0 ; version
defb 0 ; modification

defw rsx_names

; RSX jumpblock

jp rom_init

; general

jp rsx_help
jp rsx_1
jp rsx_2
jp rsx_3

rsx_names: defb 'FLIPP', 'Y'+#80

defb 'FLIPPYHEL', 'P'+#80
defb '1'+#80
defb '2'+#80
defb '3'+#80

defb 0

; --------------------------------------------------

; help for RSXs are in the order that we want to display the entire online help

hlp_all:

hlp_help: defb '|flippyhelp - Displays online help.', 0
hlp_1: defb '|1 - Change to task 1.', 0
hlp_2: defb '|2 - Change to task 2.', 0
hlp_3: defb '|3 - Change to task 3.', 0

defb 0 ; terminator for |help

; system statuses & messages

msg_signon: defb ' FLIPPY V0.9 ROM BY VORAX 2025', 0
msg_version: defb '0.9', 0
msg_newline: defb 13, 10, 0
msg_task1: defb 'Task 1', 0
msg_task2: defb 'Task 2', 0
msg_task3: defb 'Task 3', 0

rom_init: di
push af
push bc
push de
push hl

ld a,(#8000) ;skip initialisation if not the first block
cp 1 ;as we don't want to get into an infinite loop
jp nz, init_end ;#8000 is used not #be80 as #8000 is zeroed out by
;the boot process

;#be80 is used to know which current bank we are in
;currently use bank 4 for register preservation & rom state

;for |3
ld a,3
ld (#be80), a
bank_0to3
save_reg3

;for |2
ld a,2
ld (#be80), a
bank_0to2
save_reg2

;for |1
ld a,1
ld (#be80), a
bank_0to1
save_reg1

init_end:
xor a
ld (#8000), a

ld hl, msg_signon
call str_output

ld hl, msg_newline
call str_output

pop hl
pop de
pop bc
pop af

ei
ret

rsx_1: di
push af
push bc
push de
push hl

ld a,(#be80)
cp 2
jp z, rsx_1store2
cp 3
jp z, rsx_1store3

pop hl
pop de
pop bc
pop af
ei
ret

rsx_1store2:
pop hl
pop de
pop bc
pop af
save_reg2
bank_0to2
jp rsx_1end

rsx_1store3:
pop hl
pop de
pop bc
pop af
save_reg3
bank_0to3

rsx_1end: bank_1to0
load_reg1

push af
push hl
ld hl, msg_task1
call str_output

ld hl, msg_newline
call str_output
pop hl
pop af

ei
ret

rsx_2: di
push af
push bc
push de
push hl

ld a,(#be80)
cp 1
jp z, rsx_2store1
cp 3
jp z, rsx_2store3

pop hl
pop de
pop bc
pop af
ei
ret

rsx_2store1:
pop hl
pop de
pop bc
pop af
save_reg1
bank_0to1
jp rsx_2end

rsx_2store3:
pop hl
pop de
pop bc
pop af
save_reg3
bank_0to3

rsx_2end: bank_2to0
load_reg2

push af
push hl
ld hl, msg_task2
call str_output

ld hl, msg_newline
call str_output
pop hl
pop af

ei
ret

rsx_3: di
push af
push bc
push de
push hl

ld a,(#be80)
cp 1
jp z, rsx_3store1
cp 2
jp z, rsx_3store2

pop hl
pop de
pop bc
pop af
ei
ret

rsx_3store1:
pop hl
pop de
pop bc
pop af
save_reg1
bank_0to1
jp rsx_3end

rsx_3store2:
pop hl
pop de
pop bc
pop af
save_reg2
bank_0to2

rsx_3end: bank_3to0
load_reg3

push af
push hl
ld hl, msg_task3
call str_output

ld hl, msg_newline
call str_output
pop hl
pop af

ei
ret

; ------------------------- display help

rsx_help: and a
jr z, fn_help
               
ld hl, hlp_help
jp str_outputln

fn_help: ld hl, hlp_all
fn_help_lp: ld a, (hl)
and a
ret z ; no more help
call str_outputln
inc hl
jr fn_help_lp

; ------------------------- ramlam

ramlam_l:
; TODO: disable lower rom
ld hl, #0000
ld de, #4000
ld bc, #4000
ldir
; TODO: enable lower rom
ret
ramlam_l_end:

ramlam_h:
; TODO: disable upper rom
ld hl, #c000
ld de, #4000
ld bc, #4000
ldir
; TODO: enable upper rom
ret
ramlam_h_end:

; ------------------------- string output - no interrupts?
; -- parameters:
; -- HL = zero terminated string
; -- return:
; --
; -- corrupt:
; -- AF, HL

str_output: ld a, (hl)
and a
ret z
call TXT_OUT_CHAR
inc hl
jr str_output

; ------------------------- string output and a newline - no interrupts?
; -- parameters:
; -- HL = zero terminated string
; -- return:
; --
; -- corrupt:
; -- AF, HL

str_outputln:
call str_output
push hl
ld hl, msg_newline
call str_output
pop hl
ret

Title: Re: Julian's Long List of Ideas Thread
Post by: andycadley on 17:18, 26 February 25
Quote from: zhulien on 16:07, 26 February 25The juggling is already coded there, i am in the process of testing now, it is copying the ROM content though as the ROM is enabled.  I created my own ramlam sort of, it copies a small routing from ROM into RAM to disable ROMs and copy the screen RAM, but... still i have to figure out how to disable and enable the ROMs.

But when an RSX is called the ROM state should already be known, your ROM will be the active upper ROM and I think the Lower ROM is always paged in (may need to verify that). So you don't need to record how they were set as long as you put your ROM back in the foreground.

It may be possible to do the copying without every having to put a routine in RAM, although it may not be worth it.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 17:21, 26 February 25
let's say i use the firmware,  do i need to search for my own ROM so i can reenable it with the right ROM number?
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 17:22, 26 February 25

yes, you can use the firmware RAMLAM, but that will be slow as it is per byte.  I juggle the memory around so i can do it in LDIRs of 16kb at a time, it's very fast - of course a bit buggy for now (ROMS always enabled to start).  I will resume tomorrow or another day, 3am here
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 21:14, 03 March 25
I just finished coding Home Computer JavaScript over the weekend.

Enjoy!!!

https://www.cpcwiki.eu/forum/off-topic/home-computer-javascript/ (in offtopic, but I will make it relevant to CPC soon)

About 50 commands with Locomotive BASIC inspired JavaScript environment.  Create any JS (only for now) program you like as if you were using a modern CPC that used JavaScript.

CPC-like API coming soon! inspired by Locomotive BASIC!

http://8bitology.com/

I even got WhatsApp to create a hangman game for you to play in it.

next to create some libraries to make coding easier.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 08:58, 05 March 25
Thanks, I have now put the code for Open Home Computer JS into github for those who want to self-host or host at home for their xbox ones.

https://github.com/PrimalNinja/ohcjs
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 08:32, 06 March 25
RC4 available, you can now edit more than one file at once.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 17:48, 06 March 25
RC5 online, RC4 in github.

http://8bitology.com/
https://github.com/PrimalNinja/ohcjs

added support for the following human languages: chinese (simplified), chinese (traditional), english, french, german, indonesian, klingon (limited), russian, spanish, tagalog

please kindly give me some feedback if you speak one of those languages.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 00:00, 07 March 25
languages now: arabic, chinese, chineset, czech, english, french, german, greek, hindi, italian, japanese, javanese, klingon (limited), korean, russian, spanish, tagalog, thai, vietnamese
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 20:04, 07 March 25
I'm all languaged out...

arabic, chinese, chineset, czech, dutch, english, french, german, greek, hebrew, hindi, italian, japanese, javanese, klingon, korean, persian, polish, portuguese, romanian, russian, spanish, swahili, swedish, tagalog, thai, turkish, vietnamese

i spent a lot of time to make the RTL languages work correctly, very interesting exercise.

Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:25, 07 June 25
OCR support added  as well as the ability to drag files into the browser if using a desktop computer.  Mime type detection added  ocr is more POC for now, drag a pdf or image and type ocr and it displays, soon this will be changed to create a new file for the text.  Also some basic transformation ability is underway with a link to command to link files. The purpose is to allow any number of linked files to be automatically updated when editing a file, such as JS to Z80 compilation or, english to chinese translation..  whatever the transformer happens to do.

And a rebranding in progress to CyboegShell because it is the best environment for AI agents. (As well as for mobile phones and xbox ones).

I will be creating a user guide in the vein of 80s BASIC programming manuals but for JS on CyborgShell.

I will be adding my potentjs game libraries (sprites, canvas, itp,  ai and a mini neuralnet for NPCs with a variant of aclib for world state management).  Whether a JS plugin can ever be good enough to convert these to Z80, likely beyond my capabilities.

Finally for those wanting a json conversion for z80... ideal for read-only json objects, if you don't want to recode the following logic to z80... its easy to parse the json binary on the z80.

Json to bin

JSON (JavaScript Object Notation) directly supports the following data types:

1. Strings (e.g., "hello")
2. Numbers (e.g., 42, 3.14)
3. Booleans (e.g., true, false)
4. Arrays (e.g., [1, 2, 3])
5. Objects (e.g., {"name": "John", "age": 30})
6. Null (e.g., null)

{
  "name": "John",
  "age": 30,
  "address": {
    "street": "123 Main St",
    "city": "Anytown"
  }
}


db OBJ_TYPE, 3
      db STRING_TYPE
      dw name_str, john_str

      db NUMBER_TYPE
      dw age_str, 30

      db OBJ_TYPE, 2
        db STRING_TYPE
        dw street_str, main_st_str

        db STRING_TYPE
        dw city_str, anytown_str

name_str: db "name", 00h
age_str: db "age", 00h
addr_str: db "address", 00h
street_str: db "street", 00h
city_str: db "city", 00h
john_str: db "John", 00h
main_st_str: db "123 Main St", 00h
anytown_str: db "Anytown", 00h


function jsonToBin(json) {
    var result = [];
    function encode(obj) {
        if (typeof obj === 'object' && !Array.isArray(obj)) {
            result.push(0x00); // Object type
            result.push(obj.length & 0xFF); // Property count (low byte)
            result.push((obj.length >> 8) & 0xFF); // Property count (high byte)
            for (var key in obj) {
                if (obj.hasOwnProperty(key)) {
                    var keyBytes = stringToBytes(key);
                    result.push(0x00); // String type for key
                    result.push(keyBytes.length & 0xFF); // Key length (low byte)
                    result.push((keyBytes.length >> 8) & 0xFF); // Key length (high byte)
                    result.push.apply(result, keyBytes);
                    var value = obj[key];
                    if (typeof value === 'string') {
                        result.push(0x10); // String type
                        var valueBytes = stringToBytes(value);
                        result.push(valueBytes.length & 0xFF); // Value length (low byte)
                        result.push((valueBytes.length >> 8) & 0xFF); // Value length (high byte)
                        result.push.apply(result, valueBytes);
                    } else if (typeof value === 'number') {
                        result.push(0x20); // Number type
                        result.push(value & 0xFF); // Number value (low byte)
                        result.push((value >> 8) & 0xFF); // Number value (high byte)
                        result.push((value >> 16) & 0xFF); // Number value (high byte)
                        result.push((value >> 24) & 0xFF); // Number value (high byte)
                    } else if (typeof value === 'object') {
                        result.push(0x00); // Object type
                        encode(value);
                    }
                }
            }
        }
    }
    function stringToBytes(str) {
        var bytes = [];
        for (var i = 0; i < str.length; i++) {
            bytes.push(str.charCodeAt(i));
        }
        bytes.push(0x00); // Null terminator
        return bytes;
    }
    encode(json);
    return new Uint8Array(result);
}

function binToJson(bin) {
    var offset = 0;
    function decode() {
        var type = bin[offset++];
        if (type === 0x00) { // Object type
            var propertyCount = bin[offset++] | (bin[offset++] << 8);
            var obj = {};
            for (var i = 0; i < propertyCount; i++) {
                var keyLength = bin[offset++] | (bin[offset++] << 8);
                var key = bytesToString(bin, offset, keyLength);
                offset += keyLength + 1; // Skip null terminator
                var valueType = bin[offset++];
                if (valueType === 0x10) { // String type
                    var valueLength = bin[offset++] | (bin[offset++] << 8);
                    obj[key] = bytesToString(bin, offset, valueLength);
                    offset += valueLength + 1; // Skip null terminator
                } else if (valueType === 0x20) { // Number type
                    obj[key] = bin[offset++] | (bin[offset++] << 8) | (bin[offset++] << 16) | (bin[offset++] << 24);
                } else if (valueType === 0x00) { // Object type
                    obj[key] = decode();
                }
            }
            return obj;
        }
    }
    function bytesToString(bin, offset, length) {
        var str = '';
        for (var i = 0; i < length; i++) {
            str += String.fromCharCode(bin[offset + i]);
        }
        return str;
    }
    return decode();
}



var json = {
    name: 'John',
    age: 30,
    address: {
        street: '123 Main St',
        city: 'Anytown'
    }
};

var bin = jsonToBin(json);
console.log(bin);

var jsonFromBin = binToJson(bin);
console.log(jsonFromBin);
Powered by SMFPacks Menu Editor Mod