Mostrando postagens com marcador Joy232. Mostrar todas as postagens
Mostrando postagens com marcador Joy232. Mostrar todas as postagens

segunda-feira, 19 de dezembro de 2016

Nova versão do Joy232

Nova versão do Joy232, que é um programa que intercepta os caraceteres enviados para a impressora e os transmite serialmente pela porta de joystick.

Novidades desta versão (1.3):
  • Código reescrito e otimizado de forma a  caber 64 bytes da fila da RS232 que não é usada no MSX, e portanto não vai ser sobrescrito por outro programa
  • Suporta 14400 bauds (além de 1200,2400,4800,9600 e 19200 bauds)
  • Permite transmitir sem paridade (N) ou com paridade par (E) e ímpar (O)
Mais detalhes na página do projeto no https://hackaday.io/project/18552-joy232



Meus agradecimentos ao Fábio Belavenuto pela SD Mapper! Tem me ajudado pra caramba!!!

E para os apressados:
10 REM
20 REM Joy232 hook code
30 REM danjovic 2016
40 REM version 1.31 19/12/2016
50 REM
60 EI=&HFAF5:SIZE=63
70 FOR A = EI TO EI+SIZE
80 READ B$: POKE A,VAL("&H"+B$)
90 NEXT A
100 REM
110 POKE &HFFB8,&HFA
120 POKE &HFFB7,&HF5
130 POKE &HFFB6,&HC3
140 REM
150 DATA F3,F5,C5,E5,6F,3E,0F,D3
160 DATA A0,26,FF,A7,CB,15,CB,14
170 DATA 06,0B,DB,A2,CB,87,CB,1C
180 DATA CB,1D,CE,00,D3,A1,0E,11
190 DATA 0D,20,FD,10,ED,E1,C1,F1
200 DATA A7,FB,33,33,C9,CE,00,D3
210 DATA A1,0E,06,0D,20,FD,10,ED
220 DATA E1,C1,F1,FB,33,33,C9,00
230 REM
240 REM To change baudrate
250 REM
260 REM POKE &HFB27,value
270 REM
280 REM Baudrate  value
290 REM 1200      170
300 REM 2400      83
310 REM 4800      39
320 REM 9600      17
330 REM 14400     10
340 REM 19200      6
350 REM
360 REM ----------------------
370 REM To use parity
380 REM
390 REM POKE &HF96D,value
400 REM
410 REM Parity    value
420 REM NONE        0 (or 1)
430 REM EVEN        2
440 REM ODD         3


 A conexão ao PC é feito na porta A de Joystick usando-se um adaptador ("dongle") USB-Serial.

terça-feira, 19 de fevereiro de 2008

RX232 - Primeira versão compilável

Integrei hoje a rotina de recepção de um único byte na rotina de recepçao de buffer, e já tenho uma estimativa do tamanho do 'driver' de recepção após compilado: 122 bytes.
Agora tenho que passar um pente fino na lógica, no uso dos registradores e da pilha. Mas eventuais correções não vão alterar sensivelmente o tamanho do código gerado.

Tenho ainda que construir o adaptador RS232 (com um MAX232) para poder testar o hardware.

Segue abaixo o código:
;
; Recepcao serial via
; porta de Joystick do MSX
;
; danjovic@hotmail.com
; http://hotbit.blogspot.com
;
; Versao 0.1 18/02/2008
;
; Licenca de uso: GNU GPL
;
;
; Compilado no ASMSX
; http://www.robsy.net/asmsx.htm

ORG 0E000H

.BASIC
.START RX232

;
; Bits do Registro 14 do PSG
;
BRTS EQU 0 ; UP
BRXD EQU 1 ; DOWN
MRXD EQU 0FDH ; mask for bit BRXD
;
; Bits do Registro 15 do PSG
;
BTXD EQU 2 ; TRG1
BCTS EQU 5 ; TRG2
ABSEL EQU 6 ; A/B Port select

;
; Registros do PSG
;
PSGAD EQU 0A0H
PSGWR EQU 0A1H
PSGRD EQU 0A2H

; Variaveis em RAM
PSGSAV EQU 0F974H ; RS232 putback
; Not used in MSX
;
; Constantes

