Refactored ASM, added sound support

This commit is contained in:
Daniele Verducci su MatissePenguin 2020-12-06 15:51:26 +01:00
parent 97795c8111
commit 41b746525a
7 changed files with 241 additions and 55 deletions

View File

@ -5,19 +5,20 @@
* The Arduino IDE serial monitor is used to send and receive commands to the Z80.
*/
// EN 2 // Active low
// WR 11 // Active low
// DATA BUS IS: 3, 4, 5, 6, 7, 8, 9, 10;
// EN 2 // Input, Active low
// WR 11 // Input, Active low
// DATA BUS (Input/Output, active high): 3, 4, 5, 6, 7, 8, 9, 10;
byte incomingBuffer = 0; // Incoming from computer, to the Pat80
byte outgoingBuffer = 0; // Outgoing to computer, from the Pat80
void setup() {
Serial.begin(2000000);
Serial.println("Pat80 terminal");
void setup() {
DDRD = B00000010; // Port D (used arduino pins 2 (EN) and 3 to 7 (DATA)) is input. Avoid changing serial pins.
DDRB = B00000000; // Port B (used arduino pins 8 to 10 (DATA) and 11 (WR)) is input
Serial.begin(2000000);
Serial.println("Pat80 terminal");
attachInterrupt(digitalPinToInterrupt(2), onClk, CHANGE);
}
@ -35,6 +36,7 @@ void loop() {
Serial.print(outgoingBuffer, HEX);
Serial.print("]");
}
outgoingBuffer = 0;
}
}
@ -42,14 +44,15 @@ void onClk() {
// In any case, return to high impedance state
DDRD = B00000010;
DDRB = B00000000;
if (PIND & B00000100 == B00000000) {
if ((PIND & B00000100) == 0) {
// EN is LOW: Clock pulse started
if (PINB & B00001000 == B00001000) { // WR is HIGH (Pat80 wants to Read (we send data))
if ((PINB & B00001000) == B00001000) { // WR is HIGH (Pat80 wants to Read (we send data))
DDRD = DDRD | B11111000; // Port D (arduino pins 3 to 7) is output. In or to preserve serial pins and interrupt pin
DDRB = B00000111; // Port B (0,1,2) = pins 8,9,10 output
// Split byte to two parts
PORTD = incomingBuffer << 3;
PORTB = incomingBuffer >> 5;
incomingBuffer = 0;
} else {
// Pat80 wants to Write (we receive data)
outgoingBuffer = (PIND >> 3) | (PINB << 5); // Compose the final byte from the two parts

View File

@ -5,11 +5,8 @@
; call Snd_init <-- inits sound (and silences default tone)
; call Snd_beep <-- system beep
; Sound card is on port 0
SND_DATA_REG: EQU IO_0
; Settings
SND_BEEP_DURATION: EQU 1000 ; in cpu cycles
; Sound card is on port 1
SND_DATA_REG: EQU IO_1
; Init device (silence all channels)
; Bits meaning:
@ -42,8 +39,8 @@ Snd_beep:
out (SND_DATA_REG),a
ld a,%00001000
out (SND_DATA_REG),a
; wait 1 sec
ld bc, 10
; wait
ld bc, (TIME_DUR_MILLIS * 150)
call Time_delay55
; silence ch1
ld a,%10011111

View File

@ -0,0 +1,103 @@
; Vgax display driver
; @author Daniele Verducci
;
; Requires declaration of following pointers:
; VGAX_INSTR_REG
; VGAX_DATA_REG
; variables
lcd_cur_x: EQU DRV_VAR_SPACE
lcd_cur_y: EQU lcd_cur_x + 1
; functions
; Inits the lcd display
Lcd_init:
;reset procedure
ld a,0x38
out (LCD_INSTR_REG),a
ld a,0x08
out (LCD_INSTR_REG),a
ld a,0x01
out (LCD_INSTR_REG),a
;init procedure
ld a,0x38
out (LCD_INSTR_REG),a
ld a,0x0F
out (LCD_INSTR_REG),a
ret
; Writes text starting from current cursor position
; @param BC Pointer to a null-terminated string first character
Lcd_print:
ld a, (bc) ; bc is the pointer to passed string's first char
cp 0 ; compare A content with 0 (subtract 0 from value and set zero flag Z if result is 0)
ret z ; if prev compare is true (Z flag set), string is finished, return
out (LCD_DATA_REG),a ; output char
inc bc ; increment bc to move to next char
; increment x position
ld a, (lcd_cur_x)
inc a
ld (lcd_cur_x), a
; if x position > 19, increment y position and set x to 0
ld a, (lcd_cur_x)
cp 20
jp nz, Lcd_print ; if x position is not 20, continue cycle
ld a, 0
ld (lcd_cur_x), a ; else set x to 0
; and increment y
ld a, (lcd_cur_y)
inc a
ld (lcd_cur_y), a
; if y > 3 set y to 0
cp 4 ; a still contains lcd_cur_y: compare with 4
jp nz, Lcd_print ; if y position is not 4, continue cycle
ld a, 0
ld (lcd_cur_x), a ; else set y pos to 0
jp Lcd_print
ret
; Writes a single character at current cursror position
; @param A Value of character to print
Lcd_printc:
out (LCD_DATA_REG),a
ret
; Set cursor position
; @param B X-axis position (0 to 19)
; @param C Y-axis position (0 to 3)
Lcd_locate:
ld a, b
ld (lcd_cur_x), a
ld a, c
ld (lcd_cur_y), a
call lcd_locate
ret
; private
; The cursor position can seem like black magic but it makes much more sense once you know that the HD44780 is designed to control a 40 character 4-line display. So if you have a 16×2 then you will only see the first 16 characters of the top two lines. Simple enough once you get used to taking these character positions into account. For example, in a 16×2 display, the first line is position 0-15. So 0x80 is the first position, 0x80 + 12 = 0x8C is the 13th (remember, they are zero indexed). The second line is a little tricky since it shows positions 64-79. Just add the position number (in decimal) to 0x80 (in hex) to get the hex address of the cursor position. The address is the command to move the cursor to that location. So, to move to the 13th position of the top line in a 16×2 Sparkfun Display, I would send “0xFE 0x8C”. The first byte warns the onboard microcontroller that a command is coming, and the second byte is the command.
lcd_locate:
; warns the lcd microcontroller that a command is coming
ld a, 0xFE
out (LCD_INSTR_REG),a
; get line start command code from array
ld hl, LCD_LINES_LEFT ; load array pointer
ld bc, lcd_cur_y ; load line number
ld b, 0 ; since line number is only 8 bit, clean garbage on the upper bit
add hl, bc ; sum first array element to line number to access correct array element. Now hl contains array pointer
; now sum x offset to the start line code to obtain lcd controller complete position code
ld a, (lcd_cur_x) ; load cursor x position
add a, (hl) ; sum cursor x pos to line start code. Result is in a
out (LCD_INSTR_REG),a ; send cursor position to lcd controller
ret
; Clears the screen
Lcd_cls:
ld a,0x01
out (LCD_INSTR_REG),a ; clear display
ld a,0x02
out (LCD_INSTR_REG),a ; cursor to home (top left)
ret

View File

@ -1,8 +1,9 @@
; Time library
; @author Daniele Verducci
; Duration (change these values based on CPU frequency)
TIME_DUR_SECOND: EQU 255
; Duration in cpu cycles / 55 (change these values based on CPU frequency)
TIME_DUR_SECOND: EQU (2545)
TIME_DUR_MILLIS: EQU 3
; Wait bc * 55 states
; Use 1 iteration as delay between I/O bus writes

View File

@ -10,8 +10,8 @@ jp Sysinit ; Startup vector: DO NOT MOVE! Must be the first instruction
; DRIVERS VAR SPACE: 0x9000 - 0x9FFF (4kb)
; APPLICATION VAR SPACE: 0xA000 - 0xFFFF (24kb)
; I/O MAP
; I/O 0 (0x00 - 0x1F) LCD (uses 0x00 and 0x01)
; I/O 1 (0x20 - 0x3F)
; I/O 0 (0x00 - 0x1F) Parallel terminal (uses addr 0x00 only)
; I/O 1 (0x20 - 0x3F) Sound card (uses addr 0x20 only)
; I/O 2 (0x40 - 0x5F)
; I/O 3 (0x60 - 0x7F)
; I/O 4 (0x80 - 0x9F)
@ -42,46 +42,60 @@ IO_7: EQU 0xE0
;include 'drivers/hd44780.asm'
;include 'drivers/keyboard.asm'
;include 'drivers/arduino_terminal.asm'
include 'drivers/arduino_terminal.asm'
include 'drivers/sn76489.asm'
;include 'monitor.asm'
include 'monitor.asm'
include 'libs/time.asm'
;include 'tests/sndtest.asm'
; SYSTEM CALLS
; User I/O
; **** SYSTEM CALLS ****
; ; Prints string
; ; @param BC Pointer to a null-terminated string first character
; Print:
; call Term_print
; ret
; Prints string
; @param BC Pointer to a null-terminated string first character
Print:
call Term_print
ret
; ; Writes a single character
; ; @param A Value of character to print
; Printc:
; call Term_printc
; ret
; Writes a single character
; @param A Value of character to print
Printc:
call Term_printc
ret
; ; Reads a single character
; ; @return A The read character
; Readc:
; call Term_readc
; ret
; Reads a single character
; @return A The read character
Readc:
call Term_readc
ret
; ; Reads a line
; ; @return BC The pointer to a null-terminated read string
; Readline:
; call Term_readline
; ret
; Reads a line
; @return BC The pointer to a null-terminated read string
Readline:
call Term_readline
ret
; System initialization
Sysinit:
; Start Monitor
;call Monitor_main
call Snd_init
ld bc, 10
call Time_delay55
; Emits system beep
Beep:
call Snd_beep
ret
; **** SYSTEM INITIALIZATION ****
Sysinit:
; Init snd driver
call Snd_init
; Init video
; TODO
; Wait for audio amp to unmute
ld bc, TIME_DUR_SECOND
call Time_delay55
; Play startup sound
call Beep
; Run memory monitor
call Monitor_main
halt

View File

@ -5,7 +5,7 @@
; H (HELP) Shows available commands
; D (DUMP) $pos Dumps first 100 bytes of memory starting at $pos
; S (SET) $pos $val Replaces byte at $pos with $val
; L (LOAD) $pos $val
; L (LOAD) $pos $val
; R (RUN) $pos Starts executing code from $pos
; I (IMMEDIATE) Loads all the incoming bytes in application memory starting from $pos. When "0" is received 8 times starts executing the loaded code.
; The commands are entered with a single letter and the program completes the command
@ -60,9 +60,10 @@ Monitor_main:
ld hl, MON_COMMAND_IMMEDIATE
cp (hl)
jp z, monitor_immediate
; Unrecognized command: print error
; Unrecognized command: print error and beep
ld bc, MON_ERR_SYNTAX
call Print
call Beep
jp monitor_main_loop
monitor_help:
@ -104,7 +105,7 @@ monitor_immediate:
call Readc
ld (bc), a
cp a, 0
jmp z monitor_immediate_copyToAppSpace ; così esce al primo 0 che trova, ovviamente invece vogliamo aspettare 8 zeri
;jmp z monitor_immediate_copyToAppSpace ; così esce al primo 0 che trova, ovviamente invece vogliamo aspettare 8 zeri
jp APP_SPACE ; Start executing code
jp monitor_main_loop

View File

@ -0,0 +1,67 @@
SndTest_test:
; ch1 max volume
ld a,%10010000
out (SND_DATA_REG),a
; play note ch1
ld a,%10000000
out (SND_DATA_REG),a
ld a,%00100000
out (SND_DATA_REG),a
; wait
ld bc, 1200
call Time_delay55
; ch2 max volume
ld a,%10110010
out (SND_DATA_REG),a
; play note ch2
ld a,%10100000
out (SND_DATA_REG),a
ld a,%00010000
out (SND_DATA_REG),a
; wait
ld bc, 1200
call Time_delay55
; ch3 max volume
ld a,%11010100
out (SND_DATA_REG),a
; play note ch3
ld a,%11000000
out (SND_DATA_REG),a
ld a,%00001000
out (SND_DATA_REG),a
; wait
ld bc, 2400
call Time_delay55
; fade ch1,ch2,ch3
ld d, 0 ; attenuation
sndTest_fade: ; BROKEN!
inc d
; update ch1 atten
ld a, d ; use A as attenuation
and %10010000; place channel number in upper bits to compose attenuation byte
out (SND_DATA_REG),a
; update ch2 atten
ld a, d ; use A as attenuation
and %10110010; place channel number in upper bits to compose attenuation byte
out (SND_DATA_REG),a
; update ch3 atten
ld a, d ; use A as attenuation
and %11010100; place channel number in upper bits to compose attenuation byte
out (SND_DATA_REG),a
; wait
ld bc, 100
call Time_delay55
; cycle until attenuation is 1111
cp d %1111
jp nz, sndTest_fade
; wait
ld bc, 2400
call Time_delay55
; play noise
ret