After successfully using port[0]
to read a port value in Turbo Pascal, I thought I'd try to understand how to do this using inline assembly/machine code.
I'm able to write to the port (my OutPort
procedure works fine), but unfortunately my read procedure (InPort
) doesn't work... it just does nothing. Due to my limited assembly/machine code knowledge, I'm unable to see what I'm doing wrong.
Using Turbo Pascal 3.01A (CP/M-80, Z80).
Edit: I'm using an RC2014 with the Digital IO module.
program IOBtnASM;
{$U+}
var i: Byte;
procedure OutPort(Port: Byte; Value: Byte);
begin
inline ($3A/Port/ { ld a,Port }
$4F/ { ld c,a }
$3A/Value/ { ld a,(Value) }
$ED/$79 { out (c),a });
end;
procedure InPort(Port: Byte; var Value: Byte);
begin
(* TODO: This inline doesn't work; read port value using asm/mc *)
inline ($3A/Port/ { ld a,Port }
$4F/ { ld c,a }
$ED/ { out a,(c) }
$3A/Value { ld (Value),a });
end;
begin
writeln('IO Button ASM');
writeln('Using Assembly, light LED when button pressed');
writeln('Press Ctrl+C to break');
while true do
begin
InPort(0, i);
OutPort(0, i);
delay(50);
end;
end.
Edit: Adapted from: Simple Turbo Pascal program to output byte to an I/O port
Edit 2
For reference, the following simpler program works, using port[0]
to read and write. I'm writing it in assembly/machine code for fun.
program IOBtnLED;
{$U+}
var i: integer;
begin
writeln('IO Button LED');
writeln('Light LED when button pressed');
writeln('Press Ctrl+C to break');
while true do
begin
i := port[0];
port[0] := i;
delay(50);
end;
end.
Edit 3
Based on Raffzahn's answer, I tried the following, but unfortunately this still doesn't read the value from the port.
program IOBtnASM;
{$U+}
var i: Byte;
procedure OutPort(Port: Byte; Value: Byte);
begin
inline (
$3A/Port/ { ld a,Port }
$4F/ { ld c,a }
$3A/Value/ { ld a,(Value) }
$ED/$79 { out (c),a }
);
end;
(* Raffzahn's 1st attempt (missing something) *)
procedure InPort(Port: Byte; var Value: Byte);
begin
inline (
$3A/Port/ { ld a,Port }
$4F/ { ld c,a }
$ED/$78/ { in a,(c) }
$32/Value { ld (Value),a }
);
end;
begin
writeln('IO Button ASM');
writeln('Using Assembly, light LED when button pressed');
writeln('Press Ctrl+C to break');
while true do
begin
InPort(0, i);
OutPort(0, i);
delay(50);
end;
end.
Edit 4
Working code, thanks to Raffzahn's very detailed answer: IOBtnASM.pas (don't forget to upvote the answer).
InPort
: SinceValue
is a parameter by reference, I would expect its address for example in HL, not at a static address. An instruction likeld (hl),a
should work then. Unfortunately I don't have the time to check, and no CP/M system at hand at all. -- Why don't you use a function that returns the value? This seems more natural to me.