; BaudRates
;RBAUD EQU 6 ; 19200 Bauds, (6)
;RBAUD EQU 10 ; 14400 Bauds, (10)
RBAUD EQU 18 ; 9600 Bauds, (17-19)
;RBAUD EQU 42 ; 4800 Bauds, (41-43)
;RBAUD EQU 92 ; 2400 Bauds, (90-93)
;RBAUD EQU 190 ; 1200 Bauds, (188-191)

ERFUL EQU 0FFH ; Buffer cheito
ERFRM EQU 0FEH ; Framing error
ERBRK EQU 0FDH ; RTS off antes startbit


RX232:
; Entradas: HL = Ender Buffer em RAM
; C = Tam maximo do buffer
; Saicas : D = Bytes recebidos
; CY = 0, OK
; CY = 1, Error; A=Codigo erro
;
LD A,15
OUT [PSGAD],A
IN A,[PSGRD]
LD [PSGSAV],A
SET ABSEL,A
LD E,A
LD D,0
NEWBYTE: LD A,14
OUT [PSGAD],A
IN A,[PSGRD]
AND A ; Clear carry
BIT BRTS,A
LD A,D
JR NZ,EXIT ; RTS off

LD A,D
CP C
LD A,ERFUL
JR C,EXIT ; Buffer full

PUSH BC
PUSH HL
CALL RECEIVE
POP HL
POP BC
JR C,EXIT ; Error

LD [HL],A ; Save byte
INC HL
INC D ; Incr counter
JR NEWBYTE ; Next byte

EXIT: PUSH AF
LD A,15
OUT [PSGAD],A
LD A,[PSGSAV]
OUT [PSGWR],A
POP AF
RET


RECEIVE:
; Recebe um único caractere
; E - State of PSG register 15
; Currently selected PSG rgister 14
; Return Byte received in Register A

; init local variables
LD B,10 ; bits to receive
LD H,RBAUD ; Baud rate delay
LD L,H
AND A ; Clear CY
RR L ; L= L\2, Half bit timer
SET BCTS,E ; CTS ON

; CTS=ON
; Set PSG register 15
LD A,15
OUT [PSGAD],A
LD A,E
RES BCTS,E ; Reg 15 with CTS OFF
OUT [PSGWR],A

; Set PSG register 14
LD A,14
OUT [PSGAD],A

WAITSTRT: ; Awaits Start Bit
IN A,[PSGRD]
BIT BRXD,A
JR Z,MEIOBIT ;
BIT BRTS,A
JR NZ,WAITSTRT

;Break: RTS went off before
; Start bit
LD A,ERBRK
SCF
RET

; Receive 10 bits
; First is discarded,
; last is the Stop Bit
RXBIT: LD L,H ; Reload delay time

; Delay for bit time
MEIOBIT: DEC L
JR NZ,MEIOBIT

RR C
IN A,[PSGRD]
AND MRXD ; Mask RXD bit
NEG ; RXD to Carry Flag
DJNZ RXBIT ;
; Here Carry contains Stop Bit

; CTS=OFF
; Set PSG register 15
LD A,15
OUT [PSGAD],A
LD A,E ; Reg E has bit CTS off
OUT [PSGWR],A

LD A,ERFRM
CCF ; invert CY to indicate
; Framing error
RET C

LD A,C ; Se sucesso, retorna
RET ; NC, A=byte recebido

segunda-feira, 18 de fevereiro de 2008

Código base RS232

Eis o código da rotina de recepção de "buffer". Agora é preciso adaptar o código da rotina anterior para criar a rotina RXBYTE. Também é preciso acrescentar o código que chaveia do registro 14 para o registro 15 do PSG. Essa operação é necessária devido à arquitetura do PSG

RX232:
; Entradas: HL = Ender Buffer em RAM
; C = Tam maximo do buffer
; Saicas : D = Bytes recebidos
; CY = 0, OK
; CY = 1, Error, A=Codigo erro
;
LD A,15
OUT [PSGAC],A
IN A,[PSGRD]
LD [PSGSAV],A
SET ABSEL,A
LD E,A
LD D,0
NEWBYTE: LD A,14
OUT [PSGAD],A
IN A,[PSGRD]
AND A ; Clear carry
BIT RTS,A
LD A,D
JR NZ,EXIT ; RTS off

