Skip to content

Commit

Permalink
Automatic recognition of memory capacity of P2000T
Browse files Browse the repository at this point in the history
  • Loading branch information
ifilot committed Jul 15, 2023
1 parent 48463a8 commit 4f56609
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 74 deletions.
51 changes: 51 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Change Log
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [0.2.0] - 2023-07-15

### Added

- Reading memory capacity of P2000T in source code and using that to automatically
determine the top part of RAM for transfer over RS232.

### Changed

### Fixed

- Fixed error in memory address for the BASIC code for 32kb machines in the
README.md

## [0.1.3] - 2023-07-14

### Added

- Added instruction message on screen when executing `?USR1(0)`
- Adding software LICENSE

### Changed

### Fixed

## [0.1.2] - 2023-07-14

### Added

- Automatic compilation of ROM binary in release procedure

### Changed

### Fixed

## [0.1.1] - 2023-07-14

### Added

- Expanded upon documentation
- Adding CI/CD procecure

### Changed

### Fixed
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ all: src/BASIC-MODIFIED.bin
src/ollie.bin: src/ollie.asm
z80asm src/ollie.asm -o src/ollie.bin

src/BASIC-MODIFIED.bin: src/ollie.bin
src/BASIC-MODIFIED.bin: src/ollie.bin src/build.py
python3 src/build.py

clean:
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ After booting the P2000T with the modified BASIC-NL image, run

```basic
10 CLEAR 50,&H9DFF
20 DEF USR1=&H4EC7
20 DEF USR1=&H4EEE
```

> **Note**: Use `&H9DFF` in the above instructions if your P2000T has 16kb of memory.
> If your P2000T has 32kb or 48kb of memory, use `&HBDFF` or `&HDDFF`, respectively.
> If your P2000T has 32kb or 48kb of memory, use `&HDDFF` or `&HFDFF`, respectively.
> Alternatively, you can also use the following one-liner to let the P2000T
> figure it out for you: `10 CLEAR 50,&H9DFF+256*32*(PEEK(&H605C)+PEEK(&H605C)=1))`.
Expand Down
22 changes: 19 additions & 3 deletions src/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
import numpy as np
import os
import subprocess
import hashlib

# set root path
ROOT = os.path.dirname(__file__)
START = 0x3EC7 # start position on ROM

def main():
print('Building ROM...\n')

# open standard BASIC rom
f = open(os.path.join(ROOT, 'BASICROM.BIN'), 'rb')
rom = bytearray(f.read())
Expand All @@ -33,13 +37,25 @@ def main():
f = open(os.path.join(ROOT, 'ollie.bin'), 'rb')
ollie = bytearray(f.read())
f.close()
rom[0x3EC7:0x3EC7+len(ollie)] = ollie
rom[START:START+len(ollie)] = ollie
print("Inserting code; using %i / %i bytes of free space" %
(len(ollie),0x4000-0x3EC7))
(len(ollie),0x4000-START))

f = open(os.path.join(ROOT, 'BASIC-MODIFIED.bin'), 'wb')
# verify that the byte at 0x3EEE corresponds to the opt code for ld hl
print('Checking opt code at 0x3EEE=0x%02X ?= 0x21 (%s)' %
(rom[0x3EEE], 'true' if rom[0x3EEE]==0x21 else 'false'))
assert(rom[0x3EEE]==0x21)

# store file
filename = os.path.join(ROOT, 'BASIC-MODIFIED.bin')
f = open(filename, 'wb')
f.write(rom)
f.close()

# generate checksum
print()
print('Done writing modified ROM.')
print('Checksum: %s' % hashlib.md5(open(filename, 'rb').read()).hexdigest())

