I have plans regarding this memory for future iterations of the operating system, so right after I finished the RTC / BRAM card I got to working on enhancing the driver to have read / write access to this memory.
The new API:
/*
* File: mkhbcos_ds1685.h
* Purpose: Declarations and definitions for
* DS1685 RTC (Real Time Clock) chip API.
* Author: Marek Karcz
* Created: 02/05/2012
*
* Revision history:
*
*
*/
#ifndef MKHBCOS_DS1685
#define MKHBCOS_DS1685
// DS RTC registers mask bits
// reg. A
#define DSC_REGA_UIP 0x80 // %10000000
#define DSC_REGA_DV2 0x40 // %01000000
#define DSC_REGA_DV1 0x20 // 100000
#define DSC_REGA_DV0 0x10 // 010000
#define DSC_REGA_RS3 0x08 // 001000
#define DSC_REGA_RS2 0x04 // 000100
#define DSC_REGA_RS1 0x02 // 000010
#define DSC_REGA_RS0 0x01 // 000001
// aliases
#define DSC_REGA_CTDWN DSC_REGA_DV2
#define DSC_REGA_OSCEN DSC_REGA_DV1
#define DSC_REGA_BSEL DSC_REGA_DV0
#define DSC_REGA_BANK0 0xEF
#define DSC_REGA_BANK1 0x10
// reg. B
#define DSC_REGB_SET 0x80 // %10000000
#define DSC_REGB_PIE 0x40 // %01000000
#define DSC_REGB_AIE 0x20 // 100000
#define DSC_REGB_UIE 0x10 // 010000
#define DSC_REGB_SQWE 0x08 // 001000
#define DSC_REGB_DM 0x04 // 000100
#define DSC_REGB_24o12 0x02 // 000010
#define DSC_REGB_DSE 0x01 // 000001
// aliases
#define DSC_REGB_UNSET 0x7F // %01111111
struct ds1685_clkdata
{
unsigned char seconds;
unsigned char minutes;
unsigned char hours;
unsigned char dayofweek;
unsigned char date; // day
unsigned char month;
unsigned char year;
unsigned char century;
};
unsigned char __fastcall__ ds1685_init (unsigned char regb,
unsigned char rega,
unsigned char regextb,
unsigned char regexta);
struct ds1685_clkdata *ds1685_rdclock (struct ds1685_clkdata *buf);
void ds1685_setclock (struct ds1685_clkdata *buf);
void ds1685_settime (struct ds1685_clkdata *buf);
/* bank - 0 or 1, addr - $00 - $7f ($0e - $7f for Bank 0), data - 0..255 */
void ds1685_storeram (unsigned char bank,
unsigned char addr,
unsigned char data);
unsigned char __fastcall__ ds1685_readram(unsigned char bank,
unsigned char addr);
#endif
and the code:
;------------------------------------------------------------------
;
; File: mkhbcos_ds1685.s
; Author: Marek Karcz
; Purpose: Implements initialization routines and API for
; Real Time Clock chip DS1685 with multiplexed
; address bus connected to buffered I/O bus as an I/O
; device.
;
; Revision history:
; 2012-01-31:
; Initial revision.
; (NOTE: These routines will eventually make their way
; to EPROM as a part of firmware. At that time,
; this file will be revised to call up the API
; functions in the kernal table, instead of
; being full implementation.)
;
; 2012-02-06:
; Implementation.
;
; 2015-11-29
; I/O slot assignment changed.
;
; 2015-12-5
; Modification due to hardware changes (Chris Ward variant):
; DSCALADDR and DSCALDATA order changed.
;
; 2017-06-15:
; Added functions to store and read non-volatile RAM.
;
;------------------------------------------------------------------
; M.O.S. API defines (kernal)
.define mos_StrPtr $E0
.define tmp_zpgPt $F6
.define IOBase $C000
.define RTC IOBase+256
;.define RTC IOBase+7*256
.define DSCALADDR RTC
.define DSCALDATA RTC+1
.setcpu "6502"
.import ldaxysp,pushax,popax,pusha,popa,staspidx
.import incsp2,incsp3,incsp4,ldauidx
.define sp $20
;RegB = tmp_zpgPt
;RegA = tmp_zpgPt+1
;RegXB = tmp_zpgPt+2
;RegXA = tmp_zpgPt+3
;RegC = tmp_zpgPt+4
;Temp = tmp_zpgPt+5
;BankNum = tmp_zpgPt
;RamAddr = tmp_zpgPt+1
;RamVal = tmp_zpgPt+2
.segment "DATA"
RegB: .byte $00
RegA: .byte $00
RegXB: .byte $00
RegXA: .byte $00
RegC: .byte $00
Temp: .byte $00
BankNum: .byte $00
RamAddr: .byte $00
RamVal: .byte $00
ExtRamAddr = $50
ExtRamPort = $53
; DS RTC registers mask bits
; reg. A
DSC_REGA_UIP = %10000000
DSC_REGA_DV2 = %01000000
DSC_REGA_DV1 = 100000
DSC_REGA_DV0 = 010000
DSC_REGA_RS3 = 001000
DSC_REGA_RS2 = 000100
DSC_REGA_RS1 = 000010
DSC_REGA_RS0 = 000001
; aliases
DSC_REGA_CTDWN = DSC_REGA_DV2
DSC_REGA_OSCEN = DSC_REGA_DV1
DSC_REGA_BSEL = DSC_REGA_DV0
DSC_REGA_BANK0 = $EF
DSC_REGA_BANK1 = $10
; reg. B
DSC_REGB_SET = %10000000
DSC_REGB_PIE = %01000000
DSC_REGB_AIE = 100000
DSC_REGB_UIE = 010000
DSC_REGB_SQWE = 001000
DSC_REGB_DM = 000100
DSC_REGB_24o12 = 000010
DSC_REGB_DSE = 000001
; aliases
DSC_REGB_UNSET = %01111111
; code
.export _ds1685_init,_ds1685_rdclock,_ds1685_setclock,_ds1685_settime
.export _ds1685_readram,_ds1685_storeram
;,_read
.segment "CODE"
; Initialize DS1685 RTC chip.
; unsigned char __fastcall__ ds1685_init (unsigned char regb,
; unsigned char rega,
; unsigned char regextb,
; unsigned char regexta)
.proc _ds1685_init: near
.segment "CODE"
; get parameters, put them in temp. buffer
jsr pusha
ldy #$03
;ldx #$00
lda (sp),y
sta RegB
ldy #$02
;ldx #$00
lda (sp),y
sta RegA
ldy #$01
;ldx #$00
lda (sp),y
sta RegXB
ldy #$00
;ldx #$00
lda (sp),y
sta RegXA
; initialize control register B
ldx RegB
lda #$0b
jsr WrRTC
; read status register C
lda #$0c
jsr RdRTC
sta RegC
; initialize control register A, switch to bank 1
lda RegA
ora #DSC_REGA_BANK1 ; switch to bank 1
tax
lda #$0a
jsr WrRTC
; initialize extended control register B
ldx RegXB
lda #$4b
jsr WrRTC
; initialize extended control register A
ldx RegXA
lda #$4a
jsr WrRTC
; switch to bank 0
jsr Switch2Bank0
ldx #$00
lda RegC
jsr incsp4
rts
.endproc
.segment "CODE"
; read clock data
; struct ds1685_clkdata *ds1685_rdclock(struct ds1685_clkdata *buf);
; struct ds1685_clkdata
; {
; unsigned char seconds;
; unsigned char minutes;
; unsigned char hours;
; unsigned char dayofweek;
; unsigned char date; // day
; unsigned char month;
; unsigned char year;
; unsigned char century;
; };
.proc _ds1685_rdclock:near
.segment "CODE"
; disable update transfers
lda #$0b
jsr RdRTC
sta RegB ; save register B for later
ora #DSC_REGB_SET
tax
lda #$0b
jsr WrRTC
; determine mode (BCD or BIN)
lda #DSC_REGB_DM
sta Temp
lda RegB
bit Temp
bne binmoderead
; can't do BCD mode yet, return
ldy #$01
jsr ldaxysp
jsr incsp2
rts
binmoderead:
; binary mode read
lda #$00 ; load register address of seconds
jsr RdRTC ; read register value to Acc
and #111111 ; mask 2 upper bits
ldy #$00
jsr Tfer2RetBuf ; transfer to return buffer at index 0 (seconds)
lda #$02 ; load register address of minutes
jsr RdRTC ; read register value to Acc
and #111111 ; mask 2 upper bits
ldy #$01
jsr Tfer2RetBuf ; transfer to return buffer at index 1 (minutes)
lda #$04 ; load register address of hours
jsr RdRTC ; read register value to Acc
pha
lda #DSC_REGB_24o12
sta Temp
lda RegB ; determine which hours mode (12/24 hours)
bit Temp
beq mode12hbin
pla
and #011111 ; mask 3 upper bits for 24H mode read
clc
bcc storehours
mode12hbin:
pla
and #001111 ; mask 4 upper bits for 12H mode read
storehours:
ldy #$02
jsr Tfer2RetBuf ; transfer to return buffer at index 2 (hours)
lda #$06 ; load register address of day (of week)
jsr RdRTC ; read register value to Acc
and #000111 ; mask 5 upper bits
ldy #$03
jsr Tfer2RetBuf ; transfer to return buffer at index 3 (dayofweek)
lda #$07 ; load register address of date (day of month)
jsr RdRTC ; read register value to Acc
and #011111 ; mask 3 upper bits
ldy #$04
jsr Tfer2RetBuf ; transfer to return buffer at index 4 (date)
lda #$08 ; load register address of month
jsr RdRTC ; read register value to Acc
and #001111 ; mask 4 upper bits
ldy #$05
jsr Tfer2RetBuf ; transfer to return buffer at index 5 (month)
lda #$09 ; load register address of year
jsr RdRTC ; read register value to Acc
and #%011111111 ; mask the highest bit
ldy #$06
jsr Tfer2RetBuf ; transfer to return buffer at index 6 (year)
jsr Switch2Bank1
lda #$48 ; load register address of century
jsr RdRTC ; read register value to Acc
ldy #$07
jsr Tfer2RetBuf ; transfer to return buffer at index 7 (century)
jsr Switch2Bank0
; enable update transfers
lda #$0b
jsr RdRTC
and #DSC_REGB_UNSET
tax
lda #$0b
jsr WrRTC
ldy #$01
jsr ldaxysp
jsr incsp2
rts
.endproc
.segment "CODE"
; set clock data
; void ds1685_setclock (struct ds1685_clkdata *buf);
.proc _ds1685_setclock:near
.segment "CODE"
; disable update transfers
; set binary mode
lda #$0b
jsr RdRTC
ora #DSC_REGB_SET
ora #DSC_REGB_DM
tax
lda #$0b
jsr WrRTC
ldy #$00 ; get argument 0 (seconds)
jsr GetParFromSpIdx
tax
lda #$00 ; write to DS1685 seconds register
jsr WrRTC
ldy #$01 ; get argument 1 (minutes)
jsr GetParFromSpIdx
tax
lda #$02 ; write to DS1685 minutes register
jsr WrRTC
ldy #$02 ; hours
jsr GetParFromSpIdx
tax
lda #$04
jsr WrRTC
ldy #$03 ; day of week
jsr GetParFromSpIdx
tax
lda #$06
jsr WrRTC
ldy #$04 ; date (day of month)
jsr GetParFromSpIdx
tax
lda #$07
jsr WrRTC
ldy #$05 ; month
jsr GetParFromSpIdx
tax
lda #$08
jsr WrRTC
ldy #$06 ; year
jsr GetParFromSpIdx
tax
lda #$09
jsr WrRTC
; enable update transfers
lda #$0b
jsr RdRTC
and #DSC_REGB_UNSET
tax
lda #$0b
jsr WrRTC
; disable update transfers
lda #$0b
jsr RdRTC
ora #DSC_REGB_SET
tax
lda #$0b
jsr WrRTC
lda #$0a ; get reg. A
jsr RdRTC
ora #DSC_REGA_BANK1 ; switch to bank 1
tax
lda #$0a
jsr WrRTC
ldy #$07 ; century
jsr GetParFromSpIdx
tax
lda #$48
jsr WrRTC
jsr Switch2Bank0
; enable update transfers
lda #$0b
jsr RdRTC
and #DSC_REGB_UNSET
tax
lda #$0b
jsr WrRTC
jsr incsp2
rts
.endproc
.segment "CODE"
; set clock data
; void ds1685_settime (struct ds1685_clkdata *buf);
.proc _ds1685_settime:near
.segment "CODE"
jsr Switch2Bank0
; disable update transfers
; set binary mode
lda #$0b
jsr RdRTC
ora #DSC_REGB_SET
ora #DSC_REGB_DM
tax
lda #$0b
jsr WrRTC
ldy #$00 ; get argument 0 (seconds)
jsr GetParFromSpIdx
tax
lda #$00 ; write to DS1685 seconds register
jsr WrRTC
ldy #$01 ; get argument 1 (minutes)
jsr GetParFromSpIdx
tax
lda #$02 ; write to DS1685 minutes register
jsr WrRTC
ldy #$02 ; hours
jsr GetParFromSpIdx
tax
lda #$04
jsr WrRTC
; enable update transfers
lda #$0b
jsr RdRTC
and #DSC_REGB_UNSET
tax
lda #$0b
jsr WrRTC
jsr incsp2
rts
.endproc
.segment "CODE"
; store value in non-volatile RAM
; void ds1685_storeram (unsigned char bank,
; unsigned char addr,
; unsigned char data);
.proc _ds1685_storeram: near
.segment "CODE"
; get parameters, put them in temp. buffer
;jsr pusha
ldy #$02
;ldx #$00
lda (sp),y
sta BankNum
ldy #$01
;ldx #$00
lda (sp),y
sta RamAddr
ldy #$00
;ldx #$00
lda (sp),y
sta RamVal
; if Bank #1, jump to lwrextram
lda BankNum
bne lwrextram
; switch to Bank 0
jsr Switch2Bank0
; A = address
; X = value
; write RAM
lda RamAddr
ldx RamVal
jsr WrRTC
; exit
jsr incsp3
rts
; Write RAM in Bank 1
lwrextram:
jsr Switch2Bank1
; load RAM addr. into extended ram address register
ldx RamAddr
lda #ExtRamAddr
jsr WrRTC
; load RAM value into extended RAM port
ldx RamVal
lda #ExtRamPort
jsr WrRTC
; switch to Bank 0
jsr Switch2Bank0
; exit
jsr incsp3
rts
.endproc
.segment "CODE"
; read value from non-volatile RAM
; unsigned char __fastcall__ ds1685_readram (unsigned char bank,
; unsigned char addr);
.proc _ds1685_readram: near
.segment "CODE"
; get parameters, put them in temp. buffer
jsr pusha
ldy #$01
;ldx #$00
lda (sp),y
sta BankNum
ldy #$00
;ldx #$00
lda (sp),y
sta RamAddr
; if Bank #1, jump to lwrextram
lda BankNum
bne lrdextram
; switch to Bank 0
jsr Switch2Bank0
; A = address
; read RAM
lda RamAddr
jsr RdRTC
sta Temp
; exit
lda Temp
ldx #00
jsr incsp2
rts
; read RAM from Bank 1
lrdextram:
jsr Switch2Bank1
; load RAM addr. into extended ram address register
ldx RamAddr
lda #ExtRamAddr
jsr WrRTC
; load RAM value into extended RAM port
lda #ExtRamPort
jsr RdRTC
sta Temp
; switch to Bank 0
jsr Switch2Bank0
; exit
lda Temp
ldx #00
jsr incsp2
rts
.endproc
.segment "CODE"
; helper procedures
;-------------------------------------------------------------------------------
; Write DS1685 address (Acc).
;-------------------------------------------------------------------------------
WrRTCAddr:
sta DSCALADDR
rts
;-------------------------------------------------------------------------------
; Write DS1685 data (Acc).
;-------------------------------------------------------------------------------
WrRTCData:
sta DSCALDATA
rts
;-------------------------------------------------------------------------------
; Read DS1685 data (-> Acc).
;-------------------------------------------------------------------------------
RdRTCData:
lda DSCALDATA
rts
;-------------------------------------------------------------------------------
; Write DS1685 Acc = Addr, X = Data
;-------------------------------------------------------------------------------
WrRTC:
jsr WrRTCAddr
txa
jsr WrRTCData
rts
;-------------------------------------------------------------------------------
; Read DS1685 Acc = Addr -> A = Data
;-------------------------------------------------------------------------------
RdRTC:
jsr WrRTCAddr
jsr RdRTCData
rts
;-------------------------------------------------------------------------------
; Transfer A to return buffer at index Y.
;-------------------------------------------------------------------------------
Tfer2RetBuf:
pha
tya
pha
ldy #$01 ; transfer to return buffer
jsr ldaxysp
jsr pushax
ldx #$00
pla
tay
pla
jsr staspidx
rts
;-------------------------------------------------------------------------------
; Load to A from arguments buffer/stack at index Y.
;-------------------------------------------------------------------------------
GetParFromSpIdx:
tya
pha
ldy #$01 ; get buffer
jsr ldaxysp
sta Temp
pla
tay
lda Temp
jsr ldauidx
rts
;-------------------------------------------------------------------------------
; Swicth to RTC registers in bank 0.
;-------------------------------------------------------------------------------
Switch2Bank0:
lda #$0a ; get register A
jsr RdRTC
and #DSC_REGA_BANK0 ; switch to bank 0
tax
lda #$0a ; write register A
jsr WrRTC
rts
;-------------------------------------------------------------------------------
; Swicth to RTC registers in bank 0.
;-------------------------------------------------------------------------------
Switch2Bank1:
lda #$0a ; get reg. A
jsr RdRTC
ora #DSC_REGA_BANK1 ; switch to bank 1
tax
lda #$0a ; write reg. A
jsr WrRTC
rts
;------------------------------ END OF FILE -------------------------------------
Presented below is the computer now in full glory with PropTermMK device, PC keyboard and small VGA display.
I also added few screenshots of the PropTermMK features and NV RAM access functions in action.
This is all I have time for today. I know I promised to finally publish all firmware code and blueprints to GitHub, but I need to clean up the code some more before I do that and some pressing home improvement projects are now pulling me away from this one.
Thank you for visiting my blog.
MK 6/19/2017