Merge pull request #3 from mgcaret/neon816

Neon816
This commit is contained in:
mgcaret 2019-12-04 21:20:06 -08:00 committed by GitHub
commit 84c936075c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 426 additions and 0 deletions

4
.gitignore vendored
View File

@ -9,3 +9,7 @@ t
/platform.inc
*.po
romfs
.DS_Store
*.hex
of816-neon.bin

View File

@ -0,0 +1,104 @@
; Bank Map from FB posting by Lenore:
; 00 Bank Mapper (16 blocks of 4k each, configured via MMU)
; 08-0F Bus Controller Peripherals
; - 08 0000-003F MMU
; -- 00: 0-3 Unused, 4-7: Upper RAM bits
; -- 01: Bank
; - 09 FDC
; 10-1F Internal Bus Bridge
; 20-27 Flash ROM
; 28-3F Reserved for Flash
; 30-3F Reserved for Expansion Flash
; 40-47 Video RAM
; 48-7F Reserved for VRAM
; 80-87 RAM 1
; 88-8F RAM 2
; 90-FF Reserved for RAM
cpu_clk = 14000000
; *****************
; Memory regions
; *****************
Neon_ROM = $200000
Neon_VRAM = $400000
Neon_RAM1 = $800000
Neon_RAM2 = $880000
; *****************
; MMU
; *****************
NeonMMU = $080000
; *****************
; I/O Ports
;
; Generally for the status ports, unless otherwise stated
; b3 = transmit buffer full (output is busy)
; b0 = receive buffer full (input is ready)
; *****************
SERio = $100008
SERstat = $100009
; Presumably baud and line setup
SERctrlA = $10000A ; NeonForth sets this to $8D
SERctrlB = $10000B ; ditto $06
SERctrlC = $10000C ; ditto $00
; MIDI ports
MIDIio = $100020
MIDIstat = $100021
; PS/2 Keyboard Port
PS2Kio = $100022
PS2Kstat = $100023
; PS/2 Mouse Port
PS2Mio = $100024
PS2Mstat = $100025
; *****************
; RTC
; *****************
RTCus = $100100 ; 2 bytes
RTCms = $100102 ; 2 bytes
RTCsec = $100104 ; 1 byte
RTCmin = $100105 ; 1 byte
RTChour = $100106 ; 1 byte
RTCday = $100108 ; 2 bytes
; *****************
; I2C
; *****************
I2C2io = $100014
I2C2ctrl = $100015 ; read: b3 = busy; write: $01 = start, $02 = stop, $04 = receive, $08 = send, $44 = receive/ack
; *****************
; SPI
; *****************
SPI2io = $10001C
SPI2ctrl = $10001D ; read: b3 = tx busy, b2 = rx full; write: $01 = start, $00 = stop; init = $00
SPI2ctrl2 = $10001E ; init = $00
SPI2ctrl3 = $10001F ; init = $05
; *****************
; VDC
; *****************
VDCio = $100120 ; read: 1 byte, write: 1 or 2 bytes
; *****************
; FDC
; *****************
FDCio = $090004
FDCstat = $090005 ; b7=0 = tx busy

View File

@ -0,0 +1,18 @@
FEATURES {
STARTADDRESS: default = $200000;
}
MEMORY {
ROM: start = $200000, size = $10000, fillval=$FF, file = %O;
ZP: start = $0000, size = $100;
}
SEGMENTS {
FStartup: load=ROM, type=ro, fillval=$00;
FSystem: load=ROM, type=ro, fillval=$00;
FCode: load=ROM, type=ro, fillval=$00, optional=yes;
ROMBOOT: load=ROM, type=ro, offset=$FF00;
VECTORS: load=ROM, type=ro, offset=$FFE0;
ZEROPAGE: load=ZP, type=bss;
}

View File