LDA A,D
CP C
LD A,ERFUL
JR C,EXIT ; Buffer full

PUSH BC
PUSH HL
CALL RXBYTE
POP HL
POP BC
JR C,EXIT ; Error

LD [HL],A ; Save byte
INC HL
INC D ; Incr counter
JR NEWBYTE ; Next byte

EXIT: PUSH AF
LD A,15
OUT [PSGAD],A
LD A,[PSGSAV]
OUT [PSGWR],A
POP AF
RET

Delineando a rotina de recepção

Após alguns tropeços enquanto escrevia a rotina de recepção de um "buffer", resolvi definir melhor o funcionamento do código que chama a rotina de recepção de dados, do post anterior.

Eis abaixo o fluxograma da rotina, que deve ser chamada com 2 parâmetros:
- Endereço do buffer que vai receber os dados
- Tamanho do buffer de recepção

Uma simplificação importante que fiz, foi que considerar que o buffer está vazio na inícion da chamada da rotina. Isso evita a necessidade de uma chamada de inicialização do buffer e simplifica o tratamento de erros.

Outra vantagem é não depender diretamente de um buffer em RAM para receber temporariamente os caracteres da RS232, o que gerava a necessidade de um LDIR para o destino dos bytes. Com o esquema atual, basta apontar para a região de memória que deve receber os dados e dizer qual o tamanho máximo do buffer de dados.

Caso tudo a recepção tenha se processado corretamente, a quantidade de bytes recebidos é retornada. Caso contrário, um dos códigos de erro é retornado:
  • ERFUL - Buffer Cheiro
  • ERFRA - "Framing error", ou stop bit recebido incorretamente
  • ERBRK - Sinal RTS foi desativado pelo PC antes que o "Start" Bit fosse enviado.


sexta-feira, 15 de fevereiro de 2008

Código para a recepção RS232

Estive trabalhando no código para a recepção RS232 na porta de joystick. .

Eis um trecho da rotina de recepção de dados, que aguarda pelo Start Bit, tão logo ele seja detectado, recebe os 10 bits da palavra de dados, dentro de um só loop, para simplificar a temporização. Ao final da rotina, flag Carry contém o estado do Stop bit. Note que start bit é descartado, pois ele já havia sido detectado.
Outro detalhe importante é que o primeiro delay é de meio bit, e os subsequentes de 1 bit inteiro. Isso faz com que a amostragem seja feita no meio do tempo de bit, diminuindo assim a taxa de erro. Após o stop bit ser amostrado, ainda temos meio tempo de bit disponível, o que é importante, pois é necessário mudar registro do PSG antes de levantar novamente o sinal CTS, para fazer o PC esperar o MSX processar o dado antes de enviar outro.

;...
WAITSTART: IN A,(PSGRD)
BIT RXD,A ; Start bit?
JR Z,MEIOBIT ;yes, wait 1/2 bit before start
; to acquire samples
BIT RTS,A ; PC stopped TX ?
JR Z,WAITSTART ; No, sample again
JP BREAKERROR

MEIOBIT: LD L,BITTIME ;
SRL L ; divide by two
LD B,10 ; Ten bits.
PROXBIT: CALL DELAYBIT ; Wait Bit Time
RR C ; CY->7...0->CY
IN A,(PSGRD) ; Sample bit
AND RXD
NEG ; Bit RXD->CARRY
LD L,BITTIME ; Reload delay preset
DJNZ PROXBIT ; Wait full bit time before
; get another sample
LD A,(15)
OUT (PSGAD),A ; Select Register 15
LD A,E ; Previous state of reg 15
SET RTS,A
OUT (PSGWR),A ; deassert RTS
LD E,A ; Save state of reg15

JR NC,FRAMERR ; If stop bit=0 an framing
; error has occoured
;...
PROCESSABIT:

quinta-feira, 14 de fevereiro de 2008

Recepção serial na porta de Joystick

