News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_zhulien

Julian's Long List of Ideas Thread

Started by zhulien, 17:54, 12 February 25

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

zhulien

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.

eto

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?

zhulien

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

zhulien

#28
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?

zhulien

#29
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

zhulien

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.

andycadley

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).

andycadley

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.

zhulien

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.

zhulien

#34
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


andycadley

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.

zhulien

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?

zhulien


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

zhulien

#38
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.

zhulien

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

zhulien

RC4 available, you can now edit more than one file at once.

zhulien

#41
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.

zhulien

languages now: arabic, chinese, chineset, czech, english, french, german, greek, hindi, italian, japanese, javanese, klingon (limited), korean, russian, spanish, tagalog, thai, vietnamese

zhulien

#43
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.


zhulien

#44
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);

zhulien

CyborgShell now moved to http://cyborgshell.com/

Note yet CPC-capable development tool, but... soon 

mv

Quote from: zhulien on 18:24, 15 June 25CyborgShell now moved to http://cyborgshell.com/
Note yet CPC-capable development tool, but... soon
Interesting project — I find the idea of combining JavaScript with a CPC-style environment very appealing.

When working with LocoBasic, I sometimes wondered: could we start from (simple) JavaScript and compile it into Locomotive BASIC? Or even run a LocoBasic shell and compiler directly on a CPC?

I tried out CyborgShell — nice concept! A few impressions and suggestions:
    • There's a blinking cursor, when the shell is active. For some reason I always try to press Enter but nothing happens.
    • Copy & paste works into the shell, but it would be great to support copying from the shell too.
    • Command history would be a real productivity boost... ;)
    • Command auto-completion would also help with discoverability.
    • Some of the public examples like hello.js and cat.js appear to be binary files and can't be run as-is.
    • I (accidentally!) deleted 3d.js from the public space during testing.
    • I downloaded cat.js from GitHub and used drag & drop to upload it — nothing changed in the UI, so at first I thought it didn't work, but I later found it in the editor.
      Just tried that const {cls, print} = api; cls(); print(...); also works.
    • Minor quirk: I kept typing load"file, but it seems it must be load "file" — maybe a bit more leniency would help.


Looking forward to seeing how the CPC-style API evolves. Keep it up!

zhulien

Quote from: mv on 23:16, 26 June 25
Quote from: zhulien on 18:24, 15 June 25CyborgShell now moved to http://cyborgshell.com/
Note yet CPC-capable development tool, but... soon
Interesting project — I find the idea of combining JavaScript with a CPC-style environment very appealing.

When working with LocoBasic, I sometimes wondered: could we start from (simple) JavaScript and compile it into Locomotive BASIC? Or even run a LocoBasic shell and compiler directly on a CPC?

I tried out CyborgShell — nice concept! A few impressions and suggestions:
    • There's a blinking cursor, when the shell is active. For some reason I always try to press Enter but nothing happens.
    • Copy & paste works into the shell, but it would be great to support copying from the shell too.
    • Command history would be a real productivity boost... ;)
    • Command auto-completion would also help with discoverability.
    • Some of the public examples like hello.js and cat.js appear to be binary files and can't be run as-is.
    • I (accidentally!) deleted 3d.js from the public space during testing.
    • I downloaded cat.js from GitHub and used drag & drop to upload it — nothing changed in the UI, so at first I thought it didn't work, but I later found it in the editor.
      Just tried that const {cls, print} = api; cls(); print(...); also works.
    • Minor quirk: I kept typing load"file, but it seems it must be load "file" — maybe a bit more leniency would help.


Looking forward to seeing how the CPC-style API evolves. Keep it up!

Thanks for the feedback,

I plan to allow uploading and downloading from the shell. Currently you can drag files there and they are added to the memory-resident files, you can then just type saveall to save them usually.  You can paste code with line numbers on the first line and it will assume line numbers on every other, otherwise it will assume it's not code / or line numbered and allocate line numbers.  I plan to add an upload command (with popup file selector) and a download command soon, download might also support zipping lots of files.

I plan to add a full screen editor, perhaps type fed or somethings to edit the currently selected file fullscreen, but ultimately it's a secondary feature for those using a PC to code and not their phone or an AI.

If you open files with the extension they will be treated with the mime type of that extension otherwise they will be treated as binary.  The intent is that you can edit both ways, and later i intend to allow binary to be saved again.

We could make enter create a blank line, just didn't think of it.

Command history would be possible, auto completion likely possible too but not the immediate priority, i will add them to the todo list.

I'm fine with deleting from the public area, that was my first ever THREE.js program - the public area is intended for people to do what they like.

i do plan to support " in filenames, but more to allow for spaces within filenames.  For now, it is "load cat.js" to load it as a JS or "load cat" to load it as a bin.

I haven't updated the help, but you can use the mimetype command to change it after it's loaded also, eg "mimetype text/octet-stream" - there does seem to be an issue currently in converting JavaScript to and from binary.