@ -0,0 +1,44 @@
.p816
.a16
.i16
.include "macros.inc"
.include "./Neon816-hw.inc"
.import _Forth_initialize
.import _Forth_ui
.import _system_interface
.pushseg
.segment "FStartup"
.proc startup
clc
xce
phk
plb
rep #SHORT_A|SHORT_I
.a16
.i16
lda #$0000 ; direct page for Forth
tcd
lda #.hiword(Neon_RAM1+$020000) ; top of dictionary memory
pha
lda #.loword(Neon_RAM1+$020000)
pha
lda #.hiword(Neon_RAM1+$010000) ; bottom of dictionary
pha
lda #.loword(Neon_RAM1+$010000)
pha
lda #$0400 ; first usable stack cell (relative to direct page)
pha
lda #$0204 ; last usable stack cell+1 (relative to direct page)
pha
lda #$01EF ; return stack first usable byte
pha
lda #.hiword(_system_interface)
pha
lda #.loword(_system_interface)
pha
jsl _Forth_initialize
jsl _Forth_ui
jmp startup
.endproc
.popseg

View File

@ -0,0 +1,66 @@
# Neon816
This is a port to Lenore Byron's [Neon816](https://hackaday.io/project/164325-neon816) system. The Neon816 Developer Edition ships with a small 16-bit Forth.
OF816 for the Neon816 is configured to run as an alternative firmware out of bank $20. With a little ajustment, it could be configured to run out of bank $21 (but starting it is an excercise for the reader).
It configures the MMU and serial port like NeonFORTH does. The direct page, stack, and return stack occupy the first $400 bytes of RAM.
To build OF816 for the Neon816, change to the platform directory and run
``build.sh``. It will output a 64K binary named ``of816-neon.bin`` that can be flashed into the Neon's firmware. See below for installation instructions.
## Port Features
Hopefully this section will be filled up with stuff that works like Lenore's
Forth. See the [Neon816 Manual](https://cdn.hackaday.io/files/1643257030480800/sysmanual.pdf). But right now, it's just a bare port with no system-specific extensions.
## Installation
**THIS WILL OVERWRITE THE NEON'S ORIGINAL FIRMWARE.**
**IT IS STRONGLY RECOMMENDED YOU BACK UP THE ORIGINAL FIRMWARE**
**READ _ALL_ OF THE FOLLOWING BEFORE PROCEEDING AND DO NOT PROCEED IF ANY OF THIS MAKES YOU UNCOMFORTABLE**
After building the firmware image, the image must be converted to Intel Hex format. I like the bin2hex tool found [here](https://grumpf.hope-2000.org) (page is in German). Build the ``bin2hex`` binary and execute: ``bin2hex of816-neon.bin > of816-neon.hex``
Once you have the .hex file, you will need to use the [Neon firmware loader](https://hackaday.io/project/164325-neon816) to install the image. This requires an FTDI cable connected to the 3.3V UART header on the Neon816 system board.
To back up the original firmware, you will need to add an additional command routine to neonprog.cpp (add it after the write command):
```
else if(!strcmp(cmd,"dumprom")) {
char* fn=strtok(nullptr," ");
char buf[0x40];
if(!fn) return;
auto st=Releaser(
fopen(fn,"w"),
[](auto f){if(f) fclose(f);});
if(!st) {
printf("Could not open file\n");
return;
}
for (int addr=0x200000; addr<0x220000; addr+=sizeof(buf)) {
writeHex(addr>>16,2); writeChar(':');
writeHex(addr,4); writeChar('#');
for (int i=0; i<sizeof(buf); i++) {
writeChar('@');
unsigned char c=readByte();
buf[i]=c;
}
fwrite(&buf, sizeof(buf), 1, st);
printf("%08X\n",addr);
}
}
```
then start neonprog with ``neonprog /dev/ttyUSBx`` (replace device with actual serial device for FTDI cable.
From within neonprog, execute ``dumprom backup.bin`` to save an image of both ROM banks to ``backup.bin``.
Once the backup has finished (it will take a while), you can proceed to the installation of OF816 with ``flash of816-neon.hex``. This will also take a while. When it is done, reset your Neon and OF816 should start.
## Restoring the Original NeonFORTH Firmware
Since the Neon (at the time of this writing) only ships with the first bank of flash occupied, first, split your backup with ``split backup.bin``. This will output two files, ``xaa`` and ``xab`` that are bank $20 and bank $21, respectively. Then run ``hex2bin xaa > neonforth.hex``. You can then flash this with neonprog using ``flash neonforth.hex``. Once it's done, reset your Neon and you should see the original firmware running.

12
platforms/Neon816/build.sh Executable file
View File

@ -0,0 +1,12 @@
#!/bin/bash
set -e -x
ca65 -I ../../inc Neon816.s -l Neon816.lst
ca65 -I ../../inc romboot.s -l romboot.lst
../../build.sh Neon816
ld65 -C Neon816.l -S 0x8000 Neon816.o ../../forth.o ./romboot.o -m forth.map -o of816-neon.bin
ls -l of816-neon.bin
if which -s bin2hex; then
hex2bin of816-neon.bin > of816-neon.hex
ls -l of816-neon.hex
fi

View File

@ -0,0 +1,2 @@
; nothing here yet!

View File

@ -0,0 +1,128 @@
; Platform support library for Neon816
;
.include "./Neon816-hw.inc"
.proc _system_interface
;wdm 3
phx
asl
tax
jmp (.loword(table),x)
table: .addr _sf_pre_init
.addr _sf_post_init
.addr _sf_emit
.addr _sf_keyq
.addr _sf_key
.addr _sf_fcode
.addr _sf_reset_all
.endproc
.export _system_interface
.proc _sf_success
lda #$0000
tay
clc
rtl
.endproc
.proc _sf_fail
ldy #.loword(-21)
lda #.hiword(-21)
sec
rtl
.endproc
.proc _sf_pre_init
; NeonFORTH does this, presumably to initialize the serial port
sep #SHORT_A
.a8
lda #$8D
sta f:SERctrlA
lda #$06
sta f:SERctrlB
lda #$00
sta f:SERctrlC
rep #SHORT_A
.a16
plx
jmp _sf_success
.endproc
.proc _sf_post_init
plx
jmp _sf_success
.endproc
.proc _sf_emit
plx ; get forth SP
jsr _popay ; grab the top item
phx ; and save new SP
sep #SHORT_A
.a8
tya
sta f:SERio
: lda f:SERstat
bit #$08
bne :-
rep #SHORT_A
.a16
plx
jmp _sf_success
.endproc
.proc _sf_keyq
ldy #$0000 ; anticipate false
sep #SHORT_A
.a8
lda f:SERstat ; b0=1 if data ready
ror
bcc :+
iny
: rep #SHORT_A
.a16
tya
plx
jsr _pushay
jmp _sf_success
.endproc
.proc _sf_key
sep #SHORT_A
.a8
: lda f:SERstat
ror
bcc :-
lda f:SERio
rep #SHORT_A
.a16
and #$00FF
tay
lda #$0000
plx
jsr _pushay
jmp _sf_success
.endproc
.proc _sf_fcode
.if include_fcode
ldy #.loword(list)
lda #.hiword(list)
.else
lda #$0000
tay
.endif
plx
jsr _pushay
jmp _sf_success
.if include_fcode
list:
.dword 0
.endif
.endproc
; TODO....
.proc _sf_reset_all
plx
jmp _sf_fail
.endproc

View File

@ -0,0 +1,2 @@
; Platform support dictionary words for Neon816

View File

@ -0,0 +1,46 @@
.p816
.a16
.i16
.include "macros.inc"
.include "./Neon816-hw.inc"
.segment "ROMBOOT"
.proc romboot
clc
xce
rep #SHORT_A|SHORT_I
.a16
.i16
lda #$01FF
tcs
; Set up MMU for bank 0
ldx #$001C
lda #$8000
: sta f:NeonMMU,x
dex
dex
bpl :-
jml f:Neon_ROM
.endproc
.segment "VECTORS"
.proc vectors
; native mode vectors
.word $FFFF ; FFE0 - reserved
.word $FFFF ; FFE2 - reserved
.word $FFFF ; FFE4 - COP
.word $FFFF ; FFE6 - BRK
.word $FFFF ; FFE8 - ABORT
.word $FFFF ; FFEA - NMI
.word $FFFF ; FFEC - reserved
.word $FFFF ; FFEE - IRQ
; emulation mode vectors
.word $FFFF ; FFF0 - reserved
.word $FFFF ; FFF2 - reserved
.word $FFFF ; FFF4 - COP
.word $FFFF ; FFF6 - reserved
.word $FFFF ; FFF8 - ABORT
.word $FFFF ; FFFA - NMI
.word .loword(romboot) ; FFFC - RESET
.word $FFFF ; FFFE - IRQ/BRK
.endproc