Refactored ASM, added sound support
This commit is contained in:
parent
97795c8111
commit
41b746525a
@ -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
|
||||
|
@ -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
|
||||
|
103
assembly/bios/drivers/vgax.asm
Normal file
103
assembly/bios/drivers/vgax.asm
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
67
assembly/bios/tests/sndtest.asm
Normal file
67
assembly/bios/tests/sndtest.asm
Normal 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
|
Loading…
x
Reference in New Issue
Block a user