.Z80 ASEG ; absolute addressing ORG 100h ; skip CP/M CR EQU 0Dh ; carriage return LF EQU 0Ah ; new line BDOS EQU 0005h ; BDOS entry point PSTR EQU 09h ; print string CRED EQU 01h ; read console FOPE EQU 0Fh ; file open FRED EQU 14h ; file read next record FCB EQU 5Ch ; File Control Block FCBFNAME EQU FCB+01h ; FCB File Name FCBEX EQU FCB+0Ch ; FCB Excent Number FCBRC EQU FCB+0Fh ; FCB Record Count FCBCR EQU FCB+20h ; FCB Current Record FB EQU 80h ; File Buffer OLED EQU 50h ; base addr of OLED card ORST EQU 04h ; reset command (H) OBUF EQU 02h ; chip select (L), buffer (H) ODB EQU 01h ; display byte (H) OCMD EQU 00h ; command (L) ; 4 rows of display OROWA EQU 0B0h ; select top row OROWB EQU 0B1h ; select second row OROWC EQU 0B2h ; select third row OROWD EQU 0B3h ; select bottom row OCOL0 EQU 04h ; left most column OSELC EQU 10h ; select column command OCOL EQU 80h ; column count: 128 columns ; 128 columns from 4 to 131 ; 1Xh, 0Yh - XY = 04h to 83h ; MAIN CALL OINIT ; init OLED CALL OCLS ; clear screen CALL OCSTART ; go to start LD A,(FCBFNAME) ; load first char of file name CP ' ' ; check file name provided JP NZ,MAIN1 CALL PROMPTREAD ; read from prompt RET ; exit to CP/M MAIN1: CALL FILEREAD ; read from file RET ; exit to CP/M PROMPTREAD: LD DE,MSGPROMPT CALL PRINT ; print prompt CALL READLINE ; read row A CALL READLINE ; read row B CALL READLINE ; read row C CALL READLINE ; read row D RET FILEREAD: LD DE,MSGFILEREAD CALL PRINT ; print reading from file XOR A LD (FCBEX),A ; select 0'th extent LD (FCBRC),A ; clear LD (FCBCR),A ; select 0'th record LD C,FOPE ; open file LD DE,FCB ; use default FCB CALL BDOS CP 0FFh ; is error JP Z,FILEREAD1 XOR A LD (FCBCR),A ; start from beginning CALL READRECORD ; read 128 byte record CALL READRECORD CALL READRECORD CALL READRECORD RET FILEREAD1: LD DE,MSGOPENERR CALL PRINT LD A,0FFh RET READLINE: LD D,OCOL ; number of columns READLINE1: PUSH DE CALL READHEX ; read hex input from console CALL ODATA ; write to OLED POP DE DEC D ; count down columns JP NZ,READLINE1 ; next column RET ; reads block using default FCB ; A=0 - OK ; A=FFh - error READRECORD: LD C,FRED ; read file LD DE,FCB ; use default FCB CALL BDOS CP 0 ; check status code JP NZ,READRECORD1 LD D,OCOL ; bytes to read LD HL,FB ; start of file buffer READRECORD0: LD A,(HL) ; load byte PUSH DE PUSH HL CALL ODATA ; send to oled POP HL POP DE INC HL ; next byte DEC D ; count columns down JP NZ,READRECORD0 RET READRECORD1: LD DE,MSGREADERR CALL PRINT LD A,0FFh ; error RET OINIT: CALL ORESET ; reset OLED LD HL,OINITSEQ ; commands to send OINITLOOP: LD A,(HL) ; load command byte to A CP 0FFh ; check if we are done RET Z ; marker reached CALL OCOMMAND ; send command from A INC HL ; next command JR OINITLOOP ; do next command ORESET: LD C,OLED ; base I/O address LD B,ORST OR OBUF ; RST H, /CS H, DB L OUT (C),A ; write any A, to (C) + B REPT 4 NOP ; delay ENDM LD B,OBUF ; clear RST OUT (C),A ; send REPT 20 NOP ; long delay ENDM RET OCLS: CALL OCSTART ; set start CALL OCLSROW ; clear row A CALL OCLSROW ; clear row B CALL OCLSROW ; clear row C CALL OCLSROW ; clear row D RET ; set cursor to start OCSTART: LD A,OSELC ; select column CALL OCOMMAND LD A,OCOL0 ; column 0 CALL OCOMMAND LD A,OROWA ; select first row CALL OCOMMAND RET OCLSROW: ;XOR A ; display byte to write (0) LD A,0FFh ; turn on all pixels LD D,OCOL ; count columns in D OCLSROW1: CALL ODATA ; write A to displey DEC D ; next column JR NZ,OCLSROW1 RET ; A = command to send to OLED OCOMMAND: LD C,OLED ; base I/O LD B,OCMD ; send command OUT (C),A ; send REPT 4 NOP ENDM LD B,OCMD OR OBUF OUT (C),A ; send REPT 10 NOP ENDM RET ; Write to OLED memory ; A = graphic byte to dispaly memory ODATA: LD C,OLED ; base I/O LD B,ODB ; select Data Byte mode OUT (C),A ; output byte REPT 4 NOP ENDM LD B,OBUF OR ODB OUT (C),A ; output byte NOP NOP RET ; Read byte from console READ: LD C,CRED ; read from console CALL BDOS ; call CP/M RET ; A=char ; Reads 4 bit value (0-F) READNIB: CALL READ LD B,41h ; compare with 'A' (10) CP B JP NC,RNB1 ; A>=B SUB 30h ; sub '0' RET RNB1: SUB 41h-10 ; sub 'A'-10 AND 0Fh ; clear to 4 bits so 'a-f' also work RET ; Reads two bytes (0-F) from console ; A = byte read READHEX: CALL READNIB ; read MSD nibble SLA A ; shift 4 bits SLA A SLA A SLA A LD B,A ; B=A PUSH BC ; save B CALL READNIB ; read LSD nibble POP BC ; restore B OR B ; OR B to A RET ; DE - address to $ terminated string PRINT: LD C,PSTR ; load function number CALL BDOS ; call CP/M RET MSGPROMPT: DB 'OLED:>', CR, LF,'$' ; string terminated with $ MSGFILEREAD: DB 'Reading from file', CR, LF, '$' MSGOPENERR: DB 'Error opening file', CR, LF, '$' MSGREADERR: DB 'Error reading file', CR, LF, '$' ; Initialization sequence ; 081h,080h - set contrast (080h full) ; 020h,000h - set horizontal window wrapping ; 021h,004h,083h - window full width ; 022h,000h,003h - window full height OINITSEQ: DB 0AEh,0D5h,0A0h,0A8h DB 01Fh,0D3h,000h,0ADh DB 08Eh,0D8h,005h,0A1h DB 0C8h,0DAh,012h,091h DB 03Fh,03Fh,03Fh,03Fh DB 081h,070h,0D9h,0D2h DB 0DBh,034h,0A6h,0A4h DB 0AFh,020h,000h,021h DB 004h,083h,000h,003h DB 0FFh ; end marker END