Fiz uns testes para determinar se o controle de fluxo por RTS/CTS poderia ser utilizado para fazer o PC esperar o MSX atender o pedido de solicitação de transmissão, e também para ver se a transmissão pode ser interrompida a qualquer momento. Os resultados do teste demonstraram que sim.

A correspondência entre os pinos da porta de joystick do MSX e a porta de PC pode ser vista na figura abaixo. Entre os dois deve ser utilizado um conversor de nível, tipo um MAX232.

MSX – Porta Joystick Dir PC – Porta Serial
Função Pino RS232 - Pino RS232
DOWN 2 RxD <- 3 TxD
UP 1 RTS <- 7 RTS
TRGA 6 TxD -> 2 RxD
TRGB 7 CTS -> 8 CTS
GND 9 GND - 5 GND

sexta-feira, 18 de janeiro de 2008

Recepção RS-232 na porta de Joystick

Tenho uma estratégia para poder fazer a parte de recepção, utilizando os sinais RTS e CTS.

O Sinal RTS serve para indicar ao dispositivo de recepção, que o dispositivo de transmissão quer enviar dados. Já o sinal CTS diz é a resposta que o dispositivo de recepção dá ao dispositivo de transmissão de que já pode receber os dados.

Pois bem, utilizando estes sinais é possível sincronizar o MSX com o PC criando assim uma rotina de recepção mais inteligente, de forma a sinalizar ao PC quando este deve aguardar antes de enviar os dados. Desta maneira pode-se perder um tempo salvando o caractere, ou mesmo movendo um buffer.

É possível, por exemplo redirecionar a entrada (de teclado) para ler a partir da RS232 (como no apple) utilizando o hook da interrupção externa do Z80, gerada pelo VDP, que ocorre a 60Hz. O funcionamento é o seguinte:

Quando o VDP gera uma interrupção, a BIOS chama o Hook HTIMI no endereço 0FD9Fh. Neste momento pode-se checar a entrada de joystick para ver se o PC ativou o sinal RTS. Se o sinal RTS não estiver ativo, então não há caracteres a serem enviados e a rotina termina, devolvendo o controle à BIOS.

Mas se o sinal RTS estiver ativo, as interrupções são desabilitadas, e a rotina de recepção de um caractere é chamada. Esta rotina ativa o sinal CTS para indicar ao PC que o MSX está pronto para receber os dados.

O MSX então aguarda pelo start bit, e em seguida recebe os 8 bits do dado, e o stop bit. Depois ela desativa novamente o sinal CTS e vai processar o caractere recebido.

O Stop bit é checado para garantir que é válido. Se for inválido (“0”), então o caractere recebido é ignorado, caso contrário, ele é colocado no buffer do teclado, que é incrementado. Se o buffer estiver cheio, então a rotina termina. Se não estiver, o MSX checa se o sinal RTS ainda está ativo, e se estiver, ele recebe o próximo caractere, caso contrário, retorna

segunda-feira, 14 de janeiro de 2008

Conversor TTL-232 testado

Acabei de testar com sucesso o circuito de conversão TTL para RS-232 do post anterior. Agora o projeto está completo.

LPRINT na porta de Joystick - Código em BASIC

Acabei de testar a impressão via 'hook' na porta de joystick. O código tinha um pequeno erro mas já corrigi.

O programa ocupa apenas 83 na memória e é carregado a partir do endereço &HE000

A listagem abaixo foi capturada utilizando o lprint para o PC, após o programa ter sido executado:


5 '
10 ' Imprime na porta de Joystick B
20 ' via protocolo rs-232, 9600,N,8,1
30 '
40 ' danjovic@hotmail.com
50 '
60 FOR E=0 TO 82
70 READ B$:POKE &HE000+E,VAL("&H"+B$)
80 NEXT E
90 '
100 DEFUSR=&HE047: B=USR(0)
110 '
200 DATA F3,F5,C5,E5,4F,26,12,3E
210 DATA 0F,D3,A0,DB,A2,CB,F7,D3
220 DATA A1,CD,1C,E0,E1,C1,F1,A7
230 DATA FB,33,33,C9,6C,CD,34,E0
240 DATA 06,08,6C,CB,09,DC,3D,E0
250 DATA D4,34,E0,10,F5,2E,12,CD
260 DATA 3D,E0,47,C9,CB,97,D3,A1
270 DATA 2D,C2,38,E0,C9,CB,D7,D3
280 DATA A1,2D,C2,41,E0,C9,00,21
290 DATA 00,E0,22,B7,FF,3E,C3,32
300 DATA B6,FF,C9