if __name__ == '__main__':
main()
175 changes: 107 additions & 68 deletions src/ollie.asm
Original file line number Diff line number Diff line change
@@ -1,44 +1,52 @@
;-------------------------------------------------------------------------------
; This code is largely based on the source code as developed by
; This code is based on the source code as developed by
; dionoid(https://github.com/dionoid) as found via the link below:
; https://github.com/p2000t/software/blob/master/utilities/pc2p2000t/pc2p2000t.z80.asm
;-------------------------------------------------------------------------------
BasicProgStart: EQU $6547
ProgramBlocks: EQU $9f4f ; byte
ProgramLength: EQU $9f34 ; word
basic_start_addr: EQU $6547

org $4ec7

pageaddr:
DB $9f,$df,$ff ; set page address positions (upper byte)

; exactly 27 bytes of data should be placed here such that the starting
; instruction is at $4eee; this allows for an easy BASIC command of
; `20 DEF USR1=&H4EEE`

; dummy data (36 bytes)
DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00

start:
ld hl,.line1
ld de,$5000+20*$50
call printstring
ld hl,.line2
ld de,$5000+21*$50
call printstring
ld hl,.line3
ld de,$5000+22*$50
call printstring
jp read_program

.line1: DB "P2000T IS IN LISTENING MODE",255
.line2: DB "COPY FILE OVER RS232",255
.line3: DB "BAUD=9600, PARITY=N, DATA=8, STOP=1",255
.line1: DB "P2000T READY TO COPY FILE OVER RS232",255
.line2: DB "BAUD=9600, PARITY=N, DATA=8, STOP=1",255

;-------------------------------------------------------------------------------
; reads a byte from the serial port (9600 baud) and returns in A
;-------------------------------------------------------------------------------
read_byte:
push bc ; C5 [11]
push bc
check_start_bit:
in a,($20) ; DB 20 [11]
and $01 ; E6 01 [7] - check if bit D0 is 0
jr nz, check_start_bit ; 20 FA [7]
ld b, $15 ; 06 15 [7]
in a,($20)
and $01 ; check if bit D0 is 0
jr nz, check_start_bit
ld b, $15
delay_on_start_bit:
djnz delay_on_start_bit ; 10 FE [13/8]
ld b, $08 ; 06 08 [7]
djnz delay_on_start_bit
ld b, $08

read_next_bit:
in a,($20) ; DB 20 [11]
in a,($20)

; 58 clocks without extra delay
; 1.2 * 1041.67 = 1250. Need delay in B:
Expand All @@ -50,78 +58,109 @@ read_next_bit:
; 9600 baud: 1.2 * 260.42 = 312.5
; delay in B: (312.5 - 58) / 13 = 19.6 + 1 = 21 (&h15)

rra ; 1F [4] - bit 0 into carry
rr c ; CB 19 [8]
push bc ; C5 [11]
ld b, $10 ; 06 10 [7]
rra ; bit 0 into carry
rr c
push bc
ld b, $10
delay_bit:
djnz delay_bit ; 10 FE [13/8]
pop bc ; C1 [10]
djnz read_next_bit ; 10 F3 [13]
djnz delay_bit
pop bc
djnz read_next_bit

; 72 clocks without extra delay. So delay in B:
; 2400 baud: (1041.67 - 72) / 13 = 74.6 + 1 = 76 (&h4C)
; 4800 baud: (520.84 - 72) / 13 = 34.53 + 1 = 35 (&h23)
; 9600 baud: (260.42 - 72) / 13 = 14.49 + 1 = 16 (&h10)

ld a,c ; 79 [4]
pop bc ; C1 [10]
ret ; C9 [10]
ld a,c
pop bc
ret

;-------------------------------------------------------------------------------
; read a program over the RS232 port
;-------------------------------------------------------------------------------
read_program: ; start the program
di ; F3 - disable interrupts
di ; disable interrupts

read_header: ; read 256-byte header into $9f00 - $9fff
ld b,0 ; 06 00
ld hl, $9f00 ; 21 00 9F
read_header: ; read 256-byte header into top of memory
call setpage
ld l,0
ld b,0
read_header_loop:
call read_byte ; CD 00 9E
ld (hl),a ; 77
inc hl ; 23
djnz read_header_loop ; 10 F9
call read_byte
ld (hl),a
inc hl
djnz read_header_loop

;read the blocks and put into basic memory
ld hl, ProgramBlocks ; 21 4F 9F
ld c, (hl) ; 4E - load number of blocks into C
ld hl, BasicProgStart ; 21 47 65 - IDEA: read pointer from $625c?
jr read_block ; 18 07 - first header already read, so skip
push bc
call setpage
pop bc
ld l,$4f ; set pointer to address containing number of blocks
ld c, (hl) ; load number of blocks into c
ld hl, basic_start_addr ; ?read pointer from $625c?
jr read_block ; first header already read, so skip
ignore_header:
ld b, $00 ; 06 00 - ignore later 256-byte headers
ld b, $00 ; ignore later 256-byte headers
ignore_header_loop:
call read_byte ; CD 00 9E
djnz ignore_header_loop ; 10 FB
call read_byte
djnz ignore_header_loop
read_block:
ld de, $400 ; 11 00 04
ld de, $400
read_block_loop:
call read_byte ; CD 00 9E
ld (hl),a ; 77
inc hl ; 23
dec de ; 1B
ld a,d ; 7A
or e ; B3
jr nz, read_block_loop ; 20 F6
dec c ; 0D
jr nz, ignore_header ; 20 E9

ld de, BasicProgStart ; 11 47 65
ld hl, (ProgramLength) ; 2A 34 9F
add hl,de ; 19
ld ($6405), hl ; 22 05 64 - set basic pointers to var space
ld ($6407), hl ; 22 07 64
ld ($6409), hl ; 22 09 64
call read_byte
ld (hl),a
inc hl
dec de
ld a,d
or e
jr nz, read_block_loop
dec c
jr nz, ignore_header

ld de, basic_start_addr ; set de to start of basic program
call setpage ; set page in h
ld l,$34
ld c,(hl) ; load lower byte program length
inc hl ; increment pointer
ld b,(hl) ; lower upper byte program length
ld a,b ; copy b->a->h
ld h,a
ld a,c ; copy c->a->l
ld l,a
add hl,de
ld ($6405), hl ; set basic pointers to var space
ld ($6407), hl
ld ($6409), hl

; reset the pointers to end of memory for BASIC
ld a, ($63b9) ; 3A B9 63
add a, 2 ; C6 02
ld ($63b9), a ; 32 B9 63
ld ($6259), a ; 32 59 62
ld a, ($63b9)
add a, 2
ld ($63b9), a
ld ($6259), a

; succes: play beep
ld a,$07 ; 3E 07
call $104a ; CD 4A 10
ld a,$07
call $104a

ei ; FB - enable interrupts
ret ; C9
ei ; enable interrupts
ret

;-------------------------------------------------------------------------------
; set the page to which the header data is written in h
; output: hl - start of buffer area
; uses: a,bc
;-------------------------------------------------------------------------------
setpage:
ld bc,pageaddr ; set pointer to page addresses
ld a,($605c) ; read RAM value, 1->16kb,2->32kb,3->48kb
dec a ; decrement such that index starts at 0
add a,c ; add lower byte of page addr to it
ld c,a ; update lower byte page address pointer
ld a,(bc) ; load page byte into a
ld h,a ; set upper byte into h
ld l,$00 ; set lower byte to 0
ret

;-------------------------------------------------------------------------------
; print string to screen
Expand Down

0 comments on commit 4f56609

Please sign in to comment.