An example of linking is like this.

reset with F5
type "files" to see the one file that you have
type "newfile" to create a new file
type "files" to see you now have 2 of them, and your current file is now file 2
type "linkto 1" to link file 2 to file 1
type "files" again to see the link is in place
type "file 1" to go back to file 1
type a new program in, ie: "10 api.print("Hello, World!");
type "files" again, the linked files are now the same as file 1.

Currently as many linked files as you like can be made, but only 1 level deep (a bug for me to fix).
It's only a POC the linking, but the intent is... links can be associated with a translation plugin.  
A real World example would be to setup the links and translators, save the project (which saves the linkages).
Type in your program for example in JavaScript, or LocoBasic, and like magic the linked files are compiled in realtime - like my youtube video from JS to Z80.

It's designed for programming as well as other tasks, that's why you can drag JPGs or PDFs there, then type "ocr" to turn them into a file that you can list and save.

But you can also as manus.im to do tasks on cyborgshell, and it's pretty cool to watch that it can do something with no prior knowledge - just type to manus.im "go to cyborgshell.com, read the help, then do blah", or  "go to cyborgshell.com, read the help, then do what is contained in blah.txt" (if you want multiple agents to do things concurrently).  Can be work-flow based, or programming related, all works to some degree.  I will put together a single page instructions for the AI agents so it can load it in a single go rather than it taking several minutes to read each one.  You can likely download openmanus if you want to try a free AI agent with it.

zhulien

Actually i have big plans for CyborgShell and all things are intended to fall into place oneday.

CyborgShell is where i plan to be able to code in JS to get Z80 output, or perhaps other languages etc  The JS translator I do want to be able to eventually cross compile itself to Z80, but likely that will be commandline based.  Maybe directly to Z80, or via JSASM (my JS based assembly language).  JSASM is much easier to then translate to Z80 or 6502.

Primal is my cross platform Z80 kernel, oneday this will be finished - it isn't intended to be a full OS like FutureOS or Symbos, but rather a way to code once and run it on many platforms - including FutureOS and Symbos.

potent.js is my game framework which of course works fine in JS and will be available in CyborgShell - i suspect this might never be cross-compilable to Z80, but who knows.  This includes JCanvas, JSprites (Automatic Sprite Animations, Collision detections etc), JGameLoop, JITP (internet connectivity), ACLIB, JNeuralNet (very lightweight enforcement training decision maker) and dAIbolic for NPC behaviour.  Although ACLib was designed for text adventure structure, it actually suits game state management nicely. dAIbolic is a JS tree-based AI for which you can influence behaviour by interacting with it's senses, it can use LLMs for comms or JNeuralNet for identifying things. So as an example, you can talk to an NPC, it can note some things about you, let's say what you are wearing, or what sex you are, what your hair colour might be, later if you met the same NPC, it might recognise you - just like a human, it's based on probability. 

mv

Quote from: zhulien on 15:05, 27 June 25Thanks for the feedback,

I plan to allow uploading and downloading from the shell. Currently you can drag files there and they are added to the memory-resident files...
Thanks for the detailed description.
It seems I've only scratched the surface of what's already possible, and what's coming next.


The ability to drag files into memory and use "saveall" is very handy. I had missed that behavior, so thanks for pointing it out. Also great to hear that upload/download commands, command history, and auto-completion are on your radar.

JavaScript with line numbers? Interesting, maybe just for visualization in the future full-screen editor?
In LocoBasic, I tend to avoid line numbers where possible. They're useful for marking call targets. In JavaScript, the structure comes more naturally through functions anyway.

When loading files, I tried the BASIC-style LOAD "cat.js", but that also treated the file as binary. I thought LOAD cat.js or LOAD cat was just a convenience, but now I understand it depends on the MIME type handling.

I also tried some JavaScript output from LocoBasic, but found the API quite limited for now, and api.print behaves differently (it appends a newline and accepts only one parameter). Of course, I can always fall back to putting more functionality directly into the script.

The linking and translator system sounds powerful. I hadn't realized how far you're taking the cross-language and real-time transformation concept.
When I typed "files", I saw that there's a second level of file management, "linked" in-memory files. What's the main benefit of having that second layer which cannot be done in one layer?


The AI agent integration is wild. I took the opportunity to try manus.im, and yes, it could do it:
"Go to cyborgshell.com, read the help, then run cat.js and print the result".
I also gave it a try getting the result of the "Nine Digits Puzzle" using LocoBasic. It struggled a lot with the UI, checking the long example selection list again and again. But after some nudges and about 6 minutes, it finally pulled it off. Maybe the LocoBasic UI could be a bit more AI-agent-friendly in the future.

So you are building a whole ecosystem here, with Primal, potent.js, and dAIbolic... Looking forward to seeing how all these parts come together.

Keep up the great work!

Powered by SMFPacks Menu Editor Mod