domingo, 13 de janeiro de 2008

Conversor TTL-RS232

Fiz o layout de um conversor de nível RS232 para TTL a partir de um esquema que encontrei. Aproveitei apenas a parte de transmissão, que resultou no circuito abaixo.


Fiz o "layout" de uma placa de circuito impresso em face simples, de forma que ficasse o menor possível. Segue abaixo uma imagem em 300 dpi




E a disposiçao dos componentes na placa fica como a figura abaixo:




Os dois conectores são do tipo para cabo (solda) mas são soldados diretamente na placa, um virado para cima e outro virado para baixo. Assim só foi necessário um Jumper para ligar o pino 5 do conector de joystick do MSX (Vcc) ao circuito.

LPRINT na porta de Joystick

Estou trabalhando numa rotina para capturar o Hook de impressão e redirecionar o caractere à porta de joystick. O código, até o presente momento, consome 86 bytes.



;
; Impressao serial via
; porta de Joystick do MSX
;
; danjovic@hotmail.com
; http://hotbit.blogspot.com
;
; Versao 1.0 14/01/2008
;
; Licenca de uso: GNU GPL
;
;
; Compilado no ASMSX
; http://www.robsy.net/asmsx.htm


ORG 0E000H

.BASIC
.START INSTALA



; Bits do Registro 15 do PSG
BTXD EQU 2
ABSEL EQU 6

; Registros do PSG
PSGAD EQU 0A0H
PSGWR EQU 0A1H
PSGRD EQU 0A2H


; BaudRates
;BAUD EQU 6 ; 19200 Bauds, (6)
;BAUD EQU 10 ; 14400 Bauds, (10)
BAUD EQU 18 ; 9600 Bauds, (17-19)
;BAUD EQU 42 ; 4800 Bauds, (41-43)
;BAUD EQU 92 ; 2400 Bauds, (90-93)
;BAUD EQU 190 ; 1200 Bauds, (188-191)



;
; Envia o Caractere no reg A
; para a porta de B (Joystick)
; 9600,8,n,1

PRNTJ232:
;CALL 0a2h
DI
PUSH AF
PUSH BC
PUSH HL

LD C,A ; Caractere a ser impresso
LD H,BAUD ; define taxa Baud

LD A,15 ; Registro 15
OUT [PSGAD],A
IN A,[PSGRD]
;LD [PSGSAV],A
SET ABSEL,A ; Porta Joystick B
OUT [PSGWR],A
;LD B,A ; salva conteudo reg 15

CALL SND232
;LD A,[PSGSAV]
;OUT [PSGWR],A

POP HL
POP BC
POP AF
AND A
EI
INC SP ; descarta stack
INC SP
RET




SND232:
; Entradas:
; C: Byte a ser transmitido
; A: Estado atual do registrador 15 do PSG
; H: Constante para Baud Rate
;

;
; Envia Start bit (txd=0)
;
LD L,H ; 4+1
CALL SND0 ; 17+1 + (SEND0)

;
; 8 bits do dado, LSbit primeiro
;
LD B,08H ; 7+1
S20:
LD L,H ; 4+1
RRC C ; 8+2
CALL C,SND1 ; 17+1 + (SEND0)/ 10+1 F
CALL NC,SND0 ; 17+1 + (SEND0)/ 10+1 F
DJNZ S20 ; 13+1 b


;
; Stopbit - retorna linha txd para IDLE
;
LD L,BAUD ; 8
CALL SND1 ; 17+1 + (SEND1)
LD B,A ; 4+1
RET ; 10+1


;
; Envia um bit 0
;
SND0:
RES BTXD,A ; txd=0 8+2
OUT [PSGWR],A ; 11+1
S01: DEC L ; 4+1
JP NZ,S01 ; 10+1 ;
RET ; 10+1

;
; Envia um bit 1
;
SND1:
SET BTXD,A ; txd=1 8+2
OUT [PSGWR],A ; 11+1
S11: DEC L ; 4+1
JP NZ,S11 ; 10+1 ;
RET ; 10+1


PSGSAV:
DS 1


;
; Instala subrotina no
; HOOK da impressora
;
; Do livro +50 dicas para o MSX
;
HLPT EQU 0FFB6H
;
INSTALA:
LD HL,PRNTJ232
LD [HLPT+1],HL
LD A,0C3H
LD [HLPT],A
RET

sábado, 12 de janeiro de 2008

Serial Bitbang a 19200 bauds na porta de Joystick

Fiz funcionar a rotina de transmissão serial na porta de joystick. Removidos alguns erros de lógica, consegui transmitir para o PC nas seguintes velocidades:

19200 Bauds, (6)
14400 Bauds, (10)
9600 Bauds, (17-19)
4800 Bauds, (41-43)
2400 Bauds, (90-93)
1200 Bauds, (188-191)

Toda a temporização é feita por software. Os números em parênteses são o parâmetro de temporização. As velocidades de 14400 e 19200 são meio críticas, mas funcionam bem.

A conexão com o PC é através do pino 6 da porta de Joystick B. Eu utilizei um MAX232, alimentado pelo pino 5 (Vcc), mas há outras alternativas[1], [2], embora eu ainda não as tenha testado.

O código fonte encontra-se abaixo.

;
; Rotinas de impressão na porta
; de Joystick do MSX
;
; danjovic@hotmail.com
; http://hotbit.blogspot.com
;
; Versao 0.5 12/01/2008
;
; Licenca de uso: GNU GPL
;
;


ORG 09000H

; Compilado no ASMSX
; http://www.robsy.net/asmsx.htm
.BASIC
.START PRNTJ232

;
; Bits do Registro 15 do PSG
;
BTXD EQU 2
BPLS EQU 5
ABSEL EQU 6

;
; Registros do PSG
;
PSGAD EQU 0A0H
PSGWR EQU 0A1H
PSGRD EQU 0A2H


;
; Constantes

; BaudRates
;BAUD EQU 6 ; 19200 Bauds, (6)
;BAUD EQU 10 ; 14400 Bauds, (10)
BAUD EQU 18 ; 9600 Bauds, (17-19)
;BAUD EQU 42 ; 4800 Bauds, (41-43)
;BAUD EQU 92 ; 2400 Bauds, (90-93)
;BAUD EQU 190 ; 1200 Bauds, (188-191)


;
; Rotina de teste de impressão
; na porta de Joystick
;



PRNTJ232:
DI
LD A,15
OUT [PSGAD],A
IN A,[PSGRD]
LD [PSGSAV],A

SET ABSEL,A ; JOY B
SET BTXD,A ; SDA=1

SYNC:
SET BPLS,A ; start sync
OUT [PSGWR],A
NOP
NOP
NOP
NOP
RES BPLS,A ; stop sync
OUT [PSGWR],A
LD B,A ; B=conteudo reg 15

MUDABAUD:
LD H,BAUD
LD DE,MENSAGEM
REPETE:
LD A,[DE]
INC DE
OR A
JR Z,FIM
LD C,A
CALL SND232
JR REPETE

FIM:
EI
RET


MENSAGEM:
DB "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG 0123456789 ",0

PSGSAV:
DS 1


SND232:
; Entradas:
; C: Byte a ser transmitido
; B: Estado atual do registrador 15 do PSG
; H: Constante para Baud Rate
;
; Modifica A,F,B,C,L

LD A,B ; B=Estado registro 15 PSG

;
; Start bit (txd=0)
;
LD L,H ; 4+1
CALL SND0 ; 17+1 + (SEND0)

;
; 8 bits do dado, LSbit primeiro
;
LD B,08H ; 7+1
S20:
LD L,H ; 4+1
RRC C ; 8+2
CALL C,SND1 ; 17+1 + (SEND0)/ 10+1 F
CALL NC,SND0 ; 17+1 + (SEND0)/ 10+1 F
DJNZ S20 ; 13+1 b<>0/ 8+1 b=0

;
; Stopbit - retorna linha txd para IDLE
;
LD L,BAUD ; 8
CALL SND1 ; 17+1 + (SEND1)
LD B,A ; 4+1
RET ; 10+1


;
; Envia um bit 0
;
SND0:
RES BTXD,A ; txd=0 8+2
OUT [PSGWR],A ; 11+1
S01: DEC L ; 4+1
JP NZ,S01 ; 10+1 ;
RET ; 10+1

;
; Envia um bit 1
;
SND1:
SET BTXD,A ; txd=1 8+2
OUT [PSGWR],A ; 11+1
S11: DEC L ; 4+1
JP NZ,S11 ; 10+1 ;
RET ; 10+1




sexta-feira, 9 de novembro de 2007

Enviando dados via RS232 na porta de Joystick

Em muitos microcontroladores sem UART real é comum emular este periférico gerando os bits, um a um, via Software. Mas para fazer isso é necessário saber exatamente o tempo de execução de cada instrução, de forma a se produzir as temporizações corretas.

No MSX deve-se levar em consideração não somente os ciclos de máquina gastos com cada instrução, mas também o WAIT STATE inserido a cada ciclo M1.

O Ciclo M1 é gerado durante a busca de instruções do Z80 ("opcode fetch"), mas há algumas instruções onde esse ciclo ocorre mais de uma vez, ou seja, é necessário somar um ciclo a mais para cada ciclo M1 gerado.

Um exemplo é a instrução NEG:

INSTR BYTES M1
NEG 2 OCF(4)/OCF(4)
Esta instrução gasta ao todo 10 ciclos de máquina para ser executada no MSX.

Uma relação completa das instruções do Z80, bem como da quantidade de ciclos por instrução, e a quantidade de ciclos M1 pode ser encontrada neste link: http://www.z80.info/z80ins.txt

A rotina abaixo envia um byte recebido no registrador A pelo pino 6 da porta B de joystick.


;
; Bits do Registro 15 do PSG
;
BTXD EQU 2
ABSEL EQU 6

;
; Registros do PSG
;
PSGAD EQU 0A0H
PSGWR EQU 0A1H
PSGRD EQU 0A2H


;
; Constantes

; BaudRates
;BAUD EQU 8 ; 19200 Bauds, -0.32% erro
;BAUD EQU 14 ; 14400 Bauds, -1.8% erro
BAUD EQU 25 ; 9600 Bauds, -0.32% erro
;BAUD EQU 59 ; 4800 Bauds, -0.32% erro
;BAUD EQU 127; 2400 Bauds, -0.32% erro
;BAUD EQU 255 ;1200 Bauds, 2.6% erro



;
; A: Byte a ser transmitido
; B: Estado atual do registrador 15 do PSG
;
SND232:
LD C,A
LD A,B

; Start bit
LD L,BAUD
CALL SND0 ; 17+1 + (SEND0)

; 8 bits
LD B,08H ; 7+1
LD L,BAUD ; 8

S20:
RRC C ; 8+2
CALL C,SND1 ; 17+1 + (SEND0)/ 10+1 F
CALL NC,SND0 ; 17+1 + (SEND0)/ 10+1 F
DJNZ S20 ; 13+1 b<>0/ 8+1 b=0

; Stopbit - return line to IDLE state
LD L,BAUD ; 8
CALL SND1 ; 17+1 + (SEND0)
LD B,A ; 4+1
RET ; 10+1


SND0:
RES BTXD,A ; txd=0 8+2
OUT [PSGWR],A ; 11+1
S01: DEC L ; 4+1
JP NZ,S01 ; 10+1 ;
RET ; 10+1


SND1:
SET BTXD,A ; txd=1 8+2
OUT [PSGWR],A ; 11+1
S01: DEC L ; 4+1
JP NZ,S01 ; 10+1 ;
RET ; 10+1


E Antes de imprimir, é necessário desabilitar as interrupções e inicializar o registro 15:
PRNTJ232:
DI
LD A,15
OUT [PSGAD],A
IN A,[PSGRD]
LD [PSGSAV],A

SET ABSEL,A ; JOY B
SET BTXD,A ; SDA=1
OUT [PSGWR],A
LD B,A